aboutsummaryrefslogtreecommitdiff
path: root/desiredata/src
diff options
context:
space:
mode:
authorIOhannes m zmölnig <zmoelnig@users.sourceforge.net>2008-02-08 13:00:32 +0000
committerIOhannes m zmölnig <zmoelnig@users.sourceforge.net>2008-02-08 13:00:32 +0000
commit4d84d14ac1aa13958eaa2971b03f7f929a519105 (patch)
tree6579d3f2cea5410a10c4baac8d0f372fb0dff372 /desiredata/src
parentb334d38aefbd8e0e159d7af6c20d63c5d2b64859 (diff)
reorganized
svn path=/trunk/; revision=9400
Diffstat (limited to 'desiredata/src')
-rw-r--r--desiredata/src/ChangeLog233
-rw-r--r--desiredata/src/TODO454
-rw-r--r--desiredata/src/bgerror.tcl254
-rw-r--r--desiredata/src/builtins.c3060
-rw-r--r--desiredata/src/builtins_dsp.c3844
-rw-r--r--desiredata/src/config.h.in5
-rwxr-xr-xdesiredata/src/configure6562
-rw-r--r--desiredata/src/configure.in213
-rwxr-xr-xdesiredata/src/cvs-switch-user5
-rw-r--r--desiredata/src/d_fftroutine.c999
-rw-r--r--desiredata/src/d_mayer_fft.c422
-rw-r--r--desiredata/src/d_soundfile.c2059
-rw-r--r--desiredata/src/d_ugen.c1016
-rw-r--r--desiredata/src/defaults.ddrc193
-rw-r--r--desiredata/src/desire.c7332
-rw-r--r--desiredata/src/desire.h353
-rw-r--r--desiredata/src/desire.tk9019
-rw-r--r--desiredata/src/dzinc.tcl157
-rw-r--r--desiredata/src/icons/array.gifbin0 -> 129 bytes
-rw-r--r--desiredata/src/icons/bang.gifbin0 -> 123 bytes
-rw-r--r--desiredata/src/icons/canvas.gifbin0 -> 89 bytes
-rw-r--r--desiredata/src/icons/comment.gifbin0 -> 108 bytes
-rw-r--r--desiredata/src/icons/graph.gifbin0 -> 115 bytes
-rw-r--r--desiredata/src/icons/hradio.gifbin0 -> 104 bytes
-rw-r--r--desiredata/src/icons/hslider.gifbin0 -> 115 bytes
-rw-r--r--desiredata/src/icons/message.gifbin0 -> 82 bytes
-rw-r--r--desiredata/src/icons/mode_edit.gifbin0 -> 90 bytes
-rw-r--r--desiredata/src/icons/mode_run.gifbin0 -> 85 bytes
-rw-r--r--desiredata/src/icons/number.gifbin0 -> 84 bytes
-rw-r--r--desiredata/src/icons/number2.gifbin0 -> 83 bytes
-rw-r--r--desiredata/src/icons/object.gifbin0 -> 121 bytes
-rw-r--r--desiredata/src/icons/symbol.gifbin0 -> 91 bytes
-rw-r--r--desiredata/src/icons/toggle.gifbin0 -> 116 bytes
-rw-r--r--desiredata/src/icons/vradio.gifbin0 -> 112 bytes
-rw-r--r--desiredata/src/icons/vslider.gifbin0 -> 114 bytes
-rw-r--r--desiredata/src/icons/vu.gifbin0 -> 106 bytes
-rw-r--r--desiredata/src/install-sh251
-rw-r--r--desiredata/src/iostream.txt61
-rw-r--r--desiredata/src/kb-mode.tcl210
-rw-r--r--desiredata/src/kernel.c2348
-rw-r--r--desiredata/src/locale/bokmal.tcl453
-rw-r--r--desiredata/src/locale/brasiliano.tcl577
-rw-r--r--desiredata/src/locale/catala.tcl58
-rw-r--r--desiredata/src/locale/chinese.tcl560
-rw-r--r--desiredata/src/locale/dansk.tcl564
-rw-r--r--desiredata/src/locale/deutsch.tcl280
-rw-r--r--desiredata/src/locale/english.tcl573
-rw-r--r--desiredata/src/locale/espanol.tcl526
-rw-r--r--desiredata/src/locale/euskara.tcl554
-rw-r--r--desiredata/src/locale/francais.tcl539
-rw-r--r--desiredata/src/locale/index.tcl21
-rw-r--r--desiredata/src/locale/italiano.tcl544
-rwxr-xr-xdesiredata/src/locale/localeutils.tcl109
-rw-r--r--desiredata/src/locale/nederlands.tcl599
-rw-r--r--desiredata/src/locale/nihongo.tcl574
-rw-r--r--desiredata/src/locale/polski.tcl557
-rw-r--r--desiredata/src/locale/portugues.tcl119
-rw-r--r--desiredata/src/locale/russkij.tcl574
-rw-r--r--desiredata/src/locale/turkce.tcl572
-rw-r--r--desiredata/src/m_atomic.h55
-rw-r--r--desiredata/src/m_fifo.c443
-rw-r--r--desiredata/src/m_pd.h936
-rw-r--r--desiredata/src/m_sched.c654
-rw-r--r--desiredata/src/m_simd.c145
-rw-r--r--desiredata/src/m_simd.h82
-rw-r--r--desiredata/src/m_simd_sse_gcc.c1131
-rw-r--r--desiredata/src/m_simd_ve_gcc.c748
-rw-r--r--desiredata/src/m_simd_ve_gcc.h18
-rw-r--r--desiredata/src/main.c17
-rw-r--r--desiredata/src/makefile.in122
-rw-r--r--desiredata/src/notes.txt300
-rw-r--r--desiredata/src/pkgIndex.tcl15
-rwxr-xr-xdesiredata/src/plusminus42
-rw-r--r--desiredata/src/poe.tcl281
-rw-r--r--desiredata/src/pre8.5.tcl209
-rw-r--r--desiredata/src/profile_dd.tcl20
-rw-r--r--desiredata/src/rules.txt42
-rw-r--r--desiredata/src/s_audio.c724
-rw-r--r--desiredata/src/s_audio_alsa.c594
-rw-r--r--desiredata/src/s_audio_alsa.h40
-rw-r--r--desiredata/src/s_audio_alsamm.c889
-rw-r--r--desiredata/src/s_audio_asio.cpp1014
-rw-r--r--desiredata/src/s_audio_jack.c381
-rw-r--r--desiredata/src/s_audio_mmio.c571
-rw-r--r--desiredata/src/s_audio_oss.c532
-rw-r--r--desiredata/src/s_audio_pa.c332
-rw-r--r--desiredata/src/s_audio_pablio.c304
-rw-r--r--desiredata/src/s_audio_pablio.h112
-rw-r--r--desiredata/src/s_audio_paring.c172
-rw-r--r--desiredata/src/s_audio_paring.h101
-rwxr-xr-xdesiredata/src/s_audio_portaudio.c416
-rw-r--r--desiredata/src/s_audio_sgi.c313
-rw-r--r--desiredata/src/s_inter.c732
-rw-r--r--desiredata/src/s_loader.c196
-rw-r--r--desiredata/src/s_main.c632
-rw-r--r--desiredata/src/s_midi.c619
-rw-r--r--desiredata/src/s_midi_alsa.c209
-rw-r--r--desiredata/src/s_midi_mmio.c505
-rw-r--r--desiredata/src/s_midi_none.c16
-rw-r--r--desiredata/src/s_midi_oss.c234
-rw-r--r--desiredata/src/s_midi_pm.c239
-rw-r--r--desiredata/src/s_midi_sgi.c143
-rw-r--r--desiredata/src/s_path.c350
-rw-r--r--desiredata/src/s_stuff.h321
-rw-r--r--desiredata/src/s_watchdog.c40
-rw-r--r--desiredata/src/tests/abstr-test.pd3
-rw-r--r--desiredata/src/tests/abstr.pd11
-rw-r--r--desiredata/src/tests/abstr2.pd15
-rw-r--r--desiredata/src/tests/all_guis_and_gop.pd116
-rw-r--r--desiredata/src/tests/all_guis_and_gop.pd.gifbin0 -> 11002 bytes
-rw-r--r--desiredata/src/tests/bof.pd27
-rw-r--r--desiredata/src/tests/chun.pd36
-rw-r--r--desiredata/src/tests/city.pd128
-rw-r--r--desiredata/src/tests/desiredata-presentation-piksel06.pd26
-rw-r--r--desiredata/src/tests/gop-one.pd18
-rw-r--r--desiredata/src/tests/gop-three.pd41
-rw-r--r--desiredata/src/tests/gop-two.pd19
-rw-r--r--desiredata/src/tests/sub.pd21
-rw-r--r--desiredata/src/tests/subgop-test.pd8
-rw-r--r--desiredata/src/u_pdreceive.c321
-rw-r--r--desiredata/src/u_pdsend.c138
-rw-r--r--desiredata/src/valgrind3.supp89
122 files changed, 64411 insertions, 0 deletions
diff --git a/desiredata/src/ChangeLog b/desiredata/src/ChangeLog
new file mode 100644
index 00000000..84cf1b43
--- /dev/null
+++ b/desiredata/src/ChangeLog
@@ -0,0 +1,233 @@
+$Id: ChangeLog,v 1.1.4.11.2.44 2007-09-06 16:12:01 chunlee Exp $
+
+DesireData 2007.08.22 :
+
+ * added more Bokml (Norwegian) translations from Gisle Frysland
+ * added Nihongo (Japanese) translations from Kentaro Fukuchi
+ * added Dansk (Danish) translations from Steffen Leve Poulsen
+ * added History class to unify command history for Listener/Runcommand/TextBox
+ * KeyboardDialog clean up, added font selector for console and virtual keyboard
+ * Appearance settings can be applied at run time
+ * new object/wire indexing system (diff-friendly)
+ * Added keyboard/mouse macro recording, playback, and copy (to clipboard)
+ * [select] has as many inlets as it has arguments
+ * Added [macro] so that a macro can be played back in a patch using messagebox
+ * Added [clipboard] to pull the content of system clipboard
+ * Fixed variable width font support and TextBox code clean up
+ * Added object id display toggle
+ * Added [display] object
+ * Added patch editing commands
+ * Added expand_port
+ * Added profiler (object speed measurements) (not compiled in by default)
+ * Can now use spaces and \{} in IEM labels and some other places.
+ * Added Locale diff tool: localeutils.tcl
+
+DesireData 2007.08.04 :
+
+ * Unicode locales
+ * fixed type mismatch bug recently introduced in [unpack]...
+ * fixed lost console posts at startup
+ * turned most fprintf() into post() or error()
+ * added Chinese locale from Chun Lee
+ * added Polish locale from Michal Seta
+ * added object creation history
+ * added arrow keys and mouse clicks to KeyboardDialog
+ * added click drag and copy
+ * added background grid
+ * added snap to grid
+ * added new font selector (in client prefs)
+
+DesireData 2007.07.30 :
+
+ * added classes [unpost], [tracecall], [parse], [unparse]
+ * non-constructed objects finally have a dashed box like they used to
+ * most of the rest of the C code switched to C++,PD_PLUSPLUS_FACE
+ * beginning to use C++ standard library components
+ * added event history view (help menu)
+ * added keyboard view
+ * fixed several bugs in copy/paste, undo/redo, subpatches, gop.
+ * added atom_ostream (similar to atom_string)
+ * lifted many string length restrictions
+ * fixed the hexmunge generator (for classnames with special chars)
+ * pd_error() is deprecated
+ * added verror(), added open_via_path2(), canvas_open2(), outlet_atom(), ...
+ * [route] and [select] support mixed floats and symbols
+ * [unpack] supports type "e" meaning any atom ("e" stands for "element")
+ * added variable mouse cursor sensitivity
+ * various fixes on keyboard navigation
+
+DesireData 2007.06.27 (which should have been 2007.01.12) :
+
+ * merged new loader from Miller's pd 0.40-2
+ * merged (but not tested) the rest of the [declare] code from pd 0.40-2
+ * added gensym2 (support for NUL in symbols)
+ * most of the code now uses C++,PD_PLUSPLUS_FACE,class_new2,etc
+ * auto show/hide scrollbars
+ * menu bar can be disabled
+ * new Find widget (FireFox style)
+ * added "subpatcherize" (turn a selection into a subpatch)
+ * IEMGUI can now by controled with keyboard
+ * more general keyboard control
+ * merged t_alist and t_binbuf together and aliased them to t_list
+ * delay uploading until #X restore or #X pop
+ * don't upload all abstractions instances to client (much faster)
+ * introduced zombie objects to deal with dead objects
+ * Command evaluator per canvas window
+ * Added locale for Euskara (Basque) by Ibon Rodriguez Garcia
+ * PureUnity is now part of the DesireData project (but is designed to
+ run also on Miller's 0.40).
+ * added -port option in desire.tk so that server and client may
+ be started separately.
+ * PureUnity has type suffixes for some class families; for each $1 in
+ f,~,# (float,signal,grid) there is [inlet.$1] [outlet.$1] [taa.$1]
+ [op2.$1] [rand.$1] [norm.$1] [swap.$1] [packunpack3.$1]
+ * Other new PureUnity classes: [^] [commutator] [associator]
+ [invertor] [distributor] [tree] [protocols-tree]
+
+DesireData 0.40.pre5 (2006.12.19) (-r desiredata; ./configure && make) :
+
+ * merged changes from Miller's pd 0.40-2 (80% of it)
+ * new canvas method "reply_with" of canvases replaces the implicit
+ reply-matching of pre4. (even less bug-prone)
+ * server-side wires and scalars appear to client just like other objects.
+ * floatatom,symbolatom,[nbx] use normal Tk text edition just like
+ ObjectBox,MessageBox,Comment have done for a while
+ * obsolete t_object fields removed: te_type te_width
+ * global object table (crash protection for bindless .x targets)
+ * variable width font usable in ObjectBoxes and MessageBoxes and Comments.
+ * [hsl] [vsl] support jump-on-click again
+ * lots of bugfixes
+ * -console and -lang moved to Client Preferences dialog
+ * added some more translations by Patrice Colet
+ * removed Find menu in main window
+ * added Find, Find Next, Find Last Error (canvas windows only)
+ * choose between horizontal and vertical in Properties of slider or radio.
+
+DesireData 0.39.A.pre4 (2006.12.07) (-r desiredata; ./configure && make) :
+
+ * major speedup of the GUI (sometimes 3-4 times faster)
+ * lots of bugfixes
+ * logging of the socket into the terminal is now disabled by default
+ * introducing PD_PLUSPLUS_FACE, a new way to use <m_pd.h> and <desire.h>
+ * new branch "desiredata" instead of "devel_0_39".
+ * got rid of #ifdef DESIRE
+ * reply-matching in client-server protocol (less bug-prone)
+ * reversing the connection to what it was supposed to be:
+ the client connects to the server, not the other way around.
+ * the server uses [netreceive] to receive the connection from the GUI
+ * removed support for .pdsettings, .plist, microsoft registry.
+ * cross-platform libpd
+ * new titlebar icon
+ * removed t_guiconnect
+ * removed [scope]
+
+DesireData 0.39.A.pre3 (2006.11.27) (-r devel_0_39; ./configure && make) :
+ * franais updated by Patrice Colet
+ * italiano updated by Federico Ferri
+ * tons of bugfixes
+ * better pdrc editor (renamed to server prefs)
+ * removed media menu (split to: help menu, file menu, server prefs)
+ * removed Gdb box, added crash report dialog
+ * renamed objective.tcl to poe.tcl (because the name was already taken)
+ * replaced scons by autoconf and make (starting from Miller's 0.39's files)
+ * removed detection of Tcl (we don't need to use libtcl)
+ * removed the setuid option because no-one needs it; also fixed the
+ setuid security vulnerability in case someone does chmod u+s anyway
+ * Portaudio 18 is no longer supported.
+ * simplified configure.in (detector and makefile generator)
+ * APIs not compiled in show up in "pd -help", with a special mention
+ "(support not compiled in)"; those options don't give you a "unknown
+ option" when trying them, it says "option -foo not compiled in this pd".
+ * switched desire.c to C++, as another way to reduce redundancy in code.
+ * can be compiled without audio support.
+ * can be compiled without MIDI support.
+ * can --disable-portaudio on OSX
+ * added multiple wire connection support
+ * fixed copy/paste on canvas
+ * keyboard navigation pointer makeover
+ * added automatic object insertion support
+
+DesireData 0.39.A.pre2 (2006.11.12) (-r devel_0_39; scons desire=1) :
+ * espaol updated by Mario Mora
+ * subpatches
+ * GOPs
+ * abstraction instances
+ * multi-line objectboxes, messageboxes and comments
+ * keyboard-based navigation
+ * made desire.c C++ compatible (for future use)
+ * lots of things not written here
+
+DesireData 0.39.A.pre1 (-r devel_0_39; scons desire=1) :
+ * merged into the devel branch; enable with scons desire=1, which
+ disables lots of g_*.c files (and s_print.c) and enables desire.c;
+ use the std devel gui using desire=0.
+ * added an object-oriented programming system in desire.tk (do not
+ confuse with a dataflow system). added proc unknown, which allows
+ subject-verb-complement method-calling in tcl (aka objective.tcl)
+ * run the client to start the server and not the other way around: do wish desire.tk
+ * the client can make the server start via GDB
+ * added Pd box (like Ctrl+M but with history)
+ * added Gdb box
+ * menu translations in 8 languages
+ * classbrowser now show short descriptions in 3 languages
+ * objectbox tooltip now replaced by mini-classbrowser
+ * client conf editor
+ * other stuff I forget to write about
+ * looks for .ddrc
+ * pdrc and ddrc config becomes server and client configuration editor
+ * graphics rendering completely removed from the server
+ * toolbar and status bar can be enabled/disabled
+ * added Patcher->View->Reload: client reloads the patch from the server
+ * localization support (currently 8 languages: english, franais, deutsch,
+ catal, espaol, portugus, bokml, italiano.)
+ * lots of things not written here
+
+ImpureData 0.37.B :
+ * moving rendering to the TCL side
+ * moving event-handling to the TCL side too
+ * new file u_object.tk
+ * added pd_scanargs(), pd_upload(), sys_mgui().
+ * added color schemes (modifiable in u_main.tk)
+ * switched to a jmaxish look
+ * merged g_vdial.c into g_hdial.c
+ * merged g_vslider.c into g_hslider.c
+ * added Patcher->View->Redraw
+ * added proc populate_menu, proc property_dialog
+ * added ~/.pd.tk loading
+ * inlet tooltips have new look
+ * rewrote all of the property dialogs
+ * added object class name completion (the <Tab> key)
+ * mouse scrollwheel works in patchers
+ * plus/minus button on tcl listener
+ * changed default font and borderwidth
+ * if conf not found in ~ ($HOME),
+ looks in Pd's install directory (eg. /usr/local/lib/pd)
+ * looks for .impdrc before .pdrc
+ * pdrc editor
+ * -help lists unavailable options with note "not compiled in"
+ * sys_vgui() message size limit removed
+ * new peak meters (thanks Carmen)
+ * dropper object outputs symbols of filenames (requires tkdnd)
+ * joe sarlo's VST-plugin i/o scheduler available on windows
+ * error() merged into pd_error()
+ and using strerror() to get meaningful error messages for failed I/O
+ * completely breaking compatibility with Pd's GUI externals
+ (for a good reason)
+
+ImpureData 0.37.A.2 (-r impd_0_37_A_2) :
+ * merged GG's reverting of "quote hack"
+
+ImpureData 0.37.A (-r impd_0_37_A) :
+ * forked from devel_0_37, 2004.02.21
+ * added console for post()
+ * .pdrc: -console <number_of_lines>
+ * added button bar (that does like Ctrl+E & Put menu)
+ * .pdrc: -look <directory_of_icons>
+ (remember you can't use ~ nor $HOME in .pdrc)
+ * includes a selectable windowid (for those who know how to use it)
+ * class list dialog
+ * scans for loaded classes, abstractions/externs dirs
+ * help button fetches help file without needing to instantiate first
+ * filter box helps finding classes quickly
+ * displays some info on the class, like a list of defined methods and such.
+ * statusbar shows cursor position (enable with -statusbar)
diff --git a/desiredata/src/TODO b/desiredata/src/TODO
new file mode 100644
index 00000000..0e866840
--- /dev/null
+++ b/desiredata/src/TODO
@@ -0,0 +1,454 @@
+DesireData's TODO list, $Id: TODO,v 1.1.2.28.2.63 2007-09-09 17:45:45 matju Exp $
+
+LEGEND:
+ [c] client
+ [s] server
+ [b] both
+ [x] done
+
+------------------8<--------cut-here--------8<------------------
+
+[s] encapsulate wires list
+[s] observable boxes list
+[s] observable wires list
+[s] gop filter
+[s] triad
+
+------------------8<--------cut-here--------8<------------------
+
+[s] class_setreinit(t_pd *, t_symbol *s, int argc, t_atom *argv)
+[s] fix canvas_merge, canvas_remove_nth, canvas_sort
+[s] recreate abstr instances after abstr save
+[s] [bng] messages get duplicated upon entering a subpatch???
+[s] rewrite [any]
+[s] counter-test.pd shows [nbx] jamming the update queue if too many updates at once...?
+[s] queue priorities cause double call to changed() to change the expected order of updates (dangling pointer in client)
+[c] Ctrl+e doesn't change Edit menu entry; likewise for visual_diff
+[c] Save Changes? Save Changes? Save Changes? Save Changes? Save Changes? Save Changes? Save Changes? Save Changes? Save Changes?
+[s] canvas_resortinlets confuses wire upload
+[s] should do canvas_resortinlets after moving objects
+[c] split View into several classes
+[s] extraneous space at end of binbuf_gettext
+[s] make t_hash thread-safe (use external iterator)
+[s] take advantage of the support for zero-size arrays in gcc.
+[s] writesf_free has deadlock. (assigned to Sylvain)
+[b] look into race conditions and locking
+[c] figure out what to do about the existence of [$self look] vs ordinary attributes (pointer_sense= and such)
+[s] [error]
+[b] localise error messages
+[b] colorised console with hyperlinked error messages
+[c] atomic undo
+[c] undo subpatch
+[c] numbox: is_log
+[c] change the order of the fields in Properties if it makes things more logical than the order of fields of savefn
+[c] [hradio] : chg -> is_log
+[c] [vu] props : scale should appear instead of is_log
+[s] figure out how to keep [pd] subscribed even when closed.
+[s] new parser for nested lists and extended symbols
+[s] update s_audio.c to support any number of devices (not just max 4)
+[s] look for new bugs involving %*s added around 2007.06.28
+[c] new way to do View get_canvas
+[b] too much duplication of inlets vs outlets
+[s] too much duplication of adc vs dac (see s_audio.c)
+[c] implement multiple cascaded languages (use listbox+up+down)
+[c] def Menuable raise {} {wm withdraw $w; wm deiconify $w
+[s] what to do with post() in case of -listdev, etc.?
+[s] turn old [dropper] code into a feature of SymbolBox
+[s] inheritance: [super] "instantiates" other abstraction with same $0; [self] allows sending messages to self; [declare super ...] makes the tree.
+
+[b] GOP problems are back due to recent changes in canvas_map and canvas_vis.
+ now that abstractions don't get loaded into the client anymore, GOP can't always be drawn anymore too.
+ i mean, because the content of GOP is not uploaded to the client, so the client can't draw anything about it..
+ unless def View outside_of_the_box are moved to the server side and the server only uploads what needs to be drawn
+ for gop
+
+ another side effect of not uploading the content of [pd]/abs that i just found out is that, when deleting such object,
+ 1. the client won't be able to perform things like $wire deconstruct in def Canvas del,
+ as the object don't exists in the client side
+ 2. even if client don't call things like that, the server would still send -> delete message to the client,
+ which causes the same error because the object don't exists...
+
+[s] it might make sense to always upload subpatches but upload instances only when needed
+[s] server don't send delete message back after client sending "object_delete" (http://pastebin.ca/318343)
+[s] serial got sent too early when creating [pd] with push & #N canvas (http://pastebin.ca/318318)
+[s] GOP problems are back due to recent changes in canvas_map and canvas_vis
+[s] [route] should be reconfigurable and accept pointer
+[s] [select] should accept pointer
+[s] [moses] should be multi-arg (and be aliased to [range] ?)
+[s] get rid of stderr in server
+[s] prevent hidden subpatches/abstraction-instances from being loaded in the client all of the time.
+[s] -lib in .pdrc crashes server: http://pastebin.ca/286300
+[s] server don't pick up changes via NumBox reload, ie the width:
+ <- .x8068058 reload 2 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 256;
+ -> change x8068058 x8067c50 {#X obj 335 166 nbx 8 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 256;}
+[b] fix gop
+ [c] reimplement View get_canvas so that it does not rely on [focus]
+ [s] gop contains can be drawn if not uploaded to client
+[ ] fix deleteing/closing Canvas
+ [ ] server sends -> x806a3b8 delete twice
+ [ ] fix deletion order
+[ ] graphical array rendering optimization
+[ ] fix double delete of [pd].
+[s] added "version 2" syntax parser (optional), which has nested lists,
+ extended quoting, extended float syntax
+ (some ex-symbols now parsed as floats: +1 +1.0 +1e8 0x10 and so on.)
+[ ] note that Marius Schebella is interested in benchmarks
+[ ] atomically with multiple level
+[ ] tidy_up/snap to grid
+[ ] cleaner parsing of [expr]... remove int type because it causes e.g. [expr 8.0 / 10.0] = 0 but [expr 8.0/10.0] = 0.8
+[ ] how does [declare -stdpath] work? this is a mystery. can't get it to work in pd 0.40.
+
+[ ] PureUnity
+ [ ] benchmark
+ [ ] signals
+ [ ] grids
+ [ ] transitive, antisymmetric, predicate
+ [ ] contracts : *-rule.pd
+ [ ] tests for the frameworks' own components?
+ * not finished:
+ [glue-test]
+ [comparators-test] [arith-test]
+ [operator1-rule] [operator1-test]
+ [operator2-rule] [operator2-test]
+
+[s] those are the externs that have to be recompiled if I want to trap calls to return values of getfn.
+ ./externals/olafmatt/clone/clone.c:544: mess1(&cv->gl_pd, gensym("dsp"), sp);
+ ./externals/grill/dynext/src/main.cpp:952: mess1((t_pd *)canvas,const_cast<t_symbol *>(sym_dsp),NULL);
+
+<shift8> matju: another big bug for me - v/h sliders in existing patches bounce
+ repeatedly back to bottom when some kind of event occurs. you have to move the
+ mouse very gently back and forth until the slider stays at the location you want,
+ then without moving the mouse, release the mouse button :(
+
+[s] allow helpfiles to load without having to "make install".
+[s] switch iemguis to using only t_atoms
+[s] MIDI loopback pseudo-device (inside pd)
+[s] audio loopback pseudo-device (inside pd)
+[s] use vector doubling in binbuf_add,binbuf_addv...
+[c] opening an already-open subpatch should just raise that subpatch
+[c] bug: you can move parts of gop subpatches, from the parent patch!
+[c] pixel offsets are not correct in [hsl] [vsl]:
+ distinguish between $@w or $@h and actual size. there should be 4 extra pixels.
+[c] hide inlets/outlets of IEMGUI when they have receive-symbols/send-symbols
+[c] rightclick help doesn't work on [cnv]: tries to find help for "cnv.pd" ???
+[s] creating a graph causes crash.
+[b] fix NumBox's width and height (or remove those settings)
+[x] Implement (or fix) Find, Find Again in class Client
+ [x] with ability to search substrings
+ [ ] with ability to search across canvases
+ [ ] all canvases
+ [x] all subcanvases
+ [x] only the current one
+ [ ] with regexps
+ [ ] with replace
+[ ] in hsl-help.pd, [hsl] shouldn't appear as a Radio.
+[ ] canvas dialog:
+ [ ] add option for old-style GOP
+ [ ] make hidetext work
+ [ ] add units/pixel
+[c] array button doesn't work (menuarray)
+[c] implement timeout in def Manager call
+[s] finish merging 0.40 (wasn't it finished?)
+[s] merge 0.41 (no?)
+[s] proper symbol quoting
+[s] refcounted symbols
+[c] patching-in-tongues follow-up
+[c] def def
+[c] take care of needless "save changes?"
+[c] make List objects, to manage children, visible_children, wires, selection, selection_wires.
+[c] skip unneeded motion events inside client (do we need this?)
+[b] rename pd to pd-server, desire.tk to pd-client, add new program "pd" which would launch both (will we really do this?)
+[b] #V test with bg color
+[c] kill global tooltip variable ?
+[c] iemprops: min,max labels broken
+[b] fix the [key] and [keyup] and [mouse] (?) classes
+[s] fix all issues with backslashes and braces.
+[-] write an installer in Tcl/Tk.
+[s] canvas_object_insert()
+[c] simplify def Dialog add
+[c] devlist isn't supposed to be like a choice, rather like several choices.
+[c] implement def Canvas tidy
+[c] set tk::mac::useCGDrawing 1
+[s] differential upload
+[c] differential redraw
+[b] improved dirty_lists including proper array support
+[b] bang counter (instead of sending every bang message to client)
+[b] implement garray
+[c] implement a mark-and-sweep in order to find leaks... (?)
+[b] rewrite [image], [display], [knob], [grid], [popup], ...
+[ ] this seems fishy but might have good ideas -> http://www.rebelscience.org/Cosas/Reliability.htm
+[c] make a statistical profiler for Tcl, if possible
+[c] try to use profiler.tcl (tcllib) in a sensible way
+[s] try C-oriented tools:
+ [ ] oprofile (with GUI)
+ [ ] memprof
+ [ ] sysprof
+ [ ] kprof
+ [ ] gprof
+ [ ] prospect
+
+[s] iirc, bang~ registers a timer callback. the problem is that the timer callbacks are only executed every dac block,
+ which is 64 samples. so running bang~ in subpatch with less than 64 samples, bang~ sets the same timer several times,
+ but it's only executed once.
+
+[b] think about this if you are reconsidering properties panels, I strongly encourage all y'all to make them Pd patches.
+ This is how Max/MSP does it and I think it would work very well for Pd as well. Sounds like this is a good opportunity
+ to make the switch. -- hcs
+
+<chun> 1. a keyboard operated cursor, a bit like Active, but one can use it like the mouse pointer
+<chun> 2. snap to grid feature, or similiar
+<chun> 3. prefix keybindings, like M-x in emacs
+
+Iohannes said about redirecting stdout/stderr:
+ pd -verbose -stderr 2>&1 | while read line; do echo "${line};" | pdsend 6666 localhost udp; done
+
+[b] [struct], scalar, DS-array, [plot], [drawpolygon], [drawnumber], ...
+[c] desire.tk can be *really* loaded without Tk
+[c] ReadLine or NCurses interface
+[c] make commandline options reloadable at runtime
+[x] canvas scrollbars auto-disappear when not needed.
+[b] implement dirty flag
+[s] use gensym2() in builtin classes and stuff.
+[s] fix 64-bit arrays so that carmen gets a use for DD.
+[s] carmen also needs strings (no symbol leakage)
+[c] right-click on labels for translations.
+[b] http://www.w3.org/DesignIssues/Diff
+[c] solve printing problems with GDB. use a pty (pseudo-teletype) ---> http://wiki.tcl.tk/3916
+[c] try TkZinc
+[c] try Tcl/Gtk (Gnocl) with emulation layer
+[?] http://www.comparisonics.com/gallery.html
+[c] obiwannabe writes:
+ it would be good to have the choice as a comandline arg of the first one launched with a way
+ to accept patches to open in the same instance from, say a web browser. Like also when you are
+ in a file manager and browsing some .pd files you really want them to open in the same running instance.
+[s] must work with ALL gridflow samples
+[b] objectbox argument completion
+[b] messagebox completion
+[c] tooltips on arguments/inlets/outlets
+[c] option to make non-gui objects appear on a GOP (?)
+[b] multilingual labels in objects
+[b] multilingual comments
+[b] what would be needed to be able to use gdb --pid=... ?
+[ ] set tk::mac::CGAntialiasLimit 2
+[ ] try Doxygen's callgraphs
+[ ] try splint (http://www.splint.org/)
+[ ] try uno
+[ ] try CCCC
+[ ] try OSX Shark
+[ ] try http://www.drugphish.ch/~jonny/cca.html
+[-] do we move the trac to artengine or not?
+[c] remember that it's possible to use break in a bind-handler, to completely override system's behaviour.
+[c] try: itcl itk iwidgets (itk implements megawidgets)
+[c] try tkgate, a hardware sim program
+[ ] try libentity
+[c] try vtk-tcl
+[s] make sure $0 actually works (see canvas_realizedollar)
+[c] test rcv_able, snd_able
+[?] iem: snd/rcv problem(s) ? (what was that?)
+[c] [vu] have fcol in props !
+[c] [vu] has snd in props !
+[b] Duplicate wires?
+[c] Can connect object to an object that is inside a GOP (!!!!)
+[c] weird offset stuff when there are negative canvas coords sometimes.
+[s] Bug: bad quoting in sys_mgui()
+[b] Bug: spaces in name of vslider cause corruption of properties (devel_0_37)
+[b] classlist: add method signatures
+[c] bang flash delays should be reimplemented
+[c] pdrc_options radio don't load/save
+[c] patch window may open off-screen (all branches)
+[c] patch window may open too big (all branches, osx)
+[b] properties on objectboxes (generic dialogs tapping into method signatures) (?)
+ [s] hooks for outsourcing the preceding stuff to a plugin (eg: GridFlow, PyExt)
+[b] VT100 colours in console
+[b] [graph] is too slow (gui) for real big arrays
+[b] freeform comments (no atom parsing)
+[b] preserve whitespace in textboxes?
+[b] inlet inspector to show what are the message types expected by an inlet
+ that could read like "int: set left operand; bang: do it"
+[c] custom buttonbars (including premade objects with args like a [t b f] and such)
+ [c] with configurable hotkeys
+[b] colored wires
+[b] insert_object makes error with multiple selection.
+[c] popup_properties on multiple selection.
+[b] segmented patchcords:
+ [c] a hotkey to click on the cord, and add a new segment
+ [c] a hotkey to drag the "points" (where two lines meet)
+ [c] a modifier key to delete a segment (actually the others should be that way too)
+ [c] you should be able to right click on a regular wire, and press "segment" or do a hotkey with it
+ and it automatically turns it into an straight-elbow multisegmented wire
+[b] [t a] could be a very small GUI object (called "null object")
+[b] all the [t] could be GUI objects
+[b] GUI objects for [inlet] and [outlet] and [pd] ([page])
+[-] make a sort of pd-extended, call it DesireData Express or (gasp) Extraordinaire.
+
+[s] symbol vs strings: Ruby is right: the Symbol vs String distinction is annoying and possibly obsolete.
+ according to me, symbols exist mostly because LISP had them before they had strings, and because most
+ Strings implementations aren't powerful enough to be as fast (or almost as fast) as Symbols.
+ (well, for compatibility reasons, just like in Ruby, we can't remove symbol support completely, but
+ at least we can reduce the difference between strings and symbols to a minimum.)
+
+[b] server-side IEMGUI could be turned into Tcl-based externs OR EVEN become abstractions.
+ it's possible to make a DesireData GUI for any Pd class, including abstractions.
+ to turn IEMGUI into an abstraction, what's missing is the savefn/saveargs/scanargs business.
+
+[s] I would like to know how much it is feasible to compress the t_atom
+ structure so that even with 64-bit pointers the t_atom still stays 8 bytes
+ instead of 16. I think it's possible, but not necessarily in a
+ backwards-compatible way, and not necessarily in a portable way. also maybe it's not that useful.
+
+[c] splashscreen: we could make it different than other programs by inserting the splashscreen
+ inside the main window or we could make it a separate window but no timer, just an [OK] button,
+ so actually, this would be exactly the same as the "About" dialog.
+
+[s] turn [makefilename] into something that doesn't suck. (alias it to [sprintf] or [format])
+
+[s] merge martin peach's tcp externs into the core
+[b] data inspector: when this tool is enabled, it prints on the console any data coming through whatever cable you
+ currently have selected. if you select multiple wires, it reports whats going through multiple wires.
+[b] you need a way to see cpu usage on individual objects or on patchers or on groups of selected objects
+[c] objectbox history: see whether ddrc should have a history count entry;
+ think about saving history; matju thought that it could be turned into a dynamic button bar that you can drag from.
+[?] send to front, send to back
+[c] make windows not get auto-resized to the width of the toolbar, so that people can have tiny windows.
+[c] <Dossy> fconfigure -encoding binary ...
+[s] implement the stuff that is in iostreams.txt
+
+[c] Luke Iannini suggests some OSX bindings:
+ Command-` to switch between different windows within the application.
+ Command-, to bring up preferences (though this one is more difficult since there are multiple preference windows...)
+ Command-m to minimize the window (this currently brings up the "send message" dialogue box)
+
+[s] Claude:
+ Sending a message to vline~ creates a t_vseg, which are stored in a
+ sorted linear linked list, which means the time taken to add each new
+ line segment would be O(n), where n is the number of existing line segments.
+
+[-] look at some object sync protocols that we can think of: NFS for folders, palm sync for calendars, rsync for file contents
+
+Marius Schebella:
+I have a small keyboard shortcut wish: change between "entering mode" and "selected mode" with boxes.
+when I create a new object/message... then it would be nice to have a
+shortcut that switches from the mode, where the cursor is in the box to the
+mode, where the object is selected. I think the tab-key could be used for
+that. As it is now, I type something in, then I have to grab the mouse, then
+klick, then select, then I can adjust it (which I also do with the keyboard,
+because it is more precise).
+I know the toggeling will not be possible when more objects are selected,
+but maybe someone has an idea for that.
+
+[c] command for unpatcherizing a subpatch or abstraction (useful for making variants)
+ or for turning an abstraction into a subpatch.
+
+[s] I fixed it now, but I don't know if this is not a bug in pd 0.40:
+
+"The problem is, that canvas-local search path really tread each path as local to the canvas-path ( see line 1561 in g_canvas.c).
+So if you add e.g. /usr/local/lib/pd/extra/iemmatrix, it will search for this path, but local to the canvas path - so if I started
+Pd from /home/me it will search in /home/me//usr/local/lib/pd/extra/iemmatrix ! Is this a feature or a bug of Pd ?" -- Holzi
+
+[s] "I don't quite understand how this explains why wrap~ of -1 returns 1." -- steffen
+
+[s] there's a [wrap~] but no [wrap]. there's a [>] but no [>~] (without externals). -- matju
+
+dmotd about converting patches to postscript:
+"the internal pd postscript printer grabs the viewable canvas size,
+this would need to change to encompass the virtual limits of the patch.
+tcl/tk's 'canvas postscript' command takes the -width -height flags,
+so making it the virtual bounds is trivial. this works for snapshotting
+canvas bounds: sys_vgui("set cnv_bbox [.x%x.c bbox all] \n .x%x.c
+postscript -file /tmp/canvas.ps -width [lindex $cnv_bbox 2] -height
+[lindex $cnv_bbox 3] \n ", canvas, canvas);
+
+------------------8<--------cut-here--------8<------------------
+
+Patching-in-tongues Project
+
+[ ] make entries counter and matcher.
+
+ entries
+en: english [ ]
+es: espaol [ ] Mario Mora & Ramiro Cosentino
+de: deutsch [ ] M Neupert, G Holzmann, T Grill
+nb: bokml [ ] Gisle Frysland
+it: italiano [ ] Davide Morelli + Federico Ferri
+pt: portugus [ ] Nuno Godinho
+fr: franais [ ] Patrice Colet
+ca: catal [ ] Nria Verges
+pl: polski [ ] Michal Seta
+eu: euskara [ ] Ibon Rodriguez Garcia (Enrike Hurtado)
+cn: chinese [ ] Chun Lee
+jp: nihongo [ ] Kentaro Fukuchi
+tu: trke [ ] ... Koray Tahiroglu
+sv: svenska [ ] ... Daniel Skoglund (NOT FOUND)
+br: brasiliano [ ] ... Gabriel Menotti
+dk: dansk [ ] ... Steffen Leve Poulsen
+
+------------------8<--------cut-here--------8<------------------
+Dec 18 2006
+
+1. there's no way to limit the size of the output buffer. If the other
+side of the connection doesn't respond, the sending buffer just
+inflates quickly. I've seen it happen that a bug in the sender causes
+it to try to send so fast that it ate memory like an infinite recursion
+or a forkbomb.
+
+2. That operation is not realtime-safe (but still it's much closer to
+being so than just blocking...)
+
+3. It's only usable by the GUI socket and never by [netsend].
+
+4. While that buffer together with t_guiqueue allow GUI updates to be
+delayed for as long as necessary, it doesn't solve the problem that it can
+send information that is already outdated and redundant. This can be
+important in preventing problem #1 for a very heavy GUI. DesireData has
+had this problem essentially dealt with since a long time, but it lacks
+some fine tuning to get more robust.
+
+------------------8<--------cut-here--------8<------------------
+
+<arjen> matju, you may be interested in "Jim" - that does have closures and on the Wiki you can find several attempts and
+ experiments regarding closures: http://wiki.tcl.tk/closures
+
+<matju> is there something like listbox but which works as a popup menu ?
+<tclguy> tk_optionMenu is an old-school version
+<tclguy> or get a combobox from BWidget or tile
+
+1. wish8.5 desire.tk city.pd &> err
+2. ctrl+e, ctrl+a, shift+right*3 (or just once if profiling)
+3. times (tclx)
+
+<matju> is there a wrapper for libagg for tcl? AGG of antigrain.com
+<ijchain> <kbk> don't know of one, but SWIG, Critcl, or ffidl might plug the gap
+
+[initbang] & [closebang]: https://sourceforge.net/tracker/?func=detail&atid=478072&aid=1544041&group_id=55736
+
+[s] Ed Kelly <morph_2016@yahoo.co.uk> reports that ALSA 24-bit output does not work?
+
+to dave griffiths: I think that this is three feature requests:
+1. performing replacement of wire-object-wire by a single wire, as a
+single operation in the GUI
+2. make that operation atomic in terms of DSP recompilation.
+3. break down DSP recompilation in pieces so that it is more "incremental"
+for large patches.
+In the case of object insertion, (2) and (3) are not implemented either,
+but step (1) already has most of the desired effect; for the message
+system, step (1) is all that is needed. DSP is more work and I know less
+about DSP. It'll take me a while to get there; but (2) doesn't seem so
+hard.
+
+http://www.tomsawyer.com/gallery/index.php
+
+[b] matju to atwood:
+ If I had automatic positioning in DesireData, it would be as an option: e.g. objects could default to "floating around"
+ (that is, automatic positioning), but be pinned down into specific positions. In that case, an exception has to be done
+ for [inlet] and [outlet] objects mostly. (the DS subsystem should be skipped over as well...) I could also have a use
+ for some semi-automatic repositionings: for example, there could be a keyboard shortcut to reposition a non-"floating"
+ object wherever it would go if it were floating, and if the user doesn't want it s/he can Ctrl+z it.
+
+http://www.graphdrawing.org/
+
+<mamalala> you select a bunch of objects and group them together .... then you can select all the objects in that group
+later, if needed, by its name like, you start to build some mixer patch .. and then you add a chain for an external fx,
+so you can put all associated objects in the "ext.fx" group ... whenever it gets so messed up that you forgot what is
+what, you can just select the groupt you want, and see/move/whatever the involved objects the group name could also act
+as a template for the name of a subpatch, if one decides to finally put them into one ....
+
diff --git a/desiredata/src/bgerror.tcl b/desiredata/src/bgerror.tcl
new file mode 100644
index 00000000..bff0dd2c
--- /dev/null
+++ b/desiredata/src/bgerror.tcl
@@ -0,0 +1,254 @@
+# bgerror.tcl --
+#
+# Implementation of the bgerror procedure. It posts a dialog box with
+# the error message and gives the user a chance to see a more detailed
+# stack trace, and possible do something more interesting with that
+# trace (like save it to a log). This is adapted from work done by
+# Donal K. Fellows.
+#
+# Copyright (c) 1998-2000 by Ajuba Solutions.
+# All rights reserved.
+#
+# RCS: @(#) $Id: bgerror.tcl,v 1.1.2.2.2.2 2007-08-12 02:38:45 matju Exp $
+# $Id: bgerror.tcl,v 1.1.2.2.2.2 2007-08-12 02:38:45 matju Exp $
+
+package provide bgerror 8.4
+
+namespace eval ::tk::dialog::error {
+ namespace import -force ::tk::msgcat::*
+ namespace export bgerror
+ option add *ErrorDialog.function.text [mc "Save To Log"] \
+ widgetDefault
+ option add *ErrorDialog.function.command [namespace code SaveToLog]
+}
+
+proc ::tk::dialog::error::Return {} {
+ variable button
+ .bgerrorDialog.ok configure -state active -relief sunken
+ update idletasks
+ after 100
+ set button 0
+}
+
+proc ::tk::dialog::error::Details {} {if {[catch {Details2}]} {::error_dump}}
+proc ::tk::dialog::error::Details2 {} {
+ set w .bgerrorDialog
+ set caption [option get $w.function text {}]
+ set command [option get $w.function command {}]
+ if { ($caption eq "") || ($command eq "") } {
+ grid forget $w.function
+ }
+ lappend command [.bgerrorDialog.top.info.text get 1.0 end-1c]
+ $w.function configure -text $caption -command $command
+ grid $w.top.info - -sticky nsew -padx 3m -pady 3m
+}
+
+proc ::tk::dialog::error::SaveToLog {text} {
+ if { $::tcl_platform(platform) eq "windows" } {
+ set allFiles *.*
+ } else {
+ set allFiles *
+ }
+ set types [list \
+ [list [mc "Log Files"] .log] \
+ [list [mc "Text Files"] .txt] \
+ [list [mc "All Files"] $allFiles]]
+ set filename [tk_getSaveFile -title [mc "Select Log File"] \
+ -filetypes $types -defaultextension .log -parent .bgerrorDialog]
+ if {![string length $filename]} {
+ return
+ }
+ set f [open $filename w]
+ puts -nonewline $f $text
+ close $f
+}
+
+proc ::tk::dialog::error::Destroy {w} {
+ if {$w eq ".bgerrorDialog"} {
+ variable button
+ set button -1
+ }
+}
+
+# ::tk::dialog::error::bgerror --
+# This is the default version of bgerror.
+# It tries to execute tkerror, if that fails it posts a dialog box containing
+# the error message and gives the user a chance to ask to see a stack
+# trace.
+# Arguments:
+# err - The error message.
+
+proc ::tk::dialog::error::bgerror {err} {if {[catch {
+ global errorInfo tcl_platform
+ variable button
+
+# matju: use objective.tcl's
+# set info $errorInfo
+ set info [::error_text]
+
+ set ret [catch {::tkerror $err} msg];
+ if {$ret != 1} {return -code $ret $msg}
+
+ # Ok the application's tkerror either failed or was not found
+ # we use the default dialog then :
+ if {($tcl_platform(platform) eq "macintosh")
+ || ([tk windowingsystem] eq "aqua")} {
+ set ok [mc Ok]
+ set messageFont system
+ set textRelief flat
+ set textHilight 0
+ } else {
+ set ok [mc OK]
+ set messageFont {Helvetica -14 bold}
+ set textRelief sunken
+ set textHilight 1
+ }
+
+ # Truncate the message if it is too wide (longer than 30 characacters) or
+ # too tall (more than 4 newlines). Truncation occurs at the first point at
+ # which one of those conditions is met.
+ set displayedErr ""
+ set lines 0
+ foreach line [split $err \n] {
+ if {[string length $line]>30} {
+ append displayedErr "[string range $line 0 29]..."
+ break
+ }
+ if {$lines>4} {
+ append displayedErr "..."
+ break
+ } else {
+ append displayedErr "${line}\n"
+ }
+ incr lines
+ }
+
+ set w .bgerrorDialog
+ set title [mc "Application Error"]
+ set text [mc {Error: %1$s} $err]
+ set buttons [list ok $ok dismiss [mc "Skip Messages"] \
+ function [mc "Details >>"]]
+
+ # 1. Create the top-level window and divide it into top
+ # and bottom parts.
+
+ catch {destroy .bgerrorDialog}
+ toplevel .bgerrorDialog -class ErrorDialog
+ wm withdraw .bgerrorDialog
+ wm title .bgerrorDialog $title
+ wm iconname .bgerrorDialog ErrorDialog
+ wm protocol .bgerrorDialog WM_DELETE_WINDOW { }
+
+ if {($tcl_platform(platform) eq "macintosh")
+ || ([tk windowingsystem] eq "aqua")} {
+ ::tk::unsupported::MacWindowStyle style .bgerrorDialog zoomDocProc
+ }
+
+ frame .bgerrorDialog.bot
+ frame .bgerrorDialog.top
+ if {[tk windowingsystem] eq "x11"} {
+ .bgerrorDialog.bot configure -relief raised -bd 1
+ .bgerrorDialog.top configure -relief raised -bd 1
+ }
+ pack .bgerrorDialog.bot -side bottom -fill both
+ pack .bgerrorDialog.top -side top -fill both -expand 1
+
+ set W [frame $w.top.info]
+ text $W.text -bd 2 -yscrollcommand [list $W.scroll set] -setgrid true \
+ -width 80 -height 10 -state normal -relief $textRelief -highlightthickness $textHilight -wrap char
+
+ scrollbar $W.scroll -relief sunken -command [list $W.text yview]
+ pack $W.scroll -side right -fill y
+ pack $W.text -side left -expand yes -fill both
+# $W.text insert 0.0 "$err\n$info"
+ $W.text insert 0.0 $info
+ $W.text mark set insert 0.0
+ bind $W.text <ButtonPress-1> { focus %W }
+ $W.text configure -state disabled
+
+ # 2. Fill the top part with bitmap and message.
+ # Max-width of message is the width of the screen...
+ set wrapwidth [winfo screenwidth .bgerrorDialog]
+ # ...minus the width of the icon, padding and a fudge factor for
+ # the window manager decorations and aesthetics.
+ set wrapwidth [expr {$wrapwidth-60-[winfo pixels .bgerrorDialog 9m]}]
+ label .bgerrorDialog.msg -justify left -text $text -font $messageFont \
+ -wraplength $wrapwidth
+ if {($tcl_platform(platform) eq "macintosh")
+ || ([tk windowingsystem] eq "aqua")} {
+ # On the Macintosh, use the stop bitmap
+ label .bgerrorDialog.bitmap -bitmap stop
+ } else {
+ # On other platforms, make the error icon
+ canvas .bgerrorDialog.bitmap -width 32 -height 32 -highlightthickness 0 -bd 0
+ .bgerrorDialog.bitmap create oval 0 0 31 31 -fill red -outline black
+ .bgerrorDialog.bitmap create line 9 9 23 23 -fill white -width 4
+ .bgerrorDialog.bitmap create line 9 23 23 9 -fill white -width 4
+ }
+ grid .bgerrorDialog.bitmap .bgerrorDialog.msg \
+ -in .bgerrorDialog.top \
+ -row 0 \
+ -padx 3m \
+ -pady 3m
+ grid configure .bgerrorDialog.msg -sticky nsw -padx {0 3m}
+ grid rowconfigure .bgerrorDialog.top 1 -weight 1
+ grid columnconfigure .bgerrorDialog.top 1 -weight 1
+
+ # 3. Create a row of buttons at the bottom of the dialog.
+ set i 0
+ foreach {name caption} $buttons {
+ button .bgerrorDialog.$name -text $caption -default normal -command [namespace code [list set button $i]]
+ grid .bgerrorDialog.$name -in .bgerrorDialog.bot -column $i -row 0 -sticky ew -padx 10
+ grid columnconfigure .bgerrorDialog.bot $i -weight 1
+ # We boost the size of some Mac buttons for l&f
+ if {($tcl_platform(platform) eq "macintosh")
+ || ([tk windowingsystem] eq "aqua")} {
+ if {($name eq "ok") || ($name eq "dismiss")} {
+ grid columnconfigure .bgerrorDialog.bot $i -minsize 79
+ }
+ }
+ incr i
+ }
+ # The "OK" button is the default for this dialog.
+ .bgerrorDialog.ok configure -default active
+
+ bind .bgerrorDialog <Return> [namespace code Return]
+ bind .bgerrorDialog <Destroy> [namespace code [list Destroy %W]]
+ .bgerrorDialog.function configure -command [namespace code Details]
+
+ # 6. Update all the geometry information so we know how big it wants
+ # to be, then center the window in the display and deiconify it.
+ ::tk::PlaceWindow .bgerrorDialog
+
+ # 7. Ensure that we are topmost.
+ raise .bgerrorDialog
+ if {$tcl_platform(platform) eq "windows"} {
+ # Place it topmost if we aren't at the top of the stacking
+ # order to ensure that it's seen
+ if {[lindex [wm stackorder .] end] ne ".bgerrorDialog"} {
+ wm attributes .bgerrorDialog -topmost 1
+ }
+ }
+
+ # 8. Set a grab and claim the focus too.
+ ::tk::SetFocusGrab .bgerrorDialog .bgerrorDialog.ok
+
+ # 9. Wait for the user to respond, then restore the focus and
+ # return the index of the selected button. Restore the focus
+ # before deleting the window, since otherwise the window manager
+ # may take the focus away so we can't redirect it. Finally,
+ # restore any grab that was in effect.
+ vwait [namespace which -variable button]
+ set copy $button; # Save a copy...
+ ::tk::RestoreFocusGrab .bgerrorDialog .bgerrorDialog.ok destroy
+ if {$copy == 1} {return -code break}
+}]} {
+ ::error_dump
+}}
+
+namespace eval :: {
+ # Fool the indexer
+ proc bgerror err {}
+ rename bgerror {}
+ namespace import ::tk::dialog::error::bgerror
+}
diff --git a/desiredata/src/builtins.c b/desiredata/src/builtins.c
new file mode 100644
index 00000000..891e1f60
--- /dev/null
+++ b/desiredata/src/builtins.c
@@ -0,0 +1,3060 @@
+/* Copyright (c) 2007 Mathieu Bouchard
+ Copyright (c) 1997-1999 Miller Puckette.
+ For information on usage and redistribution,
+ and for a DISCLAIMER OF ALL WARRANTIES,
+ see the file "LICENSE.txt" in this distribution. */
+
+#define PD_PLUSPLUS_FACE
+#include "desire.h"
+#include "s_stuff.h"
+#include <stdlib.h>
+#include <stdarg.h>
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+#include <sstream>
+#ifdef UNISTD
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/times.h>
+#include <sys/param.h>
+#include <unistd.h>
+#endif
+#ifdef MSW
+#include <wtypes.h>
+#include <time.h>
+#endif
+#ifdef MSW
+#include <winsock.h>
+#else
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <netdb.h>
+#include <stdio.h>
+#define SOCKET_ERROR -1
+#endif
+#ifdef MSW
+#include <io.h>
+#endif
+#if defined (__APPLE__) || defined (__FreeBSD__)
+#define HZ CLK_TCK
+#endif
+#ifndef HAVE_ALLOCA
+#ifdef _WIN32
+#define HAVE_ALLOCA 0 /* LATER this should be set by configure script! */
+#else
+#define HAVE_ALLOCA 1 /* LATER this should be set by configure script! */
+#endif
+#endif
+
+#define a_float a_w.w_float
+#define a_symbol a_w.w_symbol
+#define a_pointer a_w.w_gpointer
+
+#define LIST_NGETBYTE 100 /* bigger that this we use alloc, not alloca */
+
+/* #include <string.h> */
+#ifdef MSW
+#include <malloc.h>
+#else
+#include <alloca.h>
+#endif
+
+#define LOGTEN 2.302585092994
+#undef min
+#undef max
+
+//conflict with min,max
+//using namespace std;
+
+float mtof(float f) {return f>-1500 ? 8.17579891564 * exp(.0577622650 * min(f,1499.f)) : 0;}
+float ftom(float f) {return f>0 ? 17.3123405046 * log(.12231220585 * f) : -1500;}
+float powtodb(float f) {return f>0 ? max(100 + 10./LOGTEN * log(f),0.) : 0;}
+float rmstodb(float f) {return f>0 ? max(100 + 20./LOGTEN * log(f),0.) : 0;}
+float dbtopow(float f) {return f>0 ? exp((LOGTEN * 0.1 ) * (min(f,870.f)-100.)) : 0;}
+float dbtorms(float f) {return f>0 ? exp((LOGTEN * 0.05) * (min(f,485.f)-100.)) : 0;}
+
+/* ------------- corresponding objects ----------------------- */
+
+#define FUNC1(C,EXPR) \
+static t_class *C##_class; \
+static void *C##_new() { \
+ t_object *x = (t_object *)pd_new(C##_class); \
+ outlet_new(x, &s_float); return x;} \
+static void C##_float(t_object *x, t_float a) {outlet_float(x->outlet, EXPR);}
+#define FUNC1DECL(C,SYM) \
+ C##_class = class_new2(SYM,C##_new,0,sizeof(t_object),0,""); \
+ class_addfloat(C##_class, (t_method)C##_float); \
+ class_sethelpsymbol(C##_class,s);
+
+FUNC1(mtof, mtof(a))
+FUNC1(ftom, ftom(a))
+FUNC1(powtodb,powtodb(a))
+FUNC1(rmstodb,rmstodb(a))
+FUNC1(dbtorms,dbtorms(a))
+FUNC1(dbtopow,dbtopow(a))
+
+/* -------------------------- openpanel ------------------------------ */
+static t_class *openpanel_class;
+struct t_openpanel : t_object {
+ t_symbol *s;
+ t_symbol *path;
+};
+static void *openpanel_new(t_symbol *s) {
+ t_openpanel *x = (t_openpanel *)pd_new(openpanel_class);
+ x->s = symprintf("d%lx",(t_int)x);
+ x->path = s;
+ pd_bind(x,x->s);
+ outlet_new(x,&s_symbol);
+ return x;
+}
+static void openpanel_bang(t_openpanel *x) {
+ sys_vgui("pdtk_openpanel {%s} {%s}\n", x->s->name, (x->path&&x->path->name)?x->path->name:"\"\"");
+}
+static void openpanel_symbol(t_openpanel *x, t_symbol *s) {
+ sys_vgui("pdtk_openpanel {%s} {%s}\n", x->s->name, (s && s->name) ? s->name : "\"\"");
+}
+static void openpanel_callback(t_openpanel *x, t_symbol *s) {outlet_symbol(x->outlet, s);}
+static void openpanel_path(t_openpanel *x, t_symbol *s) {x->path=s;}
+static void openpanel_free(t_openpanel *x) {pd_unbind(x, x->s);}
+static void openpanel_setup() {
+ t_class *c = openpanel_class = class_new2("openpanel",openpanel_new,openpanel_free,sizeof(t_openpanel),0,"S");
+ class_addbang(c, openpanel_bang);
+ class_addmethod2(c, openpanel_path, "path","s");
+ class_addmethod2(c, openpanel_callback,"callback","s");
+ class_addsymbol(c, openpanel_symbol);
+}
+
+/* -------------------------- savepanel ------------------------------ */
+static t_class *savepanel_class;
+struct t_savepanel : t_object {
+ t_symbol *s;
+ t_symbol *path;
+};
+static void *savepanel_new(t_symbol*s) {
+ t_savepanel *x = (t_savepanel *)pd_new(savepanel_class);
+ x->s = symprintf("d%lx",(t_int)x);
+ x->path=s;
+ pd_bind(x, x->s);
+ outlet_new(x, &s_symbol);
+ return x;
+}
+static void savepanel_bang(t_savepanel *x) {
+ sys_vgui("pdtk_savepanel {%s} {%s}\n", x->s->name, (x->path&&x->path->name)?x->path->name:"\"\"");
+}
+static void savepanel_symbol(t_savepanel *x, t_symbol *s) {
+ sys_vgui("pdtk_savepanel {%s} {%s}\n", x->s->name, (s && s->name) ? s->name : "\"\"");
+}
+static void savepanel_callback(t_savepanel *x, t_symbol *s) {outlet_symbol(x->outlet, s);}
+static void savepanel_free(t_savepanel *x) {pd_unbind(x, x->s);}
+static void savepanel_setup() {
+ t_class *c = savepanel_class = class_new2("savepanel",savepanel_new,savepanel_free,sizeof(t_savepanel),0,"S");
+ class_addbang(c, savepanel_bang);
+ class_addmethod2(c, openpanel_path, "path","s");
+ class_addmethod2(c, savepanel_callback, "callback","s");
+ class_addsymbol(c, savepanel_symbol);
+}
+
+/* ---------------------- key and its relatives ------------------ */
+static t_symbol *key_sym, *keyup_sym, *keyname_sym;
+static t_class *key_class, *keyup_class, *keyname_class;
+struct t_key : t_object {};
+static void *key_new() {
+ t_key *x = (t_key *)pd_new(key_class);
+ outlet_new(x, &s_float);
+ pd_bind(x, key_sym);
+ return x;
+}
+static void key_float(t_key *x, t_floatarg f) {outlet_float(x->outlet, f);}
+
+struct t_keyup : t_object {};
+static void *keyup_new() {
+ t_keyup *x = (t_keyup *)pd_new(keyup_class);
+ outlet_new(x, &s_float);
+ pd_bind(x, keyup_sym);
+ return x;
+}
+static void keyup_float(t_keyup *x, t_floatarg f) {outlet_float(x->outlet, f);}
+
+struct t_keyname : t_object {};
+static void *keyname_new() {
+ t_keyname *x = (t_keyname *)pd_new(keyname_class);
+ outlet_new(x, &s_float);
+ outlet_new(x, &s_symbol);
+ pd_bind(x, keyname_sym);
+ return x;
+}
+static void keyname_list(t_keyname *x, t_symbol *s, int ac, t_atom *av) {
+ outlet_symbol(x->out(1), atom_getsymbolarg(1, ac, av));
+ outlet_float( x->out(0), atom_getfloatarg( 0, ac, av));
+}
+static void key_free( t_key *x) {pd_unbind(x, key_sym);}
+static void keyup_free( t_keyup *x) {pd_unbind(x, keyup_sym);}
+static void keyname_free(t_keyname *x) {pd_unbind(x, keyname_sym);}
+
+static void key_setup() {
+ key_class = class_new2("key", key_new, key_free, sizeof(t_key), CLASS_NOINLET,"");
+ keyup_class = class_new2("keyup", keyup_new, keyup_free, sizeof(t_keyup), CLASS_NOINLET,"");
+ keyname_class = class_new2("keyname",keyname_new,keyname_free,sizeof(t_keyname),CLASS_NOINLET,"");
+ class_addfloat(key_class, key_float);
+ class_addfloat(keyup_class, keyup_float);
+ class_addlist( keyname_class, keyname_list);
+ class_sethelpsymbol(keyup_class, gensym("key"));
+ class_sethelpsymbol(keyname_class, gensym("key"));
+ key_sym = gensym("#key");
+ keyup_sym = gensym("#keyup");
+ keyname_sym = gensym("#keyname");
+}
+
+static t_class *netsend_class;
+struct t_netsend : t_object {
+ int fd;
+ int protocol;
+};
+static void *netsend_new(t_floatarg udpflag) {
+ t_netsend *x = (t_netsend *)pd_new(netsend_class);
+ outlet_new(x, &s_float);
+ x->fd = -1;
+ x->protocol = (udpflag != 0 ? SOCK_DGRAM : SOCK_STREAM);
+ return x;
+}
+static void netsend_connect(t_netsend *x, t_symbol *hostname, t_floatarg fportno) {
+ struct sockaddr_in server;
+ int portno = (int)fportno;
+ if (x->fd >= 0) {error("netsend_connect: already connected"); return;}
+ /* create a socket */
+ int sockfd = socket(AF_INET, x->protocol, 0);
+ if (sockfd < 0) {sys_sockerror("socket"); return;}
+ /* connect socket using hostname provided in command line */
+ server.sin_family = AF_INET;
+ struct hostent *hp = gethostbyname(hostname->name);
+ if (!hp) {error("bad host?"); return;}
+#if 0
+ int intarg = 0;
+ if (setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, &intarg, sizeof(intarg)) < 0)
+ error("setsockopt (SO_RCVBUF) failed");
+#endif
+ /* for stream (TCP) sockets, specify "nodelay" */
+ if (x->protocol == SOCK_STREAM) {
+ int intarg = 1;
+ if (setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &intarg, sizeof(intarg)) < 0)
+ error("setsockopt (TCP_NODELAY) failed");
+ }
+ memcpy((char *)&server.sin_addr, (char *)hp->h_addr, hp->h_length);
+ /* assign client port number */
+ server.sin_port = htons((u_short)portno);
+ post("connecting to port %d", portno);
+ /* try to connect. LATER make a separate thread to do this because it might block */
+ if (connect(sockfd, (struct sockaddr *) &server, sizeof (server)) < 0) {
+ sys_sockerror("connecting stream socket");
+ sys_closesocket(sockfd);
+ return;
+ }
+ x->fd = sockfd;
+ outlet_float(x->outlet, 1);
+}
+
+static void netsend_disconnect(t_netsend *x) {
+ if (x->fd < 0) return;
+ sys_closesocket(x->fd);
+ x->fd = -1;
+ outlet_float(x->outlet, 0);
+}
+static void netsend_send(t_netsend *x, t_symbol *s, int argc, t_atom *argv) {
+ if (x->fd < 0) {error("netsend: not connected"); return;}
+ t_binbuf *b = binbuf_new();
+ t_atom at;
+ binbuf_add(b, argc, argv);
+ SETSEMI(&at);
+ binbuf_add(b, 1, &at);
+ char *buf;
+ int length, sent=0;
+ binbuf_gettext(b, &buf, &length);
+ char *bp = buf;
+ while (sent < length) {
+ static double lastwarntime;
+ static double pleasewarn;
+ double timebefore = sys_getrealtime();
+ int res = send(x->fd, buf, length-sent, 0);
+ double timeafter = sys_getrealtime();
+ int late = (timeafter - timebefore > 0.005);
+ if (late || pleasewarn) {
+ if (timeafter > lastwarntime + 2) {
+ post("netsend blocked %d msec", (int)(1000 * ((timeafter - timebefore) + pleasewarn)));
+ pleasewarn = 0;
+ lastwarntime = timeafter;
+ } else if (late) pleasewarn += timeafter - timebefore;
+ }
+ if (res <= 0) {
+ sys_sockerror("netsend");
+ netsend_disconnect(x);
+ break;
+ } else {
+ sent += res;
+ bp += res;
+ }
+ }
+ free(buf);
+ binbuf_free(b);
+}
+static void netsend_free(t_netsend *x) {netsend_disconnect(x);}
+static void netsend_setup() {
+ netsend_class = class_new2("netsend",netsend_new,netsend_free,sizeof(t_netsend),0,"F");
+ class_addmethod2(netsend_class, netsend_connect, "connect","sf");
+ class_addmethod2(netsend_class, netsend_disconnect, "disconnect","");
+ class_addmethod2(netsend_class, netsend_send, "send","*");
+}
+
+static t_class *netreceive_class;
+struct t_netreceive : t_object {
+ t_outlet *msgout;
+ t_outlet *connectout;
+ int connectsocket;
+ int nconnections;
+ int udp;
+/* only used for sending (bidirectional socket to desire.tk) */
+ t_socketreceiver *sr;
+};
+static void netreceive_notify(t_netreceive *x) {
+ outlet_float(x->connectout, --x->nconnections);
+}
+static void netreceive_doit(t_netreceive *x, t_binbuf *b) {
+ int natom = binbuf_getnatom(b);
+ t_atom *at = binbuf_getvec(b);
+ for (int msg = 0; msg < natom;) {
+ int emsg;
+ for (emsg = msg; emsg < natom && at[emsg].a_type != A_COMMA && at[emsg].a_type != A_SEMI; emsg++) {}
+ if (emsg > msg) {
+ for (int i = msg; i < emsg; i++) if (at[i].a_type == A_DOLLAR || at[i].a_type == A_DOLLSYM) {
+ error("netreceive: got dollar sign in message");
+ goto nodice;
+ }
+ if (at[msg].a_type == A_FLOAT) {
+ if (emsg > msg + 1) outlet_list(x->msgout, 0, emsg-msg, at + msg);
+ else outlet_float(x->msgout, at[msg].a_float);
+ } else if (at[msg].a_type == A_SYMBOL)
+ outlet_anything(x->msgout, at[msg].a_symbol, emsg-msg-1, at + msg + 1);
+ }
+ nodice:
+ msg = emsg + 1;
+ }
+}
+static void netreceive_connectpoll(t_netreceive *x) {
+ int fd = accept(x->connectsocket, 0, 0);
+ if (fd < 0) post("netreceive: accept failed");
+ else {
+ t_socketreceiver *y = socketreceiver_new((t_pd *)x, fd,
+ (t_socketnotifier)netreceive_notify, x->msgout?(t_socketreceivefn)netreceive_doit:0, 0);
+ sys_addpollfn(fd, (t_fdpollfn)socketreceiver_read, y);
+ outlet_float(x->connectout, ++x->nconnections);
+ y->next = x->sr;
+ x->sr = y;
+ }
+}
+extern "C" t_text *netreceive_new(t_symbol *compatflag, t_floatarg fportno, t_floatarg udpflag) {
+ struct sockaddr_in server;
+ int udp = !!udpflag;
+ int old = !strcmp(compatflag->name , "old");
+ int intarg;
+ /* create a socket */
+ int sockfd = socket(AF_INET, (udp ? SOCK_DGRAM : SOCK_STREAM), 0);
+ if (sockfd < 0) {sys_sockerror("socket"); return 0;}
+ server.sin_family = AF_INET;
+ server.sin_addr.s_addr = INADDR_ANY;
+#if 1
+ /* ask OS to allow another Pd to reopen this port after we close it. */
+ intarg = 1;
+ if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &intarg, sizeof(intarg)) < 0)
+ post("setsockopt (SO_REUSEADDR) failed");
+#endif
+#if 0
+ intarg = 0;
+ if (setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &intarg, sizeof(intarg)) < 0)
+ post("setsockopt (SO_RCVBUF) failed");
+#endif
+ /* Stream (TCP) sockets are set NODELAY */
+ if (!udp) {
+ intarg = 1;
+ if (setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &intarg, sizeof(intarg)) < 0)
+ post("setsockopt (TCP_NODELAY) failed");
+ }
+ /* assign server port number */
+ server.sin_port = htons((u_short)fportno);
+ /* name the socket */
+ if (bind(sockfd, (struct sockaddr *)&server, sizeof(server)) < 0) {
+ sys_sockerror("bind");
+ sys_closesocket(sockfd);
+ return 0;
+ }
+ t_netreceive *x = (t_netreceive *)pd_new(netreceive_class);
+ if (old) {
+ /* old style, nonsecure version */
+ x->msgout = 0;
+ } else x->msgout = outlet_new(x, &s_anything);
+ if (udp) { /* datagram protocol */
+ t_socketreceiver *y = socketreceiver_new((t_pd *)x, sockfd, (t_socketnotifier)netreceive_notify,
+ x->msgout ? (t_socketreceivefn)netreceive_doit : 0, 1);
+ sys_addpollfn(sockfd, (t_fdpollfn)socketreceiver_read, y);
+ x->connectout = 0;
+ } else { /* streaming protocol */
+ if (listen(sockfd, 5) < 0) {
+ sys_sockerror("listen");
+ sys_closesocket(sockfd);
+ sockfd = -1;
+ } else {
+ sys_addpollfn(sockfd, (t_fdpollfn)netreceive_connectpoll, x);
+ x->connectout = outlet_new(x, &s_float);
+ }
+ }
+ x->connectsocket = sockfd;
+ x->nconnections = 0;
+ x->udp = udp;
+ x->sr = 0;
+ return x;
+}
+static void netreceive_free(t_netreceive *x) {
+ /* LATER make me clean up open connections */
+ if (x->connectsocket >= 0) {
+ sys_rmpollfn(x->connectsocket);
+ sys_closesocket(x->connectsocket);
+ }
+}
+static void netreceive_setup() {
+ netreceive_class = class_new2("netreceive",netreceive_new,netreceive_free,sizeof(t_netreceive),CLASS_NOINLET,"FFS");
+}
+extern "C" t_socketreceiver *netreceive_newest_receiver(t_netreceive *x) {return x->sr;}
+
+struct t_qlist : t_object {
+ t_binbuf *binbuf;
+ int onset; /* playback position */
+ t_clock *clock;
+ float tempo;
+ double whenclockset;
+ float clockdelay;
+ t_symbol *dir;
+ t_canvas *canvas;
+ int reentered;
+};
+static void qlist_tick(t_qlist *x);
+static t_class *qlist_class;
+static void *qlist_new() {
+ t_qlist *x = (t_qlist *)pd_new(qlist_class);
+ x->binbuf = binbuf_new();
+ x->clock = clock_new(x, (t_method)qlist_tick);
+ outlet_new(x, &s_list);
+ outlet_new(x, &s_bang);
+ x->onset = 0x7fffffff;
+ x->tempo = 1;
+ x->whenclockset = 0;
+ x->clockdelay = 0;
+ x->canvas = canvas_getcurrent();
+ x->reentered = 0;
+ return x;
+}
+static void qlist_rewind(t_qlist *x) {
+ x->onset = 0;
+ if (x->clock) clock_unset(x->clock);
+ x->whenclockset = 0;
+ x->reentered = 1;
+}
+static void qlist_donext(t_qlist *x, int drop, int automatic) {
+ t_pd *target = 0;
+ while (1) {
+ int argc = binbuf_getnatom(x->binbuf), count, onset = x->onset, onset2, wasreentered;
+ t_atom *argv = binbuf_getvec(x->binbuf);
+ t_atom *ap = argv + onset, *ap2;
+ if (onset >= argc) goto end;
+ while (ap->a_type == A_SEMI || ap->a_type == A_COMMA) {
+ if (ap->a_type == A_SEMI) target = 0;
+ onset++, ap++;
+ if (onset >= argc) goto end;
+ }
+ if (!target && ap->a_type == A_FLOAT) {
+ ap2 = ap + 1;
+ onset2 = onset + 1;
+ while (onset2 < argc && ap2->a_type == A_FLOAT) onset2++, ap2++;
+ x->onset = onset2;
+ if (automatic) {
+ clock_delay(x->clock, x->clockdelay = ap->a_float * x->tempo);
+ x->whenclockset = clock_getsystime();
+ } else outlet_list(x->outlet, 0, onset2-onset, ap);
+ return;
+ }
+ ap2 = ap + 1;
+ onset2 = onset + 1;
+ while (onset2 < argc && (ap2->a_type == A_FLOAT || ap2->a_type == A_SYMBOL)) onset2++, ap2++;
+ x->onset = onset2;
+ count = onset2 - onset;
+ if (!target) {
+ if (ap->a_type != A_SYMBOL) continue;
+ target = ap->a_symbol->thing;
+ if (!target) {error("qlist: %s: no such object", ap->a_symbol->name); continue;}
+ ap++;
+ onset++;
+ count--;
+ if (!count) {x->onset = onset2; continue;}
+ }
+ wasreentered = x->reentered;
+ x->reentered = 0;
+ if (!drop) {
+ if (ap->a_type == A_FLOAT) typedmess(target, &s_list, count, ap);
+ else if (ap->a_type == A_SYMBOL) typedmess(target, ap->a_symbol, count-1, ap+1);
+ }
+ if (x->reentered) return;
+ x->reentered = wasreentered;
+ } /* while (1); never falls through */
+
+end:
+ x->onset = 0x7fffffff;
+ outlet_bang(x->out(1));
+ x->whenclockset = 0;
+}
+static void qlist_next(t_qlist *x, t_floatarg drop) {qlist_donext(x, drop != 0, 0);}
+static void qlist_bang(t_qlist *x) {qlist_rewind(x); qlist_donext(x, 0, 1);}
+static void qlist_tick(t_qlist *x) {x->whenclockset=0; qlist_donext(x, 0, 1);}
+static void qlist_add(t_qlist *x, t_symbol *s, int ac, t_atom *av) {
+ t_atom a;
+ SETSEMI(&a);
+ binbuf_add(x->binbuf, ac, av);
+ binbuf_add(x->binbuf, 1, &a);
+}
+static void qlist_add2(t_qlist *x, t_symbol *s, int ac, t_atom *av) {
+ binbuf_add(x->binbuf, ac, av);
+}
+static void qlist_clear(t_qlist *x) {
+ qlist_rewind(x);
+ binbuf_clear(x->binbuf);
+}
+static void qlist_set(t_qlist *x, t_symbol *s, int ac, t_atom *av) {
+ qlist_clear(x);
+ qlist_add(x, s, ac, av);
+}
+static void qlist_read(t_qlist *x, t_symbol *filename, t_symbol *format) {
+ int cr = 0;
+ if (!strcmp(format->name, "cr")) cr = 1;
+ else if (*format->name) error("qlist_read: unknown flag: %s", format->name);
+ if (binbuf_read_via_canvas(x->binbuf, filename->name, x->canvas, cr))
+ error("%s: read failed", filename->name);
+ x->onset = 0x7fffffff;
+ x->reentered = 1;
+}
+static void qlist_write(t_qlist *x, t_symbol *filename, t_symbol *format) {
+ int cr = 0;
+ char *buf = canvas_makefilename(x->canvas,filename->name,0,0);
+ if (!strcmp(format->name, "cr")) cr = 1;
+ else if (*format->name) error("qlist_read: unknown flag: %s", format->name);
+ if (binbuf_write(x->binbuf, buf, "", cr)) error("%s: write failed", filename->name);
+ free(buf);
+}
+static void qlist_print(t_qlist *x) {
+ post("--------- textfile or qlist contents: -----------");
+ binbuf_print(x->binbuf);
+}
+static void qlist_tempo(t_qlist *x, t_float f) {
+ float newtempo;
+ if (f < 1e-20) f = 1e-20;
+ else if (f > 1e20) f = 1e20;
+ newtempo = 1./f;
+ if (x->whenclockset != 0) {
+ float elapsed = clock_gettimesince(x->whenclockset);
+ float left = x->clockdelay - elapsed;
+ if (left < 0) left = 0;
+ left *= newtempo / x->tempo;
+ clock_delay(x->clock, left);
+ }
+ x->tempo = newtempo;
+}
+static void qlist_free(t_qlist *x) {
+ binbuf_free(x->binbuf);
+ if (x->clock) clock_free(x->clock);
+}
+
+static t_class *textfile_class;
+typedef t_qlist t_textfile;
+static void *textfile_new() {
+ t_textfile *x = (t_textfile *)pd_new(textfile_class);
+ x->binbuf = binbuf_new();
+ outlet_new(x, &s_list);
+ outlet_new(x, &s_bang);
+ x->onset = 0x7fffffff;
+ x->reentered = 0;
+ x->tempo = 1;
+ x->whenclockset = 0;
+ x->clockdelay = 0;
+ x->clock = NULL;
+ x->canvas = canvas_getcurrent();
+ return x;
+}
+static void textfile_bang(t_textfile *x) {
+ int argc = binbuf_getnatom(x->binbuf), onset = x->onset, onset2;
+ t_atom *argv = binbuf_getvec(x->binbuf);
+ t_atom *ap = argv + onset, *ap2;
+ while (onset < argc && (ap->a_type == A_SEMI || ap->a_type == A_COMMA)) onset++, ap++;
+ onset2 = onset;
+ ap2 = ap;
+ while (onset2 < argc && (ap2->a_type != A_SEMI && ap2->a_type != A_COMMA)) onset2++, ap2++;
+ if (onset2 > onset) {
+ x->onset = onset2;
+ if (ap->a_type == A_SYMBOL)
+ outlet_anything(x->outlet, ap->a_symbol, onset2-onset-1, ap+1);
+ else outlet_list(x->outlet, 0, onset2-onset, ap);
+ } else {
+ x->onset = 0x7fffffff;
+ outlet_bang(x->out(1));
+ }
+}
+
+static void textfile_rewind(t_qlist *x) {x->onset = 0;}
+static void textfile_free(t_textfile *x) {binbuf_free(x->binbuf);}
+
+extern t_pd *newest;
+
+/* the "list" object family.
+
+ list append - append a list to another
+ list prepend - prepend a list to another
+ list split - first n elements to first outlet, rest to second outlet
+ list trim - trim off "list" selector
+ list length - output number of items in list
+
+Need to think more about:
+ list foreach - spit out elements of a list one by one (also in reverse?)
+ list array - get items from a named array as a list
+ list reverse - permute elements of a list back to front
+ list pack - synonym for 'pack'
+ list unpack - synonym for 'unpack'
+ list cat - build a list by accumulating elements
+
+Probably don't need:
+ list first - output first n elements.
+ list last - output last n elements
+ list nth - nth item in list, counting from zero
+*/
+
+/* -------------- utility functions: storage, copying -------------- */
+
+#if HAVE_ALLOCA
+#define ATOMS_ALLOCA(x, n) ((x) = (t_atom *)((n) < LIST_NGETBYTE ? \
+ alloca((n) * sizeof(t_atom)) : getbytes((n) * sizeof(t_atom))))
+#define ATOMS_FREEA(x, n) ( \
+ ((n) < LIST_NGETBYTE || (free((x)), 0)))
+#else
+#define ATOMS_ALLOCA(x, n) ((x) = (t_atom *)getbytes((n) * sizeof(t_atom)))
+#define ATOMS_FREEA(x, n) (free((x)))
+#endif
+
+static void atoms_copy(int argc, t_atom *from, t_atom *to) {
+ for (int i = 0; i < argc; i++) to[i] = from[i];
+}
+
+/* ------------- fake class to divert inlets to ----------------- */
+static void alist_list(t_binbuf *x, t_symbol *s, int argc, t_atom *argv) {
+ binbuf_clear(x);
+ x->v = (t_atom *)getbytes(argc * sizeof(*x->v));
+ if (!x->v) {x->n = 0; error("list_alloc: out of memory"); return;}
+ x->n = argc;
+ for (int i = 0; i < argc; i++) x->v[i] = argv[i];
+}
+static void alist_anything(t_binbuf *x, t_symbol *s, int argc, t_atom *argv) {
+ binbuf_clear(x);
+ x->v = (t_atom *)getbytes((argc+1) * sizeof(*x->v));
+ if (!x->v) {x->n = 0; error("list_alloc: out of memory"); return;}
+ x->n = argc+1;
+ SETSYMBOL(&x->v[0], s);
+ for (int i = 0; i < argc; i++) x->v[i+1] = argv[i];
+}
+static void alist_toatoms(t_binbuf *x, t_atom *to) {for (size_t i=0; i<x->n; i++) to[i] = x->v[i];}
+
+t_class *list_append_class; struct t_list_append : t_object {t_binbuf *alist;};
+t_class *list_prepend_class; struct t_list_prepend : t_object {t_binbuf *alist;};
+t_class *list_split_class; struct t_list_split : t_object {t_float f;};
+t_class *list_trim_class; struct t_list_trim : t_object {};
+t_class *list_length_class; struct t_list_length : t_object {};
+
+static t_pd *list_append_new(t_symbol *s, int argc, t_atom *argv) {
+ t_list_append *x = (t_list_append *)pd_new(list_append_class);
+ x->alist = binbuf_new(); alist_list(x->alist, 0, argc, argv); outlet_new(x, &s_list); inlet_new(x,x->alist, 0, 0);
+ return x;
+}
+static t_pd *list_prepend_new(t_symbol *s, int argc, t_atom *argv) {
+ t_list_prepend *x = (t_list_prepend *)pd_new(list_prepend_class);
+ x->alist = binbuf_new(); alist_list(x->alist, 0, argc, argv); outlet_new(x, &s_list); inlet_new(x,x->alist,0,0);
+ return x;
+}
+static void list_append_free (t_list_append *x) {binbuf_free(x->alist);}
+static void list_prepend_free(t_list_prepend *x) {binbuf_free(x->alist);}
+
+static void list_append_list(t_list_append *x, t_symbol *s, int argc, t_atom *argv) {
+ t_atom *outv; int outc = x->alist->n + argc; ATOMS_ALLOCA(outv, outc);
+ atoms_copy(argc, argv, outv);
+ alist_toatoms(x->alist, outv+argc);
+ outlet_list(x->outlet, &s_list, outc, outv); ATOMS_FREEA(outv, outc);
+}
+static void list_append_anything(t_list_append *x, t_symbol *s, int argc, t_atom *argv) {
+ t_atom *outv; int outc = x->alist->n+argc+1; ATOMS_ALLOCA(outv, outc);
+ SETSYMBOL(outv, s);
+ atoms_copy(argc, argv, outv + 1);
+ alist_toatoms(x->alist, outv + 1 + argc);
+ outlet_list(x->outlet, &s_list, outc, outv); ATOMS_FREEA(outv, outc);
+}
+static void list_prepend_list(t_list_prepend *x, t_symbol *s, int argc, t_atom *argv) {
+ t_atom *outv; int outc = x->alist->n + argc; ATOMS_ALLOCA(outv, outc);
+ alist_toatoms(x->alist, outv);
+ atoms_copy(argc, argv, outv + x->alist->n);
+ outlet_list(x->outlet, &s_list, outc, outv); ATOMS_FREEA(outv, outc);
+}
+static void list_prepend_anything(t_list_prepend *x, t_symbol *s, int argc, t_atom *argv) {
+ t_atom *outv; int outc = x->alist->n+argc+1; ATOMS_ALLOCA(outv, outc);
+ alist_toatoms(x->alist, outv);
+ SETSYMBOL(outv + x->alist->n, s);
+ atoms_copy(argc, argv, outv + x->alist->n + 1);
+ outlet_list(x->outlet, &s_list, outc, outv); ATOMS_FREEA(outv, outc);
+}
+static t_pd *list_split_new(t_floatarg f) {
+ t_list_split *x = (t_list_split *)pd_new(list_split_class);
+ outlet_new(x, &s_list);
+ outlet_new(x, &s_list);
+ outlet_new(x, &s_list);
+ floatinlet_new(x, &x->f);
+ x->f = f;
+ return x;
+}
+static void list_split_list(t_list_split *x, t_symbol *s, int argc, t_atom *argv) {
+ int n = (int)x->f;
+ if (n < 0) n = 0;
+ if (argc >= n) {
+ outlet_list(x->out(1), &s_list, argc-n, argv+n);
+ outlet_list(x->out(0), &s_list, n, argv);
+ } else outlet_list(x->out(2), &s_list, argc, argv);
+}
+static void list_split_anything(t_list_split *x, t_symbol *s, int argc, t_atom *argv) {
+ t_atom *outv;
+ ATOMS_ALLOCA(outv, argc+1);
+ SETSYMBOL(outv, s);
+ atoms_copy(argc, argv, outv + 1);
+ list_split_list(x, &s_list, argc+1, outv);
+ ATOMS_FREEA(outv, argc+1);
+}
+
+static t_pd *list_trim_new() {
+ t_list_trim *x = (t_list_trim *)pd_new(list_trim_class);
+ outlet_new(x, &s_list);
+ return x;
+}
+static void list_trim_list(t_list_trim *x, t_symbol *s, int argc, t_atom *argv) {
+ if (argc < 1 || argv[0].a_type != A_SYMBOL) outlet_list(x->outlet, &s_list, argc, argv);
+ else outlet_anything(x->outlet, argv[0].a_symbol, argc-1, argv+1);
+}
+static void list_trim_anything(t_list_trim *x, t_symbol *s, int argc, t_atom *argv) {
+ outlet_anything(x->outlet, s, argc, argv);
+}
+
+static t_pd *list_length_new() {
+ t_list_length *x = (t_list_length *)pd_new(list_length_class);
+ outlet_new(x, &s_float);
+ return x;
+}
+static void list_length_list( t_list_length *x, t_symbol *s, int argc, t_atom *argv) {outlet_float(x->outlet, (float)argc);}
+static void list_length_anything(t_list_length *x, t_symbol *s, int argc, t_atom *argv) {outlet_float(x->outlet, (float)argc+1);}
+
+static void *list_new(t_pd *dummy, t_symbol *s, int argc, t_atom *argv) {
+ t_pd *newest = 0; /* hide global var */
+ if (!argc || argv[0].a_type != A_SYMBOL) newest = list_append_new(s, argc, argv);
+ else {
+ t_symbol *s2 = argv[0].a_symbol;
+ if (s2 == gensym("append")) newest = list_append_new(s, argc-1, argv+1);
+ else if (s2 == gensym("prepend")) newest = list_prepend_new(s, argc-1, argv+1);
+ else if (s2 == gensym("split")) newest = list_split_new(atom_getfloatarg(1, argc, argv));
+ else if (s2 == gensym("trim")) newest = list_trim_new();
+ else if (s2 == gensym("length")) newest = list_length_new();
+ else error("list %s: unknown function", s2->name);
+ }
+ /* workaround for bug in kernel.c */
+ if (newest) pd_set_newest(newest);
+ return newest;
+}
+
+#define LISTOP(name,argspec,freer) \
+ list_##name##_class = class_new2("list " #name,list_##name##_new,freer,sizeof(t_list_##name),0,argspec); \
+ class_addlist(list_##name##_class, list_##name##_list); \
+ class_addanything(list_##name##_class, list_##name##_anything); \
+ class_sethelpsymbol(list_##name##_class, &s_list);
+
+static void list_setup () {
+ LISTOP(append,"*",list_append_free)
+ LISTOP(prepend,"*",list_prepend_free)
+ LISTOP(split,"F",0)
+ LISTOP(trim,"",0)
+ LISTOP(length,"",0)
+ class_addcreator2("list",list_new,"*");
+}
+
+/* miller's "homebrew" linear-congruential algorithm */
+static t_class *random_class;
+struct t_random : t_object {
+ t_float f;
+ unsigned int state;
+};
+static int makeseed() {
+ static unsigned int random_nextseed = 1489853723;
+ random_nextseed = random_nextseed * 435898247 + 938284287;
+ return random_nextseed & 0x7fffffff;
+}
+static void *random_new(t_floatarg f) {
+ t_random *x = (t_random *)pd_new(random_class);
+ x->f = f;
+ x->state = makeseed();
+ floatinlet_new(x,&x->f);
+ outlet_new(x,&s_float);
+ return x;
+}
+static void random_bang(t_random *x) {
+ int n = (int)x->f, nval;
+ int range = max(n,1);
+ unsigned int randval = x->state;
+ x->state = randval = randval * 472940017 + 832416023;
+ nval = (int)((double)range * (double)randval * (1./4294967296.));
+ if (nval >= range) nval = (int)(range-1);
+ outlet_float(x->outlet, nval);
+}
+static void random_seed(t_random *x, float f, float glob) {x->state = (int)f;}
+static void random_setup() {
+ random_class = class_new2("random",random_new,0,sizeof(t_random),0,"F");
+ class_addbang(random_class, random_bang);
+ class_addmethod2(random_class, random_seed,"seed","f");
+}
+
+static t_class *loadbang_class;
+struct t_loadbang : t_object {};
+static void *loadbang_new() {
+ t_loadbang *x = (t_loadbang *)pd_new(loadbang_class);
+ outlet_new(x,&s_bang);
+ return x;
+}
+static void loadbang_loadbang(t_loadbang *x) {
+ if (!sys_noloadbang) outlet_bang(x->outlet);
+}
+static void loadbang_setup() {
+ loadbang_class = class_new2("loadbang",loadbang_new,0,sizeof(t_loadbang),CLASS_NOINLET,"");
+ class_addmethod2(loadbang_class, loadbang_loadbang, "loadbang","");
+}
+
+static t_class *namecanvas_class;
+struct t_namecanvas : t_object {
+ t_symbol *sym;
+ t_pd *owner;
+};
+static void *namecanvas_new(t_symbol *s) {
+ t_namecanvas *x = (t_namecanvas *)pd_new(namecanvas_class);
+ x->owner = (t_pd *)canvas_getcurrent();
+ x->sym = s;
+ if (*s->name) pd_bind(x->owner, s);
+ return x;
+}
+static void namecanvas_free(t_namecanvas *x) {
+ if (*x->sym->name) pd_unbind(x->owner, x->sym);
+}
+static void namecanvas_setup() {
+ namecanvas_class = class_new2("namecanvas",namecanvas_new,namecanvas_free,sizeof(t_namecanvas),CLASS_NOINLET,"S");
+}
+
+static t_class *cputime_class;
+struct t_cputime : t_object {
+#ifdef UNISTD
+ struct tms setcputime;
+#endif
+#ifdef MSW
+ LARGE_INTEGER kerneltime;
+ LARGE_INTEGER usertime;
+ bool warned;
+#endif
+};
+static t_class *realtime_class; struct t_realtime : t_object {double setrealtime;};
+static t_class *timer_class; struct t_timer : t_object {double settime;};
+
+
+static void cputime_bang(t_cputime *x) {
+#ifdef UNISTD
+ times(&x->setcputime);
+#endif
+#ifdef MSW
+ FILETIME ignorethis, ignorethat;
+ BOOL retval = GetProcessTimes(GetCurrentProcess(), &ignorethis, &ignorethat,
+ (FILETIME *)&x->kerneltime, (FILETIME *)&x->usertime);
+ if (!retval) {
+ if (!x->warned) {error("cputime is apparently not supported on your platform"); return;}
+ x->warned = 1;
+ x->kerneltime.QuadPart = 0;
+ x->usertime.QuadPart = 0;
+ }
+#endif
+}
+static void cputime_bang2(t_cputime *x) {
+#ifdef UNISTD
+ struct tms newcputime;
+ times(&newcputime);
+ float elapsedcpu = 1000 * (newcputime.tms_utime + newcputime.tms_stime
+ - x->setcputime.tms_utime - x->setcputime.tms_stime) / HZ;
+#endif
+#ifdef MSW
+ FILETIME ignorethis, ignorethat;
+ LARGE_INTEGER usertime, kerneltime;
+ BOOL retval = GetProcessTimes(GetCurrentProcess(), &ignorethis, &ignorethat, (FILETIME *)&kerneltime, (FILETIME *)&usertime);
+ float elapsedcpu = retval ? 0.0001 *
+ ((kerneltime.QuadPart - x->kerneltime.QuadPart) +
+ (usertime.QuadPart - x->usertime.QuadPart)) : 0;
+#endif
+ outlet_float(x->outlet, elapsedcpu);
+}
+
+static void realtime_bang(t_realtime *x) {x->setrealtime = sys_getrealtime();}
+static void timer_bang(t_timer *x ) {x->settime = clock_getsystime();}
+static void realtime_bang2(t_realtime *x) {outlet_float(x->outlet, (sys_getrealtime() - x->setrealtime) * 1000.);}
+static void timer_bang2(t_timer *x ) {outlet_float(x->outlet, clock_gettimesince(x->settime));}
+
+static void *cputime_new() {
+ t_cputime *x = (t_cputime *)pd_new(cputime_class);
+ outlet_new(x,gensym("float"));
+ inlet_new(x,x,gensym("bang"),gensym("bang2"));
+#ifdef MSW
+ x->warned = 0;
+#endif
+ cputime_bang(x);
+ return x;
+}
+static void *realtime_new() {
+ t_realtime *x = (t_realtime *)pd_new(realtime_class);
+ outlet_new(x,gensym("float"));
+ inlet_new(x,x,gensym("bang"),gensym("bang2"));
+ realtime_bang(x);
+ return x;
+}
+static void *timer_new(t_floatarg f) {
+ t_timer *x = (t_timer *)pd_new(timer_class);
+ timer_bang(x);
+ outlet_new(x, gensym("float"));
+ inlet_new(x, x, gensym("bang"), gensym("bang2"));
+ return x;
+}
+static void timer_setup() {
+ realtime_class = class_new2("realtime",realtime_new,0,sizeof(t_realtime),0,"");
+ cputime_class = class_new2("cputime", cputime_new, 0,sizeof(t_cputime), 0,"");
+ timer_class = class_new2("timer", timer_new, 0,sizeof(t_timer), 0,"F");
+ class_addbang(realtime_class, realtime_bang);
+ class_addbang(cputime_class, cputime_bang);
+ class_addbang(timer_class, timer_bang);
+ class_addmethod2(realtime_class,realtime_bang2,"bang2","");
+ class_addmethod2(cputime_class, cputime_bang2, "bang2","");
+ class_addmethod2(timer_class, timer_bang2, "bang2","");
+}
+
+static t_class *print_class;
+struct t_print : t_object {
+ t_symbol *sym;
+};
+static void *print_new(t_symbol *s) {
+ t_print *x = (t_print *)pd_new(print_class);
+ if (*s->name) x->sym = s;
+ else x->sym = gensym("print");
+ return x;
+}
+static void print_bang(t_print *x) {post("%s: bang", x->sym->name);}
+static void print_pointer(t_print *x, t_gpointer *gp) {post("%s: (gpointer)", x->sym->name);}
+static void print_float(t_print *x, t_float f) {post("%s: %g", x->sym->name, f);}
+static void print_list(t_print *x, t_symbol *s, int argc, t_atom *argv) {
+ if (argc && argv->a_type != A_SYMBOL) startpost("%s:", x->sym->name);
+ else startpost("%s: %s", x->sym->name, (argc>1 ? s_list : argc==1 ? s_symbol : s_bang).name);
+ postatom(argc, argv);
+ endpost();
+}
+static void print_anything(t_print *x, t_symbol *s, int argc, t_atom *argv) {
+ startpost("%s: %s", x->sym->name, s->name);
+ postatom(argc, argv);
+ endpost();
+}
+static void print_setup() {
+ t_class *c = print_class = class_new2("print",print_new,0,sizeof(t_print),0,"S");
+ class_addbang(c, print_bang);
+ class_addfloat(c, print_float);
+ class_addpointer(c, print_pointer);
+ class_addlist(c, print_list);
+ class_addanything(c, print_anything);
+}
+
+/*---- Macro ----*/
+static t_class *macro_class;
+struct t_macro : t_object {
+ t_symbol *sym;
+ t_outlet *bangout;
+};
+
+static void *macro_new(t_symbol *s) {
+ t_macro *x = (t_macro *)pd_new(macro_class);
+ if (*s->name) x->sym = s;
+ else x->sym = gensym("macro");
+ x-> bangout = outlet_new(x, &s_bang);
+ return x;
+}
+
+static void macro_bang(t_macro *x) {outlet_bang(x->bangout);}
+
+static void macro_send(t_macro *x, t_symbol *s, int argc, t_atom *argv) {
+ std::ostringstream t;
+ t << s->name;
+ for (int i=0; i<argc; i++) {t << " " << &argv[i];}
+ sys_mgui(x->dix->canvas, "macro_event_append", "Sp", t.str().data(), x);
+}
+static void macro_setup() {
+ t_class *c = macro_class = class_new2("macro",macro_new,0,sizeof(t_macro),0,"S");
+ class_addanything(c, macro_send);
+ class_addmethod2(c, macro_bang, "mbang","");
+}
+
+/*---- Clipboard ----*/
+static t_class *clipboard_class;
+struct t_clipboard : t_object {
+ t_binbuf *alist;
+ t_symbol *sym;
+ t_outlet *dump;
+};
+
+static void *clipboard_new(t_symbol *s) {
+ t_clipboard *x = (t_clipboard *)pd_new(clipboard_class);
+ if (*s->name) x->sym = s;
+ else x->sym = gensym("clipboard");
+ x->alist = binbuf_new();
+ x->dump = outlet_new(x,&s_list);
+ return x;
+}
+
+static void clipboard_bang(t_clipboard *x) {sys_mgui(x->dix->canvas, "get_clipboard", "p", x);}
+
+static void clipboard_reply (t_clipboard *x, t_symbol *s, int argc, t_atom *argv) {
+ outlet_list(x->dump, &s_list, argc, argv);
+}
+
+static void clipboard_setup() {
+ t_class *c = clipboard_class = class_new2("clipboard",clipboard_new,0,sizeof(t_clipboard),0,"S");
+ class_addbang(c, clipboard_bang);
+ class_addmethod2(c, clipboard_reply,"clipboard_set","*");
+}
+
+/*---- Display ----*/
+static t_class *display_class;
+struct t_display : t_object {
+ t_float height;
+};
+
+static void *display_new(t_floatarg f) {
+ t_display *x = (t_display *)pd_new(display_class);
+ x->height = f;
+ if (!x->height) x->height = 1;
+ return x;
+}
+
+static void display_height (t_display *x) {sys_mgui(x, "height=", "i", (int)x->height);}
+
+static void display_send(t_display *x, t_symbol *s, int argc, t_atom *argv) {
+ std::ostringstream t;
+ t << s->name;
+ for (int i=0; i<argc; i++) {t << " " << &argv[i];}
+ sys_mgui(x, "dis", "S", t.str().data());
+}
+
+static void display_setup() {
+ t_class *c = display_class = class_new2("display",display_new,0,sizeof(t_display),0,"F");
+ class_addanything(c, display_send);
+ class_addmethod2(c, display_height, "height","");
+}
+
+/*---- Any ----*/
+static t_class *any_class;
+struct t_any : t_object {t_binbuf *alist;};
+
+static void *any_new(t_symbol *s,int argc, t_atom *argv) {
+ t_any *x = (t_any *)pd_new(any_class);
+ x->alist = binbuf_new();
+ if (argc) {
+ if (argv[0].a_type == A_FLOAT) {alist_list(x->alist, 0, argc, argv);}
+ if (argv[0].a_type == A_SYMBOL) {alist_anything(x->alist, argv[0].a_symbol, argc-1, argv+1);}
+ }
+ outlet_new(x, &s_anything);
+ inlet_new(x,x->alist, 0, 0);
+ return x;
+}
+
+static void any_anything(t_any *x, t_symbol *s, int argc, t_atom *argv) {
+ t_atom *outv; int outc = x->alist->n+argc+1; ATOMS_ALLOCA(outv, outc);
+ if (argv[0].a_type == A_FLOAT && s->name == "list" || s->name == "float") {
+ alist_list(x->alist, 0, argc, argv); outlet_anything(x->outlet, &s_list, argc, argv);return;
+ }
+ if (argv[0].a_type == A_SYMBOL || s->name != "list" || s->name != "float") {
+ alist_anything(x->alist, s, argc, argv); outlet_anything(x->outlet, s, argc, argv);
+ }
+}
+
+static void any_bang(t_any *x) {
+ t_atom *outv; int outc = x->alist->n;
+ ATOMS_ALLOCA(outv, outc);
+ alist_toatoms(x->alist, outv);
+ if (!binbuf_getnatom(x->alist)) {outlet_bang(x->outlet);return;}
+ if (outv[0].a_type == A_FLOAT) {outlet_anything(x->outlet, &s_list, outc, outv);}
+ if (outv[0].a_type == A_SYMBOL) {outlet_anything(x->outlet, outv[0].a_symbol, outc-1, outv+1);}
+ ATOMS_FREEA(outv, outc);
+}
+
+static void any_setup() {
+ post("DesireData iemlib2 [any] clone");
+ t_class *c = any_class = class_new2("any",any_new,0,sizeof(t_any),0,"*");
+ class_addanything(c, any_anything);
+ class_addbang(c, any_bang);
+}
+
+/* MSW and OSX don't appear to have single-precision ANSI math */
+#if defined(MSW) || defined(__APPLE__)
+#define sinf sin
+#define cosf cos
+#define atanf atan
+#define atan2f atan2
+#define sqrtf sqrt
+#define logf log
+#define expf exp
+#define fabsf fabs
+#define powf pow
+#endif
+
+struct t_binop : t_object {
+ t_float f1;
+ t_float f2;
+};
+static void *binop_new(t_class *floatclass, t_floatarg f) {
+ t_binop *x = (t_binop *)pd_new(floatclass);
+ outlet_new(x, &s_float);
+ floatinlet_new(x, &x->f2);
+ x->f1 = 0;
+ x->f2 = f;
+ return x;
+}
+
+#define BINOP(NAME,EXPR) \
+static t_class *NAME##_class; \
+static void *NAME##_new(t_floatarg f) {return binop_new(NAME##_class, f);} \
+static void NAME##_bang(t_binop *x) {float a=x->f1,b=x->f2; outlet_float(x->outlet,(EXPR));} \
+static void NAME##_float(t_binop *x, t_float f) {x->f1=f; NAME##_bang(x);}
+
+BINOP(binop_plus,a+b)
+BINOP(binop_minus,a-b)
+BINOP(binop_times,a*b)
+BINOP(binop_div,a/b)
+BINOP(binop_pow, a>0?powf(a,b):0)
+BINOP(binop_max, a>b?a:b)
+BINOP(binop_min, a<b?a:b)
+BINOP(binop_ee,a==b)
+BINOP(binop_ne,a!=b)
+BINOP(binop_gt,a>b)
+BINOP(binop_lt,a<b)
+BINOP(binop_ge,a>=b)
+BINOP(binop_le,a<=b)
+BINOP(binop_ba,(int)a&(int)b)
+BINOP(binop_la,a&&b)
+BINOP(binop_bo,(int)a|(int)b)
+BINOP(binop_lo,a||b)
+BINOP(binop_ls,(int)a<<(int)b)
+BINOP(binop_rs,(int)a>>(int)b)
+BINOP(binop_pc,(int)a % (b?(int)b:1))
+static int mymod(int a, int b) {
+ int n2 = (int)b;
+ if (n2 < 0) n2 = -n2; else if (!n2) n2 = 1;
+ int r = (int)a % n2;
+ return r<0 ? r+n2 : r;
+}
+BINOP(binop_mymod, (float)mymod((int)a,(int)b))
+static int mydiv(int a, int b) {
+ if (b < 0) b=-b; else if (!b) b=1;
+ if (a < 0) a -= b-1;
+ return a/b;
+}
+BINOP(binop_mydiv, (float)mydiv((int)a,(int)b))
+
+FUNC1(sin,sinf(a))
+FUNC1(cos,cosf(a))
+FUNC1(tan,tanf(a))
+FUNC1(atan,atanf(a))
+
+static t_class *atan2_class;
+struct t_atan2 : t_object {
+ float f;
+};
+static void *atan2_new() {
+ t_atan2 *x = (t_atan2 *)pd_new(atan2_class);
+ static int warned;
+ if (!warned) post("warning: atan2 inlets switched from Pd 0.37 to 0.38"), warned=1;
+ floatinlet_new(x, &x->f);
+ x->f = 0;
+ outlet_new(x, &s_float);
+ return x;
+}
+static void atan2_float(t_atan2 *x, t_float f) {
+ float r = (f == 0 && x->f == 0 ? 0 : atan2f(f, x->f));
+ outlet_float(x->outlet, r);
+}
+
+FUNC1(sqrt,sqrtf(a))
+FUNC1(log, a>0 ? logf(a) : -1000)
+FUNC1(exp,expf(min(a,87.3365f)))
+FUNC1(abs,fabsf(a))
+
+static t_class *clip_class;
+struct t_clip : t_object {
+ float f1;
+ float f2;
+ float f3;
+};
+static void *clip_new(t_floatarg f2, t_floatarg f3) {
+ t_clip *x = (t_clip *)pd_new(clip_class);
+ floatinlet_new(x, &x->f2); x->f2 = f2;
+ floatinlet_new(x, &x->f3); x->f3 = f3;
+ outlet_new(x, &s_float);
+ return x;
+}
+static void clip_bang( t_clip *x) { outlet_float(x->outlet, clip(x->f1,x->f2,x->f3));}
+static void clip_float(t_clip *x, t_float f) {x->f1 = f; outlet_float(x->outlet, clip(x->f1,x->f2,x->f3));}
+
+void arithmetic_setup() {
+ t_symbol *s = gensym("operators");
+#define BINOPDECL(NAME,SYM) \
+ NAME##_class = class_new2(SYM,NAME##_new,0,sizeof(t_binop),0,"F"); \
+ class_addbang(NAME##_class, NAME##_bang); \
+ class_addfloat(NAME##_class, (t_method)NAME##_float); \
+ class_sethelpsymbol(NAME##_class,s);
+
+ BINOPDECL(binop_plus,"+")
+ BINOPDECL(binop_minus,"-")
+ BINOPDECL(binop_times,"*")
+ BINOPDECL(binop_div,"/")
+ BINOPDECL(binop_pow,"pow")
+ BINOPDECL(binop_max,"max")
+ BINOPDECL(binop_min,"min")
+
+ s = gensym("otherbinops");
+
+ BINOPDECL(binop_ee,"==")
+ BINOPDECL(binop_ne,"!=")
+ BINOPDECL(binop_gt,">")
+ BINOPDECL(binop_lt,"<")
+ BINOPDECL(binop_ge,">=")
+ BINOPDECL(binop_le,"<=")
+
+ BINOPDECL(binop_ba,"&")
+ BINOPDECL(binop_la,"&&")
+ BINOPDECL(binop_bo,"|")
+ BINOPDECL(binop_lo,"||")
+ BINOPDECL(binop_ls,"<<")
+ BINOPDECL(binop_rs,">>")
+
+ BINOPDECL(binop_pc,"%")
+ BINOPDECL(binop_mymod,"mod")
+ BINOPDECL(binop_mydiv,"div")
+
+ s = gensym("math");
+
+#define FUNCDECL(NAME,SYM) \
+ NAME##_class = class_new2(SYM,NAME##_new,0,sizeof(t_object),0,""); \
+ class_addfloat(NAME##_class, (t_method)NAME##_float); \
+ class_sethelpsymbol(NAME##_class,s);
+
+ FUNCDECL(sin,"sin");
+ FUNCDECL(cos,"cos");
+ FUNCDECL(tan,"tan");
+ FUNCDECL(atan,"atan");
+ FUNCDECL(atan2,"atan2"); /* actually a binop */
+ FUNCDECL(sqrt,"sqrt");
+ FUNCDECL(log,"log");
+ FUNCDECL(exp,"exp");
+ FUNCDECL(abs,"abs");
+
+ clip_class = class_new2("clip",clip_new,0,sizeof(t_clip),0,"FF");
+ class_addfloat(clip_class, clip_float);
+ class_addbang(clip_class, clip_bang);
+}
+
+static t_class *pdint_class; struct t_pdint : t_object {t_float f;};
+static t_class *pdfloat_class; struct t_pdfloat : t_object {t_float f;};
+static t_class *pdsymbol_class; struct t_pdsymbol : t_object {t_symbol *s;};
+static t_class *bang_class; struct t_bang : t_object {};
+
+static void pdint_bang(t_pdint *x) {outlet_float(x->outlet, (t_float)(int)x->f);}
+static void pdint_float(t_pdint *x, t_float f) {x->f = f; pdint_bang(x);}
+
+static void pdfloat_bang(t_pdfloat *x) {outlet_float(x->outlet, x->f);}
+static void pdfloat_float(t_pdfloat *x, t_float f) {x->f=f; pdfloat_bang(x);}
+
+static void pdsymbol_bang(t_pdsymbol *x) {outlet_symbol(x->outlet, x->s);}
+static void pdsymbol_symbol( t_pdsymbol *x, t_symbol *s ) {x->s=s; pdsymbol_bang(x);}
+static void pdsymbol_anything(t_pdsymbol *x, t_symbol *s, int ac, t_atom *av) {x->s=s; pdsymbol_bang(x);}
+
+/* For "list" message don't just output "list"; if empty, we want to bang the symbol and
+ if it starts with a symbol, we output that. Otherwise it's not clear what we should do
+ so we just go for the "anything" method. LATER figure out if there are other places
+ where empty lists aren't equivalent to "bang"??? Should Pd's message passer always check
+ and call the more specific method, or should it be the object's responsibility? Dunno... */
+#if 0
+static void pdsymbol_list(t_pdsymbol *x, t_symbol *s, int ac, t_atom *av) {
+ if (!ac) pdsymbol_bang(x);
+ else if (av->a_type == A_SYMBOL) pdsymbol_symbol(x, av->a_symbol);
+ else pdsymbol_anything(x, s, ac, av);
+}
+#endif
+
+static void *pdint_new(t_floatarg f) {
+ t_pdint *x = (t_pdint *)pd_new(pdint_class);
+ x->f = f; outlet_new(x, &s_float); floatinlet_new(x, &x->f);
+ return x;
+}
+static void *pdfloat_new(t_pd *dummy, t_float f) {
+ t_pdfloat *x = (t_pdfloat *)pd_new(pdfloat_class);
+ x->f = f; outlet_new(x, &s_float); floatinlet_new(x, &x->f);
+ pd_set_newest((t_pd *)x);
+ return x;
+}
+static void *pdfloat_new2(t_floatarg f) {return pdfloat_new(0, f);}
+static void *pdsymbol_new(t_pd *dummy, t_symbol *s) {
+ t_pdsymbol *x = (t_pdsymbol *)pd_new(pdsymbol_class);
+ x->s = s; outlet_new(x, &s_symbol);symbolinlet_new(x, &x->s);
+ pd_set_newest((t_pd *)x);
+ return x;
+}
+static void *bang_new(t_pd *dummy) {
+ t_bang *x = (t_bang *)pd_new(bang_class);
+ outlet_new(x, &s_bang);
+ pd_set_newest((t_pd *)x);
+ return x;
+}
+static void *bang_new2(t_bang f) {return bang_new(0);}
+static void bang_bang(t_bang *x) {outlet_bang(x->outlet);}
+
+void misc_setup() {
+ pdint_class = class_new2("int",pdint_new,0,sizeof(t_pdint),0,"F");
+ class_addcreator2("i",pdint_new,"F");
+ class_addbang(pdint_class, pdint_bang);
+ class_addfloat(pdint_class, pdint_float);
+ pdfloat_class = class_new2("float",pdfloat_new,0,sizeof(t_pdfloat),0,"F");
+ class_addcreator2("f",pdfloat_new2,"F");
+ class_addbang(pdfloat_class, pdfloat_bang);
+ class_addfloat(pdfloat_class, pdfloat_float);
+ pdsymbol_class = class_new2("symbol",pdsymbol_new,0,sizeof(t_pdsymbol),0,"S");
+ class_addbang(pdsymbol_class, pdsymbol_bang);
+ class_addsymbol(pdsymbol_class, pdsymbol_symbol);
+ class_addanything(pdsymbol_class, pdsymbol_anything);
+ t_class *c = bang_class = class_new2("bang",bang_new,0,sizeof(t_bang),0,"");
+ class_addcreator2("b",bang_new2,"");
+ class_addbang(c, bang_bang);
+ class_addfloat(c, bang_bang);
+ class_addsymbol(c, bang_bang);
+ class_addlist(c, bang_bang);
+ class_addanything(c, bang_bang);
+}
+
+/* -------------------- send & receive ------------------------------ */
+
+static t_class * send_class; struct t_send : t_object {t_symbol *sym;};
+static t_class *receive_class; struct t_receive : t_object {t_symbol *sym;};
+
+static void send_bang( t_send *x) { if (x->sym->thing) pd_bang(x->sym->thing);}
+static void send_float( t_send *x, t_float f) { if (x->sym->thing) pd_float(x->sym->thing,f);}
+static void send_symbol( t_send *x, t_symbol *s) { if (x->sym->thing) pd_symbol(x->sym->thing,s);}
+static void send_pointer( t_send *x, t_gpointer *gp) { if (x->sym->thing) pd_pointer(x->sym->thing,gp);}
+static void send_list( t_send *x, t_symbol *s, int argc, t_atom *argv) {if (x->sym->thing) pd_list(x->sym->thing,s,argc,argv);}
+static void send_anything(t_send *x, t_symbol *s, int argc, t_atom *argv) {if (x->sym->thing) typedmess(x->sym->thing,s,argc,argv);}
+
+static void receive_bang( t_receive *x) { outlet_bang(x->outlet);}
+static void receive_float( t_receive *x, t_float f) { outlet_float(x->outlet, f);}
+static void receive_symbol( t_receive *x, t_symbol *s) { outlet_symbol(x->outlet, s);}
+static void receive_pointer( t_receive *x, t_gpointer *gp) { outlet_pointer(x->outlet, gp);}
+static void receive_list( t_receive *x, t_symbol *s, int argc, t_atom *argv) { outlet_list(x->outlet, s, argc, argv);}
+static void receive_anything(t_receive *x, t_symbol *s, int argc, t_atom *argv) {outlet_anything(x->outlet, s, argc, argv);}
+static void *receive_new(t_symbol *s) {
+ t_receive *x = (t_receive *)pd_new(receive_class);
+ x->sym = s;
+ pd_bind(x, s);
+ outlet_new(x, 0);
+ return x;
+}
+static void receive_free(t_receive *x) {pd_unbind(x, x->sym);}
+
+static void *send_new(t_symbol *s) {
+ t_send *x = (t_send *)pd_new(send_class);
+ if (!*s->name) symbolinlet_new(x, &x->sym);
+ x->sym = s;
+ return x;
+}
+static void sendreceive_setup() {
+ t_class *c;
+ c = send_class = class_new2("send",send_new,0,sizeof(t_send),0,"S");
+ class_addcreator2("s",send_new,"S");
+ class_addbang(c, send_bang);
+ class_addfloat(c, send_float);
+ class_addsymbol(c, send_symbol);
+ class_addpointer(c, send_pointer);
+ class_addlist(c, send_list);
+ class_addanything(c, send_anything);
+ c = receive_class = class_new2("receive",receive_new,receive_free,sizeof(t_receive),CLASS_NOINLET,"S");
+ class_addcreator2("r",receive_new,"S");
+ class_addbang(c, receive_bang);
+ class_addfloat(c, receive_float);
+ class_addsymbol(c, receive_symbol);
+ class_addpointer(c, receive_pointer);
+ class_addlist(c, receive_list);
+ class_addanything(c, receive_anything);
+}
+
+/* -------------------------- select ------------------------------ */
+
+static t_class *select_class;
+struct t_selectelement {
+ t_atom a;
+ t_outlet *out;
+};
+struct t_select : t_object {
+ t_int nelement;
+ t_selectelement *vec;
+ t_outlet *rejectout;
+};
+#define select_each(e,x) for (t_selectelement *e = x->vec;e;e=0) for (int nelement = x->nelement; nelement--; e++)
+
+static void select_float(t_select *x, t_float f) {
+ select_each(e,x) if (e->a.a_type==A_FLOAT && e->a.a_float==f) {outlet_bang(e->out); return;}
+ outlet_float(x->rejectout, f);
+}
+static void select_symbol(t_select *x, t_symbol *s) {
+ select_each(e,x) if (e->a.a_type==A_SYMBOL && e->a.a_symbol==s) {outlet_bang(e->out); return;}
+ outlet_symbol(x->rejectout, s);
+}
+static void select_free(t_select *x) {free(x->vec);}
+static void *select_new(t_symbol *s, int argc, t_atom *argv) {
+ t_atom a;
+ if (argc == 0) {
+ argc = 1;
+ SETFLOAT(&a, 0);
+ argv = new t_atom[1];
+ }
+ t_select *x = (t_select *)pd_new(select_class);
+ x->nelement = argc;
+ x->vec = (t_selectelement *)getbytes(argc * sizeof(*x->vec));
+ t_selectelement *e = x->vec;
+ for (int n = 0; n < argc; n++, e++) {
+ e->out = outlet_new(x, &s_bang);
+ e->a = argv[n];
+ if (e->a.a_type == A_FLOAT)
+ floatinlet_new(x, &x->vec[n].a.a_float);
+ else symbolinlet_new(x, &x->vec[n].a.a_symbol);
+ }
+ x->rejectout = outlet_new(x, &s_float);
+ return x;
+}
+void select_setup() {
+ select_class = class_new2("select",0,select_free,sizeof(t_select),0,"");
+ class_addfloat(select_class, select_float);
+ class_addsymbol(select_class, select_symbol);
+ class_addcreator2("select",select_new,"*");
+ class_addcreator2("sel", select_new,"*");
+}
+
+/* -------------------------- route ------------------------------ */
+
+static t_class *route_class;
+struct t_routeelement {
+ t_atom a;
+ t_outlet *out;
+};
+struct t_route : t_object {
+ t_int n;
+ t_routeelement *vec;
+ t_outlet *rejectout;
+};
+static void route_anything(t_route *x, t_symbol *sel, int argc, t_atom *argv) {
+ t_routeelement *e = x->vec;
+ post("1: sel=%s",sel->name);
+ for (int n = x->n; n--; e++) if (e->a.a_type == A_SYMBOL) if (e->a.a_symbol == sel) {
+ if (argc > 0 && argv[0].a_type == A_SYMBOL) outlet_anything(e->out, argv[0].a_symbol, argc-1, argv+1);
+ else { /* tb {: avoid 1 element lists */
+ if (argc > 1) outlet_list(e->out, 0, argc, argv);
+ else if (argc == 0) outlet_bang(e->out);
+ else outlet_atom(e->out,&argv[0]);
+ } /* tb } */
+ return;
+ }
+ outlet_anything(x->rejectout, sel, argc, argv);
+}
+
+#define route_eachr(E,L) for (t_routeelement *E = L->vec;E;E=0) for (int ROUTEN = x->n; ROUTEN--; E++)
+static void route_list(t_route *x, t_symbol *sel, int argc, t_atom *argv) {
+ if (argc && argv->a_type == A_FLOAT) {
+ float f = atom_getfloat(argv);
+ route_eachr(e,x) if (e->a.a_type == A_FLOAT && e->a.a_float == f) {
+ if (argc > 1 && argv[1].a_type == A_SYMBOL)
+ outlet_anything(e->out, argv[1].a_symbol, argc-2, argv+2);
+ else {
+ argc--; argv++;
+ if (argc > 1) outlet_list(e->out, 0, argc, argv);
+ else if (argc == 0) outlet_bang(e->out);
+ else outlet_atom(e->out,&argv[0]);
+ }
+ return;
+ } else if (e->a.a_type == A_SYMBOL && e->a.a_symbol == &s_float) {
+ outlet_float(e->out, argv[0].a_float);
+ return;
+ }
+ } else { /* symbol arguments */
+ if (argc > 1) { /* 2 or more args: treat as "list" */
+ route_eachr(e,x) if (e->a.a_type == A_SYMBOL && e->a.a_symbol == &s_list) {
+ if (argv[0].a_type==A_SYMBOL) outlet_anything(e->out, argv[0].a_symbol, argc-1, argv+1);
+ else outlet_list(e->out, 0, argc, argv);
+ return;
+ }
+ } else if (argc==0) {route_eachr(e,x) {if (e->a.a_symbol==&s_bang ) {outlet_bang(e->out ); return;}}
+ } else if (argv[0].a_type==A_FLOAT) {route_eachr(e,x) {if (e->a.a_symbol==&s_float ) {outlet_atom(e->out,&argv[0]); return;}}
+ } else if (argv[0].a_type==A_SYMBOL) {route_eachr(e,x) {if (e->a.a_symbol==&s_symbol ) {outlet_atom(e->out,&argv[0]); return;}}
+ } else if (argv[0].a_type==A_POINTER){route_eachr(e,x) {if (e->a.a_symbol==&s_pointer) {outlet_atom(e->out,&argv[0]); return;}}
+ }
+ }
+ if (!argc) outlet_bang(x->rejectout); else outlet_list(x->rejectout, 0, argc, argv);
+}
+
+static void route_free(t_route *x) {free(x->vec);}
+static void *route_new(t_symbol *s, int argc, t_atom *argv) {
+ t_route *x = (t_route *)pd_new(route_class);
+ if (argc == 0) {
+ t_atom a;
+ argc = 1;
+ SETFLOAT(&a, 0);
+ argv = &a;
+ }
+ x->n = argc;
+ x->vec = (t_routeelement *)getbytes(argc * sizeof(*x->vec));
+ t_routeelement *e = x->vec;
+ for (int n = 0; n < argc; n++, e++) {
+ e->out = outlet_new(x, &s_list);
+ e->a = argv[n];
+ }
+ x->rejectout = outlet_new(x, &s_list);
+ return x;
+}
+void route_setup() {
+ route_class = class_new2("route",route_new,route_free,sizeof(t_route),0,"*");
+ class_addlist(route_class, route_list);
+ class_addanything(route_class, route_anything);
+}
+
+static t_class *pack_class;
+struct t_pack : t_object {
+ t_int n; /* number of args */
+ t_atom *vec; /* input values */
+ t_atom *outvec; /* space for output values */
+};
+static void *pack_new(t_symbol *s, int argc, t_atom *argv) {
+ t_pack *x = (t_pack *)pd_new(pack_class);
+ t_atom defarg[2], *ap, *vec, *vp;
+ if (!argc) {
+ argv = defarg;
+ argc = 2;
+ SETFLOAT(&defarg[0], 0);
+ SETFLOAT(&defarg[1], 0);
+ }
+ x->n = argc;
+ vec = x->vec = (t_atom *)getbytes(argc * sizeof(*x->vec));
+ x->outvec = (t_atom *)getbytes(argc * sizeof(*x->outvec));
+ vp = x->vec;
+ ap = argv;
+ for (int i = 0; i < argc; i++, ap++, vp++) {
+ if (ap->a_type == A_FLOAT) {
+ *vp = *ap;
+ if (i) floatinlet_new(x, &vp->a_float);
+ } else if (ap->a_type == A_SYMBOL) {
+ char c = *ap->a_symbol->name;
+ if (c == 's') { SETSYMBOL(vp, &s_symbol); if (i) symbolinlet_new(x, &vp->a_symbol);}
+ else if (c == 'p') { /* SETPOINTER(vp, gpointer_new()) if (i) pointerinlet_new(x, gp); */}
+ else if (c == 'f') { SETFLOAT(vp, 0); if (i) floatinlet_new(x, &vp->a_float);}
+ else error("pack: %s: bad type '%c'", ap->a_symbol->name, c);
+ }
+ }
+ outlet_new(x, &s_list);
+ return x;
+}
+static void pack_bang(t_pack *x) {
+ int reentered = 0, size = x->n * sizeof (t_atom);
+ t_atom *outvec;
+ /* reentrancy protection. The first time through use the pre-allocated outvec; if we're reentered we have to allocate new memory. */
+ if (!x->outvec) {
+ outvec = (t_atom *)t_getbytes(size);
+ reentered = 1;
+ } else {
+ outvec = x->outvec;
+ x->outvec = 0;
+ }
+ memcpy(outvec, x->vec, size);
+ outlet_list(x->outlet, &s_list, x->n, outvec);
+ if (reentered) free(outvec); else x->outvec = outvec;
+}
+
+static void pack_pointer(t_pack *x, t_gpointer *gp) {
+ if (x->vec->a_type == A_POINTER) {
+ //gpointer_unset(x->gpointer);
+ //*x->gpointer = *gp;
+ //if (gp->o) gp->o->refcount++;
+ pack_bang(x);
+ } else error("pack_pointer: wrong type");
+}
+static void pack_float(t_pack *x, t_float f) {
+ if (x->vec->a_type == A_FLOAT ) {x->vec->a_float = f; pack_bang(x);} else error("pack_float: wrong type");
+}
+static void pack_symbol(t_pack *x, t_symbol *s) {
+ if (x->vec->a_type == A_SYMBOL) {x->vec->a_symbol = s; pack_bang(x);} else error("pack_symbol: wrong type");
+}
+static void pack_list(t_pack *x, t_symbol *s, int ac, t_atom *av) {obj_list(x, 0, ac, av);}
+static void pack_anything(t_pack *x, t_symbol *s, int ac, t_atom *av) {
+ t_atom *av2 = (t_atom *)getbytes((ac + 1) * sizeof(t_atom));
+ for (int i = 0; i < ac; i++) av2[i + 1] = av[i];
+ SETSYMBOL(av2, s);
+ obj_list(x, 0, ac+1, av2);
+ free(av2);
+}
+static void pack_free(t_pack *x) {
+ free(x->vec);
+ free(x->outvec);
+}
+static void pack_setup() {
+ t_class *c = pack_class = class_new2("pack",pack_new,pack_free,sizeof(t_pack),0,"*");
+ class_addbang(c, pack_bang);
+ class_addpointer(c, pack_pointer);
+ class_addfloat(c, pack_float);
+ class_addsymbol(c, pack_symbol);
+ class_addlist(c, pack_list);
+ class_addanything(c, pack_anything);
+}
+
+static t_class *unpack_class;
+struct t_unpack : t_object {
+ t_int n;
+ t_outlet **vec;
+ char *vat;
+};
+
+static t_atomtype atomtype_from_letter(char c) {
+ switch (c) {
+ case 'e': return A_ATOM;
+ case 'f': return A_FLOAT;
+ case 's': return A_SYMBOL;
+ case 'p': return A_POINTER;
+ default: return A_CANT;
+ }
+}
+
+static void *unpack_new(t_symbol *s, int argc, t_atom *argv) {
+ t_unpack *x = (t_unpack *)pd_new(unpack_class);
+ t_atom defarg[2];
+ if (!argc) {
+ argv = defarg;
+ argc = 2;
+ SETFLOAT(&defarg[0], 0);
+ SETFLOAT(&defarg[1], 0);
+ }
+ x->n = argc;
+ x->vec = (t_outlet **)getbytes(argc * sizeof(*x->vec));
+ x->vat = (char *)getbytes(argc);
+ t_atom *ap=argv;
+ for (int i=0; i<argc; ap++, i++) {
+ x->vec[i] = outlet_new(x,0);
+ switch (argv[i].a_type) {
+ case A_FLOAT: x->vat[i]=A_FLOAT; break;
+ case A_SYMBOL: {
+ const char *s = atom_getstring(&argv[i]);
+ if (strlen(s)<1 || (x->vat[i]=atomtype_from_letter(s[0]))==A_CANT) {error("%s: bad type", s); x->vat[i]=A_FLOAT;}
+ break;
+ }
+ default: error("bad type");
+ }
+ }
+ return x;
+}
+static void unpack_list(t_unpack *x, t_symbol *s, int argc, t_atom *argv) {
+ if (argc > x->n) argc = x->n;
+ //for (int i=argc-1; i>=0; i--) outlet_atom(x->vec[i],&argv[i]);
+ for (int i=argc-1; i>=0; i--) {
+ if (x->vat[i]==A_ATOM || x->vat[i]==argv[i].a_type) outlet_atom(x->vec[i],&argv[i]);
+ else error("type mismatch");
+ }
+}
+static void unpack_anything(t_unpack *x, t_symbol *s, int ac, t_atom *av) {
+ t_atom *av2 = (t_atom *)getbytes((ac+1) * sizeof(t_atom));
+ for (int i=0; i<ac; i++) av2[i+1] = av[i];
+ SETSYMBOL(av2, s);
+ unpack_list(x, 0, ac+1, av2);
+ free(av2);
+}
+static void unpack_free(t_unpack *x) {free(x->vec); free(x->vat);}
+static void unpack_setup() {
+ unpack_class = class_new2("unpack",unpack_new,unpack_free,sizeof(t_unpack),0,"*");
+ class_addlist(unpack_class, unpack_list);
+ class_addanything(unpack_class, unpack_anything);
+}
+
+static t_class *trigger_class;
+struct t_triggerout {
+ int type;
+ t_outlet *outlet;
+};
+typedef struct t_trigger : t_object {
+ t_int n;
+ t_triggerout *vec;
+};
+static void *trigger_new(t_symbol *s, int argc, t_atom *argv) {
+ t_trigger *x = (t_trigger *)pd_new(trigger_class);
+ t_atom defarg[2];
+ if (!argc) {
+ argv = defarg;
+ argc = 2;
+ SETSYMBOL(&defarg[0], &s_bang);
+ SETSYMBOL(&defarg[1], &s_bang);
+ }
+ x->n = argc;
+ x->vec = (t_triggerout *)getbytes(argc * sizeof(*x->vec));
+ t_triggerout *u = x->vec;
+ t_atom *ap = argv;
+ for (int i=0; i<argc; u++, ap++, i++) {
+ t_atomtype thistype = ap->a_type;
+ char c;
+ if (thistype == A_SYMBOL) c = ap->a_symbol->name[0];
+ else if (thistype == A_FLOAT) c = 'f';
+ else c = 0;
+ if (c == 'p') u->outlet = outlet_new(x, &s_pointer);
+ else if (c == 'f') u->outlet = outlet_new(x, &s_float);
+ else if (c == 'b') u->outlet = outlet_new(x, &s_bang);
+ else if (c == 'l') u->outlet = outlet_new(x, &s_list);
+ else if (c == 's') u->outlet = outlet_new(x, &s_symbol);
+ else if (c == 'a') u->outlet = outlet_new(x, &s_symbol);
+ else {
+ error("trigger: %s: bad type", ap->a_symbol->name);
+ c='f'; u->outlet = outlet_new(x, &s_float);
+ }
+ u->type = c;
+ }
+ return x;
+}
+static void trigger_list(t_trigger *x, t_symbol *s, int argc, t_atom *argv) {
+ t_triggerout *u = x->vec+x->n;
+ for (int i = x->n; u--, i--;) {
+ if (u->type == 'f') outlet_float(u->outlet, argc ? atom_getfloat(argv) : 0);
+ else if (u->type == 'b') outlet_bang(u->outlet);
+ else if (u->type == 's') outlet_symbol(u->outlet, argc ? atom_getsymbol(argv) : &s_symbol);
+ else if (u->type == 'p') {
+ if (!argc || argv->a_type != 'p') error("unpack: bad pointer");
+ else outlet_pointer(u->outlet, argv->a_pointer);
+ } else outlet_list(u->outlet, &s_list, argc, argv);
+ }
+}
+static void trigger_anything(t_trigger *x, t_symbol *s, int argc, t_atom *argv) {
+ t_triggerout *u = x->vec+x->n;
+ for (int i = x->n; u--, i--;) {
+ if (u->type == 'b') outlet_bang(u->outlet);
+ else if (u->type == 'a') outlet_anything(u->outlet, s, argc, argv);
+ else error("trigger: can only convert 's' to 'b' or 'a'", s->name);
+ }
+}
+static void trigger_bang(t_trigger *x) {trigger_list(x, 0, 0, 0);}
+static void trigger_pointer(t_trigger *x, t_gpointer *gp) {t_atom at; SETPOINTER(&at, gp); trigger_list(x, 0, 1, &at);}
+static void trigger_float(t_trigger *x, t_float f) { t_atom at; SETFLOAT(&at, f); trigger_list(x, 0, 1, &at);}
+static void trigger_symbol(t_trigger *x, t_symbol *s) { t_atom at; SETSYMBOL(&at, s); trigger_list(x, 0, 1, &at);}
+static void trigger_free(t_trigger *x) {free(x->vec);}
+static void trigger_setup() {
+ t_class *c = trigger_class = class_new2("trigger",trigger_new,trigger_free,sizeof(t_trigger),0,"*");
+ class_addcreator2("t",trigger_new,"*");
+ class_addlist(c, trigger_list);
+ class_addbang(c, trigger_bang);
+ class_addpointer(c, trigger_pointer);
+ class_addfloat(c, trigger_float);
+ class_addsymbol(c, trigger_symbol);
+ class_addanything(c, trigger_anything);
+}
+
+static t_class *spigot_class;
+struct t_spigot : t_object {float state;};
+static void *spigot_new(t_floatarg f) {
+ t_spigot *x = (t_spigot *)pd_new(spigot_class);
+ floatinlet_new(x, &x->state);
+ outlet_new(x, 0);
+ x->state = f;
+ return x;
+}
+static void spigot_bang( t_spigot *x) { if (x->state) outlet_bang(x->outlet);}
+static void spigot_pointer( t_spigot *x, t_gpointer *gp) { if (x->state) outlet_pointer(x->outlet, gp);}
+static void spigot_float( t_spigot *x, t_float f) { if (x->state) outlet_float(x->outlet, f);}
+static void spigot_symbol( t_spigot *x, t_symbol *s) { if (x->state) outlet_symbol(x->outlet, s);}
+static void spigot_list( t_spigot *x, t_symbol *s, int argc, t_atom *argv) {if (x->state) outlet_list(x->outlet, s, argc, argv);}
+static void spigot_anything(t_spigot *x, t_symbol *s, int argc, t_atom *argv) {if (x->state) outlet_anything(x->outlet, s, argc, argv);}
+static void spigot_setup() {
+ t_class *c = spigot_class = class_new2("spigot",spigot_new,0,sizeof(t_spigot),0,"F");
+ class_addbang(c, spigot_bang);
+ class_addpointer(c, spigot_pointer);
+ class_addfloat(c, spigot_float);
+ class_addsymbol(c, spigot_symbol);
+ class_addlist(c, spigot_list);
+ class_addanything(c, spigot_anything);
+}
+
+static t_class *moses_class;
+struct t_moses : t_object {float y;};
+static void *moses_new(t_floatarg f) {
+ t_moses *x = (t_moses *)pd_new(moses_class);
+ floatinlet_new(x, &x->y);
+ outlet_new(x, &s_float);
+ outlet_new(x, &s_float);
+ x->y = f;
+ return x;
+}
+static void moses_float(t_moses *x, t_float f) {outlet_float(x->out(f>=x->y), f);}
+static void moses_setup() {
+ moses_class = class_new2("moses",moses_new,0,sizeof(t_moses),0,"F");
+ class_addfloat(moses_class, moses_float);
+}
+static t_class *until_class;
+struct t_until : t_object {
+ int run;
+ int count;
+};
+static void *until_new() {
+ t_until *x = (t_until *)pd_new(until_class);
+ inlet_new(x, x, gensym("bang"), gensym("bang2"));
+ outlet_new(x, &s_bang);
+ x->run = 0;
+ return x;
+}
+static void until_bang(t_until *x) { x->run=1; x->count=-1; while (x->run && x->count) {x->count--; outlet_bang(x->outlet);}}
+static void until_float(t_until *x, t_float f) {x->run=1; x->count=(int)f; while (x->run && x->count) {x->count--; outlet_bang(x->outlet);}}
+static void until_bang2(t_until *x) {x->run = 0;}
+static void until_setup() {
+ until_class = class_new2("until",until_new,0,sizeof(t_until),0,"");
+ class_addbang(until_class, until_bang);
+ class_addfloat(until_class, until_float);
+ class_addmethod2(until_class, until_bang2,"bang2","");
+}
+
+static t_class *makefilename_class;
+struct t_makefilename : t_object {t_symbol *format;};
+static void *makefilename_new(t_symbol *s) {
+ t_makefilename *x = (t_makefilename *)pd_new(makefilename_class);
+ if (!s->name) s = gensym("file.%d");
+ outlet_new(x, &s_symbol);
+ x->format = s;
+ return x;
+}
+
+/* doesn't do any typechecking or even counting the % signs properly */
+static void makefilename_float(t_makefilename *x, t_floatarg f) {outlet_symbol(x->outlet,symprintf(x->format->name,(int)f));}
+static void makefilename_symbol(t_makefilename *x, t_symbol *s) {outlet_symbol(x->outlet,symprintf(x->format->name,s->name));}
+static void makefilename_set(t_makefilename *x, t_symbol *s) {x->format = s;}
+
+static void makefilename_setup() {
+ t_class *c = makefilename_class = class_new2("makefilename",makefilename_new,0,sizeof(t_makefilename),0,"S");
+ class_addfloat(c, makefilename_float);
+ class_addsymbol(c, makefilename_symbol);
+ class_addmethod2(c, makefilename_set, "set","s");
+}
+
+static t_class *swap_class;
+struct t_swap : t_object {
+ t_float f1;
+ t_float f2;
+};
+static void *swap_new(t_floatarg f) {
+ t_swap *x = (t_swap *)pd_new(swap_class);
+ x->f2 = f;
+ x->f1 = 0;
+ outlet_new(x, &s_float);
+ outlet_new(x, &s_float);
+ floatinlet_new(x, &x->f2);
+ return x;
+}
+static void swap_bang(t_swap *x) {
+ outlet_float(x->out(1), x->f1);
+ outlet_float(x->out(0), x->f2);
+}
+static void swap_float(t_swap *x, t_float f) {
+ x->f1 = f;
+ swap_bang(x);
+}
+void swap_setup() {
+ swap_class = class_new2("swap",swap_new,0,sizeof(t_swap),0,"F");
+ class_addcreator2("fswap",swap_new,"F");
+ class_addbang(swap_class, swap_bang);
+ class_addfloat(swap_class, swap_float);
+}
+
+static t_class *change_class;
+struct t_change : t_object {t_float f;};
+static void *change_new(t_floatarg f) {
+ t_change *x = (t_change *)pd_new(change_class);
+ x->f = f;
+ outlet_new(x, &s_float);
+ return x;
+}
+static void change_bang(t_change *x) {outlet_float(x->outlet, x->f);}
+static void change_float(t_change *x, t_float f) {
+ if (f != x->f) {
+ x->f = f;
+ outlet_float(x->outlet, x->f);
+ }
+}
+static void change_set(t_change *x, t_float f) {x->f = f;}
+void change_setup() {
+ change_class = class_new2("change",change_new,0,sizeof(t_change),0,"F");
+ class_addbang(change_class, change_bang);
+ class_addfloat(change_class, change_float);
+ class_addmethod2(change_class, change_set, "set","F");
+}
+
+static t_class *value_class, *vcommon_class;
+struct t_vcommon : t_pd {
+ int c_refcount;
+ t_float f;
+};
+typedef struct t_value : t_object {
+ t_symbol *sym;
+ t_float *floatstar;
+};
+
+/* get a pointer to a named floating-point variable. The variable
+ belongs to a "vcommon" object, which is created if necessary. */
+t_float *value_get(t_symbol *s) {
+ t_vcommon *c = (t_vcommon *)pd_findbyclass(s, vcommon_class);
+ if (!c) {
+ c = (t_vcommon *)pd_new(vcommon_class);
+ c->f = 0;
+ c->c_refcount = 0;
+ pd_bind(c,s);
+ }
+ c->c_refcount++;
+ return &c->f;
+}
+/* release a variable. This only frees the "vcommon" resource when the last interested party releases it. */
+void value_release(t_symbol *s) {
+ t_vcommon *c = (t_vcommon *)pd_findbyclass(s, vcommon_class);
+ if (c) {
+ if (!--c->c_refcount) {
+ pd_unbind(c,s);
+ pd_free(c);
+ }
+ } else bug("value_release");
+}
+int value_getfloat(t_symbol *s, t_float *f) {t_vcommon *c=(t_vcommon *)pd_findbyclass(s,vcommon_class); if (!c) return 1; *f=c->f;return 0;}
+int value_setfloat(t_symbol *s, t_float f) {t_vcommon *c=(t_vcommon *)pd_findbyclass(s,vcommon_class); if (!c) return 1; c->f=f; return 0;}
+static void *value_new(t_symbol *s) {
+ t_value *x = (t_value *)pd_new(value_class);
+ x->sym = s;
+ x->floatstar = value_get(s);
+ outlet_new(x, &s_float);
+ return x;
+}
+static void value_bang(t_value *x) {outlet_float(x->outlet, *x->floatstar);}
+static void value_float(t_value *x, t_float f) {*x->floatstar = f;}
+static void value_ff(t_value *x) {value_release(x->sym);}
+static void value_setup() {
+ value_class = class_new2("value",value_new,value_ff,sizeof(t_value),0,"S");
+ class_addcreator2("v",value_new,"S");
+ class_addbang(value_class, value_bang);
+ class_addfloat(value_class, value_float);
+ vcommon_class = class_new2("value",0,0,sizeof(t_vcommon),CLASS_PD,"");
+}
+
+/* MIDI. */
+
+void outmidi_noteon(int portno, int channel, int pitch, int velo);
+void outmidi_controlchange(int portno, int channel, int ctlno, int value);
+void outmidi_programchange(int portno, int channel, int value);
+void outmidi_pitchbend(int portno, int channel, int value);
+void outmidi_aftertouch(int portno, int channel, int value);
+void outmidi_polyaftertouch(int portno, int channel, int pitch, int value);
+void outmidi_mclk(int portno);
+
+static t_symbol *midiin_sym, *sysexin_sym, *notein_sym, *ctlin_sym;
+static t_class *midiin_class, *sysexin_class, *notein_class, *ctlin_class;
+struct t_midiin : t_object {};
+struct t_notein : t_object {t_float ch;};
+struct t_ctlin : t_object {t_float ch; t_float ctlno;};
+
+static void midiin_list(t_midiin *x, t_symbol *s, int ac, t_atom *av) {
+ outlet_float(x->out(1), atom_getfloatarg(1, ac, av) + 1);
+ outlet_float(x->out(0), atom_getfloatarg(0, ac, av));
+}
+void inmidi_byte(int portno, int byte) {
+ if ( midiin_sym->thing) {t_atom at[2]; SETFLOAT(at, byte); SETFLOAT(at+1, portno+1); pd_list( midiin_sym->thing, 0, 2, at);}
+}
+void inmidi_sysex(int portno, int byte) {
+ if (sysexin_sym->thing) {t_atom at[2]; SETFLOAT(at, byte); SETFLOAT(at+1, portno+1); pd_list(sysexin_sym->thing, 0, 2, at);}
+}
+
+static void notein_list(t_notein *x, t_symbol *s, int argc, t_atom *argv) {
+ float pitch = atom_getfloatarg(0, argc, argv);
+ float velo = atom_getfloatarg(1, argc, argv);
+ float channel = atom_getfloatarg(2, argc, argv);
+ if (x->ch) {if (channel != x->ch) return;} else outlet_float(x->out(2), channel);
+ outlet_float(x->out(1), velo);
+ outlet_float(x->out(0), pitch);
+}
+
+void inmidi_noteon(int portno, int channel, int pitch, int velo) {
+ if (notein_sym->thing) {
+ t_atom at[3];
+ SETFLOAT(at, pitch);
+ SETFLOAT(at+1, velo);
+ SETFLOAT(at+2, (channel + (portno << 4) + 1));
+ pd_list(notein_sym->thing, &s_list, 3, at);
+ }
+}
+
+static void *midiin_new() {
+ t_midiin *x = (t_midiin *)pd_new(midiin_class);
+ outlet_new(x, &s_float);
+ outlet_new(x, &s_float);
+ pd_bind(x, midiin_sym);
+ return x;
+}
+static void *sysexin_new() {
+ t_midiin *x = (t_midiin *)pd_new(sysexin_class);
+ outlet_new(x, &s_float);
+ outlet_new(x, &s_float);
+ pd_bind(x, sysexin_sym);
+ return x;
+}
+static void *notein_new(t_floatarg f) {
+ t_notein *x = (t_notein *)pd_new(notein_class);
+ x->ch = f;
+ outlet_new(x, &s_float);
+ outlet_new(x, &s_float);
+ if (f == 0) outlet_new(x, &s_float);
+ pd_bind(x, notein_sym);
+ return x;
+}
+static void *ctlin_new(t_symbol *s, int argc, t_atom *argv) {
+ t_ctlin *x = (t_ctlin *)pd_new(ctlin_class);
+ int ctlno = (int)(argc ? atom_getfloatarg(0, argc, argv) : -1);
+ int channel = (int)atom_getfloatarg(1, argc, argv);
+ x->ch = channel;
+ x->ctlno = ctlno;
+ outlet_new(x, &s_float);
+ if (!channel) {
+ if (x->ctlno < 0) outlet_new(x, &s_float);
+ outlet_new(x, &s_float);
+ }
+ pd_bind(x, ctlin_sym);
+ return x;
+}
+static void ctlin_list(t_ctlin *x, t_symbol *s, int argc, t_atom *argv) {
+ t_float ctlnumber = atom_getfloatarg(0, argc, argv);
+ t_float value = atom_getfloatarg(1, argc, argv);
+ t_float channel = atom_getfloatarg(2, argc, argv);
+ if (x->ctlno >= 0 && x->ctlno != ctlnumber) return;
+ if (x->ch > 0 && x->ch != channel) return;
+ if (x->ch == 0) outlet_float(x->out(2), channel);
+ if (x->ctlno < 0) outlet_float(x->out(1), ctlnumber);
+ outlet_float(x->out(0), value);
+}
+
+static void midiin_free(t_midiin *x) {pd_unbind(x, midiin_sym);}
+static void sysexin_free(t_midiin *x) {pd_unbind(x, sysexin_sym);}
+static void notein_free(t_notein *x) {pd_unbind(x, notein_sym);}
+static void ctlin_free(t_ctlin *x) {pd_unbind(x, ctlin_sym);}
+
+void inmidi_controlchange(int portno, int channel, int ctlnumber, int value) {
+ if (ctlin_sym->thing) {
+ t_atom at[3];
+ SETFLOAT(at, ctlnumber);
+ SETFLOAT(at+1, value);
+ SETFLOAT(at+2, (channel + (portno << 4) + 1));
+ pd_list(ctlin_sym->thing, &s_list, 3, at);
+ }
+}
+
+struct t_midi2 : t_object {t_float ch;};
+static void *midi2_new(t_class *cl, t_floatarg ch) {
+ t_midi2 *x = (t_midi2 *)pd_new(cl);
+ x->ch = ch;
+ outlet_new(x, &s_float);
+ if (!ch) outlet_new(x, &s_float);
+ return x;
+}
+static void midi2_list(t_midi2 *x, t_symbol *s, int argc, t_atom *argv) {
+ float value = atom_getfloatarg(0, argc, argv);
+ float channel = atom_getfloatarg(1, argc, argv);
+ if (x->ch) {if (channel != x->ch) return;} else outlet_float(x->out(1), channel);
+ outlet_float(x->out(0), value);
+}
+static t_symbol *pgmin_sym, *bendin_sym, *touchin_sym;
+static t_class *pgmin_class, *bendin_class, *touchin_class;
+struct t_pgmin : t_midi2 {};
+struct t_bendin : t_midi2 {};
+struct t_touchin : t_midi2 {};
+static void *pgmin_new(t_floatarg f) {
+ t_pgmin *x = (t_pgmin *) midi2_new(pgmin_class ,f); pd_bind(x, pgmin_sym); return x;}
+static void *bendin_new(t_floatarg f) {
+ t_bendin *x = (t_bendin *) midi2_new(bendin_class ,f); pd_bind(x, bendin_sym); return x;}
+static void *touchin_new(t_floatarg f) {
+ t_touchin *x = (t_touchin *)midi2_new(touchin_class,f); pd_bind(x, touchin_sym); return x;}
+static void pgmin_free( t_pgmin *x) {pd_unbind(x, pgmin_sym);}
+static void bendin_free( t_bendin *x) {pd_unbind(x, bendin_sym);}
+static void touchin_free(t_touchin *x) {pd_unbind(x, touchin_sym);}
+void inmidi_programchange(int portno, int channel, int value) {
+ if (pgmin_sym->thing) {
+ t_atom at[2]; SETFLOAT(at,value+1); SETFLOAT(at+1, channel+(portno<<4)+1); pd_list( pgmin_sym->thing, &s_list, 2, at);
+ }
+}
+void inmidi_pitchbend(int portno, int channel, int value) {
+ if (bendin_sym->thing) {
+ t_atom at[2]; SETFLOAT(at,value); SETFLOAT(at+1, channel+(portno<<4)+1); pd_list( bendin_sym->thing, &s_list, 2, at);
+ }
+}
+void inmidi_aftertouch(int portno, int channel, int value) {
+ if (touchin_sym->thing) {
+ t_atom at[2]; SETFLOAT(at,value); SETFLOAT(at+1, channel+(portno<<4)+1); pd_list(touchin_sym->thing, &s_list, 2, at);
+ }
+}
+
+/* ----------------------- polytouchin ------------------------- */
+static t_symbol *polytouchin_sym;
+static t_class *polytouchin_class;
+struct t_polytouchin : t_object {
+ t_float ch;
+};
+static void *polytouchin_new(t_floatarg f) {
+ t_polytouchin *x = (t_polytouchin *)pd_new(polytouchin_class);
+ x->ch = f;
+ outlet_new(x, &s_float);
+ outlet_new(x, &s_float);
+ if (f == 0) outlet_new(x, &s_float);
+ pd_bind(x, polytouchin_sym);
+ return x;
+}
+static void polytouchin_list(t_polytouchin *x, t_symbol *s, int argc, t_atom *argv) {
+ t_float channel = atom_getfloatarg(2, argc, argv);
+ if (x->ch) {if (channel != x->ch) return;} else outlet_float(x->out(2), channel);
+ outlet_float(x->out(1), atom_getfloatarg(0, argc, argv)); /*pitch*/
+ outlet_float(x->out(0), atom_getfloatarg(1, argc, argv)); /*value*/
+}
+static void polytouchin_free(t_polytouchin *x) {pd_unbind(x, polytouchin_sym);}
+static void polytouchin_setup() {
+ polytouchin_class = class_new2("polytouchin",polytouchin_new,polytouchin_free,
+ sizeof(t_polytouchin), CLASS_NOINLET,"F");
+ class_addlist(polytouchin_class, polytouchin_list);
+ class_sethelpsymbol(polytouchin_class, gensym("midi"));
+ polytouchin_sym = gensym("#polytouchin");
+}
+void inmidi_polyaftertouch(int portno, int channel, int pitch, int value) {
+ if (polytouchin_sym->thing) {
+ t_atom at[3];
+ SETFLOAT(at, pitch);
+ SETFLOAT(at+1, value);
+ SETFLOAT(at+2, (channel + (portno << 4) + 1));
+ pd_list(polytouchin_sym->thing, &s_list, 3, at);
+ }
+}
+
+/*----------------------- midiclkin--(midi F8 message )---------------------*/
+static t_symbol *midiclkin_sym;
+static t_class *midiclkin_class;
+struct t_midiclkin : t_object {};
+static void *midiclkin_new(t_floatarg f) {
+ t_midiclkin *x = (t_midiclkin *)pd_new(midiclkin_class);
+ outlet_new(x, &s_float);
+ outlet_new(x, &s_float);
+ pd_bind(x, midiclkin_sym);
+ return x;
+}
+static void midiclkin_list(t_midiclkin *x, t_symbol *s, int argc, t_atom *argv) {
+ outlet_float(x->out(1), atom_getfloatarg(1, argc, argv)); /*count*/
+ outlet_float(x->out(0), atom_getfloatarg(0, argc, argv)); /*value*/
+}
+static void midiclkin_free(t_midiclkin *x) {pd_unbind(x, midiclkin_sym);}
+static void midiclkin_setup() {
+ midiclkin_class = class_new2("midiclkin",midiclkin_new,midiclkin_free,sizeof(t_midiclkin),CLASS_NOINLET,"F");
+ class_addlist(midiclkin_class, midiclkin_list);
+ class_sethelpsymbol(midiclkin_class, gensym("midi"));
+ midiclkin_sym = gensym("#midiclkin");
+}
+void inmidi_clk(double timing) {
+ static float prev = 0;
+ static float count = 0;
+ if (midiclkin_sym->thing) {
+ t_atom at[2];
+ float diff = timing - prev;
+ count++;
+ /* 24 count per quarter note */
+ if (count == 3) {SETFLOAT(at, 1); count = 0;} else SETFLOAT(at, 0);
+ SETFLOAT(at+1, diff);
+ pd_list(midiclkin_sym->thing, &s_list, 2, at);
+ prev = timing;
+ }
+}
+
+/*----------midirealtimein (midi FA,FB,FC,FF message)-----------------*/
+static t_symbol *midirealtimein_sym;
+static t_class *midirealtimein_class;
+struct t_midirealtimein : t_object {};
+static void *midirealtimein_new() {
+ t_midirealtimein *x = (t_midirealtimein *)pd_new(midirealtimein_class);
+ outlet_new(x, &s_float);
+ outlet_new(x, &s_float);
+ pd_bind(x, midirealtimein_sym);
+ return x;
+}
+static void midirealtimein_list(t_midirealtimein *x, t_symbol *s, int argc, t_atom *argv) {
+ outlet_float(x->out(1), atom_getfloatarg(0, argc, argv)); /*portno*/
+ outlet_float(x->out(0), atom_getfloatarg(1, argc, argv)); /*byte*/
+}
+static void midirealtimein_free(t_midirealtimein *x) {pd_unbind(x, midirealtimein_sym);}
+static void midirealtimein_setup() {
+ midirealtimein_class = class_new2("midirealtimein",midirealtimein_new,midirealtimein_free,
+ sizeof(t_midirealtimein),CLASS_NOINLET,"F");
+ class_addlist(midirealtimein_class, midirealtimein_list);
+ class_sethelpsymbol(midirealtimein_class, gensym("midi"));
+ midirealtimein_sym = gensym("#midirealtimein");
+}
+void inmidi_realtimein(int portno, int SysMsg) {
+ if (midirealtimein_sym->thing) {
+ t_atom at[2];
+ SETFLOAT(at, portno);
+ SETFLOAT(at+1, SysMsg);
+ pd_list(midirealtimein_sym->thing, &s_list, 2, at);
+ }
+}
+
+void outmidi_byte(int portno, int byte);
+static t_class *midiout_class; struct t_midiout : t_object {t_float portno;};
+static t_class *noteout_class; struct t_noteout : t_object {t_float v; t_float ch;};
+static t_class *ctlout_class; struct t_ctlout : t_object {t_float v; t_float ch;};
+
+static void *noteout_new(t_floatarg channel) {
+ t_noteout *x = (t_noteout *)pd_new(noteout_class);
+ x->v = 0;
+ x->ch = channel<1?channel:1;
+ floatinlet_new(x, &x->v);
+ floatinlet_new(x, &x->ch);
+ return x;
+}
+static void *ctlout_new(t_floatarg v, t_floatarg channel) {
+ t_ctlout *x = (t_ctlout *)pd_new(ctlout_class);
+ x->v = v;
+ x->ch = channel<1?channel:1;
+ floatinlet_new(x, &x->v);
+ floatinlet_new(x, &x->ch);
+ return x;
+}
+static void *midiout_new(t_floatarg portno) {
+ t_midiout *x = (t_midiout *)pd_new(midiout_class);
+ if (portno <= 0) portno = 1;
+ x->portno = portno;
+ floatinlet_new(x, &x->portno);
+#ifdef __irix__
+ post("midiout: unimplemented in IRIX");
+#endif
+ return x;
+}
+
+static void midiout_float(t_midiout *x, t_floatarg f){
+ outmidi_byte((int)x->portno-1, (int)f);
+}
+static void noteout_float(t_noteout *x, t_float f) {
+ int binchan = max(0,(int)x->ch-1);
+ outmidi_noteon((binchan >> 4), (binchan & 15), (int)f, (int)x->v);
+}
+static void ctlout_float(t_ctlout *x, t_float f) {
+ int binchan = (int)x->ch - 1;
+ if (binchan < 0) binchan = 0;
+ outmidi_controlchange((binchan >> 4), (binchan & 15), (int)x->v, (int)f);
+}
+
+static t_class *pgmout_class, *bendout_class, *touchout_class;
+struct t_mido2 : t_object {t_float ch;};
+struct t_pgmout : t_mido2 {};
+struct t_bendout : t_mido2 {};
+struct t_touchout : t_mido2 {};
+static void *mido2_new(t_class *cl, t_floatarg channel) {
+ t_pgmout *x = (t_pgmout *)pd_new(cl);
+ x->ch = channel<1?channel:1; floatinlet_new(x, &x->ch); return x;
+}
+static void *pgmout_new( t_floatarg ch) {return mido2_new(pgmout_class,ch);}
+static void *bendout_new( t_floatarg ch) {return mido2_new(bendout_class,ch);}
+static void *touchout_new(t_floatarg ch) {return mido2_new(touchout_class,ch);}
+static void pgmout_float(t_pgmout *x, t_floatarg f) {
+ int binchan = max(0,(int)x->ch-1);
+ outmidi_programchange(binchan>>4, binchan&15, min(127,max(0,(int)f-1)));
+}
+static void bendout_float(t_bendout *x, t_float f) {
+ int binchan = max(0,(int)x->ch-1);
+ outmidi_pitchbend(binchan>>4, binchan&15, (int)f+8192);
+}
+static void touchout_float(t_touchout *x, t_float f) {
+ int binchan = max(0,(int)x->ch-1);
+ outmidi_aftertouch(binchan>>4, binchan&15, (int)f);
+}
+
+static t_class *polytouchout_class;
+struct t_polytouchout : t_object {
+ t_float ch;
+ t_float pitch;
+};
+static void *polytouchout_new(t_floatarg channel) {
+ t_polytouchout *x = (t_polytouchout *)pd_new(polytouchout_class);
+ x->ch = channel<1?channel:1;
+ x->pitch = 0;
+ floatinlet_new(x, &x->pitch);
+ floatinlet_new(x, &x->ch);
+ return x;
+}
+static void polytouchout_float(t_polytouchout *x, t_float n) {
+ int binchan = max(0,(int)x->ch-1);
+ outmidi_polyaftertouch((binchan >> 4), (binchan & 15), (int)x->pitch, (int)n);
+}
+static void polytouchout_setup() {
+ polytouchout_class = class_new2("polytouchout",polytouchout_new,0,sizeof(t_polytouchout),0,"F");
+ class_addfloat(polytouchout_class, polytouchout_float);
+ class_sethelpsymbol(polytouchout_class, gensym("midi"));
+}
+
+static t_class *makenote_class;
+struct t_hang {
+ t_clock *clock;
+ t_hang *next;
+ t_float pitch;
+ struct t_makenote *owner;
+};
+struct t_makenote : t_object {
+ t_float velo;
+ t_float dur;
+ t_hang *hang;
+};
+static void *makenote_new(t_floatarg velo, t_floatarg dur) {
+ t_makenote *x = (t_makenote *)pd_new(makenote_class);
+ x->velo = velo;
+ x->dur = dur;
+ floatinlet_new(x, &x->velo);
+ floatinlet_new(x, &x->dur);
+ outlet_new(x, &s_float);
+ outlet_new(x, &s_float);
+ x->hang = 0;
+ return x;
+}
+static void makenote_tick(t_hang *hang) {
+ t_makenote *x = hang->owner;
+ t_hang *h2, *h3;
+ outlet_float(x->out(1), 0);
+ outlet_float(x->out(0), hang->pitch);
+ if (x->hang == hang) x->hang = hang->next;
+ else for (h2 = x->hang; (h3 = h2->next); h2 = h3) {
+ if (h3 == hang) {
+ h2->next = h3->next;
+ break;
+ }
+ }
+ clock_free(hang->clock);
+ free(hang);
+}
+static void makenote_float(t_makenote *x, t_float f) {
+ if (!x->velo) return;
+ outlet_float(x->out(1), x->velo);
+ outlet_float(x->out(0), f);
+ t_hang *hang = (t_hang *)getbytes(sizeof *hang);
+ hang->next = x->hang;
+ x->hang = hang;
+ hang->pitch = f;
+ hang->owner = x;
+ hang->clock = clock_new(hang, (t_method)makenote_tick);
+ clock_delay(hang->clock, (x->dur >= 0 ? x->dur : 0));
+}
+static void makenote_stop(t_makenote *x) {
+ t_hang *hang;
+ while ((hang = x->hang)) {
+ outlet_float(x->out(1), 0);
+ outlet_float(x->out(0), hang->pitch);
+ x->hang = hang->next;
+ clock_free(hang->clock);
+ free(hang);
+ }
+}
+static void makenote_clear(t_makenote *x) {
+ t_hang *hang;
+ while ((hang = x->hang)) {
+ x->hang = hang->next;
+ clock_free(hang->clock);
+ free(hang);
+ }
+}
+static void makenote_setup() {
+ makenote_class = class_new2("makenote",makenote_new,makenote_clear,sizeof(t_makenote),0,"FF");
+ class_addfloat(makenote_class, makenote_float);
+ class_addmethod2(makenote_class, makenote_stop, "stop","");
+ class_addmethod2(makenote_class, makenote_clear,"clear","");
+}
+
+static t_class *stripnote_class;
+struct t_stripnote : t_object {
+ t_float velo;
+};
+static void *stripnote_new() {
+ t_stripnote *x = (t_stripnote *)pd_new(stripnote_class);
+ floatinlet_new(x, &x->velo);
+ outlet_new(x, &s_float);
+ outlet_new(x, &s_float);
+ return x;
+}
+static void stripnote_float(t_stripnote *x, t_float f) {
+ if (!x->velo) return;
+ outlet_float(x->out(1), x->velo);
+ outlet_float(x->out(0), f);
+}
+static void stripnote_setup() {
+ stripnote_class = class_new2("stripnote",stripnote_new,0,sizeof(t_stripnote),0,"");
+ class_addfloat(stripnote_class, stripnote_float);
+}
+
+static t_class *poly_class;
+struct t_voice {
+ float pitch;
+ int used;
+ unsigned long serial;
+};
+struct t_poly : t_object {
+ int n;
+ t_voice *vec;
+ float vel;
+ unsigned long serial;
+ int steal;
+};
+static void *poly_new(float fnvoice, float fsteal) {
+ int i, n = (int)fnvoice;
+ t_poly *x = (t_poly *)pd_new(poly_class);
+ t_voice *v;
+ if (n < 1) n = 1;
+ x->n = n;
+ x->vec = (t_voice *)getbytes(n * sizeof(*x->vec));
+ for (v = x->vec, i = n; i--; v++) v->pitch = v->used = v->serial = 0;
+ x->vel = 0;
+ x->steal = (fsteal != 0);
+ floatinlet_new(x, &x->vel);
+ outlet_new(x, &s_float);
+ outlet_new(x, &s_float);
+ outlet_new(x, &s_float);
+ x->serial = 0;
+ return x;
+}
+static void poly_float(t_poly *x, t_float f) {
+ int i;
+ t_voice *v;
+ t_voice *firston, *firstoff;
+ unsigned int serialon, serialoff, onindex = 0, offindex = 0;
+ if (x->vel > 0) {
+ /* note on. Look for a vacant voice */
+ for (v=x->vec, i=0, firston=firstoff=0, serialon=serialoff=0xffffffff; i<x->n; v++, i++) {
+ if (v->used && v->serial < serialon)
+ firston = v, serialon = v->serial, onindex = i;
+ else if (!v->used && v->serial < serialoff)
+ firstoff = v, serialoff = v->serial, offindex = i;
+ }
+ if (firstoff) {
+ outlet_float(x->out(2), x->vel);
+ outlet_float(x->out(1), firstoff->pitch = f);
+ outlet_float(x->out(0), offindex+1);
+ firstoff->used = 1;
+ firstoff->serial = x->serial++;
+ }
+ /* if none, steal one */
+ else if (firston && x->steal) {
+ outlet_float(x->out(2), 0);
+ outlet_float(x->out(1), firston->pitch);
+ outlet_float(x->out(0), onindex+1);
+ outlet_float(x->out(2), x->vel);
+ outlet_float(x->out(1), firston->pitch = f);
+ outlet_float(x->out(0), onindex+1);
+ firston->serial = x->serial++;
+ }
+ } else { /* note off. Turn off oldest match */
+ for (v = x->vec, i = 0, firston = 0, serialon = 0xffffffff; i < x->n; v++, i++)
+ if (v->used && v->pitch == f && v->serial < serialon)
+ firston = v, serialon = v->serial, onindex = i;
+ if (firston) {
+ firston->used = 0;
+ firston->serial = x->serial++;
+ outlet_float(x->out(2), 0);
+ outlet_float(x->out(1), firston->pitch);
+ outlet_float(x->out(0), onindex+1);
+ }
+ }
+}
+static void poly_stop(t_poly *x) {
+ t_voice *v = x->vec;
+ for (int i = 0; i < x->n; i++, v++) if (v->used) {
+ outlet_float(x->out(2), 0L);
+ outlet_float(x->out(1), v->pitch);
+ outlet_float(x->out(0), i+1);
+ v->used = 0;
+ v->serial = x->serial++;
+ }
+}
+static void poly_clear(t_poly *x) {
+ t_voice *v = x->vec;
+ for (int i = x->n; i--; v++) v->used = v->serial = 0;
+}
+static void poly_free(t_poly *x) {free(x->vec);}
+static void poly_setup() {
+ poly_class = class_new2("poly",poly_new,poly_free,sizeof(t_poly),0,"FF");
+ class_addfloat(poly_class, poly_float);
+ class_addmethod2(poly_class, poly_stop, "stop","");
+ class_addmethod2(poly_class, poly_clear, "clear","");
+}
+
+static t_class *bag_class;
+struct t_bagelem {
+ struct t_bagelem *next;
+ t_float value;
+};
+struct t_bag : t_object {
+ t_float velo;
+ t_bagelem *first;
+};
+static void *bag_new() {
+ t_bag *x = (t_bag *)pd_new(bag_class);
+ x->velo = 0;
+ floatinlet_new(x, &x->velo);
+ outlet_new(x, &s_float);
+ x->first = 0;
+ return x;
+}
+static void bag_float(t_bag *x, t_float f) {
+ t_bagelem *bagelem, *e2, *e3;
+ if (x->velo != 0) {
+ bagelem = (t_bagelem *)getbytes(sizeof *bagelem);
+ bagelem->next = 0;
+ bagelem->value = f;
+ if (!x->first) x->first = bagelem;
+ else { /* LATER replace with a faster algorithm */
+ for (e2 = x->first; (e3 = e2->next); e2 = e3) {}
+ e2->next = bagelem;
+ }
+ } else {
+ if (!x->first) return;
+ if (x->first->value == f) {
+ bagelem = x->first;
+ x->first = x->first->next;
+ free(bagelem);
+ return;
+ }
+ for (e2 = x->first; (e3 = e2->next); e2 = e3) if (e3->value == f) {
+ e2->next = e3->next;
+ free(e3);
+ return;
+ }
+ }
+}
+static void bag_flush(t_bag *x) {
+ t_bagelem *bagelem;
+ while ((bagelem = x->first)) {
+ outlet_float(x->outlet, bagelem->value);
+ x->first = bagelem->next;
+ free(bagelem);
+ }
+}
+static void bag_clear(t_bag *x) {
+ t_bagelem *bagelem;
+ while ((bagelem = x->first)) {
+ x->first = bagelem->next;
+ free(bagelem);
+ }
+}
+static void bag_setup() {
+ bag_class = class_new2("bag",bag_new,bag_clear,sizeof(t_bag),0,"");
+ class_addfloat(bag_class, bag_float);
+ class_addmethod2(bag_class,bag_flush,"flush","");
+ class_addmethod2(bag_class,bag_clear,"clear","");
+}
+void midi_setup() {
+ midiin_class = class_new2( "midiin", midiin_new, midiin_free,sizeof(t_midiin),CLASS_NOINLET,"F");
+ sysexin_class = class_new2("sysexin",sysexin_new,sysexin_free,sizeof(t_midiin),CLASS_NOINLET,"F");
+ notein_class = class_new2( "notein", notein_new, notein_free,sizeof(t_notein),CLASS_NOINLET,"F");
+ ctlin_class = class_new2( "ctlin", ctlin_new, ctlin_free,sizeof( t_ctlin),CLASS_NOINLET,"*");
+ class_addlist( midiin_class, midiin_list); midiin_sym = gensym( "#midiin"); class_sethelpsymbol( midiin_class, gensym("midi"));
+ class_addlist(sysexin_class, midiin_list); sysexin_sym = gensym("#sysexin"); class_sethelpsymbol(sysexin_class, gensym("midi"));
+ class_addlist( notein_class, notein_list); notein_sym = gensym( "#notein"); class_sethelpsymbol( notein_class, gensym("midi"));
+ class_addlist( ctlin_class, ctlin_list); ctlin_sym = gensym( "#ctlin"); class_sethelpsymbol( ctlin_class, gensym("midi"));
+
+ pgmin_class = class_new2("pgmin", pgmin_new, pgmin_free, sizeof(t_pgmin), CLASS_NOINLET,"F");
+ bendin_class = class_new2("bendin", bendin_new, bendin_free, sizeof(t_bendin), CLASS_NOINLET,"F");
+ touchin_class = class_new2("touchin",touchin_new,touchin_free,sizeof(t_touchin),CLASS_NOINLET,"F");
+ class_addlist( pgmin_class,midi2_list);
+ class_addlist( bendin_class,midi2_list);
+ class_addlist(touchin_class,midi2_list);
+ class_sethelpsymbol( pgmin_class, gensym("midi"));
+ class_sethelpsymbol( bendin_class, gensym("midi"));
+ class_sethelpsymbol(touchin_class, gensym("midi"));
+ pgmin_sym = gensym("#pgmin");
+ bendin_sym = gensym("#bendin");
+ touchin_sym = gensym("#touchin");
+
+ polytouchin_setup(); midirealtimein_setup(); midiclkin_setup();
+ midiout_class = class_new2("midiout", midiout_new, 0, sizeof(t_midiout), 0,"FF");
+ ctlout_class = class_new2("ctlout", ctlout_new, 0, sizeof(t_ctlout), 0,"FF");
+ noteout_class = class_new2("noteout", noteout_new, 0, sizeof(t_noteout), 0,"F");
+ pgmout_class = class_new2("pgmout", pgmout_new, 0, sizeof(t_pgmout), 0,"F");
+ bendout_class = class_new2("bendout", bendout_new, 0, sizeof(t_bendout), 0,"F");
+ touchout_class = class_new2("touchout", touchout_new, 0, sizeof(t_touchout), 0,"F");
+ class_addfloat( midiout_class, midiout_float); class_sethelpsymbol( midiout_class, gensym("midi"));
+ class_addfloat( ctlout_class, ctlout_float); class_sethelpsymbol( ctlout_class, gensym("midi"));
+ class_addfloat( noteout_class, noteout_float); class_sethelpsymbol( noteout_class, gensym("midi"));
+ class_addfloat( pgmout_class, pgmout_float); class_sethelpsymbol( pgmout_class, gensym("midi"));
+ class_addfloat( bendout_class, bendout_float); class_sethelpsymbol( bendout_class, gensym("midi"));
+ class_addfloat(touchout_class, touchout_float); class_sethelpsymbol(touchout_class, gensym("midi"));
+ polytouchout_setup(); makenote_setup(); stripnote_setup(); poly_setup(); bag_setup();
+}
+
+static t_class *delay_class;
+struct t_delay : t_object {
+ t_clock *clock;
+ double deltime;
+};
+static void delay_bang(t_delay *x) {clock_delay(x->clock, x->deltime);}
+static void delay_stop(t_delay *x) {clock_unset(x->clock);}
+static void delay_ft1(t_delay *x, t_floatarg g) {x->deltime = max(0.f,g);}
+static void delay_float(t_delay *x, t_float f) {delay_ft1(x, f); delay_bang(x);}
+static void delay_tick(t_delay *x) {outlet_bang(x->outlet);}
+static void delay_free(t_delay *x) {clock_free(x->clock);}
+static void *delay_new(t_floatarg f) {
+ t_delay *x = (t_delay *)pd_new(delay_class);
+ delay_ft1(x, f);
+ x->clock = clock_new(x, (t_method)delay_tick);
+ outlet_new(x, gensym("bang"));
+ inlet_new(x, x, gensym("float"), gensym("ft1"));
+ return x;
+}
+static void delay_setup() {
+ t_class *c = delay_class = class_new2("delay",delay_new,delay_free,sizeof(t_delay),0,"F");
+ class_addcreator2("del",delay_new,"F");
+ class_addbang(c, delay_bang);
+ class_addmethod2(c,delay_stop,"stop","");
+ class_addmethod2(c,delay_ft1,"ft1","f");
+ class_addfloat(c, delay_float);
+}
+
+static t_class *metro_class;
+struct t_metro : t_object {
+ t_clock *clock;
+ double deltime;
+ int hit;
+};
+static void metro_tick(t_metro *x) {
+ x->hit = 0;
+ outlet_bang(x->outlet);
+ if (!x->hit) clock_delay(x->clock, x->deltime);
+}
+static void metro_float(t_metro *x, t_float f) {
+ if (f) metro_tick(x); else clock_unset(x->clock);
+ x->hit = 1;
+}
+static void metro_bang(t_metro *x) {metro_float(x, 1);}
+static void metro_stop(t_metro *x) {metro_float(x, 0);}
+static void metro_ft1(t_metro *x, t_floatarg g) {x->deltime = max(1.f,g);}
+static void metro_free(t_metro *x) {clock_free(x->clock);}
+static void *metro_new(t_floatarg f) {
+ t_metro *x = (t_metro *)pd_new(metro_class);
+ metro_ft1(x, f);
+ x->hit = 0;
+ x->clock = clock_new(x, (t_method)metro_tick);
+ outlet_new(x, gensym("bang"));
+ inlet_new(x, x, gensym("float"), gensym("ft1"));
+ return x;
+}
+static void metro_setup() {
+ t_class *c = metro_class = class_new2("metro",metro_new,metro_free,sizeof(t_metro),0,"F");
+ class_addbang(c, metro_bang);
+ class_addmethod2(c,metro_stop,"stop","");
+ class_addmethod2(c,metro_ft1,"ft1","f");
+ class_addfloat(c, metro_float);
+}
+
+static t_class *line_class;
+struct t_line : t_object {
+ t_clock *clock;
+ double targettime;
+ t_float targetval;
+ double prevtime;
+ t_float setval;
+ int gotinlet;
+ t_float grain;
+ double oneovertimediff;
+ double in1val;
+};
+static void line_tick(t_line *x) {
+ double timenow = clock_getsystime();
+ double msectogo = - clock_gettimesince(x->targettime);
+ if (msectogo < 1E-9) {
+ outlet_float(x->outlet, x->targetval);
+ } else {
+ outlet_float(x->outlet, x->setval + x->oneovertimediff * (timenow-x->prevtime) * (x->targetval-x->setval));
+ clock_delay(x->clock, (x->grain > msectogo ? msectogo : x->grain));
+ }
+}
+static void line_float(t_line *x, t_float f) {
+ double timenow = clock_getsystime();
+ if (x->gotinlet && x->in1val > 0) {
+ if (timenow > x->targettime) x->setval = x->targetval;
+ else x->setval = x->setval + x->oneovertimediff * (timenow-x->prevtime) * (x->targetval-x->setval);
+ x->prevtime = timenow;
+ x->targettime = clock_getsystimeafter(x->in1val);
+ x->targetval = f;
+ line_tick(x);
+ x->gotinlet = 0;
+ x->oneovertimediff = 1./ (x->targettime - timenow);
+ clock_delay(x->clock, (x->grain > x->in1val ? x->in1val : x->grain));
+ } else {
+ clock_unset(x->clock);
+ x->targetval = x->setval = f;
+ outlet_float(x->outlet, f);
+ }
+ x->gotinlet = 0;
+}
+static void line_ft1(t_line *x, t_floatarg g) {
+ x->in1val = g;
+ x->gotinlet = 1;
+}
+static void line_stop(t_line *x) {
+ x->targetval = x->setval;
+ clock_unset(x->clock);
+}
+static void line_set(t_line *x, t_floatarg f) {
+ clock_unset(x->clock);
+ x->targetval = x->setval = f;
+}
+static void line_set_granularity(t_line *x, t_floatarg grain) {
+ if (grain <= 0) grain = 20;
+ x->grain = grain;
+}
+static void line_free(t_line *x) {
+ clock_free(x->clock);
+}
+static void *line_new(t_floatarg f, t_floatarg grain) {
+ t_line *x = (t_line *)pd_new(line_class);
+ x->targetval = x->setval = f;
+ x->gotinlet = 0;
+ x->oneovertimediff = 1;
+ x->clock = clock_new(x, (t_method)line_tick);
+ x->targettime = x->prevtime = clock_getsystime();
+ line_set_granularity(x, grain);
+ outlet_new(x, gensym("float"));
+ inlet_new(x, x, gensym("float"), gensym("ft1"));
+ return x;
+}
+static void line_setup() {
+ t_class *c = line_class = class_new2("line",line_new,line_free,sizeof(t_line),0,"FF");
+ class_addmethod2(c,line_ft1,"ft1","f");
+ class_addmethod2(c,line_stop,"stop","");
+ class_addmethod2(c,line_set,"set","f");
+ class_addmethod2(c,line_set_granularity,"granularity","f");
+ class_addfloat(c,line_float);
+}
+
+static t_class *pipe_class;
+struct t_hang2 {
+ t_clock *clock;
+ t_hang2 *next;
+ struct t_pipe *owner;
+ union word vec[0]; /* not the actual number of elements */
+};
+struct t_pipe : t_object {
+ int n;
+ float deltime;
+ t_atom *vec;
+ t_hang2 *hang;
+};
+static void *pipe_new(t_symbol *s, int argc, t_atom *argv) {
+ t_pipe *x = (t_pipe *)pd_new(pipe_class);
+ t_atom defarg, *ap;
+ t_atom *vec, *vp;
+ float deltime=0;
+ if (argc) {
+ if (argv[argc-1].a_type != A_FLOAT) {
+ std::ostringstream os;
+ atom_ostream(&argv[argc-1], os);
+ post("pipe: %s: bad time delay value", os.str().data());
+ } else deltime = argv[argc-1].a_float;
+ argc--;
+ }
+ if (!argc) {
+ argv = &defarg;
+ argc = 1;
+ SETFLOAT(&defarg, 0);
+ }
+ x->n = argc;
+ vec = x->vec = (t_atom *)getbytes(argc * sizeof(*x->vec));
+ vp = vec;
+ ap = argv;
+ for (int i=0; i<argc; i++, ap++, vp++) {
+ if (ap->a_type == A_FLOAT) {
+ *vp = *ap;
+ outlet_new(x, &s_float);
+ if (i) floatinlet_new(x, &vp->a_float);
+ } else if (ap->a_type == A_SYMBOL) {
+ char c = *ap->a_symbol->name;
+ if (c=='s') {SETSYMBOL(vp, &s_symbol); outlet_new(x, &s_symbol); if (i) symbolinlet_new(x, &vp->a_symbol);}
+ else if (c=='p') {vp->a_type = A_POINTER; outlet_new(x, &s_pointer); /*if (i) pointerinlet_new(x, gp);*/}
+ else if (c=='f') {SETFLOAT(vp,0); outlet_new(x, &s_float); if (i) floatinlet_new(x, &vp->a_float);}
+ else error("pack: %s: bad type", ap->a_symbol->name);
+ }
+ }
+ floatinlet_new(x, &x->deltime);
+ x->hang = 0;
+ x->deltime = deltime;
+ return x;
+}
+static void hang_free(t_hang2 *h) {
+ clock_free(h->clock);
+ free(h);
+}
+static void hang_tick(t_hang2 *h) {
+ t_pipe *x = h->owner;
+ t_hang2 *h2, *h3;
+ if (x->hang == h) x->hang = h->next;
+ else for (h2 = x->hang; (h3 = h2->next); h2 = h3) {
+ if (h3 == h) {
+ h2->next = h3->next;
+ break;
+ }
+ }
+ t_atom *p = x->vec + x->n-1;
+ t_word *w = h->vec + x->n-1;
+ for (int i = x->n; i--; p--, w--) {
+ switch (p->a_type) {
+ case A_FLOAT: outlet_float( x->out(i), w->w_float ); break;
+ case A_SYMBOL: outlet_symbol( x->out(i), w->w_symbol ); break;
+ case A_POINTER:outlet_pointer(x->out(i), w->w_gpointer); break;
+ default:{}
+ }
+ }
+ hang_free(h);
+}
+static void pipe_list(t_pipe *x, t_symbol *s, int ac, t_atom *av) {
+ t_hang2 *h = (t_hang2 *)getbytes(sizeof(*h) + (x->n - 1) * sizeof(*h->vec));
+ int n = x->n;
+ if (ac > n) ac = n;
+ t_atom *p = x->vec;
+ t_atom *ap = av;
+ for (int i=0; i<ac; i++, p++, ap++) *p = *ap;
+ t_word *w = h->vec;
+ p = x->vec;
+ for (int i=0; i< n; i++, p++, w++) *w = p->a_w;
+ h->next = x->hang;
+ x->hang = h;
+ h->owner = x;
+ h->clock = clock_new(h, (t_method)hang_tick);
+ clock_delay(h->clock, (x->deltime >= 0 ? x->deltime : 0));
+}
+static void pipe_flush(t_pipe *x) {
+ while (x->hang) hang_tick(x->hang);
+}
+static void pipe_clear(t_pipe *x) {
+ t_hang2 *hang;
+ while ((hang = x->hang)) {
+ x->hang = hang->next;
+ hang_free(hang);
+ }
+}
+static void pipe_setup() {
+ pipe_class = class_new2("pipe",pipe_new,pipe_clear,sizeof(t_pipe),0,"*");
+ class_addlist(pipe_class, pipe_list);
+ class_addmethod2(pipe_class,pipe_flush,"flush","");
+ class_addmethod2(pipe_class,pipe_clear,"clear","");
+}
+
+/* ---------------------------------------------------------------- */
+/* new desiredata classes are below this point. */
+
+static t_class *unpost_class;
+struct t_unpost : t_object {
+ t_outlet *o0,*o1;
+};
+struct t_unpost_frame {
+ t_unpost *self;
+ std::ostringstream buf;
+};
+static t_unpost_frame *current_unpost;
+
+void *unpost_new (t_symbol *s) {
+ t_unpost *x = (t_unpost *)pd_new(unpost_class);
+ x->o0 = outlet_new(x,&s_symbol);
+ x->o1 = outlet_new(x,&s_symbol);
+ return x;
+}
+extern t_printhook sys_printhook;
+void unpost_printhook (const char *s) {
+ std::ostringstream &b = current_unpost->buf;
+ b << s;
+ char *p;
+ const char *d=b.str().data(),*dd=d;
+ for (;;) {
+ p = strchr(d,'\n');
+ if (!p) break;
+ outlet_symbol(current_unpost->self->o1,gensym2(d,p-d));
+ d=p+1;
+ }
+ if (d!=dd) {
+ char *q = strdup(d); /* well i could use memmove, but i'm not supposed to use strcpy because of overlap */
+ current_unpost->buf.clear();
+ current_unpost->buf << q;
+ free(q);
+ }
+}
+void unpost_anything (t_unpost *x, t_symbol *s, int argc, t_atom *argv) {
+ t_printhook backup1 = sys_printhook;
+ t_unpost_frame *backup2 = current_unpost;
+ sys_printhook = unpost_printhook;
+ current_unpost = new t_unpost_frame;
+ current_unpost->self = x;
+ outlet_anything(x->o0,s,argc,argv);
+ sys_printhook = backup1;
+ current_unpost = backup2;
+}
+
+struct t_unparse : t_object {};
+static t_class *unparse_class;
+void *unparse_new (t_symbol *s) {
+ t_unparse *x = (t_unparse *)pd_new(unparse_class);
+ outlet_new(x,&s_symbol);
+ return x;
+}
+void unparse_list (t_unparse *x, t_symbol *s, int argc, t_atom *argv) {
+ std::ostringstream o;
+ for (int i=0; i<argc; i++) {
+ o << ' ';
+ atom_ostream(argv+i,o);
+ }
+ outlet_symbol(x->outlet,gensym(o.str().data()+1));
+}
+
+struct t_parse : t_object {};
+static t_class *parse_class;
+void *parse_new (t_symbol *s) {
+ t_parse *x = (t_parse *)pd_new(parse_class);
+ outlet_new(x,&s_list);
+ return x;
+}
+void parse_symbol (t_unpost *x, t_symbol *s) {
+ t_binbuf *b = binbuf_new();
+ binbuf_text(b,s->name,s->n);
+ outlet_anything(x->outlet,&s_list,b->n,b->v);
+ binbuf_free(b);
+}
+
+struct t_tracecall : t_object {};
+static t_class *tracecall_class;
+void *tracecall_new (t_symbol *s) {
+ t_tracecall *x = (t_tracecall *)pd_new(tracecall_class);
+ outlet_new(x,&s_list);
+ return x;
+}
+void tracecall_anything (t_tracecall *x, t_symbol *dummy, int dum, t_atom *my) {
+ t_atom a[2];
+ for (int i=pd_stackn-1; i>=0; i--) {
+ SETSYMBOL( &a[0],pd_stack[i].self->_class->name);
+ SETSYMBOL( &a[1],pd_stack[i].s);
+ //SETPOINTER(&a[2],pd_stack[i].self);
+ outlet_list(x->outlet,&s_list,2,a);
+ }
+}
+
+static void matju_setup() {
+ unpost_class = class_new2("unpost",unpost_new,0,sizeof(t_unpost),0,"");
+ class_addanything(unpost_class, unpost_anything);
+ unparse_class = class_new2("unparse",unparse_new,0,sizeof(t_unparse),0,"");
+ class_addlist(unparse_class, unparse_list);
+ parse_class = class_new2("parse",parse_new,0,sizeof(t_parse),0,"");
+ class_addsymbol(parse_class, parse_symbol);
+ tracecall_class = class_new2("tracecall",tracecall_new,0,sizeof(t_tracecall),0,"");
+ class_addanything(tracecall_class,tracecall_anything);
+}
+
+/* end of new desiredata classes */
+/* ---------------------------------------------------------------- */
+
+void builtins_setup() {
+ t_symbol *s = gensym("acoustics.pd");
+ FUNC1DECL(mtof, "mtof");
+ FUNC1DECL(ftom, "ftom");
+ FUNC1DECL(powtodb,"powtodb");
+ FUNC1DECL(rmstodb,"rmstodb");
+ FUNC1DECL(dbtopow,"dbtopow");
+ FUNC1DECL(dbtorms,"dbtorms");
+ random_setup();
+ loadbang_setup();
+ namecanvas_setup();
+ print_setup();
+ macro_setup();
+ display_setup();
+ any_setup();
+ clipboard_setup();
+ delay_setup();
+ metro_setup();
+ line_setup();
+ timer_setup();
+ pipe_setup();
+ misc_setup();
+ sendreceive_setup();
+ select_setup();
+ route_setup();
+ pack_setup();
+ unpack_setup();
+ trigger_setup();
+ spigot_setup();
+ moses_setup();
+ until_setup();
+ makefilename_setup();
+ swap_setup();
+ change_setup();
+ value_setup();
+
+ t_class *c;
+ qlist_class = c = class_new2("qlist",qlist_new,qlist_free,sizeof(t_qlist),0,"");
+ class_addmethod2(c,qlist_rewind, "rewind","");
+ class_addmethod2(c,qlist_next, "next","F");
+ class_addmethod2(c,qlist_set, "set","*");
+ class_addmethod2(c,qlist_clear, "clear","");
+ class_addmethod2(c,qlist_add, "add","*");
+ class_addmethod2(c,qlist_add2, "add2","*");
+ class_addmethod2(c,qlist_add, "append","*");
+ class_addmethod2(c,qlist_read, "read","sS");
+ class_addmethod2(c,qlist_write, "write","sS");
+ class_addmethod2(c,qlist_print, "print","S");
+ class_addmethod2(c,qlist_tempo, "tempo","f");
+ class_addbang(c,qlist_bang);
+
+ textfile_class = c = class_new2("textfile",textfile_new,textfile_free,sizeof(t_textfile),0,"");
+ class_addmethod2(c,textfile_rewind, "rewind","");
+ class_addmethod2(c,qlist_set, "set","*");
+ class_addmethod2(c,qlist_clear, "clear","");
+ class_addmethod2(c,qlist_add, "add","*");
+ class_addmethod2(c,qlist_add2, "add2","*");
+ class_addmethod2(c,qlist_add, "append","*");
+ class_addmethod2(c,qlist_read, "read","sS");
+ class_addmethod2(c,qlist_write, "write","sS");
+ class_addmethod2(c,qlist_print, "print","S");
+ class_addbang(c,textfile_bang);
+ netsend_setup();
+ netreceive_setup();
+ openpanel_setup();
+ savepanel_setup();
+ key_setup();
+
+extern t_class *binbuf_class;
+ class_addlist(binbuf_class, alist_list);
+ class_addanything(binbuf_class, alist_anything);
+ list_setup();
+ arithmetic_setup();
+ midi_setup();
+ matju_setup();
+}
diff --git a/desiredata/src/builtins_dsp.c b/desiredata/src/builtins_dsp.c
new file mode 100644
index 00000000..cf2d460e
--- /dev/null
+++ b/desiredata/src/builtins_dsp.c
@@ -0,0 +1,3844 @@
+/* Copyright (c) 2007 Mathieu Bouchard
+ Copyright (c) 1997-1999 Miller Puckette.
+ For information on usage and redistribution,
+ and for a DISCLAIMER OF ALL WARRANTIES,
+ see the file "LICENSE.txt" in this distribution. */
+
+/* arithmetic binops (+, -, *, /).
+If no creation argument is given, there are two signal inlets for vector/vector
+operation; otherwise it's vector/scalar and the second inlet takes a float
+to reset the value.
+*/
+
+//#define HAVE_LIBFFTW3F
+
+#define PD_PLUSPLUS_FACE
+#include "desire.h"
+#include "m_simd.h"
+#include "s_stuff.h"
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+extern int ugen_getsortno ();
+#define DEFDELVS 64 /* LATER get this from canvas at DSP time */
+#ifdef HAVE_LIBFFTW3F
+#include <fftw3.h>
+#endif
+#define DEFSENDVS 64 /* LATER get send to get this from canvas */
+#define LOGTEN 2.302585092994
+#define UNITBIT32 1572864. /* 3*2^19; bit 32 has place value 1 */
+#define int32 int
+#ifdef BIGENDIAN
+#define HIOFFSET 0 /* word offset to find MSB */
+#define LOWOFFSET 1 /* word offset to find LSB */
+#else
+#define HIOFFSET 1
+#define LOWOFFSET 0
+#endif
+
+#undef CLASS_MAINSIGNALIN
+/* because C++ bitches about null pointers, we'll use 8 instead (really): */
+#define CLASS_MAINSIGNALIN(c, type, field) class_domainsignalin(c, (char *)(&((type *)8)->field) - (char *)8)
+
+#define clock_new(a,b) clock_new(a,(t_method)b)
+
+#undef min
+#undef max
+
+/* ----------------------------- plus ----------------------------- */
+
+struct t_dop : t_object {
+ float a;
+ t_float b; /* inlet value, if necessary */
+};
+
+#define DSPDECL(NAME) static t_class *NAME##_class, *scalar##NAME##_class; typedef t_dop t_##NAME, t_scalar##NAME;
+DSPDECL(plus)
+DSPDECL(minus)
+DSPDECL(times)
+DSPDECL(over)
+DSPDECL(max)
+DSPDECL(min)
+DSPDECL(lt)
+DSPDECL(gt)
+DSPDECL(le)
+DSPDECL(ge)
+DSPDECL(eq)
+DSPDECL(ne)
+
+#define DSPNEW(NAME,SYM) \
+static void *NAME##_new(t_symbol *s, int argc, t_atom *argv) { \
+ if (argc > 1) error("extra arguments ignored"); \
+ t_dop *x = (t_dop *)pd_new(argc ? scalar##NAME##_class : NAME##_class); \
+ if (argc) { \
+ floatinlet_new(x, &x->b); \
+ x->b = atom_getfloatarg(0, argc, argv); \
+ } else inlet_new(x, x, &s_signal, &s_signal); \
+ outlet_new(x, &s_signal); \
+ x->a = 0; \
+ return x;} \
+static void NAME##_setup() { \
+ t_class *c = NAME##_class = class_new2(SYM,NAME##_new,0,sizeof(t_dop),0,"*"); \
+ class_addmethod2(c, NAME##_dsp, "dsp",""); \
+ CLASS_MAINSIGNALIN(c, t_dop, a); \
+ class_sethelpsymbol(NAME##_class, gensym("sigbinops")); \
+ c = scalar##NAME##_class = class_new2(SYM,0,0,sizeof(t_dop),0,""); \
+ CLASS_MAINSIGNALIN(c, t_dop, a); \
+ class_addmethod2(c, scalar##NAME##_dsp, "dsp",""); \
+ class_sethelpsymbol(scalar##NAME##_class, gensym("sigbinops"));}
+
+/* use when simd functions are present */
+#define DSPDSP(NAME) \
+static void NAME##_dsp(t_minus *x, t_signal **sp) { \
+ const int n = sp[0]->n; \
+ if(n&7) dsp_add(NAME##_perform, 4, sp[0]->v, sp[1]->v, sp[2]->v, n); \
+ else if(SIMD_CHECK3(n,sp[0]->v,sp[1]->v,sp[2]->v)) \
+ dsp_add(NAME##_perf_simd, 4, sp[0]->v, sp[1]->v, sp[2]->v, n); \
+ else dsp_add(NAME##_perf8, 4, sp[0]->v, sp[1]->v, sp[2]->v, n);} \
+static void scalar##NAME##_dsp(t_scalarminus *x, t_signal **sp) { \
+ const int n = sp[0]->n;\
+ if(n&7) dsp_add(scalar##NAME##_perform, 4, sp[0]->v, &x->b,sp[1]->v, n);\
+ else if(SIMD_CHECK2(n,sp[0]->v,sp[1]->v)) \
+ dsp_add(scalar##NAME##_perf_simd, 4, sp[0]->v, &x->b, sp[1]->v, n);\
+ else dsp_add(scalar##NAME##_perf8, 4, sp[0]->v, &x->b, sp[1]->v, n);}
+
+/* use when simd functions are missing */
+#define DSPDSP2(NAME) \
+static void NAME##_dsp(t_minus *x, t_signal **sp) { \
+ const int n = sp[0]->n; \
+ if(n&7) dsp_add(NAME##_perform, 4, sp[0]->v, sp[1]->v, sp[2]->v, n); \
+ else dsp_add(NAME##_perf8, 4, sp[0]->v, sp[1]->v, sp[2]->v, n);} \
+static void scalar##NAME##_dsp(t_scalarminus *x, t_signal **sp) { \
+ const int n = sp[0]->n;\
+ if(n&7) dsp_add(scalar##NAME##_perform, 4, sp[0]->v, &x->b,sp[1]->v, n);\
+ else dsp_add(scalar##NAME##_perf8, 4, sp[0]->v, &x->b, sp[1]->v, n);}
+
+#define PERFORM(NAME,EXPR) \
+t_int *NAME##_perform(t_int *w) { \
+ t_float *in1 = (t_float *)w[1], *in2 = (t_float *)w[2], *out = (t_float *)w[3]; \
+ int n = (int)w[4]; \
+ while (n--) {t_float a=*in1++, b=*in2++; *out++ = (EXPR);} \
+ return w+5;} \
+t_int *NAME##_perf8(t_int *w) { \
+ t_float *in1 = (t_float *)w[1], *in2 = (t_float *)w[2], *out = (t_float *)w[3]; \
+ int n = (int)w[4]; \
+ for (; n; n -= 8, in1 += 8, in2 += 8, out += 8) { \
+ {t_float a=in1[0], b=in2[0]; out[0] = (EXPR);} \
+ {t_float a=in1[1], b=in2[1]; out[1] = (EXPR);} \
+ {t_float a=in1[2], b=in2[2]; out[2] = (EXPR);} \
+ {t_float a=in1[3], b=in2[3]; out[3] = (EXPR);} \
+ {t_float a=in1[4], b=in2[4]; out[4] = (EXPR);} \
+ {t_float a=in1[5], b=in2[5]; out[5] = (EXPR);} \
+ {t_float a=in1[6], b=in2[6]; out[6] = (EXPR);} \
+ {t_float a=in1[7], b=in2[7]; out[7] = (EXPR);}} \
+ return w+5;} \
+t_int *scalar##NAME##_perform(t_int *w) { \
+ t_float *in = (t_float *)w[1]; t_float b = *(t_float *)w[2]; t_float *out = (t_float *)w[3]; \
+ int n = (int)w[4]; \
+ while (n--) {t_float a=*in++; *out++ = (EXPR);} \
+ return w+5;} \
+t_int *scalar##NAME##_perf8(t_int *w) { \
+ t_float *in = (t_float *)w[1]; t_float b = *(t_float *)w[2]; t_float *out = (t_float *)w[3]; \
+ int n = (int)w[4]; \
+ for (; n; n -= 8, in += 8, out += 8) { \
+ {t_float a=in[0]; out[0] = (EXPR);} \
+ {t_float a=in[1]; out[1] = (EXPR);} \
+ {t_float a=in[2]; out[2] = (EXPR);} \
+ {t_float a=in[3]; out[3] = (EXPR);} \
+ {t_float a=in[4]; out[4] = (EXPR);} \
+ {t_float a=in[5]; out[5] = (EXPR);} \
+ {t_float a=in[6]; out[6] = (EXPR);} \
+ {t_float a=in[7]; out[7] = (EXPR);}} \
+ return w+5;}
+
+void dsp_add_plus(t_sample *in1, t_sample *in2, t_sample *out, int n) {
+ if (n&7) dsp_add(plus_perform, 4, in1, in2, out, n);
+ else if(SIMD_CHECK3(n,in1,in2,out)) dsp_add(plus_perf_simd, 4, in1, in2, out, n);
+ else dsp_add(plus_perf8, 4, in1, in2, out, n);
+}
+
+/* T.Grill - squaring: optimized * for equal input signals */
+t_int *sqr_perf8(t_int *w) {
+ t_float *in = (t_float *)w[1];
+ t_float *out = (t_float *)w[2];
+ int n = (int)w[3];
+ for (; n; n -= 8, in += 8, out += 8) {
+ float f0 = in[0], f1 = in[1], f2 = in[2], f3 = in[3];
+ float f4 = in[4], f5 = in[5], f6 = in[6], f7 = in[7];
+ out[0] = f0 * f0; out[1] = f1 * f1; out[2] = f2 * f2; out[3] = f3 * f3;
+ out[4] = f4 * f4; out[5] = f5 * f5; out[6] = f6 * f6; out[7] = f7 * f7;
+ }
+ return w+4;
+}
+
+/* T.Grill - added optimization for equal input signals */
+static void times_dsp(t_times *x, t_signal **sp) {
+ const int n = sp[0]->n;
+ if (n&7) dsp_add(times_perform, 4, sp[0]->v, sp[1]->v, sp[2]->v, n);
+ else if(sp[0]->v == sp[1]->v) {
+ if(SIMD_CHECK2(n,sp[0]->v,sp[2]->v))
+ dsp_add(sqr_perf_simd, 3, sp[0]->v, sp[2]->v, n);
+ else dsp_add(sqr_perf8, 3, sp[0]->v, sp[2]->v, n);
+ } else {
+ if(SIMD_CHECK3(n,sp[0]->v,sp[1]->v,sp[2]->v))
+ dsp_add(times_perf_simd, 4, sp[0]->v, sp[1]->v, sp[2]->v, n);
+ else dsp_add(times_perf8, 4, sp[0]->v, sp[1]->v, sp[2]->v, n);
+ }
+}
+static void scalartimes_dsp(t_scalartimes *x, t_signal **sp) {
+ const int n = sp[0]->n;
+ if (n&7) dsp_add(scalartimes_perform, 4, sp[0]->v, &x->b,sp[1]->v, n);
+ else if(SIMD_CHECK2(n,sp[0]->v,sp[1]->v))
+ dsp_add(scalartimes_perf_simd, 4, sp[0]->v, &x->b, sp[1]->v, n);
+ else dsp_add(scalartimes_perf8, 4, sp[0]->v, &x->b, sp[1]->v, n);
+}
+
+PERFORM(plus ,a+b) DSPDSP(plus) DSPNEW(plus ,"+~")
+PERFORM(minus,a-b) DSPDSP(minus) DSPNEW(minus,"-~")
+PERFORM(times,a*b) /*DSPDSP(times)*/ DSPNEW(times,"*~")
+/*PERFORM(over,a/b)*/ DSPDSP(over) DSPNEW(over ,"/~")
+PERFORM(min ,a<b?a:b) DSPDSP(min) DSPNEW(min ,"min~")
+PERFORM(max ,a>b?a:b) DSPDSP(max) DSPNEW(max ,"max~")
+PERFORM(lt ,a<b) DSPDSP2(lt) DSPNEW(lt ,"<~")
+PERFORM(gt ,a>b) DSPDSP2(gt) DSPNEW(gt ,">~")
+PERFORM(le ,a<=b) DSPDSP2(le) DSPNEW(le ,"<=~")
+PERFORM(ge ,a>=b) DSPDSP2(ge) DSPNEW(ge ,">=~")
+PERFORM(eq ,a==b) DSPDSP2(eq) DSPNEW(eq ,"==~")
+PERFORM(ne ,a!=b) DSPDSP2(ne) DSPNEW(ne ,"!=~")
+
+t_int *over_perform(t_int *w) {
+ t_float *in1 = (t_float *)w[1], *in2 = (t_float *)w[2], *out = (t_float *)w[3];
+ int n = (int)w[4];
+ while (n--) {
+ float g = *in2++;
+ *out++ = (g ? *in1++ / g : 0);
+ }
+ return w+5;
+}
+t_int *over_perf8(t_int *w) {
+ t_float *in1 = (t_float *)w[1];
+ t_float *in2 = (t_float *)w[2];
+ t_float *out = (t_float *)w[3];
+ int n = (int)w[4];
+ for (; n; n -= 8, in1 += 8, in2 += 8, out += 8) {
+ float f0 = in1[0], f1 = in1[1], f2 = in1[2], f3 = in1[3];
+ float f4 = in1[4], f5 = in1[5], f6 = in1[6], f7 = in1[7];
+ float g0 = in2[0], g1 = in2[1], g2 = in2[2], g3 = in2[3];
+ float g4 = in2[4], g5 = in2[5], g6 = in2[6], g7 = in2[7];
+ out[0] = (g0? f0 / g0 : 0);
+ out[1] = (g1? f1 / g1 : 0);
+ out[2] = (g2? f2 / g2 : 0);
+ out[3] = (g3? f3 / g3 : 0);
+ out[4] = (g4? f4 / g4 : 0);
+ out[5] = (g5? f5 / g5 : 0);
+ out[6] = (g6? f6 / g6 : 0);
+ out[7] = (g7? f7 / g7 : 0);
+ }
+ return w+5;
+}
+/* T.Grill - added check for zero */
+t_int *scalarover_perform(t_int *w) {
+ t_float *in = (t_float *)w[1];
+ t_float f = *(t_float *)w[2];
+ t_float *out = (t_float *)w[3];
+ int n = (int)w[4];
+ if(f) f = 1./f;
+ while (n--) *out++ = *in++ * f;
+ return w+5;
+}
+t_int *scalarover_perf8(t_int *w) {
+ t_float *in = (t_float *)w[1];
+ t_float g = *(t_float *)w[2];
+ t_float *out = (t_float *)w[3];
+ int n = (int)w[4];
+ if (g) g = 1.f / g;
+ for (; n; n -= 8, in += 8, out += 8) {
+ out[0] = in[0] * g; out[1] = in[1] * g; out[2] = in[2] * g; out[3] = in[3] * g;
+ out[4] = in[4] * g; out[5] = in[5] * g; out[6] = in[6] * g; out[7] = in[7] * g;
+ }
+ return w+5;
+}
+
+/* ------------------------- tabwrite~ -------------------------- */
+static t_class *tabwrite_tilde_class;
+struct t_tabwrite_tilde : t_object {
+ int phase;
+ int nsampsintab;
+ float *vec;
+ t_symbol *arrayname;
+ float a;
+};
+static void *tabwrite_tilde_new(t_symbol *s) {
+ t_tabwrite_tilde *x = (t_tabwrite_tilde *)pd_new(tabwrite_tilde_class);
+ x->phase = 0x7fffffff;
+ x->arrayname = s;
+ x->a = 0;
+ return x;
+}
+static void tabwrite_tilde_redraw(t_tabwrite_tilde *x) {
+ t_garray *a = (t_garray *)pd_findbyclass(x->arrayname, garray_class);
+ if (!a) bug("tabwrite_tilde_redraw");
+ else garray_redraw(a);
+}
+static t_int *tabwrite_tilde_perform(t_int *w) {
+ t_tabwrite_tilde *x = (t_tabwrite_tilde *)w[1];
+ t_float *in = (t_float *)w[2];
+ int n = (int)w[3], phase = x->phase, endphase = x->nsampsintab;
+ if (!x->vec) goto bad;
+ if (endphase > phase) {
+ int nxfer = endphase - phase;
+ float *fp = x->vec + phase;
+ if (nxfer > n) nxfer = n;
+ phase += nxfer;
+ testcopyvec(fp, in, nxfer);
+ if (phase >= endphase) {
+ tabwrite_tilde_redraw(x);
+ phase = 0x7fffffff;
+ }
+ x->phase = phase;
+ } else x->phase = 0x7fffffff;
+bad:
+ return w+4;
+}
+static t_int *tabwrite_tilde_perf_simd(t_int *w) {
+ t_tabwrite_tilde *x = (t_tabwrite_tilde *)w[1];
+ t_float *in = (t_float *)w[2];
+ int n = (int)w[3], phase = x->phase, endphase = x->nsampsintab;
+ if (!x->vec) goto bad;
+ if (endphase > phase) {
+ int nxfer = endphase - phase;
+ float *fp = x->vec + phase;
+ if (nxfer > n) nxfer = n;
+ phase += nxfer;
+ if (SIMD_CHKCNT(nxfer)) testcopyvec_simd(fp, in, nxfer);
+ else testcopyvec(fp, in, nxfer);
+ if (phase >= endphase) {
+ tabwrite_tilde_redraw(x);
+ phase = 0x7fffffff;
+ }
+ x->phase = phase;
+ } else x->phase = 0x7fffffff;
+bad:
+ return w+4;
+}
+void tabwrite_tilde_set(t_tabwrite_tilde *x, t_symbol *s) {
+ x->arrayname = s;
+ t_garray *a = (t_garray *)pd_findbyclass(x->arrayname, garray_class);
+ if (!a) {
+ if (*s->name) error("tabwrite~: %s: no such array", x->arrayname->name);
+ x->vec = 0;
+ } else if (!garray_getfloatarray(a, &x->nsampsintab, &x->vec)) {
+ error("%s: bad template for tabwrite~", x->arrayname->name);
+ x->vec = 0;
+ } else garray_usedindsp(a);
+}
+static void tabwrite_tilde_dsp(t_tabwrite_tilde *x, t_signal **sp) {
+ tabwrite_tilde_set(x, x->arrayname);
+ if (SIMD_CHECK1(sp[0]->n, sp[0]->v))
+ dsp_add(tabwrite_tilde_perf_simd, 3, x, sp[0]->v, sp[0]->n);
+ else dsp_add(tabwrite_tilde_perform, 3, x, sp[0]->v, sp[0]->n);
+}
+static void tabwrite_tilde_bang(t_tabwrite_tilde *x) {x->phase = 0;}
+static void tabwrite_tilde_start(t_tabwrite_tilde *x, t_floatarg f) {x->phase = (int)max((int)f,0);}
+static void tabwrite_tilde_stop(t_tabwrite_tilde *x) {
+ if (x->phase != 0x7fffffff) {
+ tabwrite_tilde_redraw(x);
+ x->phase = 0x7fffffff;
+ }
+}
+
+/* ------------ tabplay~ - non-transposing sample playback --------------- */
+static t_class *tabplay_tilde_class;
+struct t_tabplay_tilde : t_object {
+ int phase;
+ int nsampsintab;
+ int limit;
+ float *vec;
+ t_symbol *arrayname;
+ t_clock *clock;
+};
+static void tabplay_tilde_tick(t_tabplay_tilde *x);
+static void *tabplay_tilde_new(t_symbol *s) {
+ t_tabplay_tilde *x = (t_tabplay_tilde *)pd_new(tabplay_tilde_class);
+ x->clock = clock_new(x, tabplay_tilde_tick);
+ x->phase = 0x7fffffff;
+ x->limit = 0;
+ x->arrayname = s;
+ outlet_new(x, &s_signal);
+ outlet_new(x, &s_bang);
+ return x;
+}
+static t_int *tabplay_tilde_perform(t_int *w) {
+ t_tabplay_tilde *x = (t_tabplay_tilde *)w[1];
+ t_float *out = (t_float *)w[2], *fp;
+ int n = (int)w[3], phase = x->phase, endphase = (x->nsampsintab < x->limit ? x->nsampsintab : x->limit), nxfer, n3;
+ if (!x->vec || phase >= endphase) {while (n--) *out++ = 0; goto bye;}
+ nxfer = min(endphase-phase,n);
+ fp = x->vec + phase;
+ n3 = n - nxfer;
+ phase += nxfer;
+ while (nxfer--) *out++ = *fp++;
+ if (phase >= endphase) {
+ clock_delay(x->clock, 0);
+ x->phase = 0x7fffffff;
+ while (n3--) *out++ = 0;
+ } else x->phase = phase;
+ return w+4;
+bye:
+ return w+4;
+}
+void tabplay_tilde_set(t_tabplay_tilde *x, t_symbol *s) {
+ t_garray *a = (t_garray *)pd_findbyclass(x->arrayname, garray_class);
+ x->arrayname = s;
+ if (!a) {
+ if (*s->name) error("tabplay~: %s: no such array", x->arrayname->name);
+ x->vec = 0;
+ } else if (!garray_getfloatarray(a, &x->nsampsintab, &x->vec)) {
+ error("%s: bad template for tabplay~", x->arrayname->name);
+ x->vec = 0;
+ } else garray_usedindsp(a);
+}
+static void tabplay_tilde_dsp(t_tabplay_tilde *x, t_signal **sp) {
+ tabplay_tilde_set(x, x->arrayname);
+ dsp_add(tabplay_tilde_perform, 3, x, sp[0]->v, sp[0]->n);
+}
+static void tabplay_tilde_list(t_tabplay_tilde *x, t_symbol *s, int argc, t_atom *argv) {
+ long start = atom_getintarg(0, argc, argv);
+ long length = atom_getintarg(1, argc, argv);
+ if (start < 0) start = 0;
+ if (length <= 0) x->limit = 0x7fffffff; else x->limit = start + length;
+ x->phase = start;
+}
+static void tabplay_tilde_stop(t_tabplay_tilde *x) {x->phase = 0x7fffffff;}
+static void tabplay_tilde_tick(t_tabplay_tilde *x) {outlet_bang(x->out(1));}
+static void tabplay_tilde_free(t_tabplay_tilde *x) {clock_free(x->clock);}
+
+/******************** tabread~ ***********************/
+static t_class *tabread_tilde_class;
+struct t_tabread_tilde : t_object {
+ int npoints;
+ float *vec;
+ t_symbol *arrayname;
+ float a;
+};
+static void *tabread_tilde_new(t_symbol *s) {
+ t_tabread_tilde *x = (t_tabread_tilde *)pd_new(tabread_tilde_class);
+ x->arrayname = s;
+ x->vec = 0;
+ outlet_new(x, &s_signal);
+ x->a = 0;
+ return x;
+}
+static t_int *tabread_tilde_perform(t_int *w) {
+ t_tabread_tilde *x = (t_tabread_tilde *)w[1];
+ t_float *in = (t_float *)w[2];
+ t_float *out = (t_float *)w[3];
+ int n = (int)w[4];
+ float *buf = x->vec;
+ int maxindex = x->npoints - 1;
+ if (!buf) {while (n--) *out++ = 0; goto bad;}
+ for (int i = 0; i < n; i++) {
+ int index = (int)*in++;
+ if (index < 0) index = 0; else if (index > maxindex) index = maxindex;
+ *out++ = buf[index];
+ }
+bad:return w+5;
+}
+void tabread_tilde_set(t_tabread_tilde *x, t_symbol *s) {
+ x->arrayname = s;
+ t_garray *a = (t_garray *)pd_findbyclass(x->arrayname, garray_class);
+ if (!a) {
+ if (*s->name) error("tabread~: %s: no such array", x->arrayname->name);
+ x->vec = 0;
+ } else if (!garray_getfloatarray(a, &x->npoints, &x->vec)) {
+ error("%s: bad template for tabread~", x->arrayname->name);
+ x->vec = 0;
+ } else garray_usedindsp(a);
+}
+static void tabread_tilde_dsp(t_tabread_tilde *x, t_signal **sp) {
+ tabread_tilde_set(x, x->arrayname);
+ dsp_add(tabread_tilde_perform, 4, x, sp[0]->v, sp[1]->v, sp[0]->n);
+}
+static void tabread_tilde_free(t_tabread_tilde *x) {}
+
+/******************** tabread4~ ***********************/
+static t_class *tabread4_tilde_class;
+struct t_tabread4_tilde : t_object {
+ int npoints;
+ float *vec;
+ t_symbol *arrayname;
+ float a;
+};
+static void *tabread4_tilde_new(t_symbol *s) {
+ t_tabread4_tilde *x = (t_tabread4_tilde *)pd_new(tabread4_tilde_class);
+ x->arrayname = s;
+ x->vec = 0;
+ outlet_new(x, &s_signal);
+ x->a = 0;
+ return x;
+}
+static t_int *tabread4_tilde_perform(t_int *w) {
+ t_tabread4_tilde *x = (t_tabread4_tilde *)w[1];
+ t_float *in = (t_float *)w[2];
+ t_float *out = (t_float *)w[3];
+ int n = (int)w[4];
+ int maxindex;
+ float *buf = x->vec, *fp;
+ maxindex = x->npoints - 3;
+ if (!buf) goto zero;
+#if 0 /* test for spam -- I'm not ready to deal with this */
+ for (i = 0, xmax = 0, xmin = maxindex, fp = in1; i < n; i++, fp++) {
+ float f = *in1;
+ if (f < xmin) xmin = f;
+ else if (f > xmax) xmax = f;
+ }
+ if (xmax < xmin + x->c_maxextent) xmax = xmin + x->c_maxextent;
+ for (i = 0, splitlo = xmin+ x->c_maxextent, splithi = xmax - x->c_maxextent,
+ fp = in1; i < n; i++, fp++) {
+ float f = *in1;
+ if (f > splitlo && f < splithi) goto zero;
+ }
+#endif
+ for (int i=0; i<n; i++) {
+ float findex = *in++;
+ int index = (int)findex;
+ float frac;
+ if (index < 1) index = 1, frac = 0;
+ else if (index > maxindex) index = maxindex, frac = 1;
+ else frac = findex - index;
+ fp = buf + index;
+ float a=fp[-1], b=fp[0], c=fp[1], d=fp[2];
+ /* if (!i && !(count++ & 1023)) post("fp = %lx, shit = %lx, b = %f", fp, buf->b_shit, b); */
+ float cminusb = c-b;
+ *out++ = b + frac * (cminusb - 0.1666667f * (1.-frac) * ((d - a - 3.0f * cminusb) * frac + (d + 2.0f*a - 3.0f*b)));
+ }
+ return w+5;
+ zero:
+ while (n--) *out++ = 0;
+ return w+5;
+}
+void tabread4_tilde_set(t_tabread4_tilde *x, t_symbol *s) {
+ x->arrayname = s;
+ t_garray *a = (t_garray *)pd_findbyclass(x->arrayname, garray_class);
+ if (!a) {
+ if (*s->name) error("tabread4~: %s: no such array", x->arrayname->name);
+ x->vec = 0;
+ } else if (!garray_getfloatarray(a, &x->npoints, &x->vec)) {
+ error("%s: bad template for tabread4~", x->arrayname->name);
+ x->vec = 0;
+ } else garray_usedindsp(a);
+}
+static void tabread4_tilde_dsp(t_tabread4_tilde *x, t_signal **sp) {
+ tabread4_tilde_set(x, x->arrayname);
+ dsp_add(tabread4_tilde_perform, 4, x, sp[0]->v, sp[1]->v, sp[0]->n);
+}
+static void tabread4_tilde_free(t_tabread4_tilde *x) {}
+
+/******************** tabosc4~ ***********************/
+
+#define UNITBIT32 1572864. /* 3*2^19; bit 32 has place value 1 */
+
+#ifdef BIGENDIAN
+#define HIOFFSET 0 /* word offset to find MSB */
+#define LOWOFFSET 1 /* word offset to find LSB */
+#else
+#define HIOFFSET 1
+#define LOWOFFSET 0
+#endif
+#include <sys/types.h>
+//#define int32 int32_t
+#define int32 int
+
+union tabfudge {
+ double d;
+ int32 i[2];
+};
+static t_class *tabosc4_tilde_class;
+struct t_tabosc4_tilde : t_object {
+ float fnpoints;
+ float finvnpoints;
+ float *vec;
+ t_symbol *arrayname;
+ float a;
+ double phase;
+ float conv;
+};
+static void *tabosc4_tilde_new(t_symbol *s) {
+ t_tabosc4_tilde *x = (t_tabosc4_tilde *)pd_new(tabosc4_tilde_class);
+ x->arrayname = s;
+ x->vec = 0;
+ x->fnpoints = 512.;
+ x->finvnpoints = (1./512.);
+ outlet_new(x, &s_signal);
+ inlet_new(x, x, &s_float, gensym("ft1"));
+ x->a = 0;
+ return x;
+}
+static t_int *tabosc4_tilde_perform(t_int *w) {
+ t_tabosc4_tilde *x = (t_tabosc4_tilde *)w[1];
+ t_float *in = (t_float *)w[2];
+ t_float *out = (t_float *)w[3];
+ int n = (int)w[4];
+ union tabfudge tf;
+ float fnpoints = x->fnpoints;
+ int mask = (int)(fnpoints-1);
+ float conv = fnpoints * x->conv;
+ float *tab = x->vec, *addr;
+ double dphase = fnpoints * x->phase + UNITBIT32;
+ if (!tab) {while (n--) *out++ = 0; return w+5;}
+ tf.d = UNITBIT32;
+ int normhipart = tf.i[HIOFFSET];
+#if 1
+ while (n--) {
+ tf.d = dphase;
+ dphase += *in++ * conv;
+ addr = tab + (tf.i[HIOFFSET] & mask);
+ tf.i[HIOFFSET] = normhipart;
+ float frac = tf.d - UNITBIT32;
+ float a = addr[0];
+ float b = addr[1];
+ float c = addr[2];
+ float d = addr[3];
+ float cminusb = c-b;
+ *out++ = b + frac * (cminusb - 0.1666667f * (1.-frac) * ((d - a - 3.0f * cminusb) * frac + (d + 2.0f*a - 3.0f*b)));
+ }
+#endif
+ tf.d = UNITBIT32 * fnpoints;
+ normhipart = tf.i[HIOFFSET];
+ tf.d = dphase + (UNITBIT32 * fnpoints - UNITBIT32);
+ tf.i[HIOFFSET] = normhipart;
+ x->phase = (tf.d - UNITBIT32 * fnpoints) * x->finvnpoints;
+ return w+5;
+}
+void tabosc4_tilde_set(t_tabosc4_tilde *x, t_symbol *s) {
+ t_garray *a = (t_garray *)pd_findbyclass(x->arrayname, garray_class);
+ int npoints, pointsinarray;
+ x->arrayname = s;
+ if (!a) {
+ if (*s->name) error("tabosc4~: %s: no such array", x->arrayname->name);
+ x->vec = 0;
+ } else if (!garray_getfloatarray(a, &pointsinarray, &x->vec)) {
+ error("%s: bad template for tabosc4~", x->arrayname->name);
+ x->vec = 0;
+ } else if ((npoints = pointsinarray - 3) != (1 << ilog2(pointsinarray - 3))) {
+ error("%s: number of points (%d) not a power of 2 plus three", x->arrayname->name, pointsinarray);
+ x->vec = 0;
+ garray_usedindsp(a);
+ } else {
+ x->fnpoints = npoints;
+ x->finvnpoints = 1./npoints;
+ garray_usedindsp(a);
+ }
+}
+static void tabosc4_tilde_ft1(t_tabosc4_tilde *x, t_float f) {
+ x->phase = f;
+}
+static void tabosc4_tilde_dsp(t_tabosc4_tilde *x, t_signal **sp) {
+ x->conv = 1. / sp[0]->sr;
+ tabosc4_tilde_set(x, x->arrayname);
+ dsp_add(tabosc4_tilde_perform, 4, x, sp[0]->v, sp[1]->v, sp[0]->n);
+}
+static void tabosc4_tilde_setup() {
+}
+
+static void tab_tilde_setup() {
+ t_class *c;
+ c = tabwrite_tilde_class = class_new2("tabwrite~",tabwrite_tilde_new,0,sizeof(t_tabwrite_tilde),0,"S");
+ CLASS_MAINSIGNALIN(c, t_tabwrite_tilde, a);
+ class_addmethod2(c, tabwrite_tilde_dsp, "dsp","");
+ class_addmethod2(c, tabwrite_tilde_set, "set","s");
+ class_addmethod2(c, tabwrite_tilde_stop,"stop","");
+ class_addmethod2(c, tabwrite_tilde_start,"start","F");
+ class_addbang(c, tabwrite_tilde_bang);
+ c = tabplay_tilde_class = class_new2("tabplay~",tabplay_tilde_new,tabplay_tilde_free,sizeof(t_tabplay_tilde),0,"S");
+ class_addmethod2(c, tabplay_tilde_dsp, "dsp","");
+ class_addmethod2(c, tabplay_tilde_stop, "stop","");
+ class_addmethod2(c, tabplay_tilde_set, "set","S");
+ class_addlist(c, tabplay_tilde_list);
+ c = tabread_tilde_class = class_new2("tabread~",tabread_tilde_new,tabread_tilde_free, sizeof(t_tabread_tilde),0,"S");
+ CLASS_MAINSIGNALIN(c, t_tabread_tilde, a);
+ class_addmethod2(c, tabread_tilde_dsp, "dsp","");
+ class_addmethod2(c, tabread_tilde_set, "set","s");
+ c = tabread4_tilde_class = class_new2("tabread4~",tabread4_tilde_new,tabread4_tilde_free,sizeof(t_tabread4_tilde),0,"S");
+ CLASS_MAINSIGNALIN(c, t_tabread4_tilde, a);
+ class_addmethod2(c, tabread4_tilde_dsp, "dsp","");
+ class_addmethod2(c, tabread4_tilde_set, "set","s");
+ c = tabosc4_tilde_class = class_new2("tabosc4~",tabosc4_tilde_new,0,sizeof(t_tabosc4_tilde),0,"S");
+ CLASS_MAINSIGNALIN(c, t_tabosc4_tilde, a);
+ class_addmethod2(c, tabosc4_tilde_dsp, "dsp","");
+ class_addmethod2(c, tabosc4_tilde_set, "set","s");
+ class_addmethod2(c, tabosc4_tilde_ft1, "ft1","f");
+}
+
+/* ------------------------ tabsend~ ------------------------- */
+static t_class *tabsend_class;
+struct t_tabsend : t_object {
+ float *vec;
+ int graphperiod;
+ int graphcount;
+ t_symbol *arrayname;
+ float a;
+};
+static void *tabsend_new(t_symbol *s) {
+ t_tabsend *x = (t_tabsend *)pd_new(tabsend_class);
+ x->graphcount = 0;
+ x->arrayname = s;
+ x->a = 0;
+ return x;
+}
+static t_int *tabsend_perform(t_int *w) {
+ t_tabsend *x = (t_tabsend *)w[1];
+ t_float *in = (t_float *)w[2];
+ int n = w[3];
+ t_float *dest = x->vec;
+ int i = x->graphcount;
+ if (!x->vec) goto bad;
+ testcopyvec(dest,in,n);
+ if (!i--) {
+ t_garray *a = (t_garray *)pd_findbyclass(x->arrayname, garray_class);
+ if (!a) bug("tabsend_dsp");
+ else garray_redraw(a);
+ i = x->graphperiod;
+ }
+ x->graphcount = i;
+bad:
+ return w+4;
+}
+static t_int *tabsend_perf_simd(t_int *w) {
+ t_tabsend *x = (t_tabsend *)w[1];
+ t_float *in = (t_float *)w[2];
+ int n = w[3];
+ t_float *dest = x->vec;
+ int i = x->graphcount;
+ if (!x->vec) goto bad;
+ testcopyvec_simd(dest,in,n);
+ if (!i--) {
+ t_garray *a = (t_garray *)pd_findbyclass(x->arrayname, garray_class);
+ if (!a) bug("tabsend_dsp");
+ else garray_redraw(a);
+ i = x->graphperiod;
+ }
+ x->graphcount = i;
+bad:
+ return w+4;
+}
+static void tabsend_dsp(t_tabsend *x, t_signal **sp) {
+ int vecsize;
+ t_garray *a = (t_garray *)pd_findbyclass(x->arrayname, garray_class);
+ if (!a) {
+ if (*x->arrayname->name) {error("tabsend~: %s: no such array", x->arrayname->name); return;}
+ } else if (!garray_getfloatarray(a, &vecsize, &x->vec)) {
+ error("%s: bad template for tabsend~", x->arrayname->name); return;
+ } else {
+ int n = sp[0]->n;
+ int ticksper = (int)(sp[0]->sr/n);
+ if (ticksper < 1) ticksper = 1;
+ x->graphperiod = ticksper;
+ if (x->graphcount > ticksper) x->graphcount = ticksper;
+ if (n < vecsize) vecsize = n;
+ garray_usedindsp(a);
+ if(SIMD_CHECK1(vecsize,sp[0]->v))
+ dsp_add(tabsend_perf_simd, 3, x, sp[0]->v, vecsize);
+ else dsp_add(tabsend_perform, 3, x, sp[0]->v, vecsize);
+ }
+}
+
+static void tabsend_setup() {
+ tabsend_class = class_new2("tabsend~",tabsend_new,0,sizeof(t_tabsend),0,"S");
+ CLASS_MAINSIGNALIN(tabsend_class, t_tabsend, a);
+ class_addmethod2(tabsend_class, tabsend_dsp, "dsp","");
+}
+
+/* ------------------------ tabreceive~ ------------------------- */
+static t_class *tabreceive_class;
+struct t_tabreceive : t_object {
+ float *vec;
+ int vecsize;
+ t_symbol *arrayname;
+};
+static t_int *tabreceive_perform(t_int *w) {
+ t_tabreceive *x = (t_tabreceive *)w[1];
+ t_float *out = (t_float *)w[2];
+ int n = w[3];
+ t_float *from = x->vec;
+ if (from) {
+ int vecsize = x->vecsize; while (vecsize--) *out++ = *from++;
+ vecsize = n - x->vecsize; while (vecsize--) *out++ = 0;
+ } else while (n--) *out++ = 0;
+ return w+4;
+}
+static t_int *tabreceive_perf8(t_int *w) {
+ t_tabreceive *x = (t_tabreceive *)w[1];
+ t_float *from = x->vec;
+ if (from) copyvec_8((t_float *)w[2],from,w[3]);
+ else zerovec_8((t_float *)w[2], w[3]);
+ return w+4;
+}
+static t_int *tabreceive_perfsimd(t_int *w) {
+ t_tabreceive *x = (t_tabreceive *)w[1];
+ t_float *from = x->vec;
+ if(from) copyvec_simd((t_float *)w[2],from,w[3]);
+ else zerovec_simd((t_float *)w[2], w[3]);
+ return w+4;
+}
+static void tabreceive_dsp(t_tabreceive *x, t_signal **sp) {
+ t_garray *a;
+ if (!(a = (t_garray *)pd_findbyclass(x->arrayname, garray_class))) {
+ if (*x->arrayname->name) error("tabsend~: %s: no such array", x->arrayname->name);
+ } else if (!garray_getfloatarray(a, &x->vecsize, &x->vec)) {
+ error("%s: bad template for tabreceive~", x->arrayname->name);
+ } else {
+ if (x->vecsize > sp[0]->n) x->vecsize = sp[0]->n;
+ garray_usedindsp(a);
+ /* the array is aligned in any case */
+ if(sp[0]->n&7) dsp_add(tabreceive_perform, 3, x, sp[0]->v, sp[0]->n);
+ else if(SIMD_CHECK1(sp[0]->n,sp[0]->v))
+ dsp_add(tabreceive_perfsimd, 3, x, sp[0]->v, sp[0]->n);
+ else dsp_add(tabreceive_perf8, 3, x, sp[0]->v, sp[0]->n);
+ }
+}
+static void *tabreceive_new(t_symbol *s) {
+ t_tabreceive *x = (t_tabreceive *)pd_new(tabreceive_class);
+ x->arrayname = s;
+ outlet_new(x, &s_signal);
+ return x;
+}
+static void tabreceive_setup() {
+ tabreceive_class = class_new2("tabreceive~",tabreceive_new,0,sizeof(t_tabreceive),0,"S");
+ class_addmethod2(tabreceive_class, tabreceive_dsp, "dsp","");
+}
+
+/* ---------- tabread: control, non-interpolating ------------------------ */
+static t_class *tabread_class;
+struct t_tabread : t_object {
+ t_symbol *arrayname;
+};
+static void tabread_float(t_tabread *x, t_float f) {
+ int npoints;
+ t_float *vec;
+ t_garray *a = (t_garray *)pd_findbyclass(x->arrayname, garray_class);
+ if (!a) {error("%s: no such array", x->arrayname->name); return;}
+ if (!garray_getfloatarray(a, &npoints, &vec)) {error("%s: bad template for tabread", x->arrayname->name); return;}
+ int n = clip(int(f),0,npoints-1);
+ outlet_float(x->outlet, (npoints ? vec[n] : 0));
+}
+static void tabread_set(t_tabread *x, t_symbol *s) {
+ x->arrayname = s;
+}
+static void *tabread_new(t_symbol *s) {
+ t_tabread *x = (t_tabread *)pd_new(tabread_class);
+ x->arrayname = s;
+ outlet_new(x, &s_float);
+ return x;
+}
+static void tabread_setup() {
+ tabread_class = class_new2("tabread",tabread_new,0,sizeof(t_tabread),0,"S");
+ class_addfloat(tabread_class, tabread_float);
+ class_addmethod2(tabread_class, tabread_set, "set","s");
+}
+
+/* ---------- tabread4: control, 4-point interpolation --------------- */
+static t_class *tabread4_class;
+struct t_tabread4 : t_object {
+ t_symbol *arrayname;
+};
+static void tabread4_float(t_tabread4 *x, t_float f) {
+ t_garray *ar = (t_garray *)pd_findbyclass(x->arrayname, garray_class);
+ int npoints;
+ t_float *vec;
+ if (!ar) {error("%s: no such array", x->arrayname->name); return;}
+ if (!garray_getfloatarray(ar, &npoints, &vec)) {error("%s: bad template for tabread4", x->arrayname->name); return;}
+ if (npoints < 4) {outlet_float(x->outlet, 0); return;}
+ if (f <= 1) {outlet_float(x->outlet, vec[1]); return;}
+ if (f >= npoints-2) {outlet_float(x->outlet, vec[npoints-2]); return;}
+ int n = min(int(f),npoints-3);
+ float *fp = vec + n;
+ float frac = f - n;
+ float a=fp[-1], b=fp[0], c=fp[1], d=fp[2];
+ float cminusb = c-b;
+ outlet_float(x->outlet, b + frac * (cminusb - 0.1666667f * (1.-frac) * ((d - a - 3.0f * cminusb) * frac + (d + 2.0f*a - 3.0f*b))));
+}
+static void tabread4_set(t_tabread4 *x, t_symbol *s) {x->arrayname = s;}
+static void *tabread4_new(t_symbol *s) {
+ t_tabread4 *x = (t_tabread4 *)pd_new(tabread4_class);
+ x->arrayname = s;
+ outlet_new(x, &s_float);
+ return x;
+}
+static void tabread4_setup() {
+ tabread4_class = class_new2("tabread4",tabread4_new,0,sizeof(t_tabread4),0,"S");
+ class_addfloat(tabread4_class, tabread4_float);
+ class_addmethod2(tabread4_class, tabread4_set, "set","s");
+}
+
+/* ------------------ tabwrite: control ------------------------ */
+static t_class *tabwrite_class;
+struct t_tabwrite : t_object {
+ t_symbol *arrayname;
+ float ft1;
+};
+static void tabwrite_float(t_tabwrite *x, t_float f) {
+ int vecsize;
+ t_garray *a = (t_garray *)pd_findbyclass(x->arrayname, garray_class);
+ t_float *vec;
+ if (!a) {error("%s: no such array", x->arrayname->name); return;}
+ if (!garray_getfloatarray(a, &vecsize, &vec)) {error("%s: bad template for tabwrite", x->arrayname->name); return;}
+ int n = (int)x->ft1;
+ if (n < 0) n = 0; else if (n > vecsize-1) n = vecsize-1;
+ vec[n] = f;
+ garray_redraw(a);
+}
+static void tabwrite_set(t_tabwrite *x, t_symbol *s) {x->arrayname = s;}
+static void *tabwrite_new(t_symbol *s) {
+ t_tabwrite *x = (t_tabwrite *)pd_new(tabwrite_class);
+ x->ft1 = 0;
+ x->arrayname = s;
+ floatinlet_new(x, &x->ft1);
+ return x;
+}
+void tabwrite_setup() {
+ tabwrite_class = class_new2("tabwrite",tabwrite_new,0,sizeof(t_tabwrite),0,"S");
+ class_addfloat(tabwrite_class, tabwrite_float);
+ class_addmethod2(tabwrite_class, tabwrite_set, "set","s");
+}
+
+/* -------------------------- sig~ ------------------------------ */
+static t_class *sig_tilde_class;
+struct t_sig : t_object {
+ float a;
+};
+t_int *sig_tilde_perform(t_int *w) {
+ t_float f = *(t_float *)w[1];
+ t_float *out = (t_float *)w[2];
+ int n = (int)w[3];
+ while (n--) *out++ = f;
+ return w+4;
+}
+t_int *sig_tilde_perf8(t_int *w) {
+ t_float f = *(t_float *)w[1];
+ t_float *out = (t_float *)w[2];
+ int n = (int)w[3];
+ for (; n; n -= 8, out += 8) {
+ out[0] = f; out[1] = f;
+ out[2] = f; out[3] = f;
+ out[4] = f; out[5] = f;
+ out[6] = f; out[7] = f;
+ }
+ return w+4;
+}
+void dsp_add_scalarcopy(t_sample *in, t_sample *out, int n) {
+ if (n&7)
+ dsp_add(sig_tilde_perform, 3, in, out, n);
+ else if(SIMD_CHECK1(n,out))
+ dsp_add(sig_tilde_perf_simd, 3, in, out, n);
+ else dsp_add(sig_tilde_perf8, 3, in, out, n);
+}
+static void sig_tilde_float(t_sig *x, t_float f) {
+ x->a = f;
+}
+static void sig_tilde_dsp(t_sig *x, t_signal **sp) {
+/* dsp_add(sig_tilde_perform, 3, &x->a, sp[0]->v, sp[0]->n); */
+ /* T.Grill - use chance of unrolling */
+ dsp_add_scalarcopy(&x->a, sp[0]->v, sp[0]->n);
+}
+static void *sig_tilde_new(t_floatarg f) {
+ t_sig *x = (t_sig *)pd_new(sig_tilde_class);
+ x->a = f;
+ outlet_new(x, &s_signal);
+ return x;
+}
+static void sig_tilde_setup() {
+ sig_tilde_class = class_new2("sig~",sig_tilde_new,0,sizeof(t_sig),0,"F");
+ class_addfloat(sig_tilde_class, sig_tilde_float);
+ class_addmethod2(sig_tilde_class, sig_tilde_dsp,"dsp","");
+}
+
+/* -------------------------- line~ ------------------------------ */
+static t_class *line_tilde_class;
+struct t_line : t_object {
+ float target;
+ float value;
+ float biginc;
+ float inc;
+ float oneovern;
+ float dspticktomsec;
+ float inletvalue;
+ float inletwas;
+ int ticksleft;
+ int retarget;
+ float* slopes; /* tb: for simd-optimized line */
+ float slopestep; /* tb: 4*x->inc */
+};
+static t_int *line_tilde_perform(t_int *w) {
+ t_line *x = (t_line *)w[1];
+ t_float *out = (t_float *)w[2];
+ int n = (int)w[3];
+ float f = x->value;
+ if (PD_BIGORSMALL(f)) x->value = f = 0;
+ if (x->retarget) {
+ int nticks = (int)(x->inletwas * x->dspticktomsec);
+ if (!nticks) nticks = 1;
+ x->ticksleft = nticks;
+ x->biginc = (x->target - x->value)/(float)nticks;
+ x->inc = x->oneovern * x->biginc;
+ x->retarget = 0;
+ }
+ if (x->ticksleft) {
+ float f = x->value;
+ float slope = x->inc; /* tb: make sure, x->inc is loaded to a register */
+ while (n--) *out++ = f, f += slope;
+ x->value += x->biginc;
+ x->ticksleft--;
+ } else {
+ float g = x->value = x->target;
+ while (n--)
+ *out++ = g;
+ }
+ return w+4;
+}
+/* tb: vectorized / simd version { */
+static void line_tilde_slope(t_float* out, t_int n, t_float* value, t_float* slopes, t_float* slopestep) {
+ t_float slope = slopes[1];
+ t_float f = *value;
+ n>>=3;
+ while (n--) {
+ *out++ = f;f += slope;
+ *out++ = f;f += slope;
+ *out++ = f;f += slope;
+ *out++ = f;f += slope;
+ *out++ = f;f += slope;
+ *out++ = f;f += slope;
+ *out++ = f;f += slope;
+ *out++ = f;f += slope;
+ }
+}
+static t_int *line_tilde_perf8(t_int *w) {
+ t_line *x = (t_line *)w[1];
+ t_float *out = (t_float *)w[2];
+ int n = (int)w[3];
+ float f = x->value;
+ if (PD_BIGORSMALL(f)) x->value = f = 0;
+ if (x->retarget) {
+ int nticks = (int)(x->inletwas * x->dspticktomsec);
+ if (!nticks) nticks = 1;
+ x->ticksleft = nticks;
+ x->biginc = (x->target - x->value)/(float)nticks;
+ x->inc = x->oneovern * x->biginc;
+ x->retarget = 0;
+ /* tb: rethink!!! this is ugly */
+ for (int i = 0; i != 4; ++i) x->slopes[i] = i*x->inc;
+ x->slopestep = 4 * x->inc;
+ }
+ if (x->ticksleft) {
+ line_tilde_slope(out, n, &x->value, x->slopes, &x->slopestep);
+ x->value += x->biginc;
+ x->ticksleft--;
+ } else {
+ float f = x->value = x->target;
+ setvec_8(out,f,n);
+ }
+ return w+4;
+}
+static t_int *line_tilde_perfsimd(t_int *w) {
+ t_line *x = (t_line *)w[1];
+ t_float *out = (t_float *)w[2];
+ int n = (int)w[3];
+ float f = x->value;
+ if (PD_BIGORSMALL(f)) x->value = f = 0;
+ if (x->retarget) {
+ int nticks = (int)(x->inletwas * x->dspticktomsec);
+ if (!nticks) nticks = 1;
+ x->ticksleft = nticks;
+ x->biginc = (x->target - x->value)/(float)nticks;
+ x->inc = x->oneovern * x->biginc;
+ x->retarget = 0;
+ for (int i = 0; i != 4; ++i) x->slopes[i] = i*x->inc;
+ x->slopestep = 4 * x->inc;
+ }
+ if (x->ticksleft) {
+ line_tilde_slope_simd(out, n, &x->value, x->slopes, &x->slopestep);
+ x->value += x->biginc;
+ x->ticksleft--;
+ } else {
+ float f = x->value = x->target;
+ setvec_simd(out,f,n);
+ }
+ return w+4;
+}
+/* tb } */
+static void line_tilde_float(t_line *x, t_float f) {
+ if (x->inletvalue <= 0) {
+ x->target = x->value = f;
+ x->ticksleft = x->retarget = 0;
+ } else {
+ x->target = f;
+ x->retarget = 1;
+ x->inletwas = x->inletvalue;
+ x->inletvalue = 0;
+ }
+}
+static void line_tilde_stop(t_line *x) {
+ x->target = x->value;
+ x->ticksleft = x->retarget = 0;
+}
+static void line_tilde_dsp(t_line *x, t_signal **sp) {
+ if(sp[0]->n&7)
+ dsp_add(line_tilde_perform, 3, x, sp[0]->v, sp[0]->n);
+ else if (SIMD_CHECK1(sp[0]->n,sp[0]->v))
+ dsp_add(line_tilde_perfsimd, 3, x, sp[0]->v, sp[0]->n);
+ else dsp_add(line_tilde_perf8, 3, x, sp[0]->v, sp[0]->n);
+ x->oneovern = 1./sp[0]->n;
+ x->dspticktomsec = sp[0]->sr / (1000 * sp[0]->n);
+}
+/* tb: modified for simd-optimized line~ */
+static void *line_tilde_new() {
+ t_line *x = (t_line *)pd_new(line_tilde_class);
+ outlet_new(x, &s_signal);
+ floatinlet_new(x, &x->inletvalue);
+ x->ticksleft = x->retarget = 0;
+ x->value = x->target = x->inletvalue = x->inletwas = 0;
+ x->slopes = (t_float *)getalignedbytes(4*sizeof(t_float));
+ return x;
+}
+
+static void line_tilde_free(t_line * x) {
+ freealignedbytes(x->slopes, 4*sizeof(t_float));
+}
+static void line_tilde_setup() {
+ line_tilde_class = class_new2("line~",line_tilde_new,line_tilde_free,sizeof(t_line),0,"");
+ class_addfloat(line_tilde_class, line_tilde_float);
+ class_addmethod2(line_tilde_class, line_tilde_dsp, "dsp","");
+ class_addmethod2(line_tilde_class, line_tilde_stop,"stop","");
+}
+
+/* -------------------------- vline~ ------------------------------ */
+static t_class *vline_tilde_class;
+struct t_vseg {
+ double s_targettime;
+ double s_starttime;
+ float s_target;
+ t_vseg *s_next;
+};
+struct t_vline : t_object {
+ double value;
+ double inc;
+ double referencetime;
+ double samppermsec;
+ double msecpersamp;
+ double targettime;
+ float target;
+ float inlet1;
+ float inlet2;
+ t_vseg *list;
+};
+static t_int *vline_tilde_perform(t_int *w) {
+ t_vline *x = (t_vline *)w[1];
+ t_float *out = (t_float *)w[2];
+ int n = (int)w[3], i;
+ double f = x->value;
+ double inc = x->inc;
+ double msecpersamp = x->msecpersamp;
+ double timenow = clock_gettimesince(x->referencetime) - n * msecpersamp;
+ t_vseg *s = x->list;
+ for (i = 0; i < n; i++) {
+ double timenext = timenow + msecpersamp;
+ checknext:
+ if (s) {
+ /* has starttime elapsed? If so update value and increment */
+ if (s->s_starttime < timenext) {
+ if (x->targettime <= timenext)
+ f = x->target, inc = 0;
+ /* if zero-length segment bash output value */
+ if (s->s_targettime <= s->s_starttime) {
+ f = s->s_target;
+ inc = 0;
+ } else {
+ double incpermsec = (s->s_target - f)/
+ (s->s_targettime - s->s_starttime);
+ f = f + incpermsec * (timenext - s->s_starttime);
+ inc = incpermsec * msecpersamp;
+ }
+ x->inc = inc;
+ x->target = s->s_target;
+ x->targettime = s->s_targettime;
+ x->list = s->s_next;
+ free(s);
+ s = x->list;
+ goto checknext;
+ }
+ }
+ if (x->targettime <= timenext)
+ f = x->target, inc = x->inc = 0, x->targettime = 1e20;
+ *out++ = f;
+ f = f + inc;
+ timenow = timenext;
+ }
+ x->value = f;
+ return w+4;
+}
+static void vline_tilde_stop(t_vline *x) {
+ t_vseg *s1, *s2;
+ for (s1 = x->list; s1; s1 = s2)
+ s2 = s1->s_next, free(s1);
+ x->list = 0;
+ x->inc = 0;
+ x->inlet1 = x->inlet2 = 0;
+ x->target = x->value;
+ x->targettime = 1e20;
+}
+static void vline_tilde_float(t_vline *x, t_float f) {
+ double timenow = clock_gettimesince(x->referencetime);
+ float inlet1 = (x->inlet1 < 0 ? 0 : x->inlet1);
+ float inlet2 = x->inlet2;
+ double starttime = timenow + inlet2;
+ t_vseg *s1, *s2, *deletefrom = 0, *snew;
+ if (PD_BIGORSMALL(f)) f = 0;
+ /* negative delay input means stop and jump immediately to new value */
+ if (inlet2 < 0) {
+ x->value = f;
+ vline_tilde_stop(x);
+ return;
+ }
+ snew = (t_vseg *)t_getbytes(sizeof(*snew));
+ /* check if we supplant the first item in the list. We supplant
+ an item by having an earlier starttime, or an equal starttime unless
+ the equal one was instantaneous and the new one isn't (in which case
+ we'll do a jump-and-slide starting at that time.) */
+ if (!x->list || x->list->s_starttime > starttime ||
+ (x->list->s_starttime == starttime &&
+ (x->list->s_targettime > x->list->s_starttime || inlet1 <= 0))) {
+ deletefrom = x->list;
+ x->list = snew;
+ } else {
+ for (s1 = x->list; (s2 = s1->s_next); s1 = s2) {
+ if (s2->s_starttime > starttime ||
+ (s2->s_starttime == starttime &&
+ (s2->s_targettime > s2->s_starttime || inlet1 <= 0))) {
+ deletefrom = s2;
+ s1->s_next = snew;
+ goto didit;
+ }
+ }
+ s1->s_next = snew;
+ deletefrom = 0;
+ didit: ;
+ }
+ while (deletefrom) {
+ s1 = deletefrom->s_next;
+ free(deletefrom);
+ deletefrom = s1;
+ }
+ snew->s_next = 0;
+ snew->s_target = f;
+ snew->s_starttime = starttime;
+ snew->s_targettime = starttime + inlet1;
+ x->inlet1 = x->inlet2 = 0;
+}
+static void vline_tilde_dsp(t_vline *x, t_signal **sp) {
+ dsp_add(vline_tilde_perform, 3, x, sp[0]->v, sp[0]->n);
+ x->samppermsec = ((double)(sp[0]->sr)) / 1000;
+ x->msecpersamp = ((double)1000) / sp[0]->sr;
+}
+static void *vline_tilde_new() {
+ t_vline *x = (t_vline *)pd_new(vline_tilde_class);
+ outlet_new(x, &s_signal);
+ floatinlet_new(x, &x->inlet1);
+ floatinlet_new(x, &x->inlet2);
+ x->inlet1 = x->inlet2 = 0;
+ x->value = x->inc = 0;
+ x->referencetime = clock_getlogicaltime();
+ x->list = 0;
+ x->samppermsec = 0;
+ x->targettime = 1e20;
+ return x;
+}
+static void vline_tilde_setup() {
+ vline_tilde_class = class_new2("vline~",vline_tilde_new,vline_tilde_stop,sizeof(t_vline),0,"");
+ class_addfloat(vline_tilde_class, vline_tilde_float);
+ class_addmethod2(vline_tilde_class, vline_tilde_dsp, "dsp","");
+ class_addmethod2(vline_tilde_class, vline_tilde_stop,"stop","");
+}
+
+/* -------------------------- snapshot~ ------------------------------ */
+static t_class *snapshot_tilde_class;
+struct t_snapshot : t_object {
+ t_sample value;
+ float a;
+};
+static void *snapshot_tilde_new() {
+ t_snapshot *x = (t_snapshot *)pd_new(snapshot_tilde_class);
+ x->value = 0;
+ outlet_new(x, &s_float);
+ x->a = 0;
+ return x;
+}
+static t_int *snapshot_tilde_perform(t_int *w) {
+ t_float *in = (t_float *)w[1];
+ t_float *out = (t_float *)w[2];
+ *out = *in;
+ return w+3;
+}
+static void snapshot_tilde_dsp(t_snapshot *x, t_signal **sp) {
+ dsp_add(snapshot_tilde_perform, 2, sp[0]->v + (sp[0]->n-1), &x->value);
+}
+static void snapshot_tilde_bang(t_snapshot *x) {
+ outlet_float(x->outlet, x->value);
+}
+static void snapshot_tilde_set(t_snapshot *x, t_floatarg f) {
+ x->value = f;
+}
+static void snapshot_tilde_setup() {
+ snapshot_tilde_class = class_new2("snapshot~",snapshot_tilde_new,0,sizeof(t_snapshot),0,"");
+ CLASS_MAINSIGNALIN(snapshot_tilde_class, t_snapshot, a);
+ class_addmethod2(snapshot_tilde_class, snapshot_tilde_dsp, "dsp","");
+ class_addmethod2(snapshot_tilde_class, snapshot_tilde_set, "set","s");
+ class_addbang(snapshot_tilde_class, snapshot_tilde_bang);
+}
+
+/* -------------------------- vsnapshot~ ------------------------------ */
+static t_class *vsnapshot_tilde_class;
+struct t_vsnapshot : t_object {
+ int n;
+ int gotone;
+ t_sample *vec;
+ float a;
+ float sampspermsec;
+ double time;
+};
+static void *vsnapshot_tilde_new() {
+ t_vsnapshot *x = (t_vsnapshot *)pd_new(vsnapshot_tilde_class);
+ outlet_new(x, &s_float);
+ x->a = 0;
+ x->n = 0;
+ x->vec = 0;
+ x->gotone = 0;
+ return x;
+}
+static t_int *vsnapshot_tilde_perform(t_int *w) {
+ t_float *in = (t_float *)w[1];
+ t_vsnapshot *x = (t_vsnapshot *)w[2];
+ t_float *out = x->vec;
+ int n = x->n, i;
+ for (i = 0; i < n; i++) out[i] = in[i];
+ x->time = clock_getlogicaltime();
+ x->gotone = 1;
+ return w+3;
+}
+static void vsnapshot_tilde_dsp(t_vsnapshot *x, t_signal **sp) {
+ int n = sp[0]->n;
+ if (n != x->n) {
+ if (x->vec) free(x->vec);
+ x->vec = (t_sample *)getbytes(n * sizeof(t_sample));
+ x->gotone = 0;
+ x->n = n;
+ }
+ x->sampspermsec = sp[0]->sr / 1000;
+ dsp_add(vsnapshot_tilde_perform, 2, sp[0]->v, x);
+}
+static void vsnapshot_tilde_bang(t_vsnapshot *x) {
+ float val;
+ if (x->gotone) {
+ int indx = clip((int)(clock_gettimesince(x->time) * x->sampspermsec),0,x->n-1);
+ val = x->vec[indx];
+ } else val = 0;
+ outlet_float(x->outlet, val);
+}
+static void vsnapshot_tilde_ff(t_vsnapshot *x) {
+ if (x->vec) free(x->vec);
+}
+static void vsnapshot_tilde_setup() {
+ vsnapshot_tilde_class =
+ class_new2("vsnapshot~",vsnapshot_tilde_new, vsnapshot_tilde_ff,sizeof(t_vsnapshot), 0,"");
+ CLASS_MAINSIGNALIN(vsnapshot_tilde_class, t_vsnapshot, a);
+ class_addmethod2(vsnapshot_tilde_class, vsnapshot_tilde_dsp, "dsp","");
+ class_addbang(vsnapshot_tilde_class, vsnapshot_tilde_bang);
+}
+
+/* ---------------- env~ - simple envelope follower. ----------------- */
+#define MAXOVERLAP 10
+#define MAXVSTAKEN 64
+struct t_sigenv : t_object {
+ t_clock *clock; /* a "clock" object */
+ float *buf; /* a Hanning window */
+ int phase; /* number of points since last output */
+ int period; /* requested period of output */
+ int realperiod; /* period rounded up to vecsize multiple */
+ int npoints; /* analysis window size in samples */
+ float result; /* result to output */
+ float sumbuf[MAXOVERLAP]; /* summing buffer */
+ float a;
+};
+t_class *env_tilde_class;
+static void env_tilde_tick(t_sigenv *x);
+static void *env_tilde_new(t_floatarg fnpoints, t_floatarg fperiod) {
+ int npoints = (int)fnpoints;
+ int period = (int)fperiod;
+ float *buf;
+ if (npoints < 1) npoints = 1024;
+ if (period < 1) period = npoints/2;
+ if (period < npoints / MAXOVERLAP + 1)
+ period = npoints / MAXOVERLAP + 1;
+ if (!(buf = (float *)getalignedbytes(sizeof(float) * (npoints + MAXVSTAKEN)))) {
+ error("env: couldn't allocate buffer");
+ return 0;
+ }
+ t_sigenv *x = (t_sigenv *)pd_new(env_tilde_class);
+ x->buf = buf;
+ x->npoints = npoints;
+ x->phase = 0;
+ x->period = period;
+ int i;
+ for (i = 0; i < MAXOVERLAP; i++) x->sumbuf[i] = 0;
+ for (i = 0; i < npoints; i++) buf[i] = (1. - cos((2 * 3.14159 * i) / npoints))/npoints;
+ for (; i < npoints+MAXVSTAKEN; i++) buf[i] = 0;
+ x->clock = clock_new(x, env_tilde_tick);
+ x->outlet = outlet_new(x, &s_float);
+ x->a = 0;
+ return x;
+}
+static t_int *env_tilde_perform(t_int *w) {
+ t_sigenv *x = (t_sigenv *)w[1];
+ t_float *in = (t_float *)w[2];
+ int n = (int)w[3];
+ float *sump = x->sumbuf;
+ in += n;
+ for (int count = x->phase; count < x->npoints; count += x->realperiod, sump++) {
+ float *hp = x->buf + count;
+ float *fp = in;
+ float sum = *sump;
+ for (int i = 0; i < n; i++) {
+ fp--;
+ sum += *hp++ * (*fp * *fp);
+ }
+ *sump = sum;
+ }
+ sump[0] = 0;
+ x->phase -= n;
+ if (x->phase < 0) {
+ x->result = x->sumbuf[0];
+ sump = x->sumbuf;
+ for (int count = x->realperiod; count < x->npoints; count += x->realperiod, sump++) sump[0] = sump[1];
+ sump[0] = 0;
+ x->phase = x->realperiod - n;
+ clock_delay(x->clock, 0L);
+ }
+ return w+4;
+}
+/* tb: loop unrolling and simd */
+static float env_tilde_accum_8(t_float* in, t_float* hp, t_int n) {
+ float ret = 0;
+ n>>=3;
+ for (int i = 0; i !=n; ++i) {
+ in--; ret += *hp++ * (*in * *in);
+ in--; ret += *hp++ * (*in * *in);
+ in--; ret += *hp++ * (*in * *in);
+ in--; ret += *hp++ * (*in * *in);
+ in--; ret += *hp++ * (*in * *in);
+ in--; ret += *hp++ * (*in * *in);
+ in--; ret += *hp++ * (*in * *in);
+ in--; ret += *hp++ * (*in * *in);
+ }
+ return ret;
+}
+static t_int *env_tilde_perf8(t_int *w) {
+ t_sigenv *x = (t_sigenv *)w[1];
+ t_float *in = (t_float *)w[2];
+ int n = (int)w[3];
+ float *sump = x->sumbuf;
+ in += n;
+ for (int count = x->phase; count < x->npoints; count += x->realperiod, sump++) {
+ *sump += env_tilde_accum_8(in, x->buf + count, n);
+ }
+ sump[0] = 0;
+ x->phase -= n;
+ if (x->phase < 0) {
+ x->result = x->sumbuf[0];
+ float *sump = x->sumbuf;
+ for (int count = x->realperiod; count < x->npoints; count += x->realperiod, sump++)
+ sump[0] = sump[1];
+ sump[0] = 0;
+ x->phase = x->realperiod - n;
+ clock_delay(x->clock, 0L);
+ }
+ return w+4;
+}
+static t_int *env_tilde_perf_simd(t_int *w) {
+ t_sigenv *x = (t_sigenv *)w[1];
+ t_float *in = (t_float *)w[2];
+ int n = (int)w[3];
+ float *sump = x->sumbuf;
+ in += n;
+ for (int count = x->phase; count < x->npoints; count += x->realperiod, sump++) {
+ *sump += env_tilde_accum_simd(in, x->buf + count, n);
+ }
+ sump[0] = 0;
+ x->phase -= n;
+ if (x->phase < 0) {
+ x->result = x->sumbuf[0];
+ float *sump = x->sumbuf;
+ for (int count = x->realperiod; count < x->npoints; count += x->realperiod, sump++) sump[0] = sump[1];
+ sump[0] = 0;
+ x->phase = x->realperiod - n;
+ clock_delay(x->clock, 0L);
+ }
+ return w+4;
+}
+static void env_tilde_dsp(t_sigenv *x, t_signal **sp) {
+ int mod = x->period % sp[0]->n;
+ if (mod) x->realperiod = x->period + sp[0]->n - mod; else x->realperiod = x->period;
+ if (sp[0]->n & 7)
+ dsp_add(env_tilde_perform, 3, x, sp[0]->v, sp[0]->n);
+ else if (SIMD_CHECK1(sp[0]->n, sp[0]->v))
+ dsp_add(env_tilde_perf_simd, 3, x, sp[0]->v, sp[0]->n);
+ else dsp_add(env_tilde_perf8, 3, x, sp[0]->v, sp[0]->n);
+ if (sp[0]->n > MAXVSTAKEN) bug("env_tilde_dsp");
+}
+static void env_tilde_tick(t_sigenv *x) {
+ outlet_float(x->outlet, powtodb(x->result));
+}
+static void env_tilde_ff(t_sigenv *x) {
+ clock_free(x->clock);
+ freealignedbytes(x->buf, (x->npoints + MAXVSTAKEN) * sizeof(float));
+}
+void env_tilde_setup() {
+ env_tilde_class = class_new2("env~",env_tilde_new,env_tilde_ff,sizeof(t_sigenv),0,"FF");
+ CLASS_MAINSIGNALIN(env_tilde_class, t_sigenv, a);
+ class_addmethod2(env_tilde_class, env_tilde_dsp, "dsp","");
+}
+
+/* --------------------- threshold~ ----------------------------- */
+static t_class *threshold_tilde_class;
+struct t_threshold_tilde : t_object {
+ t_clock *clock; /* wakeup for message output */
+ float a; /* scalar inlet */
+ int state; /* 1 = high, 0 = low */
+ float hithresh; /* value of high threshold */
+ float lothresh; /* value of low threshold */
+ float deadwait; /* msec remaining in dead period */
+ float msecpertick; /* msec per DSP tick */
+ float hideadtime; /* hi dead time in msec */
+ float lodeadtime; /* lo dead time in msec */
+};
+static void threshold_tilde_tick(t_threshold_tilde *x);
+/* "set" message to specify thresholds and dead times */
+static void threshold_tilde_set(t_threshold_tilde *x,
+ t_floatarg hithresh, t_floatarg hideadtime,
+ t_floatarg lothresh, t_floatarg lodeadtime) {
+ if (lothresh > hithresh) lothresh = hithresh;
+ x->hithresh = hithresh; x->hideadtime = hideadtime;
+ x->lothresh = lothresh; x->lodeadtime = lodeadtime;
+}
+static t_threshold_tilde *threshold_tilde_new(t_floatarg hithresh,
+ t_floatarg hideadtime, t_floatarg lothresh, t_floatarg lodeadtime) {
+ t_threshold_tilde *x = (t_threshold_tilde *)pd_new(threshold_tilde_class);
+ x->state = 0; /* low state */
+ x->deadwait = 0; /* no dead time */
+ x->clock = clock_new(x, threshold_tilde_tick);
+ outlet_new(x, &s_bang);
+ outlet_new(x, &s_bang);
+ inlet_new(x, x, &s_float, gensym("ft1"));
+ x->msecpertick = 0.;
+ x->a = 0;
+ threshold_tilde_set(x, hithresh, hideadtime, lothresh, lodeadtime);
+ return x;
+}
+/* number in inlet sets state -- note incompatible with JMAX which used
+ "int" message for this, impossible here because of auto signal conversion */
+static void threshold_tilde_ft1(t_threshold_tilde *x, t_floatarg f) {
+ x->state = (f != 0);
+ x->deadwait = 0;
+}
+static void threshold_tilde_tick(t_threshold_tilde *x) {
+ outlet_bang(x->out(x->state?0:1));
+}
+static t_int *threshold_tilde_perform(t_int *w) {
+ float *in1 = (float *)w[1];
+ t_threshold_tilde *x = (t_threshold_tilde *)w[2];
+ int n = (t_int)w[3];
+ if (x->deadwait > 0)
+ x->deadwait -= x->msecpertick;
+ else if (x->state) {
+ /* we're high; look for low sample */
+ for (; n--; in1++) {
+ if (*in1 < x->lothresh) {
+ clock_delay(x->clock, 0L);
+ x->state = 0;
+ x->deadwait = x->lodeadtime;
+ goto done;
+ }
+ }
+ } else {
+ /* we're low; look for high sample */
+ for (; n--; in1++) {
+ if (*in1 >= x->hithresh) {
+ clock_delay(x->clock, 0L);
+ x->state = 1;
+ x->deadwait = x->hideadtime;
+ goto done;
+ }
+ }
+ }
+done:
+ return w+4;
+}
+void threshold_tilde_dsp(t_threshold_tilde *x, t_signal **sp) {
+ x->msecpertick = 1000. * sp[0]->n / sp[0]->sr;
+ dsp_add(threshold_tilde_perform, 3, sp[0]->v, x, sp[0]->n);
+}
+static void threshold_tilde_ff(t_threshold_tilde *x) {clock_free(x->clock);}
+static void threshold_tilde_setup() {
+ t_class *c = threshold_tilde_class =
+ class_new2("threshold~",threshold_tilde_new,threshold_tilde_ff,sizeof(t_threshold_tilde), 0, "FFFF");
+ CLASS_MAINSIGNALIN(c, t_threshold_tilde, a);
+ class_addmethod2(c, threshold_tilde_set, "set","ffff");
+ class_addmethod2(c, threshold_tilde_ft1, "ft1","f");
+ class_addmethod2(c, threshold_tilde_dsp, "dsp","");
+}
+
+/* ----------------------------- dac~ --------------------------- */
+static t_class *dac_class;
+struct t_dac : t_object {
+ t_int n;
+ t_int *vec;
+ float a;
+};
+static void *dac_new(t_symbol *s, int argc, t_atom *argv) {
+ t_dac *x = (t_dac *)pd_new(dac_class);
+ t_atom defarg[2];
+ if (!argc) {
+ argv = defarg;
+ argc = 2;
+ SETFLOAT(&defarg[0], 1);
+ SETFLOAT(&defarg[1], 2);
+ }
+ x->n = argc;
+ x->vec = (t_int *)getbytes(argc * sizeof(*x->vec));
+ for (int i = 0; i < argc; i++) x->vec[i] = atom_getintarg(i, argc, argv);
+ for (int i = 1; i < argc; i++) inlet_new(x, x, &s_signal, &s_signal);
+ x->a = 0;
+ return x;
+}
+static void dac_dsp(t_dac *x, t_signal **sp) {
+ t_int i, *ip;
+ t_signal **sp2;
+ for (i = x->n, ip = x->vec, sp2 = sp; i--; ip++, sp2++) {
+ int ch = *ip - 1;
+ if ((*sp2)->n != sys_dacblocksize) error("dac~: bad vector size");
+ else if (ch >= 0 && ch < sys_get_outchannels())
+ if(SIMD_CHECK3(sys_dacblocksize,sys_soundout + sys_dacblocksize*ch, (*sp2)->v,sys_soundout + sys_dacblocksize*ch))
+ dsp_add(plus_perf_simd, 4, sys_soundout + sys_dacblocksize*ch,
+ (*sp2)->v, sys_soundout + sys_dacblocksize*ch, sys_dacblocksize);
+ else
+ dsp_add(plus_perform, 4, sys_soundout + sys_dacblocksize*ch, (*sp2)->v, sys_soundout + sys_dacblocksize*ch,
+ sys_dacblocksize);
+ }
+}
+static void dac_free(t_dac *x) {free(x->vec);}
+static void dac_setup() {
+ dac_class = class_new2("dac~",dac_new,dac_free,sizeof(t_dac),0,"*");
+ CLASS_MAINSIGNALIN(dac_class, t_dac, a);
+ class_addmethod2(dac_class, dac_dsp, "dsp","!");
+ class_sethelpsymbol(dac_class, gensym("adc~_dac~"));
+}
+
+/* ----------------------------- adc~ --------------------------- */
+static t_class *adc_class;
+struct t_adc : t_object {
+ t_int n;
+ t_int *vec;
+};
+static void *adc_new(t_symbol *s, int argc, t_atom *argv) {
+ t_adc *x = (t_adc *)pd_new(adc_class);
+ t_atom defarg[2];
+ if (!argc) {
+ argv = defarg;
+ argc = 2;
+ SETFLOAT(&defarg[0], 1);
+ SETFLOAT(&defarg[1], 2);
+ }
+ x->n = argc;
+ x->vec = (t_int *)getbytes(argc * sizeof(*x->vec));
+ for (int i = 0; i < argc; i++) x->vec[i] = atom_getintarg(i, argc, argv);
+ for (int i = 0; i < argc; i++) outlet_new(x, &s_signal);
+ return x;
+}
+t_int *copy_perform(t_int *w) {
+ t_float *in1 = (t_float *)w[1];
+ t_float *out = (t_float *)w[2];
+ int n = (int)w[3];
+ while (n--) *out++ = *in1++;
+ return w+4;
+}
+t_int *copy_perf8(t_int *w) {
+ t_float *in1 = (t_float *)w[1];
+ t_float *out = (t_float *)w[2];
+ int n = (int)w[3];
+ for (; n; n -= 8, in1 += 8, out += 8) {
+ out[0] = in1[0];
+ out[1] = in1[1];
+ out[2] = in1[2];
+ out[3] = in1[3];
+ out[4] = in1[4];
+ out[5] = in1[5];
+ out[6] = in1[6];
+ out[7] = in1[7];
+ }
+ return w+4;
+}
+void dsp_add_copy(t_sample *in, t_sample *out, int n) {
+ if (n&7)
+ dsp_add(copy_perform, 3, in, out, n);
+ else if (SIMD_CHECK2(n,in,out))
+ dsp_add(copy_perf_simd, 3, in, out, n);
+ else dsp_add(copy_perf8, 3, in, out, n);
+}
+static void adc_dsp(t_adc *x, t_signal **sp) {
+ t_int i, *ip;
+ t_signal **sp2;
+ for (i = x->n, ip = x->vec, sp2 = sp; i--; ip++, sp2++) {
+ int ch = *ip - 1;
+ if ((*sp2)->n != sys_dacblocksize)
+ error("adc~: bad vector size");
+ else if (ch >= 0 && ch < sys_get_inchannels())
+ dsp_add_copy(sys_soundin + sys_dacblocksize*ch, (*sp2)->v, sys_dacblocksize);
+ else dsp_add_zero((*sp2)->v, sys_dacblocksize);
+ }
+}
+static void adc_free(t_adc *x) {free(x->vec);}
+static void adc_setup() {
+ adc_class = class_new2("adc~",adc_new,adc_free,sizeof(t_adc),0,"*");
+ class_addmethod2(adc_class, adc_dsp, "dsp","!");
+ class_sethelpsymbol(adc_class, gensym("adc~_dac~"));
+}
+
+/* ----------------------------- delwrite~ ----------------------------- */
+static t_class *sigdelwrite_class;
+struct t_delwritectl {
+ int c_n;
+ float *c_vec;
+ int c_phase;
+};
+struct t_sigdelwrite : t_object {
+ t_symbol *sym;
+ t_delwritectl cspace;
+ int sortno; /* DSP sort number at which this was last put on chain */
+ int rsortno; /* DSP sort # for first delread or write in chain */
+ int vecsize; /* vector size for delread~ to use */
+ float a;
+};
+#define XTRASAMPS 4
+#define SAMPBLK 4
+/* routine to check that all delwrites/delreads/vds have same vecsize */
+static void sigdelwrite_checkvecsize(t_sigdelwrite *x, int vecsize) {
+ if (x->rsortno != ugen_getsortno()) {
+ x->vecsize = vecsize;
+ x->rsortno = ugen_getsortno();
+ }
+ /* LATER this should really check sample rate and blocking, once that is
+ supported. Probably we don't actually care about vecsize.
+ For now just suppress this check. */
+#if 0
+ else if (vecsize != x->vecsize)
+ error("delread/delwrite/vd vector size mismatch");
+#endif
+}
+static void *sigdelwrite_new(t_symbol *s, t_floatarg msec) {
+ t_sigdelwrite *x = (t_sigdelwrite *)pd_new(sigdelwrite_class);
+ if (!*s->name) s = gensym("delwrite~");
+ pd_bind(x, s);
+ x->sym = s;
+ int nsamps = (int)(msec * sys_getsr() * (float)(0.001f));
+ if (nsamps < 1) nsamps = 1;
+ nsamps += ((- nsamps) & (SAMPBLK - 1));
+ nsamps += DEFDELVS;
+#ifdef SIMD_BYTEALIGN
+ nsamps += (SIMD_BYTEALIGN - nsamps) % SIMD_BYTEALIGN; /* tb: for simd */
+#endif
+ x->cspace.c_n = nsamps;
+ x->cspace.c_vec = (float *)getalignedbytes((nsamps + XTRASAMPS) * sizeof(float));
+ x->cspace.c_phase = XTRASAMPS;
+ x->sortno = 0;
+ x->vecsize = 0;
+ x->a = 0;
+ return x;
+}
+static t_int *sigdelwrite_perform(t_int *w) {
+ t_float *in = (t_float *)w[1];
+ t_delwritectl *c = (t_delwritectl *)w[2];
+ int n = (int)w[3];
+ int phase = c->c_phase, nsamps = c->c_n;
+ float *vp = c->c_vec, *bp = vp + phase, *ep = vp + (c->c_n + XTRASAMPS);
+ phase += n;
+ while (n--) {
+ float f = *in++;
+ if (PD_BIGORSMALL(f))
+ f = 0;
+ *bp++ = f;
+ if (bp == ep) {
+ vp[0] = ep[-4];
+ vp[1] = ep[-3];
+ vp[2] = ep[-2];
+ vp[3] = ep[-1];
+ bp = vp + XTRASAMPS;
+ phase -= nsamps;
+ }
+ }
+ c->c_phase = phase;
+ return w+4;
+}
+static t_int *sigdelwrite_perf8(t_int *w) {
+ t_float *in = (t_float *)w[1];
+ t_delwritectl *c = (t_delwritectl *)w[2];
+ int n = (int)w[3];
+ int phase = c->c_phase, nsamps = c->c_n;
+ float *vp = c->c_vec, *bp = vp + phase, *ep = vp + (c->c_n + XTRASAMPS);
+ phase += n;
+ if (phase > nsamps)
+ while (n--) {
+ float f = *in++;
+ if (PD_BIGORSMALL(f)) f = 0;
+ *bp++ = f;
+ if (bp == ep) {
+ vp[0] = ep[-4];
+ vp[1] = ep[-3];
+ vp[2] = ep[-2];
+ vp[3] = ep[-1];
+ bp = vp + XTRASAMPS;
+ phase -= nsamps;
+ }
+ }
+ else testcopyvec_8(bp, in, n);
+ c->c_phase = phase;
+ return w+4;
+}
+static t_int *sigdelwrite_perfsimd(t_int *w) {
+ t_float *in = (t_float *)w[1];
+ t_delwritectl *c = (t_delwritectl *)w[2];
+ int n = (int)w[3];
+ int phase = c->c_phase, nsamps = c->c_n;
+ float *vp = c->c_vec, *bp = vp + phase, *ep = vp + (c->c_n + XTRASAMPS);
+ phase += n;
+ if (phase > nsamps )
+ while (n--) {
+ float f = *in++;
+ if (PD_BIGORSMALL(f)) f = 0;
+ *bp++ = f;
+ if (bp == ep) {
+ vp[0] = ep[-4];
+ vp[1] = ep[-3];
+ vp[2] = ep[-2];
+ vp[3] = ep[-1];
+ bp = vp + XTRASAMPS;
+ phase -= nsamps;
+ }
+ }
+ else testcopyvec_simd(bp, in, n);
+ c->c_phase = phase;
+ return w+4;
+}
+static void sigdelwrite_dsp(t_sigdelwrite *x, t_signal **sp) {
+ if (sp[0]->n & 7)
+ dsp_add(sigdelwrite_perform, 3, sp[0]->v, &x->cspace, sp[0]->n);
+ else if (SIMD_CHECK1(sp[0]->n, sp[0]->v))
+ dsp_add(sigdelwrite_perfsimd, 3, sp[0]->v, &x->cspace, sp[0]->n);
+ else dsp_add(sigdelwrite_perf8, 3, sp[0]->v, &x->cspace, sp[0]->n);
+ x->sortno = ugen_getsortno();
+ sigdelwrite_checkvecsize(x, sp[0]->n);
+}
+static void sigdelwrite_free(t_sigdelwrite *x) {
+ pd_unbind(x, x->sym);
+ freealignedbytes(x->cspace.c_vec, (x->cspace.c_n + XTRASAMPS) * sizeof(float));
+}
+static void sigdelwrite_setup() {
+ sigdelwrite_class = class_new2("delwrite~",sigdelwrite_new,sigdelwrite_free,sizeof(t_sigdelwrite),0,"SF");
+ CLASS_MAINSIGNALIN(sigdelwrite_class, t_sigdelwrite, a);
+ class_addmethod2(sigdelwrite_class, sigdelwrite_dsp,"dsp","");
+}
+
+/* ----------------------------- delread~ ----------------------------- */
+static t_class *sigdelread_class;
+struct t_sigdelread : t_object {
+ t_symbol *sym;
+ t_float deltime; /* delay in msec */
+ int delsamps; /* delay in samples */
+ t_float sr; /* samples per msec */
+ t_float n; /* vector size */
+ int zerodel; /* 0 or vecsize depending on read/write order */
+ void (*copy_fp)(t_float*, const t_float*, int); /* tb: copy function */
+};
+static void sigdelread_float(t_sigdelread *x, t_float f);
+static void *sigdelread_new(t_symbol *s, t_floatarg f) {
+ t_sigdelread *x = (t_sigdelread *)pd_new(sigdelread_class);
+ x->sym = s;
+ x->sr = 1;
+ x->n = 1;
+ x->zerodel = 0;
+ sigdelread_float(x, f);
+ outlet_new(x, &s_signal);
+ return x;
+}
+static void sigdelread_float(t_sigdelread *x, t_float f) {
+ t_sigdelwrite *delwriter = (t_sigdelwrite *)pd_findbyclass(x->sym, sigdelwrite_class);
+ x->deltime = f;
+ if (delwriter) {
+ x->delsamps = (int)(0.5 + x->sr * x->deltime + x->n - x->zerodel);
+ if (x->delsamps < x->n) x->delsamps = (int)x->n;
+ else if (x->delsamps > delwriter->cspace.c_n - DEFDELVS)
+ x->delsamps = (int)(delwriter->cspace.c_n - DEFDELVS);
+ }
+ if (SIMD_CHKCNT(x->delsamps)) x->copy_fp = copyvec_simd;
+ else x->copy_fp = copyvec_simd_unalignedsrc;
+}
+static t_int *sigdelread_perform(t_int *w) {
+ t_float *out = (t_float *)w[1];
+ t_delwritectl *c = (t_delwritectl *)w[2];
+ int delsamps = *(int *)w[3];
+ int n = (int)w[4];
+ int phase = c->c_phase - delsamps, nsamps = c->c_n;
+ float *vp = c->c_vec, *bp, *ep = vp + (c->c_n + XTRASAMPS);
+ if (phase < 0) phase += nsamps;
+ bp = vp + phase;
+ while (n--) {
+ *out++ = *bp++;
+ if (bp == ep) bp -= nsamps;
+ }
+ return w+5;
+}
+static t_int *sigdelread_perf8(t_int *w) {
+ t_float *out = (t_float *)w[1];
+ t_delwritectl *c = (t_delwritectl *)w[2];
+ int delsamps = *(int *)w[3];
+ int n = (int)w[4];
+ int phase = c->c_phase - delsamps, nsamps = c->c_n;
+ float *vp = c->c_vec, *bp, *ep = vp + (c->c_n + XTRASAMPS);
+ if (phase < 0) phase += nsamps;
+ bp = vp + phase;
+ if (phase + n > nsamps)
+ while (n--) {
+ *out++ = *bp++;
+ if (bp == ep) bp -= nsamps;
+ }
+ else copyvec_8(out, bp, n);
+ return w+5;
+}
+static t_int *sigdelread_perfsimd(t_int *w) {
+ t_float *out = (t_float *)w[1];
+ t_delwritectl *c = (t_delwritectl *)w[2];
+ int delsamps = *(int *)w[3];
+ int n = (int)w[4];
+ t_sigdelread *x = (t_sigdelread *)w[5];
+ int phase = c->c_phase - delsamps, nsamps = c->c_n;
+ float *vp = c->c_vec, *bp, *ep = vp + (c->c_n + XTRASAMPS);
+ if (phase < 0) phase += nsamps;
+ bp = vp + phase;
+ if (phase + n > nsamps)
+ while (n--) {
+ *out++ = *bp++;
+ if (bp == ep) bp -= nsamps;
+ }
+ else x->copy_fp(out, bp, n);
+ return w+6;
+}
+static void sigdelread_dsp(t_sigdelread *x, t_signal **sp) {
+ t_sigdelwrite *delwriter =
+ (t_sigdelwrite *)pd_findbyclass(x->sym, sigdelwrite_class);
+ x->sr = sp[0]->sr * 0.001;
+ x->n = sp[0]->n;
+ if (delwriter) {
+ sigdelwrite_checkvecsize(delwriter, sp[0]->n);
+ x->zerodel = (delwriter->sortno == ugen_getsortno() ?
+ 0 : delwriter->vecsize);
+ sigdelread_float(x, x->deltime);
+ if (sp[0]->n & 7)
+ dsp_add(sigdelread_perform, 4, sp[0]->v, &delwriter->cspace, &x->delsamps, sp[0]->n);
+ else if (SIMD_CHECK1(sp[0]->n, sp[0]->v))
+ dsp_add(sigdelread_perfsimd, 5, sp[0]->v, &delwriter->cspace, &x->delsamps, sp[0]->n, x);
+ else dsp_add(sigdelread_perf8, 4, sp[0]->v, &delwriter->cspace, &x->delsamps, sp[0]->n);
+ } else if (*x->sym->name) error("delread~: %s: no such delwrite~",x->sym->name);
+}
+static void sigdelread_setup() {
+ sigdelread_class = class_new2("delread~",sigdelread_new,0,sizeof(t_sigdelread),0,"SF");
+ class_addmethod2(sigdelread_class, sigdelread_dsp,"dsp","");
+ class_addfloat(sigdelread_class, sigdelread_float);
+}
+
+/* ----------------------------- vd~ ----------------------------- */
+static t_class *sigvd_class;
+struct t_sigvd : t_object {
+ t_symbol *sym;
+ t_float sr; /* samples per msec */
+ int zerodel; /* 0 or vecsize depending on read/write order */
+ float a;
+};
+static void *sigvd_new(t_symbol *s) {
+ t_sigvd *x = (t_sigvd *)pd_new(sigvd_class);
+ if (!*s->name) s = gensym("vd~");
+ x->sym = s;
+ x->sr = 1;
+ x->zerodel = 0;
+ outlet_new(x, &s_signal);
+ x->a = 0;
+ return x;
+}
+static t_int *sigvd_perform(t_int *w) {
+ t_float *in = (t_float *)w[1];
+ t_float *out = (t_float *)w[2];
+ t_delwritectl *ctl = (t_delwritectl *)w[3];
+ t_sigvd *x = (t_sigvd *)w[4];
+ int n = (int)w[5];
+
+ int nsamps = ctl->c_n;
+ float limit = nsamps - n - 1;
+ float fn = n-1;
+ float *vp = ctl->c_vec, *bp, *wp = vp + ctl->c_phase;
+ float zerodel = x->zerodel;
+ while (n--) {
+ float delsamps = x->sr * *in++ - zerodel, frac;
+ int idelsamps;
+ float a, b, c, d, cminusb;
+ if (delsamps < 1.00001f) delsamps = 1.00001f;
+ if (delsamps > limit) delsamps = limit;
+ delsamps += fn;
+ fn = fn - 1.0f;
+ idelsamps = (int)delsamps;
+ frac = delsamps - (float)idelsamps;
+ bp = wp - idelsamps;
+ if (bp < vp + 4) bp += nsamps;
+ d = bp[-3];
+ c = bp[-2];
+ b = bp[-1];
+ a = bp[0];
+ cminusb = c-b;
+ *out++ = b + frac * (
+ cminusb - 0.1666667f * (1.-frac) * (
+ (d - a - 3.0f * cminusb) * frac + (d + 2.0f*a - 3.0f*b)
+ )
+ );
+ }
+ return w+6;
+}
+static void sigvd_dsp(t_sigvd *x, t_signal **sp) {
+ t_sigdelwrite *delwriter = (t_sigdelwrite *)pd_findbyclass(x->sym, sigdelwrite_class);
+ x->sr = sp[0]->sr * 0.001;
+ if (delwriter) {
+ sigdelwrite_checkvecsize(delwriter, sp[0]->n);
+ x->zerodel = (delwriter->sortno == ugen_getsortno() ? 0 : delwriter->vecsize);
+ dsp_add(sigvd_perform, 5, sp[0]->v, sp[1]->v, &delwriter->cspace, x, sp[0]->n);
+ } else error("vd~: %s: no such delwrite~",x->sym->name);
+}
+static void sigvd_setup() {
+ sigvd_class = class_new2("vd~",sigvd_new,0,sizeof(t_sigvd),0,"S");
+ class_addmethod2(sigvd_class, sigvd_dsp, "dsp","");
+ CLASS_MAINSIGNALIN(sigvd_class, t_sigvd, a);
+}
+
+#ifndef HAVE_LIBFFTW3F
+/* ------------------------ fft~ and ifft~ -------------------------------- */
+/* ----------------------- rfft~ -------------------------------- */
+/* ----------------------- rifft~ -------------------------------- */
+static t_class *sigfft_class; struct t_sigfft : t_object {float a;};
+static t_class *sigifft_class; struct t_sigifft : t_object {float a;};
+static t_class *sigrfft_class; struct t_sigrfft : t_object {float a;};
+static t_class *sigrifft_class; struct t_sigrifft : t_object {float a;};
+
+static void *sigfft_new() {
+ t_sigfft *x = (t_sigfft *)pd_new(sigfft_class);
+ outlet_new(x, &s_signal);
+ outlet_new(x, &s_signal);
+ inlet_new(x, x, &s_signal, &s_signal); x->a=0; return x;}
+static void *sigifft_new() {
+ t_sigifft *x = (t_sigifft *)pd_new(sigifft_class);
+ outlet_new(x, &s_signal);
+ outlet_new(x, &s_signal);
+ inlet_new(x, x, &s_signal, &s_signal); x->a=0; return x;}
+static void *sigrfft_new() {
+ t_sigrfft *x = (t_sigrfft *)pd_new(sigrfft_class);
+ outlet_new(x, &s_signal);
+ outlet_new(x, &s_signal);
+ x->a = 0; return x;}
+static void *sigrifft_new() {
+ t_sigrifft *x = (t_sigrifft *)pd_new(sigrifft_class);
+ inlet_new(x, x, &s_signal, &s_signal);
+ outlet_new(x, &s_signal);
+ x->a = 0; return x;}
+
+static t_int *sigfft_swap(t_int *w) {
+ float *in1 = (t_float *)w[1];
+ float *in2 = (t_float *)w[2];
+ int n = w[3];
+ for (;n--; in1++, in2++) {
+ float f = *in1;
+ *in1 = *in2;
+ *in2 = f;
+ }
+ return w+4;
+}
+static t_int * sigfft_perform(t_int *w) {float *in1=(t_float *)w[1], *in2=(t_float *)w[2]; int n=w[3]; mayer_fft(n,in1,in2); return w+4;}
+static t_int * sigifft_perform(t_int *w) {float *in1=(t_float *)w[1], *in2=(t_float *)w[2]; int n=w[3]; mayer_ifft(n,in1,in2); return w+4;}
+static t_int * sigrfft_perform(t_int *w) {float *in =(t_float *)w[1]; int n = w[2]; mayer_realfft(n, in); return w+3;}
+static t_int *sigrifft_perform(t_int *w) {float *in =(t_float *)w[1]; int n = w[2]; mayer_realifft(n, in); return w+3;}
+
+static void sigfft_dspx(t_sigfft *x, t_signal **sp, t_int *(*f)(t_int *w)) {
+ int n = sp[0]->n;
+ float *in1 = sp[0]->v;
+ float *in2 = sp[1]->v;
+ float *out1 = sp[2]->v;
+ float *out2 = sp[3]->v;
+ if (out1 == in2 && out2 == in1)
+ dsp_add(sigfft_swap, 3, out1, out2, n);
+ else if (out1 == in2) {
+ dsp_add(copy_perform, 3, in2, out2, n);
+ dsp_add(copy_perform, 3, in1, out1, n);
+ } else {
+ if (out1 != in1) dsp_add(copy_perform, 3, in1, out1, n);
+ if (out2 != in2) dsp_add(copy_perform, 3, in2, out2, n);
+ }
+ dsp_add(f, 3, sp[2]->v, sp[3]->v, n);
+}
+static void sigfft_dsp(t_sigfft *x, t_signal **sp) {sigfft_dspx(x, sp, sigfft_perform);}
+static void sigifft_dsp(t_sigfft *x, t_signal **sp) {sigfft_dspx(x, sp, sigifft_perform);}
+
+static t_int *sigrfft_flip(t_int *w) {
+ float *in = (t_float *)w[1];
+ float *out = (t_float *)w[2];
+ int n = w[3];
+ while (n--) *(--out) = *in++;
+ *(--out) = 0; /* to hell with it */
+ return w+4;
+}
+static void sigrfft_dsp(t_sigrfft *x, t_signal **sp) {
+ int n = sp[0]->n, n2 = (n>>1);
+ float *in1 = sp[0]->v;
+ float *out1 = sp[1]->v;
+ float *out2 = sp[2]->v;
+ if (n < 4) {
+ error("fft: minimum 4 points");
+ return;
+ }
+ /* this probably never happens */
+ if (in1 == out2) {
+ dsp_add(sigrfft_perform, 2, out2, n);
+ dsp_add(copy_perform, 3, out2, out1, n2);
+ dsp_add(sigrfft_flip, 3, out2 + (n2+1), out2 + n2, n2-1);
+ } else {
+ if (in1 != out1) dsp_add(copy_perform, 3, in1, out1, n);
+ dsp_add(sigrfft_perform, 2, out1, n);
+ dsp_add(sigrfft_flip, 3, out1 + (n2+1), out2 + n2, n2-1);
+ }
+ dsp_add_zero(out1 + n2, n2);
+ dsp_add_zero(out2 + n2, n2);
+}
+
+static void sigrifft_dsp(t_sigrifft *x, t_signal **sp) {
+ int n = sp[0]->n, n2 = (n>>1);
+ float *in1 = sp[0]->v;
+ float *in2 = sp[1]->v;
+ float *out1 = sp[2]->v;
+ if (n < 4) {error("fft: minimum 4 points"); return;}
+ if (in2 == out1) {
+ dsp_add(sigrfft_flip, 3, out1+1, out1 + n, (n2-1));
+ dsp_add(copy_perform, 3, in1, out1, n2);
+ } else {
+ if (in1 != out1) dsp_add(copy_perform, 3, in1, out1, n2);
+ dsp_add(sigrfft_flip, 3, in2+1, out1 + n, n2-1);
+ }
+ dsp_add(sigrifft_perform, 2, out1, n);
+}
+static void sigfft_setup() {
+ sigfft_class = class_new2("fft~", sigfft_new, 0,sizeof(t_sigfft), 0,"");
+ sigifft_class = class_new2("ifft~", sigifft_new, 0,sizeof(t_sigfft), 0,"");
+ sigrfft_class = class_new2("rfft~", sigrfft_new, 0,sizeof(t_sigrfft), 0,"");
+ sigrifft_class = class_new2("rifft~",sigrifft_new,0,sizeof(t_sigrifft),0,"");
+ CLASS_MAINSIGNALIN(sigfft_class, t_sigfft, a);
+ CLASS_MAINSIGNALIN(sigifft_class, t_sigfft, a);
+ CLASS_MAINSIGNALIN(sigrfft_class, t_sigrfft, a);
+ CLASS_MAINSIGNALIN(sigrifft_class,t_sigrifft,a);
+ class_addmethod2(sigfft_class, sigfft_dsp, "dsp","");
+ class_addmethod2(sigifft_class, sigifft_dsp, "dsp","");
+ class_addmethod2(sigrfft_class, sigrfft_dsp, "dsp","");
+ class_addmethod2(sigrifft_class,sigrifft_dsp,"dsp","");
+ class_sethelpsymbol(sigifft_class, gensym("fft~"));
+ class_sethelpsymbol(sigrfft_class, gensym("fft~"));
+ class_sethelpsymbol(sigrifft_class,gensym("fft~"));
+}
+
+#else
+/* Support for fftw3 by Tim Blechmann */
+/* ------------------------ fft~ and ifft~ -------------------------------- */
+/* ----------------------- rfft~ --------------------------------- */
+/* ----------------------- rifft~ -------------------------------- */
+
+static t_class *sigfftw_class; struct t_sigfftw : t_object {float a; fftwf_plan plan; fftwf_iodim dim;};
+static t_class *sigifftw_class; struct t_sigifftw : t_object {float a; fftwf_plan plan; fftwf_iodim dim;};
+static t_class *sigrfftw_class; struct t_sigrfftw : t_object {float a; fftwf_plan plan; fftwf_iodim dim;};
+static t_class *sigrifftw_class;struct t_sigrifftw : t_object {float a; fftwf_plan plan; fftwf_iodim dim;};
+
+static void *sigfftw_new() {
+ t_sigfftw *x = (t_sigfftw *)pd_new(sigfftw_class); outlet_new(x, &s_signal); outlet_new(x, &s_signal);
+ inlet_new(x, x, &s_signal, &s_signal); x->a=0; return x;}
+static void *sigifftw_new() {
+ t_sigifftw *x = (t_sigifftw *)pd_new(sigfftw_class); outlet_new(x, &s_signal); outlet_new(x, &s_signal);
+ inlet_new(x, x, &s_signal, &s_signal); x->a=0; return x;}
+static void *sigrfftw_new() {
+ t_sigrfftw *x = (t_sigrfftw *)pd_new(sigrfftw_class);
+ outlet_new(x, &s_signal); outlet_new(x, &s_signal); x->a=0; return x;}
+static void *sigrifftw_new() {
+ t_sigrifftw *x = (t_sigrifftw *)pd_new(sigrifftw_class);
+ inlet_new(x, x, &s_signal, &s_signal);
+ outlet_new(x, &s_signal); x->a=0; return x;}
+
+static void sigfftw_free( t_sigfftw *x) {fftwf_destroy_plan(x->plan);}
+static void sigifftw_free( t_sigifftw *x) {fftwf_destroy_plan(x->plan);}
+static void sigrfftw_free( t_sigrfftw *x) {fftwf_destroy_plan(x->plan);}
+static void sigrifftw_free(t_sigrifftw *x) {fftwf_destroy_plan(x->plan);}
+
+/* for compatibility reasons with the mayer fft, we'll have to invert some samples. this is ugly, but someone might rely on that. */
+static void sigrfftw_invert(t_sample * s, t_int n) {
+ while (n!=0) {--n; s[n]=-s[n];}
+}
+static t_int *sigfftw_perform(t_int *w) {
+ fftwf_execute(*(fftwf_plan *)w[1]);
+ return w+2;
+}
+static t_int *sigrfftw_perform(t_int *w) {
+ fftwf_execute(*(fftwf_plan*)w[1]);
+ sigrfftw_invert((t_sample*)w[2],(t_int)w[3]);
+ return w+4;
+}
+static t_int *sigrifftw_perform(t_int *w) {
+ sigrfftw_invert((t_sample *)w[2],w[3]);
+ fftwf_execute(*(fftwf_plan*)w[1]);
+ return w+4;
+}
+
+static void sigfftw_dsp(t_sigfftw *x, t_signal **sp) {
+ int n = sp[0]->n;
+ float *in1 = sp[0]->v;
+ float *in2 = sp[1]->v;
+ float *out1 = sp[2]->v;
+ float *out2 = sp[3]->v;
+ x->dim.n=n;
+ x->dim.is=1;
+ x->dim.os=1;
+ x->plan = fftwf_plan_guru_split_dft(1, &(x->dim), 0, NULL, in1, in2, out1, out2, FFTW_ESTIMATE);
+ dsp_add(sigfftw_perform, 1, &x->plan);
+}
+static void sigifftw_dsp(t_sigfftw *x, t_signal **sp) {
+ int n = sp[0]->n;
+ float *in1 = sp[0]->v;
+ float *in2 = sp[1]->v;
+ float *out1 = sp[2]->v;
+ float *out2 = sp[3]->v;
+ x->dim.n=n;
+ x->dim.is=1;
+ x->dim.os=1;
+ x->plan = fftwf_plan_guru_split_dft(1, &(x->dim), 0, NULL, in2, in1, out2, out1, FFTW_ESTIMATE);
+ dsp_add(sigfftw_perform, 1, &x->plan);
+}
+
+static void sigrfftw_dsp(t_sigrfftw *x, t_signal **sp) {
+ int n = sp[0]->n, n2 = (n>>1);
+ float *in = sp[0]->v;
+ float *out1 = sp[1]->v;
+ float *out2 = sp[2]->v;
+ if (n < 4) {error("fft: minimum 4 points"); return;}
+ x->dim.n=n;
+ x->dim.is=1;
+ x->dim.os=1;
+ x->plan = fftwf_plan_guru_split_dft_r2c(1, &(x->dim), 0, NULL, in, out1, out2, FFTW_ESTIMATE | FFTW_PRESERVE_INPUT);
+ dsp_add(sigrfftw_perform,3,&x->plan,out2+1,n2-1);
+ dsp_add_zero(out1 + n2, n2);
+ dsp_add_zero(out2 + n2, n2);
+}
+
+static void sigrifftw_dsp(t_sigrifftw *x, t_signal **sp) {
+ int n = sp[0]->n, n2 = (n>>1);
+ float *in1 = sp[0]->v;
+ float *in2 = sp[1]->v;
+ float *out = sp[2]->v;
+ if (n < 4) {error("fft: minimum 4 points"); return;}
+ x->dim.n=n;
+ x->dim.is=1;
+ x->dim.os=1;
+ x->plan = fftwf_plan_guru_split_dft_c2r(1, &(x->dim), 0, NULL, in1, in2, out, FFTW_ESTIMATE | FFTW_PRESERVE_INPUT);
+ dsp_add_zero(in1+ n/2, n/2);
+ dsp_add(sigrifftw_perform,3,&x->plan,in2,n2);
+}
+static void sigfftw_setup() {
+ sigfftw_class = class_new2( "fft~",sigfftw_new, sigfftw_free, sizeof(t_sigfftw), 0,"");
+ sigifftw_class = class_new2( "ifft~",sigifftw_new, sigifftw_free, sizeof(t_sigfftw), 0,"");
+ sigrfftw_class = class_new2( "rfft~",sigrfftw_new, sigrfftw_free, sizeof(t_sigrfftw), 0,"");
+ sigrifftw_class = class_new2("rifft~",sigrifftw_new,sigrifftw_free,sizeof(t_sigrifftw),0,"");
+ CLASS_MAINSIGNALIN(sigfftw_class, t_sigfftw, a);
+ CLASS_MAINSIGNALIN(sigifftw_class, t_sigfftw, a);
+ CLASS_MAINSIGNALIN(sigrfftw_class, t_sigrfftw, a);
+ CLASS_MAINSIGNALIN(sigrifftw_class,t_sigrifftw,a);
+ class_addmethod2(sigfftw_class, sigfftw_dsp, "dsp","");
+ class_addmethod2(sigifftw_class, sigifftw_dsp, "dsp","");
+ class_addmethod2(sigrfftw_class, sigrfftw_dsp, "dsp","");
+ class_addmethod2(sigrifftw_class, sigrifftw_dsp,"dsp","");
+ class_sethelpsymbol(sigifftw_class, gensym("fft~"));
+ class_sethelpsymbol(sigrfftw_class, gensym("fft~"));
+ class_sethelpsymbol(sigrifftw_class,gensym("fft~"));
+}
+#endif /* HAVE_LIBFFTW3F */
+/* end of FFTW support */
+
+/* ----------------------- framp~ -------------------------------- */
+static t_class *sigframp_class;
+struct t_sigframp : t_object {
+ float a;
+};
+static void *sigframp_new() {
+ t_sigframp *x = (t_sigframp *)pd_new(sigframp_class);
+ inlet_new(x, x, &s_signal, &s_signal);
+ outlet_new(x, &s_signal);
+ outlet_new(x, &s_signal);
+ x->a = 0;
+ return x;
+}
+static t_int *sigframp_perform(t_int *w) {
+ float *inreal = (t_float *)w[1];
+ float *inimag = (t_float *)w[2];
+ float *outfreq = (t_float *)w[3];
+ float *outamp = (t_float *)w[4];
+ float lastreal = 0, currentreal = inreal[0], nextreal = inreal[1];
+ float lastimag = 0, currentimag = inimag[0], nextimag = inimag[1];
+ int n = w[5];
+ int m = n + 1;
+ float fbin = 1, oneovern2 = 1.f/((float)n * (float)n);
+ inreal += 2;
+ inimag += 2;
+ *outamp++ = *outfreq++ = 0;
+ n -= 2;
+ while (n--) {
+ float re, im, pow, freq;
+ lastreal = currentreal;
+ currentreal = nextreal;
+ nextreal = *inreal++;
+ lastimag = currentimag;
+ currentimag = nextimag;
+ nextimag = *inimag++;
+ re = currentreal - 0.5f * (lastreal + nextreal);
+ im = currentimag - 0.5f * (lastimag + nextimag);
+ pow = re * re + im * im;
+ if (pow > 1e-19) {
+ float detune = ((lastreal - nextreal) * re +
+ (lastimag - nextimag) * im) / (2.0f * pow);
+ if (detune > 2 || detune < -2) freq = pow = 0;
+ else freq = fbin + detune;
+ }
+ else freq = pow = 0;
+ *outfreq++ = freq;
+ *outamp++ = oneovern2 * pow;
+ fbin += 1.0f;
+ }
+ while (m--) *outamp++ = *outfreq++ = 0;
+ return w+6;
+}
+t_int *sigsqrt_perform(t_int *w);
+static void sigframp_dsp(t_sigframp *x, t_signal **sp) {
+ int n = sp[0]->n, n2 = (n>>1);
+ if (n < 4) {
+ error("framp: minimum 4 points");
+ return;
+ }
+ dsp_add(sigframp_perform, 5, sp[0]->v, sp[1]->v,
+ sp[2]->v, sp[3]->v, n2);
+ dsp_add(sigsqrt_perform, 3, sp[3]->v, sp[3]->v, n2);
+}
+static void sigframp_setup() {
+ sigframp_class = class_new2("framp~",sigframp_new,0,sizeof(t_sigframp),0,"");
+ CLASS_MAINSIGNALIN(sigframp_class, t_sigframp, a);
+ class_addmethod2(sigframp_class, sigframp_dsp, "dsp","");
+}
+
+/* ---------------- hip~ - 1-pole 1-zero hipass filter. ----------------- */
+/* ---------------- lop~ - 1-pole lopass filter. ----------------- */
+t_class *sighip_class; struct t_hipctl {float x; float coef;};
+t_class *siglop_class; struct t_lopctl {float x; float coef;};
+struct t_sighip : t_object {float sr; float hz; t_hipctl cspace; t_hipctl *ctl; float a;};
+struct t_siglop : t_object {float sr; float hz; t_lopctl cspace; t_lopctl *ctl; float a;};
+
+static void sighip_ft1(t_sighip *x, t_floatarg f) {x->hz = max(f,0.f); x->ctl->coef = clip(1-f*(2*3.14159)/x->sr,0.,1.);}
+static void siglop_ft1(t_siglop *x, t_floatarg f) {x->hz = max(f,0.f); x->ctl->coef = clip( f*(2*3.14159)/x->sr,0.,1.);}
+
+static void *sighip_new(t_floatarg f) {
+ t_sighip *x = (t_sighip *)pd_new(sighip_class);
+ inlet_new(x, x, &s_float, gensym("ft1")); outlet_new(x, &s_signal);
+ x->sr = 44100; x->ctl = &x->cspace; x->cspace.x = 0; sighip_ft1(x, f); x->a = 0; return x;}
+static void *siglop_new(t_floatarg f) {
+ t_siglop *x = (t_siglop *)pd_new(siglop_class);
+ inlet_new(x, x, &s_float, gensym("ft1")); outlet_new(x, &s_signal);
+ x->sr = 44100; x->ctl = &x->cspace; x->cspace.x = 0; siglop_ft1(x, f); x->a = 0; return x;}
+
+static void sighip_clear(t_sighip *x, t_floatarg q) {x->cspace.x = 0;}
+static void siglop_clear(t_siglop *x, t_floatarg q) {x->cspace.x = 0;}
+
+static t_int *sighip_perform(t_int *w) {
+ float *in = (float *)w[1];
+ float *out = (float *)w[2];
+ t_hipctl *c = (t_hipctl *)w[3];
+ int n = (t_int)w[4];
+ float last = c->x;
+ float coef = c->coef;
+ if (coef < 1) {
+ for (int i = 0; i < n; i++) {
+ float noo = *in++ + coef * last;
+ *out++ = noo - last;
+ last = noo;
+ }
+ if (PD_BIGORSMALL(last)) last = 0;
+ c->x = last;
+ } else {
+ for (int i = 0; i < n; i++) *out++ = *in++;
+ c->x = 0;
+ }
+ return w+5;
+}
+static t_int *siglop_perform(t_int *w) {
+ float *in = (float *)w[1];
+ float *out = (float *)w[2];
+ t_lopctl *c = (t_lopctl *)w[3];
+ int n = (t_int)w[4];
+ float last = c->x;
+ float coef = c->coef;
+ float feedback = 1 - coef;
+ for (int i = 0; i < n; i++) last = *out++ = coef * *in++ + feedback * last;
+ if (PD_BIGORSMALL(last)) last = 0;
+ c->x = last;
+ return w+5;
+}
+static void sighip_dsp(t_sighip *x, t_signal **sp) {
+ x->sr = sp[0]->sr; sighip_ft1(x, x->hz);
+ dsp_add(sighip_perform, 4, sp[0]->v, sp[1]->v, x->ctl, sp[0]->n);}
+static void siglop_dsp(t_siglop *x, t_signal **sp) {
+ x->sr = sp[0]->sr; siglop_ft1(x, x->hz);
+ dsp_add(siglop_perform, 4, sp[0]->v, sp[1]->v, x->ctl, sp[0]->n);}
+
+void sighip_setup() {
+ sighip_class = class_new2("hip~",sighip_new,0,sizeof(t_sighip),0,"F");
+ CLASS_MAINSIGNALIN(sighip_class, t_sighip, a);
+ class_addmethod2(sighip_class, sighip_dsp, "dsp","");
+ class_addmethod2(sighip_class, sighip_ft1, "ft1","f");
+ class_addmethod2(sighip_class, sighip_clear,"clear","");
+}
+void siglop_setup() {
+ siglop_class = class_new2("lop~",siglop_new,0,sizeof(t_siglop),0,"F");
+ CLASS_MAINSIGNALIN(siglop_class, t_siglop, a);
+ class_addmethod2(siglop_class, siglop_dsp, "dsp","");
+ class_addmethod2(siglop_class, siglop_ft1, "ft1","f");
+ class_addmethod2(siglop_class, siglop_clear, "clear","");
+}
+
+/* ---------------- bp~ - 2-pole bandpass filter. ----------------- */
+struct t_bpctl {
+ float x1;
+ float x2;
+ float coef1;
+ float coef2;
+ float gain;
+};
+struct t_sigbp : t_object {
+ float sr;
+ float freq;
+ float q;
+ t_bpctl cspace;
+ t_bpctl *ctl;
+ float a;
+};
+t_class *sigbp_class;
+static void sigbp_docoef(t_sigbp *x, t_floatarg f, t_floatarg q);
+static void *sigbp_new(t_floatarg f, t_floatarg q) {
+ t_sigbp *x = (t_sigbp *)pd_new(sigbp_class);
+ inlet_new(x, x, &s_float, gensym("ft1"));
+ inlet_new(x, x, &s_float, gensym("ft2"));
+ outlet_new(x, &s_signal);
+ x->sr = 44100;
+ x->ctl = &x->cspace;
+ x->cspace.x1 = 0;
+ x->cspace.x2 = 0;
+ sigbp_docoef(x, f, q);
+ x->a = 0;
+ return x;
+}
+static float sigbp_qcos(float f) {
+ if (f >= -(0.5f*3.14159f) && f <= 0.5f*3.14159f) {
+ float g = f*f;
+ return ((g*g*g * (-1.0f/720.0f) + g*g*(1.0f/24.0f)) - g*0.5) + 1;
+ } else return 0;
+}
+static void sigbp_docoef(t_sigbp *x, t_floatarg f, t_floatarg q) {
+ float r, oneminusr, omega;
+ if (f < 0.001) f = 10;
+ if (q < 0) q = 0;
+ x->freq = f;
+ x->q = q;
+ omega = f * (2.0f * 3.14159f) / x->sr;
+ if (q < 0.001) oneminusr = 1.0f;
+ else oneminusr = omega/q;
+ if (oneminusr > 1.0f) oneminusr = 1.0f;
+ r = 1.0f - oneminusr;
+ x->ctl->coef1 = 2.0f * sigbp_qcos(omega) * r;
+ x->ctl->coef2 = - r * r;
+ x->ctl->gain = 2 * oneminusr * (oneminusr + r * omega);
+ /* post("r %f, omega %f, coef1 %f, coef2 %f", r, omega, x->ctl->coef1, x->ctl->coef2); */
+}
+static void sigbp_ft1(t_sigbp *x, t_floatarg f) {sigbp_docoef(x, f, x->q);}
+static void sigbp_ft2(t_sigbp *x, t_floatarg q) {sigbp_docoef(x, x->freq, q);}
+static void sigbp_clear(t_sigbp *x, t_floatarg q) {x->ctl->x1 = x->ctl->x2 = 0;}
+static t_int *sigbp_perform(t_int *w) {
+ float *in = (float *)w[1];
+ float *out = (float *)w[2];
+ t_bpctl *c = (t_bpctl *)w[3];
+ int n = (t_int)w[4];
+ float last = c->x1;
+ float prev = c->x2;
+ float coef1 = c->coef1;
+ float coef2 = c->coef2;
+ float gain = c->gain;
+ for (int i = 0; i < n; i++) {
+ float output = *in++ + coef1 * last + coef2 * prev;
+ *out++ = gain * output;
+ prev = last;
+ last = output;
+ }
+ if (PD_BIGORSMALL(last)) last = 0;
+ if (PD_BIGORSMALL(prev)) prev = 0;
+ c->x1 = last;
+ c->x2 = prev;
+ return w+5;
+}
+static void sigbp_dsp(t_sigbp *x, t_signal **sp) {
+ x->sr = sp[0]->sr;
+ sigbp_docoef(x, x->freq, x->q);
+ dsp_add(sigbp_perform, 4, sp[0]->v, sp[1]->v, x->ctl, sp[0]->n);
+
+}
+void sigbp_setup() {
+ sigbp_class = class_new2("bp~",sigbp_new,0,sizeof(t_sigbp),0,"FF");
+ CLASS_MAINSIGNALIN(sigbp_class, t_sigbp, a);
+ class_addmethod2(sigbp_class, sigbp_dsp, "dsp","");
+ class_addmethod2(sigbp_class, sigbp_ft1, "ft1","f");
+ class_addmethod2(sigbp_class, sigbp_ft2, "ft2","f");
+ class_addmethod2(sigbp_class, sigbp_clear, "clear","");
+}
+
+/* ---------------- biquad~ - raw biquad filter ----------------- */
+struct t_biquadctl {
+ float x1;
+ float x2;
+ float fb1;
+ float fb2;
+ float ff1;
+ float ff2;
+ float ff3;
+};
+struct t_sigbiquad : t_object {
+ float a;
+ t_biquadctl cspace;
+ t_biquadctl *ctl;
+};
+t_class *sigbiquad_class;
+static void sigbiquad_list(t_sigbiquad *x, t_symbol *s, int argc, t_atom *argv);
+static void *sigbiquad_new(t_symbol *s, int argc, t_atom *argv) {
+ t_sigbiquad *x = (t_sigbiquad *)pd_new(sigbiquad_class);
+ outlet_new(x, &s_signal);
+ x->ctl = &x->cspace;
+ x->cspace.x1 = x->cspace.x2 = 0;
+ sigbiquad_list(x, s, argc, argv);
+ x->a = 0;
+ return x;
+}
+static t_int *sigbiquad_perform(t_int *w) {
+ float *in = (float *)w[1];
+ float *out = (float *)w[2];
+ t_biquadctl *c = (t_biquadctl *)w[3];
+ int n = (t_int)w[4];
+ float last = c->x1;
+ float prev = c->x2;
+ float fb1 = c->fb1;
+ float fb2 = c->fb2;
+ float ff1 = c->ff1;
+ float ff2 = c->ff2;
+ float ff3 = c->ff3;
+ for (int i = 0; i < n; i++) {
+ float output = *in++ + fb1 * last + fb2 * prev;
+ if (PD_BIGORSMALL(output)) output = 0;
+ *out++ = ff1 * output + ff2 * last + ff3 * prev;
+ prev = last;
+ last = output;
+ }
+ c->x1 = last;
+ c->x2 = prev;
+ return w+5;
+}
+/* tb: some loop unrolling & do some relaxed denormal bashing */
+/* (denormal bashing = non-Pentium4 penalised for Pentium4's failings) */
+static t_int *sigbiquad_perf8(t_int *w) {
+ float *in = (float *)w[1];
+ float *out = (float *)w[2];
+ t_biquadctl *c = (t_biquadctl *)w[3];
+ int n = (t_int)w[4]>>3;
+ float last = c->x1;
+ float prev = c->x2;
+ float fb1 = c->fb1;
+ float fb2 = c->fb2;
+ float ff1 = c->ff1;
+ float ff2 = c->ff2;
+ float ff3 = c->ff3;
+ for (int i = 0; i < n; i++) {
+ float output = *in++ + fb1*last + fb2*prev;
+ if (PD_BIGORSMALL(output)) output = 0;
+ *out++ = ff1 * output + ff2*last + ff3*prev; prev=last; last=output; output = *in++ + fb1*last + fb2*prev;
+ if (PD_BIGORSMALL(output)) output = 0;
+ *out++ = ff1 * output + ff2*last + ff3*prev; prev=last; last=output; output = *in++ + fb1*last + fb2*prev;
+ *out++ = ff1 * output + ff2*last + ff3*prev; prev=last; last=output; output = *in++ + fb1*last + fb2*prev;
+ *out++ = ff1 * output + ff2*last + ff3*prev; prev=last; last=output; output = *in++ + fb1*last + fb2*prev;
+ output += 1e-10;
+ output -= 1e-10;
+ *out++ = ff1*output + ff2*last + ff3*prev; prev=last; last=output; output = *in++ + fb1*last + fb2*prev;
+ *out++ = ff1*output + ff2*last + ff3*prev; prev=last; last=output; output = *in++ + fb1*last + fb2*prev;
+ *out++ = ff1*output + ff2*last + ff3*prev; prev=last; last=output; output = *in++ + fb1*last + fb2*prev;
+ *out++ = ff1*output + ff2*last + ff3*prev; prev=last; last=output;
+ }
+ c->x1 = last;
+ c->x2 = prev;
+ return w+5;
+}
+static void sigbiquad_list(t_sigbiquad *x, t_symbol *s, int argc, t_atom *argv) {
+ float fb1 = atom_getfloatarg(0, argc, argv);
+ float fb2 = atom_getfloatarg(1, argc, argv);
+ float ff1 = atom_getfloatarg(2, argc, argv);
+ float ff2 = atom_getfloatarg(3, argc, argv);
+ float ff3 = atom_getfloatarg(4, argc, argv);
+ float discriminant = fb1 * fb1 + 4 * fb2;
+ t_biquadctl *c = x->ctl;
+ /* imaginary roots -- resonant filter */
+ if (discriminant < 0) {
+ /* they're conjugates so we just check that the product is less than one */
+ if (fb2 >= -1.0f) goto stable;
+ } else { /* real roots */
+ /* check that the parabola 1 - fb1 x - fb2 x^2 has a
+ vertex between -1 and 1, and that it's nonnegative
+ at both ends, which implies both roots are in [1-,1]. */
+ if (fb1 <= 2.0f && fb1 >= -2.0f && 1.0f - fb1 -fb2 >= 0 && 1.0f + fb1 - fb2 >= 0) goto stable;
+ }
+ /* if unstable, just bash to zero */
+ fb1 = fb2 = ff1 = ff2 = ff3 = 0;
+stable:
+ c->fb1 = fb1;
+ c->fb2 = fb2;
+ c->ff1 = ff1;
+ c->ff2 = ff2;
+ c->ff3 = ff3;
+}
+static void sigbiquad_set(t_sigbiquad *x, t_symbol *s, int argc, t_atom *argv) {
+ t_biquadctl *c = x->ctl;
+ c->x1 = atom_getfloatarg(0, argc, argv);
+ c->x2 = atom_getfloatarg(1, argc, argv);
+}
+static void sigbiquad_dsp(t_sigbiquad *x, t_signal **sp) {
+ const int n = sp[0]->n;
+ if (n&7) dsp_add(sigbiquad_perform, 4, sp[0]->v, sp[1]->v, x->ctl, sp[0]->n);
+ else dsp_add(sigbiquad_perf8, 4, sp[0]->v, sp[1]->v, x->ctl, sp[0]->n);
+}
+void sigbiquad_setup() {
+ sigbiquad_class = class_new2("biquad~",sigbiquad_new,0,sizeof(t_sigbiquad),0,"*");
+ CLASS_MAINSIGNALIN(sigbiquad_class, t_sigbiquad, a);
+ class_addmethod2(sigbiquad_class, sigbiquad_dsp, "dsp","");
+ class_addlist(sigbiquad_class, sigbiquad_list);
+ class_addmethod2(sigbiquad_class, sigbiquad_set, "set","*");
+ class_addmethod2(sigbiquad_class, sigbiquad_set, "clear","*");
+}
+
+/* ---------------- samphold~ - sample and hold ----------------- */
+struct t_sigsamphold : t_object {
+ float a;
+ float lastin;
+ float lastout;
+};
+t_class *sigsamphold_class;
+static void *sigsamphold_new() {
+ t_sigsamphold *x = (t_sigsamphold *)pd_new(sigsamphold_class);
+ inlet_new(x, x, &s_signal, &s_signal);
+ outlet_new(x, &s_signal);
+ x->lastin = 0;
+ x->lastout = 0;
+ x->a = 0;
+ return x;
+}
+static t_int *sigsamphold_perform(t_int *w) {
+ float *in1 = (float *)w[1];
+ float *in2 = (float *)w[2];
+ float *out = (float *)w[3];
+ t_sigsamphold *x = (t_sigsamphold *)w[4];
+ int n = (t_int)w[5];
+ float lastin = x->lastin;
+ float lastout = x->lastout;
+ for (int i = 0; i < n; i++, *in1++) {
+ float next = *in2++;
+ if (next < lastin) lastout = *in1;
+ *out++ = lastout;
+ lastin = next;
+ }
+ x->lastin = lastin;
+ x->lastout = lastout;
+ return w+6;
+}
+static void sigsamphold_dsp(t_sigsamphold *x, t_signal **sp) {
+ dsp_add(sigsamphold_perform, 5, sp[0]->v, sp[1]->v, sp[2]->v, x, sp[0]->n);
+}
+static void sigsamphold_reset(t_sigsamphold *x, t_symbol *s, int argc, t_atom *argv) {
+ x->lastin = ((argc > 0 && (argv[0].a_type == A_FLOAT)) ? argv[0].a_w.w_float : 1e20);
+}
+static void sigsamphold_set(t_sigsamphold *x, t_float f) {
+ x->lastout = f;
+}
+void sigsamphold_setup() {
+ sigsamphold_class = class_new2("samphold~",sigsamphold_new,0,sizeof(t_sigsamphold),0,"");
+ CLASS_MAINSIGNALIN(sigsamphold_class, t_sigsamphold, a);
+ class_addmethod2(sigsamphold_class, sigsamphold_set, "set","F");
+ class_addmethod2(sigsamphold_class, sigsamphold_reset, "reset","*");
+ class_addmethod2(sigsamphold_class, sigsamphold_dsp, "dsp","");
+}
+
+/* ---------------- rpole~ - real one-pole filter (raw) ----------------- */
+/* ---------------- rzero~ - real one-zero filter (raw) ----------------- */
+/* --- rzero_rev~ - real, reverse one-zero filter (raw) ----------------- */
+t_class *sigrpole_class; struct t_sigrpole : t_object {float a; float last;};
+t_class *sigrzero_class; struct t_sigrzero : t_object {float a; float last;};
+t_class *sigrzrev_class; struct t_sigrzrev : t_object {float a; float last;};
+
+static void *sigrpole_new(t_float f) {
+ t_sigrpole *x = (t_sigrpole *)pd_new(sigrpole_class);
+ pd_float((t_pd *)inlet_new(x, x, &s_signal, &s_signal), f); outlet_new(x, &s_signal); x->last=0; return x;}
+static void *sigrzero_new(t_float f) {
+ t_sigrzero *x = (t_sigrzero *)pd_new(sigrzero_class);
+ pd_float((t_pd *)inlet_new(x, x, &s_signal, &s_signal), f); outlet_new(x, &s_signal); x->last=0; return x;}
+static void *sigrzrev_new(t_float f) {
+ t_sigrzrev *x = (t_sigrzrev *)pd_new(sigrzrev_class);
+ pd_float((t_pd *)inlet_new(x, x, &s_signal, &s_signal), f); outlet_new(x, &s_signal); x->last=0; return x;}
+
+static t_int *sigrpole_perform(t_int *w) {
+ float *in1 = (float *)w[1]; float *in2 = (float *)w[2]; float *out = (float *)w[3];
+ t_sigrpole *x = (t_sigrpole *)w[4]; int n = (t_int)w[5]; float last = x->last;
+ for (int i=0; i<n; i++) {
+ float next = *in1++, coef = *in2++;
+ *out++ = last = coef*last + next;
+ }
+ if (PD_BIGORSMALL(last)) last = 0;
+ x->last = last;
+ return w+6;
+}
+static t_int *sigrzero_perform(t_int *w) {
+ float *in1 = (float *)w[1]; float *in2 = (float *)w[2]; float *out = (float *)w[3];
+ t_sigrzero *x = (t_sigrzero *)w[4]; int n = (t_int)w[5]; float last = x->last;
+ for (int i = 0; i < n; i++) {
+ float next = *in1++, coef = *in2++;
+ *out++ = next - coef*last;
+ last = next;
+ }
+ x->last = last;
+ return w+6;
+}
+static t_int *sigrzrev_perform(t_int *w) {
+ float *in1 = (float *)w[1]; float *in2 = (float *)w[2]; float *out = (float *)w[3];
+ t_sigrzrev *x = (t_sigrzrev *)w[4]; int n = (t_int)w[5]; float last = x->last;
+ for (int i = 0; i < n; i++) {
+ float next = *in1++, coef = *in2++;
+ *out++ = last - coef*next;
+ last = next;
+ }
+ x->last = last;
+ return w+6;
+}
+
+static void sigrpole_dsp(t_sigrpole *x, t_signal **sp) {dsp_add(sigrpole_perform, 5, sp[0]->v, sp[1]->v, sp[2]->v, x, sp[0]->n);}
+static void sigrzero_dsp(t_sigrzero *x, t_signal **sp) {dsp_add(sigrzero_perform, 5, sp[0]->v, sp[1]->v, sp[2]->v, x, sp[0]->n);}
+static void sigrzrev_dsp(t_sigrzrev *x, t_signal **sp) {dsp_add(sigrzrev_perform, 5, sp[0]->v, sp[1]->v, sp[2]->v, x, sp[0]->n);}
+static void sigrpole_clear(t_sigrpole *x) {x->last = 0;}
+static void sigrzero_clear(t_sigrzero *x) {x->last = 0;}
+static void sigrzrev_clear(t_sigrzrev *x) {x->last = 0;}
+static void sigrpole_set(t_sigrpole *x, t_float f) {x->last = f;}
+static void sigrzero_set(t_sigrzero *x, t_float f) {x->last = f;}
+static void sigrzrev_set(t_sigrzrev *x, t_float f) {x->last = f;}
+void sigr_setup() {
+ sigrpole_class = class_new2("rpole~", sigrpole_new,0,sizeof(t_sigrpole),0,"F");
+ sigrzero_class = class_new2("rzero~", sigrzero_new,0,sizeof(t_sigrzero),0,"F");
+ sigrzrev_class = class_new2("rzero_rev~",sigrzrev_new,0,sizeof(t_sigrzrev),0,"F");
+ CLASS_MAINSIGNALIN(sigrpole_class, t_sigrpole, a);
+ CLASS_MAINSIGNALIN(sigrzero_class, t_sigrzero, a);
+ CLASS_MAINSIGNALIN(sigrzrev_class, t_sigrzrev, a);
+ class_addmethod2(sigrpole_class, sigrpole_set, "set","F");
+ class_addmethod2(sigrzero_class, sigrzero_set, "set","F");
+ class_addmethod2(sigrzrev_class, sigrzrev_set, "set","F");
+ class_addmethod2(sigrpole_class, sigrpole_clear,"clear","");
+ class_addmethod2(sigrzero_class, sigrzero_clear,"clear","");
+ class_addmethod2(sigrzrev_class, sigrzrev_clear,"clear","");
+ class_addmethod2(sigrpole_class, sigrpole_dsp, "dsp","");
+ class_addmethod2(sigrzero_class, sigrzero_dsp, "dsp","");
+ class_addmethod2(sigrzrev_class, sigrzrev_dsp, "dsp","");
+}
+
+/* -------------- cpole~ - complex one-pole filter (raw) --------------- */
+/* -------------- czero~ - complex one-pole filter (raw) --------------- */
+/* ---------- czero_rev~ - complex one-pole filter (raw) --------------- */
+
+t_class *sigcpole_class; struct t_sigcpole : t_object {float a; float lastre; float lastim;};
+t_class *sigczero_class; struct t_sigczero : t_object {float a; float lastre; float lastim;};
+t_class *sigczrev_class; struct t_sigczrev : t_object {float a; float lastre; float lastim;};
+
+static void *sigcpole_new(t_float re, t_float im) {
+ t_sigcpole *x = (t_sigcpole *)pd_new(sigcpole_class);
+ inlet_new(x, x, &s_signal, &s_signal);
+ pd_float((t_pd *)inlet_new(x, x, &s_signal, &s_signal), re);
+ pd_float((t_pd *)inlet_new(x, x, &s_signal, &s_signal), im);
+ outlet_new(x, &s_signal);
+ outlet_new(x, &s_signal);
+ x->lastre = x->lastim = 0;
+ x->a = 0;
+ return x;
+}
+static void *sigczero_new(t_float re, t_float im) {
+ t_sigczero *x = (t_sigczero *)pd_new(sigczero_class);
+ inlet_new(x, x, &s_signal, &s_signal);
+ pd_float((t_pd *)inlet_new(x, x, &s_signal, &s_signal), re);
+ pd_float((t_pd *)inlet_new(x, x, &s_signal, &s_signal), im);
+ outlet_new(x, &s_signal);
+ outlet_new(x, &s_signal);
+ x->lastre = x->lastim = 0;
+ x->a = 0;
+ return x;
+}
+static void *sigczrev_new(t_float re, t_float im) {
+ t_sigczrev *x = (t_sigczrev *)pd_new(sigczrev_class);
+ inlet_new(x, x, &s_signal, &s_signal);
+ pd_float((t_pd *)inlet_new(x, x, &s_signal, &s_signal), re);
+ pd_float((t_pd *)inlet_new(x, x, &s_signal, &s_signal), im);
+ outlet_new(x, &s_signal);
+ outlet_new(x, &s_signal);
+ x->lastre = x->lastim = 0;
+ x->a = 0;
+ return x;
+}
+
+static t_int *sigcpole_perform(t_int *w) {
+ float *inre1 = (float *)w[1], *inim1 = (float *)w[2];
+ float *inre2 = (float *)w[3], *inim2 = (float *)w[4];
+ float *outre = (float *)w[5], *outim = (float *)w[6];
+ t_sigcpole *x = (t_sigcpole *)w[7];
+ int n = (t_int)w[8];
+ float lastre = x->lastre;
+ float lastim = x->lastim;
+ for (int i = 0; i < n; i++) {
+ float nextre = *inre1++, nextim = *inim1++;
+ float coefre = *inre2++, coefim = *inim2++;
+ float tempre = *outre++ = nextre + lastre * coefre - lastim * coefim;
+ lastim = *outim++ = nextim + lastre * coefim + lastim * coefre;
+ lastre = tempre;
+ }
+ if (PD_BIGORSMALL(lastre)) lastre = 0;
+ if (PD_BIGORSMALL(lastim)) lastim = 0;
+ x->lastre = lastre;
+ x->lastim = lastim;
+ return w+9;
+}
+static t_int *sigczero_perform(t_int *w) {
+ float *inre1 = (float *)w[1], *inim1 = (float *)w[2];
+ float *inre2 = (float *)w[3], *inim2 = (float *)w[4];
+ float *outre = (float *)w[5], *outim = (float *)w[6];
+ t_sigczero *x = (t_sigczero *)w[7];
+ int n = (t_int)w[8];
+ float lastre = x->lastre;
+ float lastim = x->lastim;
+ for (int i = 0; i < n; i++) {
+ float nextre = *inre1++, nextim = *inim1++;
+ float coefre = *inre2++, coefim = *inim2++;
+ *outre++ = nextre - lastre * coefre + lastim * coefim;
+ *outim++ = nextim - lastre * coefim - lastim * coefre;
+ lastre = nextre;
+ lastim = nextim;
+ }
+ x->lastre = lastre;
+ x->lastim = lastim;
+ return w+9;
+}
+static t_int *sigczrev_perform(t_int *w) {
+ float *inre1 = (float *)w[1], *inim1 = (float *)w[2];
+ float *inre2 = (float *)w[3], *inim2 = (float *)w[4];
+ float *outre = (float *)w[5], *outim = (float *)w[6];
+ t_sigczrev *x = (t_sigczrev *)w[7];
+ int n = (t_int)w[8];
+ float lastre = x->lastre;
+ float lastim = x->lastim;
+ for (int i = 0; i < n; i++) {
+ float nextre = *inre1++, nextim = *inim1++;
+ float coefre = *inre2++, coefim = *inim2++;
+ /* transfer function is (A bar) - Z^-1, for the same frequency response as 1 - AZ^-1 from czero_tilde. */
+ *outre++ = lastre - nextre * coefre - nextim * coefim;
+ *outim++ = lastim - nextre * coefim + nextim * coefre;
+ lastre = nextre;
+ lastim = nextim;
+ }
+ x->lastre = lastre;
+ x->lastim = lastim;
+ return w+9;
+}
+
+static void sigcpole_dsp(t_sigcpole *x, t_signal **sp) {
+ dsp_add(sigcpole_perform, 8, sp[0]->v, sp[1]->v, sp[2]->v, sp[3]->v, sp[4]->v, sp[5]->v, x, sp[0]->n);}
+static void sigczero_dsp(t_sigczero *x, t_signal **sp) {
+ dsp_add(sigczero_perform, 8, sp[0]->v, sp[1]->v, sp[2]->v, sp[3]->v, sp[4]->v, sp[5]->v, x, sp[0]->n);}
+static void sigczrev_dsp(t_sigczrev *x, t_signal **sp) {
+ dsp_add(sigczrev_perform, 8, sp[0]->v, sp[1]->v, sp[2]->v, sp[3]->v, sp[4]->v, sp[5]->v, x, sp[0]->n);}
+
+static void sigcpole_clear(t_sigcpole *x) {x->lastre = x->lastim = 0;}
+static void sigczero_clear(t_sigczero *x) {x->lastre = x->lastim = 0;}
+static void sigczrev_clear(t_sigczrev *x) {x->lastre = x->lastim = 0;}
+static void sigcpole_set(t_sigcpole *x, t_float re, t_float im) {x->lastre = re; x->lastim = im;}
+static void sigczero_set(t_sigczero *x, t_float re, t_float im) {x->lastre = re; x->lastim = im;}
+static void sigczrev_set(t_sigczrev *x, t_float re, t_float im) {x->lastre = re; x->lastim = im;}
+
+void sigc_setup() {
+ sigcpole_class = class_new2("cpole~", sigcpole_new,0,sizeof(t_sigcpole),0,"FF");
+ sigczero_class = class_new2("czero~", sigczero_new,0,sizeof(t_sigczero),0,"FF");
+ sigczrev_class = class_new2("czero_rev~",sigczrev_new,0,sizeof(t_sigczrev),0,"FF");
+ CLASS_MAINSIGNALIN(sigcpole_class, t_sigcpole, a);
+ CLASS_MAINSIGNALIN(sigczero_class, t_sigczero, a);
+ CLASS_MAINSIGNALIN(sigczrev_class, t_sigczrev, a);
+ class_addmethod2(sigcpole_class, sigcpole_set, "set","FF");
+ class_addmethod2(sigczero_class, sigczero_set, "set","FF");
+ class_addmethod2(sigczrev_class, sigczrev_set, "set","FF");
+ class_addmethod2(sigcpole_class, sigcpole_clear,"clear","");
+ class_addmethod2(sigczero_class, sigczero_clear, "clear","");
+ class_addmethod2(sigczrev_class, sigczrev_clear, "clear","");
+ class_addmethod2(sigcpole_class, sigcpole_dsp, "dsp","");
+ class_addmethod2(sigczero_class, sigczero_dsp, "dsp","");
+ class_addmethod2(sigczrev_class, sigczrev_dsp, "dsp","");
+}
+
+/* ----------------------------- send~ ----------------------------- */
+static t_class *sigsend_class;
+struct t_sigsend : t_object {
+ t_symbol *sym;
+ int n;
+ float *vec;
+ float a;
+};
+static void *sigsend_new(t_symbol *s) {
+ t_sigsend *x = (t_sigsend *)pd_new(sigsend_class);
+ pd_bind(x, s);
+ x->sym = s;
+ x->n = DEFSENDVS;
+ x->vec = (float *)getalignedbytes(DEFSENDVS * sizeof(float));
+ memset((char *)(x->vec), 0, DEFSENDVS * sizeof(float));
+ x->a = 0;
+ return x;
+}
+static t_int *sigsend_perform(t_int *w) {
+ testcopyvec((t_float *)w[2],(t_float *)w[1],w[3]);
+ return w+4;
+}
+/* T.Grill - SIMD version */
+static t_int *sigsend_perfsimd(t_int *w) {
+ testcopyvec_simd((t_float *)w[2],(t_float *)w[1],w[3]);
+ return w+4;
+}
+static void sigsend_dsp(t_sigsend *x, t_signal **sp) {
+ const int n = x->n;
+ if(n != sp[0]->n) {error("sigsend %s: unexpected vector size", x->sym->name); return;}
+ if(SIMD_CHECK1(n,sp[0]->v)) /* x->vec is aligned in any case */
+ dsp_add(sigsend_perfsimd, 3, sp[0]->v, x->vec, n);
+ else dsp_add(sigsend_perform, 3, sp[0]->v, x->vec, n);
+}
+static void sigsend_free(t_sigsend *x) {
+ pd_unbind(x, x->sym);
+ freealignedbytes(x->vec,x->n* sizeof(float));
+}
+static void sigsend_setup() {
+ sigsend_class = class_new2("send~",sigsend_new,sigsend_free,sizeof(t_sigsend),0,"S");
+ class_addcreator2("s~",sigsend_new,"S");
+ CLASS_MAINSIGNALIN(sigsend_class, t_sigsend, a);
+ class_addmethod2(sigsend_class, sigsend_dsp,"dsp","");
+}
+
+/* ----------------------------- receive~ ----------------------------- */
+static t_class *sigreceive_class;
+struct t_sigreceive : t_object {
+ t_symbol *sym;
+ t_float *wherefrom;
+ int n;
+};
+static void *sigreceive_new(t_symbol *s) {
+ t_sigreceive *x = (t_sigreceive *)pd_new(sigreceive_class);
+ x->n = DEFSENDVS; /* LATER find our vector size correctly */
+ x->sym = s;
+ x->wherefrom = 0;
+ outlet_new(x, &s_signal);
+ return x;
+}
+static t_int *sigreceive_perform(t_int *w) {
+ t_sigreceive *x = (t_sigreceive *)w[1];
+ t_float *out = (t_float *)w[2];
+ int n = (int)w[3];
+ t_float *in = x->wherefrom;
+ if (in) {
+ while (n--) *out++ = *in++;
+ } else {
+ while (n--) *out++ = 0;
+ }
+ return w+4;
+}
+/* tb: vectorized receive function */
+static t_int *sigreceive_perf8(t_int *w) {
+ t_sigreceive *x = (t_sigreceive *)w[1];
+ t_float *in = x->wherefrom;
+ if (in) copyvec_8((t_float *)w[2],in,w[3]);
+ else zerovec_8((t_float *)w[2],w[3]);
+ return w+4;
+}
+/* T.Grill - SIMD version */
+static t_int *sigreceive_perfsimd(t_int *w) {
+ t_sigreceive *x = (t_sigreceive *)w[1];
+ t_float *in = x->wherefrom;
+ if(in) copyvec_simd((t_float *)w[2],in,w[3]);
+ else zerovec_simd((t_float *)w[2],w[3]);
+ return w+4;
+}
+static void sigreceive_set(t_sigreceive *x, t_symbol *s) {
+ t_sigsend *sender = (t_sigsend *)pd_findbyclass((x->sym = s),
+ sigsend_class);
+ if (sender) {
+ if (sender->n == x->n)
+ x->wherefrom = sender->vec;
+ else {
+ error("receive~ %s: vector size mismatch", x->sym->name);
+ x->wherefrom = 0;
+ }
+ } else {
+ error("receive~ %s: no matching send", x->sym->name);
+ x->wherefrom = 0;
+ }
+}
+static void sigreceive_dsp(t_sigreceive *x, t_signal **sp) {
+ const int n = x->n;
+ if (sp[0]->n != n) {error("receive~ %s: vector size mismatch", x->sym->name); return;}
+ sigreceive_set(x, x->sym);
+ /* x->wherefrom is aligned because we aligned the sender memory buffer */
+ if(n&7) dsp_add(sigreceive_perform, 3, x, sp[0]->v, n);
+ else if(SIMD_CHECK1(n,sp[0]->v))
+ dsp_add(sigreceive_perfsimd, 3, x, sp[0]->v, n);
+ else dsp_add(sigreceive_perf8, 3, x, sp[0]->v, n);
+}
+static void sigreceive_setup() {
+ sigreceive_class = class_new2("receive~",sigreceive_new,0,sizeof(t_sigreceive),0,"S");
+ class_addcreator2("r~",sigreceive_new,"S");
+ class_addmethod2(sigreceive_class, sigreceive_set, "set","s");
+ class_addmethod2(sigreceive_class, sigreceive_dsp, "dsp","");
+ class_sethelpsymbol(sigreceive_class, gensym("send~"));
+}
+
+/* ----------------------------- catch~ ----------------------------- */
+static t_class *sigcatch_class;
+struct t_sigcatch : t_object {
+ t_symbol *sym;
+ int n;
+ float *vec;
+};
+static void *sigcatch_new(t_symbol *s) {
+ t_sigcatch *x = (t_sigcatch *)pd_new(sigcatch_class);
+ pd_bind(x, s);
+ x->sym = s;
+ x->n = DEFSENDVS;
+ x->vec = (float *)getalignedbytes(DEFSENDVS * sizeof(float));
+ memset((char *)(x->vec), 0, DEFSENDVS * sizeof(float));
+ outlet_new(x, &s_signal);
+ return x;
+}
+static t_int *sigcatch_perform(t_int *w) {
+ t_float *in = (t_float *)w[1];
+ t_float *out = (t_float *)w[2];
+ int n = (int)w[3];
+ while (n--) *out++ = *in, *in++ = 0;
+ return w+4;
+}
+/* tb: vectorized catch function */
+static t_int *sigcatch_perf8(t_int *w) {
+ copyvec_8((t_float *)w[2],(t_float *)w[1],w[3]);
+ zerovec_8((t_float *)w[1],w[3]);
+ return w+4;
+}
+/* T.Grill: SIMD catch function */
+static t_int *sigcatch_perfsimd(t_int *w) {
+ copyvec_simd((t_float *)w[2],(t_float *)w[1],w[3]);
+ zerovec_simd((t_float *)w[1],w[3]);
+ return w+4;
+}
+static void sigcatch_dsp(t_sigcatch *x, t_signal **sp) {
+ const int n = sp[0]->n;
+ if (x->n != n) {error("sigcatch %s: unexpected vector size", x->sym->name); return;}
+ if(n&7) dsp_add(sigcatch_perform, 3, x->vec, sp[0]->v, n);
+ else if(SIMD_CHECK2(n,x->vec,sp[0]->v))
+ dsp_add(sigcatch_perfsimd, 3, x->vec, sp[0]->v, n);
+ else dsp_add(sigcatch_perf8, 3, x->vec, sp[0]->v, n);
+}
+static void sigcatch_free(t_sigcatch *x) {
+ pd_unbind(x, x->sym);
+ freealignedbytes(x->vec,x->n*sizeof(float));
+}
+static void sigcatch_setup() {
+ sigcatch_class = class_new2("catch~",sigcatch_new,sigcatch_free,sizeof(t_sigcatch),CLASS_NOINLET,"S");
+ class_addmethod2(sigcatch_class, sigcatch_dsp, "dsp","");
+ class_sethelpsymbol(sigcatch_class, gensym("throw~"));
+}
+
+/* ----------------------------- throw~ ----------------------------- */
+static t_class *sigthrow_class;
+struct t_sigthrow : t_object {
+ t_symbol *sym;
+ t_float *whereto;
+ int n;
+ t_float a;
+};
+static void *sigthrow_new(t_symbol *s) {
+ t_sigthrow *x = (t_sigthrow *)pd_new(sigthrow_class);
+ x->sym = s;
+ x->whereto = 0;
+ x->n = DEFSENDVS;
+ x->a = 0;
+ return x;
+}
+static t_int *sigthrow_perform(t_int *w) {
+ t_sigthrow *x = (t_sigthrow *)w[1];
+ t_float *out = x->whereto;
+ if(out) testaddvec(out,(t_float *)w[2],w[3]);
+ return w+4;
+}
+/* T.Grill - SIMD version */
+static t_int *sigthrow_perfsimd(t_int *w) {
+ t_sigthrow *x = (t_sigthrow *)w[1];
+ t_float *out = x->whereto;
+ if(out) testaddvec_simd(out,(t_float *)w[2],w[3]);
+ return w+4;
+}
+static void sigthrow_set(t_sigthrow *x, t_symbol *s) {
+ x->sym = s;
+ t_sigcatch *catcher = (t_sigcatch *)pd_findbyclass(s,sigcatch_class);
+ x->whereto = 0;
+ if (catcher) {
+ if (catcher->n == x->n) x->whereto = catcher->vec;
+ else error("throw~ %s: vector size mismatch", x->sym->name);
+ } else error("throw~ %s: no matching catch", x->sym->name);
+}
+static void sigthrow_dsp(t_sigthrow *x, t_signal **sp) {
+ const int n = x->n;
+ if (sp[0]->n != n) {error("throw~ %s: vector size mismatch", x->sym->name); return;}
+ sigthrow_set(x, x->sym);
+ if(SIMD_CHECK1(n,sp[0]->v)) /* the memory of the catcher is aligned in any case */
+ dsp_add(sigthrow_perfsimd, 3, x, sp[0]->v, n);
+ else dsp_add(sigthrow_perform, 3, x, sp[0]->v, n);
+}
+static void sigthrow_setup() {
+ sigthrow_class = class_new2("throw~",sigthrow_new,0,sizeof(t_sigthrow),0,"S");
+ class_addmethod2(sigthrow_class, sigthrow_set, "set","s");
+ CLASS_MAINSIGNALIN(sigthrow_class, t_sigthrow, a);
+ class_addmethod2(sigthrow_class, sigthrow_dsp, "dsp","");
+}
+
+/* ------------------------- clip~ -------------------------- */
+static t_class *clip_class;
+struct t_clip : t_object {
+ float a;
+ t_sample lo;
+ t_sample hi;
+};
+static void *clip_new(t_floatarg lo, t_floatarg hi) {
+ t_clip *x = (t_clip *)pd_new(clip_class);
+ x->lo = lo;
+ x->hi = hi;
+ outlet_new(x, &s_signal);
+ floatinlet_new(x, &x->lo);
+ floatinlet_new(x, &x->hi);
+ x->a = 0;
+ return x;
+}
+/* T.Grill - changed function interface so that class pointer needn't be passed */
+t_int *clip_perform(t_int *w) {
+ t_float *in = (t_float *)w[1];
+ t_float *out = (t_float *)w[2];
+ const t_float lo = *(t_float *)w[3],hi = *(t_float *)w[4];
+ int n = (int)w[5];
+ while (n--) *out++ = clip(*in++,lo,hi);
+ return w+6;
+}
+static void clip_dsp(t_clip *x, t_signal **sp) {
+ if(SIMD_CHECK2(sp[0]->n,sp[0]->v,sp[1]->v))
+ dsp_add(clip_perf_simd, 5, sp[0]->v, sp[1]->v, &x->lo, &x->hi, sp[0]->n);
+ else dsp_add(clip_perform, 5, sp[0]->v, sp[1]->v, &x->lo, &x->hi, sp[0]->n);
+}
+static void clip_setup() {
+ clip_class = class_new2("clip~",clip_new,0,sizeof(t_clip),0,"FF");
+ CLASS_MAINSIGNALIN(clip_class, t_clip, a);
+ class_addmethod2(clip_class, clip_dsp, "dsp","");
+}
+
+/* sigrsqrt - reciprocal square root good to 8 mantissa bits */
+/* sigsqrt - square root good to 8 mantissa bits */
+
+#define DUMTAB1SIZE 256
+#define DUMTAB2SIZE 1024
+static float rsqrt_exptab[DUMTAB1SIZE], rsqrt_mantissatab[DUMTAB2SIZE];
+static void init_rsqrt() {
+ for (int i = 0; i < DUMTAB1SIZE; i++) {
+ float f;
+ long l = (i ? (i == DUMTAB1SIZE-1 ? DUMTAB1SIZE-2 : i) : 1)<< 23;
+ *(int *)(&f) = l;
+ rsqrt_exptab[i] = 1./sqrt(f);
+ }
+ for (int i = 0; i < DUMTAB2SIZE; i++) {
+ float f = 1 + (1./DUMTAB2SIZE) * i;
+ rsqrt_mantissatab[i] = 1./sqrt(f);
+ }
+}
+/* these are used in externs like "bonk" */
+float q8_rsqrt(float f) {
+ long l = *(long *)(&f);
+ if (f < 0) return 0;
+ return rsqrt_exptab[(l >> 23) & 0xff] *
+ rsqrt_mantissatab[(l >> 13) & 0x3ff];
+}
+float q8_sqrt(float f) {
+ long l = *(long *)(&f);
+ if (f < 0) return 0;
+ return f * rsqrt_exptab[(l >> 23) & 0xff] *
+ rsqrt_mantissatab[(l >> 13) & 0x3ff];
+}
+
+/* the old names are OK unless we're in IRIX N32 */
+#ifndef N32
+float qsqrt(float f) {return q8_sqrt(f);}
+float qrsqrt(float f) {return q8_rsqrt(f);}
+#endif
+static t_class *sigrsqrt_class; struct t_sigrsqrt : t_object {float a;};
+static t_class * sigsqrt_class; struct t_sigsqrt : t_object {float a;};
+static void *sigrsqrt_new() {
+ t_sigrsqrt *x = (t_sigrsqrt *)pd_new(sigrsqrt_class);
+ outlet_new(x, &s_signal);
+ x->a = 0;
+ return x;
+}
+static void *sigsqrt_new() {
+ t_sigsqrt *x = (t_sigsqrt *)pd_new(sigsqrt_class);
+ outlet_new(x, &s_signal);
+ x->a = 0;
+ return x;
+}
+
+static t_int *sigrsqrt_perform(t_int *w) {
+ float *in = *(t_float **)(w+1), *out = *(t_float **)(w+2);
+ t_int n = *(t_int *)(w+3);
+ while (n--) {
+ float f = *in;
+ long l = *(long *)(in++);
+ if (f < 0) *out++ = 0;
+ else {
+ float g = rsqrt_exptab[(l >> 23) & 0xff] *
+ rsqrt_mantissatab[(l >> 13) & 0x3ff];
+ *out++ = 1.5 * g - 0.5 * g * g * g * f;
+ }
+ }
+ return w+4;
+}
+/* not static; also used in d_fft.c */
+t_int *sigsqrt_perform(t_int *w) {
+ float *in = *(t_float **)(w+1), *out = *(t_float **)(w+2);
+ t_int n = *(t_int *)(w+3);
+ while (n--) {
+ float f = *in;
+ long l = *(long *)(in++);
+ if (f < 0) *out++ = 0;
+ else {
+ float g = rsqrt_exptab[(l >> 23) & 0xff] *
+ rsqrt_mantissatab[(l >> 13) & 0x3ff];
+ *out++ = f * (1.5 * g - 0.5 * g * g * g * f);
+ }
+ }
+ return w+4;
+}
+
+static void sigrsqrt_dsp(t_sigrsqrt *x, t_signal **sp) {
+ if(SIMD_CHECK2(sp[0]->n,sp[0]->v,sp[1]->v))
+ dsp_add(sigrsqrt_perf_simd, 3, sp[0]->v, sp[1]->v, sp[0]->n);
+ else dsp_add(sigrsqrt_perform, 3, sp[0]->v, sp[1]->v, sp[0]->n);
+}
+static void sigsqrt_dsp(t_sigsqrt *x, t_signal **sp) {
+ if(SIMD_CHECK2(sp[0]->n,sp[0]->v,sp[1]->v))
+ dsp_add(sigsqrt_perf_simd, 3, sp[0]->v, sp[1]->v, sp[0]->n);
+ else dsp_add(sigsqrt_perform, 3, sp[0]->v, sp[1]->v, sp[0]->n);
+}
+
+void sigsqrt_setup() {
+ init_rsqrt();
+ sigrsqrt_class = class_new2("rsqrt~",sigrsqrt_new,0,sizeof(t_sigrsqrt),0,"");
+ sigsqrt_class = class_new2( "sqrt~", sigsqrt_new,0, sizeof(t_sigsqrt),0,"");
+ CLASS_MAINSIGNALIN(sigrsqrt_class,t_sigrsqrt,a);
+ CLASS_MAINSIGNALIN( sigsqrt_class, t_sigsqrt,a);
+ class_addmethod2( sigsqrt_class, sigsqrt_dsp,"dsp","");
+ class_addmethod2(sigrsqrt_class,sigrsqrt_dsp,"dsp","");
+ class_addcreator2("q8_rsqrt~",sigrsqrt_new,"");
+ class_addcreator2("q8_sqrt~", sigsqrt_new,"");
+}
+
+/* ------------------------------ wrap~ -------------------------- */
+struct t_sigwrap : t_object {float a;};
+t_class *sigwrap_class;
+static void *sigwrap_new() {
+ t_sigwrap *x = (t_sigwrap *)pd_new(sigwrap_class);
+ outlet_new(x, &s_signal);
+ x->a = 0;
+ return x;
+}
+static t_int *sigwrap_perform(t_int *w) {
+ float *in = *(t_float **)(w+1), *out = *(t_float **)(w+2);
+ t_int n = *(t_int *)(w+3);
+ while (n--) {
+ float f = *in++;
+ int k = (int)f;
+ if (f > 0) *out++ = f-k;
+ else *out++ = f - (k-1);
+ }
+ return w+4;
+}
+static void sigwrap_dsp(t_sigwrap *x, t_signal **sp) {
+ if(SIMD_CHECK2(sp[0]->n,sp[0]->v,sp[1]->v))
+ dsp_add(sigwrap_perf_simd, 3, sp[0]->v, sp[1]->v, sp[0]->n);
+ else dsp_add(sigwrap_perform, 3, sp[0]->v, sp[1]->v, sp[0]->n);
+}
+void sigwrap_setup() {
+ sigwrap_class = class_new2("wrap~",sigwrap_new,0,sizeof(t_sigwrap),0,"");
+ CLASS_MAINSIGNALIN(sigwrap_class, t_sigwrap, a);
+ class_addmethod2(sigwrap_class, sigwrap_dsp, "dsp","");
+}
+
+/* ------------------------------ mtof_tilde~ and such -------------------------- */
+struct t_func1 : t_object {float a;};
+t_class *mtof_tilde_class, *ftom_tilde_class;
+t_class *dbtorms_tilde_class, *rmstodb_tilde_class;
+t_class *dbtopow_tilde_class, *powtodb_tilde_class;
+
+#define FUNC1(NAME,EXPR) \
+static t_int *NAME##_perform(t_int *w) { \
+ float *in = *(t_float **)(w+1), *out = *(t_float **)(w+2); \
+ for (t_int n = *(t_int *)(w+3); n--; in++, out++) { float a = *in; *out = (EXPR); } \
+ return w+4;} \
+static void *NAME##_new() {t_func1 *x = (t_func1 *)pd_new(NAME##_class); \
+ outlet_new(x,&s_signal); x->a = 0; return x;} \
+static void NAME##_dsp(t_func1 *x, t_signal **sp) { \
+ dsp_add(NAME##_perform, 3, sp[0]->v, sp[1]->v, sp[0]->n);}
+
+
+FUNC1(mtof_tilde, a<=-1500 ? 0 : 8.17579891564 * exp(.0577622650 * min(a,1499.f)))
+FUNC1(ftom_tilde, a>0 ? 17.3123405046 * log(.12231220585 * a) : -1500)
+FUNC1(dbtorms_tilde, a<=0 ? 0 : exp((LOGTEN * 0.05) * (min(a,485.f)-100.)))
+FUNC1(dbtopow_tilde, a<=0 ? 0 : max(100 + 20./LOGTEN * log(a),0.))
+FUNC1(rmstodb_tilde, a<=0 ? 0 : exp((LOGTEN * 0.1) * (min(a,870.f)-100.)))
+FUNC1(powtodb_tilde, a<=0 ? 0 : max(100 + 10./LOGTEN * log(a),0.))
+
+#define FUNC1DECL(NAME,SYM) \
+ NAME##_class = class_new2(SYM,NAME##_new,0,sizeof(t_func1),0,""); \
+ CLASS_MAINSIGNALIN(NAME##_class,t_func1,a); \
+ class_addmethod2(NAME##_class, NAME##_dsp, "dsp","");
+
+void mtof_tilde_setup() {
+ FUNC1DECL(mtof_tilde,"mtof~")
+ FUNC1DECL(ftom_tilde,"ftom~")
+ FUNC1DECL(dbtorms_tilde,"dbtorms~")
+ FUNC1DECL(dbtopow_tilde,"dbtopow~")
+ FUNC1DECL(rmstodb_tilde,"rmstodb~")
+ FUNC1DECL(powtodb_tilde,"powtodb~")
+ t_symbol *s = gensym("acoustics~.pd");
+ class_sethelpsymbol(mtof_tilde_class, s);
+ class_sethelpsymbol(ftom_tilde_class, s);
+ class_sethelpsymbol(dbtorms_tilde_class, s);
+ class_sethelpsymbol(rmstodb_tilde_class, s);
+ class_sethelpsymbol(dbtopow_tilde_class, s);
+ class_sethelpsymbol(powtodb_tilde_class, s);
+}
+
+static t_class *print_class;
+struct t_print : t_object {
+ float a;
+ t_symbol *sym;
+ int count;
+};
+static t_int *print_perform(t_int *w) {
+ t_print *x = (t_print *)w[1];
+ t_float *in = (t_float *)w[2];
+ int n = (int)w[3];
+ if (x->count) {
+ post("%s:", x->sym->name);
+ if (n == 1) post("%8g", in[0]);
+ else if (n == 2) post("%8g %8g", in[0], in[1]);
+ else if (n == 4) post("%8g %8g %8g %8g", in[0], in[1], in[2], in[3]);
+ else while (n > 0) {
+ post("%-8.5g %-8.5g %-8.5g %-8.5g %-8.5g %-8.5g %-8.5g %-8.5g",
+ in[0], in[1], in[2], in[3], in[4], in[5], in[6], in[7]);
+ n -= 8;
+ in += 8;
+ }
+ x->count--;
+ }
+ return w+4;
+}
+static void print_dsp(t_print *x, t_signal **sp) {
+ dsp_add(print_perform, 3, x, sp[0]->v, sp[0]->n);
+}
+static void print_float(t_print *x, t_float f) {x->count = max(0,(int)f);}
+static void print_bang(t_print *x) {x->count = 1;}
+static void *print_new(t_symbol *s) {
+ t_print *x = (t_print *)pd_new(print_class);
+ x->sym = s->name[0] ? s : gensym("print~");
+ x->count = 0;
+ x->a = 0;
+ return x;
+}
+static void print_setup() {
+ print_class = class_new2("print~",print_new,0,sizeof(t_print),0,"S");
+ CLASS_MAINSIGNALIN(print_class, t_print, a);
+ class_addmethod2(print_class, print_dsp, "dsp","");
+ class_addbang(print_class, print_bang);
+ class_addfloat(print_class, print_float);
+}
+
+/* ------------------------ bang~ -------------------------- */
+static t_class *bang_tilde_class;
+struct t_bang : t_object {
+ t_clock *clock;
+};
+static t_int *bang_tilde_perform(t_int *w) {
+ t_bang *x = (t_bang *)w[1];
+ clock_delay(x->clock, 0);
+ return w+2;
+}
+static void bang_tilde_dsp(t_bang *x, t_signal **sp) {dsp_add(bang_tilde_perform, 1, x);}
+static void bang_tilde_tick(t_bang *x) {outlet_bang(x->outlet);}
+static void bang_tilde_free(t_bang *x) {clock_free(x->clock);}
+static void *bang_tilde_new(t_symbol *s) {
+ t_bang *x = (t_bang *)pd_new(bang_tilde_class);
+ x->clock = clock_new(x, bang_tilde_tick);
+ outlet_new(x, &s_bang);
+ return x;
+}
+static void bang_tilde_setup() {
+ bang_tilde_class = class_new2("bang~",bang_tilde_new,bang_tilde_free,sizeof(t_bang),0,"");
+ class_addmethod2(bang_tilde_class, bang_tilde_dsp, "dsp","");
+}
+
+/* -------------------------- phasor~ ------------------------------ */
+static t_class *phasor_class;
+/* in the style of R. Hoeldrich (ICMC 1995 Banff) */
+struct t_phasor : t_object {
+ double phase;
+ float conv;
+ float a; /* scalar frequency */
+};
+static void *phasor_new(t_floatarg f) {
+ t_phasor *x = (t_phasor *)pd_new(phasor_class);
+ x->a = f;
+ inlet_new(x, x, &s_float, gensym("ft1"));
+ x->phase = 0;
+ x->conv = 0;
+ outlet_new(x, &s_signal);
+ return x;
+}
+static t_int *phasor_perform(t_int *w) {
+ t_phasor *x = (t_phasor *)w[1];
+ t_float *in = (t_float *)w[2];
+ t_float *out = (t_float *)w[3];
+ int n = (int)w[4];
+ double dphase = x->phase + UNITBIT32;
+ union tabfudge tf;
+ int normhipart;
+ float conv = x->conv;
+ tf.d = UNITBIT32;
+ normhipart = tf.i[HIOFFSET];
+ tf.d = dphase;
+ while (n--) {
+ tf.i[HIOFFSET] = normhipart;
+ dphase += *in++ * conv;
+ *out++ = tf.d - UNITBIT32;
+ tf.d = dphase;
+ }
+ tf.i[HIOFFSET] = normhipart;
+ x->phase = tf.d - UNITBIT32;
+ return w+5;
+}
+static void phasor_dsp(t_phasor *x, t_signal **sp) {
+ x->conv = 1./sp[0]->sr;
+ dsp_add(phasor_perform, 4, x, sp[0]->v, sp[1]->v, sp[0]->n);
+}
+static void phasor_ft1(t_phasor *x, t_float f) {
+ x->phase = f;
+}
+static void phasor_setup() {
+ phasor_class = class_new2("phasor~",phasor_new,0,sizeof(t_phasor),0,"F");
+ CLASS_MAINSIGNALIN(phasor_class, t_phasor, a);
+ class_addmethod2(phasor_class, phasor_dsp, "dsp","");
+ class_addmethod2(phasor_class, phasor_ft1,"ft1","f");
+}
+/* </Hoeldrich-version> */
+
+/* ------------------------ cos~ ----------------------------- */
+float *cos_table;
+static t_class *cos_class;
+struct t_cos : t_object {
+ float a;
+};
+static void *cos_new() {
+ t_cos *x = (t_cos *)pd_new(cos_class);
+ outlet_new(x,&s_signal);
+ x->a = 0;
+ return x;
+}
+static t_int *cos_perform(t_int *w) {
+ t_float *in = (t_float *)w[1];
+ t_float *out = (t_float *)w[2];
+ int n = (int)w[3];
+ float *tab = cos_table, *addr, f1, f2, frac;
+ double dphase;
+ int normhipart;
+ union tabfudge tf;
+ tf.d = UNITBIT32;
+ normhipart = tf.i[HIOFFSET];
+
+#if 0 /* this is the readable version of the code. */
+ while (n--) {
+ dphase = (double)(*in++ * (float)(COSTABSIZE)) + UNITBIT32;
+ tf.d = dphase;
+ addr = tab + (tf.i[HIOFFSET] & (COSTABSIZE-1));
+ tf.i[HIOFFSET] = normhipart;
+ frac = tf.d - UNITBIT32;
+ f1 = addr[0];
+ f2 = addr[1];
+ *out++ = f1 + frac * (f2 - f1);
+ }
+#else /* this is the same, unwrapped by hand. */
+ dphase = (double)(*in++ * (float)(COSTABSIZE)) + UNITBIT32;
+ tf.d = dphase;
+ addr = tab + (tf.i[HIOFFSET] & (COSTABSIZE-1));
+ tf.i[HIOFFSET] = normhipart;
+ while (--n) {
+ dphase = (double)(*in++ * (float)(COSTABSIZE)) + UNITBIT32;
+ frac = tf.d - UNITBIT32;
+ tf.d = dphase;
+ f1 = addr[0];
+ f2 = addr[1];
+ addr = tab + (tf.i[HIOFFSET] & (COSTABSIZE-1));
+ *out++ = f1 + frac * (f2 - f1);
+ tf.i[HIOFFSET] = normhipart;
+ }
+ frac = tf.d - UNITBIT32;
+ f1 = addr[0];
+ f2 = addr[1];
+ *out++ = f1 + frac * (f2 - f1);
+#endif
+ return w+4;
+}
+static void cos_dsp(t_cos *x, t_signal **sp) {
+ dsp_add(cos_perform, 3, sp[0]->v, sp[1]->v, sp[0]->n);
+}
+static void cos_maketable() {
+ float phsinc = (2. * 3.14159) / COSTABSIZE;
+ union tabfudge tf;
+ if (cos_table) return;
+ cos_table = (float *)getbytes(sizeof(float) * (COSTABSIZE+1));
+ float phase=0;
+ float *fp = cos_table;
+ for (int i = COSTABSIZE + 1; i--; fp++, phase += phsinc) *fp = cos(phase);
+ /* here we check at startup whether the byte alignment
+ is as we declared it. If not, the code has to be recompiled the other way. */
+ tf.d = UNITBIT32 + 0.5;
+ if ((unsigned)tf.i[LOWOFFSET] != 0x80000000) bug("cos~: unexpected machine alignment");
+}
+static void cos_setup() {
+ cos_class = class_new2("cos~",cos_new,0,sizeof(t_cos),0,"F");
+ CLASS_MAINSIGNALIN(cos_class, t_cos, a);
+ class_addmethod2(cos_class, cos_dsp, "dsp","");
+ cos_maketable();
+}
+
+/* ------------------------ osc~ ----------------------------- */
+static t_class *osc_class;
+struct t_osc : t_object {
+ double phase;
+ float conv;
+ float a; /* frequency if scalar */
+};
+static void *osc_new(t_floatarg f) {
+ t_osc *x = (t_osc *)pd_new(osc_class);
+ x->a = f;
+ outlet_new(x,&s_signal);
+ inlet_new(x, x, &s_float, gensym("ft1"));
+ inlet_settip(x->inlet,gensym("phase"));
+ x->phase = 0;
+ x->conv = 0;
+ return x;
+}
+static t_int *osc_perform(t_int *w) {
+ t_osc *x = (t_osc *)w[1];
+ t_float *in = (t_float *)w[2];
+ t_float *out = (t_float *)w[3];
+ int n = (int)w[4];
+ float *tab = cos_table, *addr, f1, f2, frac;
+ double dphase = x->phase + UNITBIT32;
+ int normhipart;
+ union tabfudge tf;
+ float conv = x->conv;
+ tf.d = UNITBIT32;
+ normhipart = tf.i[HIOFFSET];
+#if 0
+ while (n--) {
+ tf.d = dphase;
+ dphase += *in++ * conv;
+ addr = tab + (tf.i[HIOFFSET] & (COSTABSIZE-1));
+ tf.i[HIOFFSET] = normhipart;
+ frac = tf.d - UNITBIT32;
+ f1 = addr[0];
+ f2 = addr[1];
+ *out++ = f1 + frac * (f2 - f1);
+ }
+#else
+ tf.d = dphase;
+ dphase += *in++ * conv;
+ addr = tab + (tf.i[HIOFFSET] & (COSTABSIZE-1));
+ tf.i[HIOFFSET] = normhipart;
+ frac = tf.d - UNITBIT32;
+ while (--n) {
+ tf.d = dphase;
+ f1 = addr[0];
+ dphase += *in++ * conv;
+ f2 = addr[1];
+ addr = tab + (tf.i[HIOFFSET] & (COSTABSIZE-1));
+ tf.i[HIOFFSET] = normhipart;
+ *out++ = f1 + frac * (f2 - f1);
+ frac = tf.d - UNITBIT32;
+ }
+ f1 = addr[0];
+ f2 = addr[1];
+ *out++ = f1 + frac * (f2 - f1);
+#endif
+ tf.d = UNITBIT32 * COSTABSIZE;
+ normhipart = tf.i[HIOFFSET];
+ tf.d = dphase + (UNITBIT32 * COSTABSIZE - UNITBIT32);
+ tf.i[HIOFFSET] = normhipart;
+ x->phase = tf.d - UNITBIT32 * COSTABSIZE;
+ return w+5;
+}
+static void osc_dsp(t_osc *x, t_signal **sp) {
+ x->conv = COSTABSIZE/sp[0]->sr;
+ dsp_add(osc_perform, 4, x, sp[0]->v, sp[1]->v, sp[0]->n);
+}
+static void osc_ft1(t_osc *x, t_float f) {
+ x->phase = COSTABSIZE * f;
+}
+static void osc_setup() {
+ osc_class = class_new2("osc~",osc_new,0,sizeof(t_osc),0,"F");
+ CLASS_MAINSIGNALIN(osc_class, t_osc, a);
+ class_addmethod2(osc_class, osc_dsp, "dsp","");
+ class_addmethod2(osc_class, osc_ft1, "ft1","f");
+ class_settip(osc_class,gensym("frequency"));
+ cos_maketable();
+}
+
+/* ---------------- vcf~ - 2-pole bandpass filter. ----------------- */
+struct t_vcfctl {
+ float re;
+ float im;
+ float q;
+ float isr;
+};
+struct t_sigvcf : t_object {
+ t_vcfctl cspace;
+ t_vcfctl *ctl;
+ float a;
+};
+t_class *sigvcf_class;
+static void *sigvcf_new(t_floatarg q) {
+ t_sigvcf *x = (t_sigvcf *)pd_new(sigvcf_class);
+ inlet_new(x, x, &s_signal, &s_signal);
+ inlet_new(x, x, &s_float, gensym("ft1"));
+ outlet_new(x, &s_signal);
+ outlet_new(x, &s_signal);
+ x->ctl = &x->cspace;
+ x->cspace.re = 0;
+ x->cspace.im = 0;
+ x->cspace.q = q;
+ x->cspace.isr = 0;
+ x->a = 0;
+ return x;
+}
+static void sigvcf_ft1(t_sigvcf *x, t_floatarg f) {
+ x->ctl->q = (f > 0 ? f : 0.f);
+}
+static t_int *sigvcf_perform(t_int *w) {
+ float *in1 = (float *)w[1];
+ float *in2 = (float *)w[2];
+ float *out1 = (float *)w[3];
+ float *out2 = (float *)w[4];
+ t_vcfctl *c = (t_vcfctl *)w[5];
+ int n = (t_int)w[6];
+ float re = c->re, re2;
+ float im = c->im;
+ float q = c->q;
+ float qinv = (q > 0? 1.0f/q : 0);
+ float ampcorrect = 2.0f - 2.0f / (q + 2.0f);
+ float isr = c->isr;
+ float coefr, coefi;
+ float *tab = cos_table, *addr, f1, f2, frac;
+ double dphase;
+ int normhipart, tabindex;
+ union tabfudge tf;
+ tf.d = UNITBIT32;
+ normhipart = tf.i[HIOFFSET];
+ for (int i = 0; i < n; i++) {
+ float cf, cfindx, r, oneminusr;
+ cf = *in2++ * isr;
+ if (cf < 0) cf = 0;
+ cfindx = cf * (float)(COSTABSIZE/6.28318f);
+ r = (qinv > 0 ? 1 - cf * qinv : 0);
+ if (r < 0) r = 0;
+ oneminusr = 1.0f - r;
+ dphase = ((double)(cfindx)) + UNITBIT32;
+ tf.d = dphase;
+ tabindex = tf.i[HIOFFSET] & (COSTABSIZE-1);
+ addr = tab + tabindex;
+ tf.i[HIOFFSET] = normhipart;
+ frac = tf.d - UNITBIT32;
+ f1 = addr[0]; f2 = addr[1]; coefr = r * (f1 + frac * (f2 - f1));
+ addr = tab + ((tabindex - (COSTABSIZE/4)) & (COSTABSIZE-1));
+ f1 = addr[0]; f2 = addr[1]; coefi = r * (f1 + frac * (f2 - f1));
+ f1 = *in1++;
+ re2 = re;
+ *out1++ = re = ampcorrect * oneminusr * f1 + coefr * re2 - coefi * im;
+ *out2++ = im = coefi * re2 + coefr * im;
+ }
+ if (PD_BIGORSMALL(re)) re = 0;
+ if (PD_BIGORSMALL(im)) im = 0;
+ c->re = re;
+ c->im = im;
+ return w+7;
+}
+static void sigvcf_dsp(t_sigvcf *x, t_signal **sp) {
+ x->ctl->isr = 6.28318f/sp[0]->sr;
+ dsp_add(sigvcf_perform, 6, sp[0]->v, sp[1]->v, sp[2]->v, sp[3]->v, x->ctl, sp[0]->n);
+
+}
+void sigvcf_setup() {
+ sigvcf_class = class_new2("vcf~",sigvcf_new,0,sizeof(t_sigvcf),0,"F");
+ CLASS_MAINSIGNALIN(sigvcf_class, t_sigvcf, a);
+ class_addmethod2(sigvcf_class, sigvcf_dsp, "dsp","");
+ class_addmethod2(sigvcf_class, sigvcf_ft1, "ft1","f");
+}
+
+/* -------------------------- noise~ ------------------------------ */
+static t_class *noise_class;
+struct t_noise : t_object {
+ int val;
+};
+static void *noise_new() {
+ t_noise *x = (t_noise *)pd_new(noise_class);
+ static int init = 307;
+ x->val = (init *= 1319);
+ outlet_new(x, &s_signal);
+ return x;
+}
+static t_int *noise_perform(t_int *w) {
+ t_float *out = (t_float *)w[1];
+ int *vp = (int *)w[2];
+ int n = (int)w[3];
+ int val = *vp;
+ while (n--) {
+ *out++ = ((float)((val & 0x7fffffff) - 0x40000000)) * (float)(1.0 / 0x40000000);
+ val = val * 435898247 + 382842987;
+ }
+ *vp = val;
+ return w+4;
+}
+static void noise_dsp(t_noise *x, t_signal **sp) {
+ dsp_add(noise_perform, 3, sp[0]->v, &x->val, sp[0]->n);
+}
+static void noise_setup() {
+ noise_class = class_new2("noise~",noise_new,0,sizeof(t_noise),0,"");
+ class_addmethod2(noise_class, noise_dsp, "dsp","");
+}
+void builtins_dsp_setup() {
+ plus_setup();
+ minus_setup();
+ times_setup();
+ over_setup();
+ max_setup();
+ min_setup();
+ lt_setup();
+ gt_setup();
+ le_setup();
+ ge_setup();
+ eq_setup();
+ ne_setup();
+ //abs_setup();
+
+ tab_tilde_setup();
+ tabosc4_tilde_setup();
+ tabsend_setup();
+ tabreceive_setup();
+ tabread_setup();
+ tabread4_setup();
+ tabwrite_setup();
+
+ sig_tilde_setup();
+ line_tilde_setup(); snapshot_tilde_setup();
+ vline_tilde_setup(); vsnapshot_tilde_setup();
+ env_tilde_setup();
+ threshold_tilde_setup();
+
+ dac_setup();
+ adc_setup();
+
+ sigdelwrite_setup();
+ sigdelread_setup();
+ sigvd_setup();
+
+ sigframp_setup();
+#ifdef HAVE_LIBFFTW3F
+ sigfftw_setup(); /* added by Tim Blechmann to support fftw */
+#else
+ sigfft_setup();
+#endif /* HAVE_LIBFFTW3F */
+
+ sighip_setup();
+ siglop_setup();
+ sigbp_setup();
+ sigbiquad_setup();
+ sigsamphold_setup();
+ sigr_setup();
+ sigc_setup();
+
+ sigsend_setup();
+ sigreceive_setup();
+ sigcatch_setup();
+ sigthrow_setup();
+
+ clip_setup();
+ sigsqrt_setup();
+ sigwrap_setup();
+ mtof_tilde_setup();
+ print_setup();
+ bang_tilde_setup();
+
+ phasor_setup();
+ cos_setup();
+ osc_setup();
+ sigvcf_setup();
+ noise_setup();
+}
diff --git a/desiredata/src/config.h.in b/desiredata/src/config.h.in
new file mode 100644
index 00000000..cf88ef4a
--- /dev/null
+++ b/desiredata/src/config.h.in
@@ -0,0 +1,5 @@
+
+#undef HAVE_ALLOCA
+
+#undef HAVE_ALLOCA_H
+
diff --git a/desiredata/src/configure b/desiredata/src/configure
new file mode 100755
index 00000000..205d26e7
--- /dev/null
+++ b/desiredata/src/configure
@@ -0,0 +1,6562 @@
+#! /bin/sh
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.59.
+#
+# Copyright (C) 2003 Free Software Foundation, Inc.
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+## --------------------- ##
+## M4sh Initialization. ##
+## --------------------- ##
+
+# Be Bourne compatible
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+ emulate sh
+ NULLCMD=:
+ # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then
+ set -o posix
+fi
+DUALCASE=1; export DUALCASE # for MKS sh
+
+# Support unset when possible.
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+ as_unset=unset
+else
+ as_unset=false
+fi
+
+
+# Work around bugs in pre-3.0 UWIN ksh.
+$as_unset ENV MAIL MAILPATH
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+for as_var in \
+ LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \
+ LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \
+ LC_TELEPHONE LC_TIME
+do
+ if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then
+ eval $as_var=C; export $as_var
+ else
+ $as_unset $as_var
+ fi
+done
+
+# Required to use basename.
+if expr a : '\(a\)' >/dev/null 2>&1; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+
+# Name of the executable.
+as_me=`$as_basename "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)$' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; }
+ /^X\/\(\/\/\)$/{ s//\1/; q; }
+ /^X\/\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+
+
+# PATH needs CR, and LINENO needs CR and PATH.
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ echo "#! /bin/sh" >conf$$.sh
+ echo "exit 0" >>conf$$.sh
+ chmod +x conf$$.sh
+ if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then
+ PATH_SEPARATOR=';'
+ else
+ PATH_SEPARATOR=:
+ fi
+ rm -f conf$$.sh
+fi
+
+
+ as_lineno_1=$LINENO
+ as_lineno_2=$LINENO
+ as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
+ test "x$as_lineno_1" != "x$as_lineno_2" &&
+ test "x$as_lineno_3" = "x$as_lineno_2" || {
+ # Find who we are. Look in the path if we contain no path at all
+ # relative or not.
+ case $0 in
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+done
+
+ ;;
+ esac
+ # We did not find ourselves, most probably we were run as `sh COMMAND'
+ # in which case we are not to be found in the path.
+ if test "x$as_myself" = x; then
+ as_myself=$0
+ fi
+ if test ! -f "$as_myself"; then
+ { echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2
+ { (exit 1); exit 1; }; }
+ fi
+ case $CONFIG_SHELL in
+ '')
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for as_base in sh bash ksh sh5; do
+ case $as_dir in
+ /*)
+ if ("$as_dir/$as_base" -c '
+ as_lineno_1=$LINENO
+ as_lineno_2=$LINENO
+ as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
+ test "x$as_lineno_1" != "x$as_lineno_2" &&
+ test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then
+ $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; }
+ $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; }
+ CONFIG_SHELL=$as_dir/$as_base
+ export CONFIG_SHELL
+ exec "$CONFIG_SHELL" "$0" ${1+"$@"}
+ fi;;
+ esac
+ done
+done
+;;
+ esac
+
+ # Create $as_me.lineno as a copy of $as_myself, but with $LINENO
+ # uniformly replaced by the line number. The first 'sed' inserts a
+ # line-number line before each line; the second 'sed' does the real
+ # work. The second script uses 'N' to pair each line-number line
+ # with the numbered line, and appends trailing '-' during
+ # substitution so that $LINENO is not a special case at line end.
+ # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the
+ # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-)
+ sed '=' <$as_myself |
+ sed '
+ N
+ s,$,-,
+ : loop
+ s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3,
+ t loop
+ s,-$,,
+ s,^['$as_cr_digits']*\n,,
+ ' >$as_me.lineno &&
+ chmod +x $as_me.lineno ||
+ { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2
+ { (exit 1); exit 1; }; }
+
+ # Don't try to exec as it changes $[0], causing all sort of problems
+ # (the dirname of $[0] is not the place where we might find the
+ # original and so on. Autoconf is especially sensible to this).
+ . ./$as_me.lineno
+ # Exit status is that of the last command.
+ exit
+}
+
+
+case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in
+ *c*,-n*) ECHO_N= ECHO_C='
+' ECHO_T=' ' ;;
+ *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;;
+ *) ECHO_N= ECHO_C='\c' ECHO_T= ;;
+esac
+
+if expr a : '\(a\)' >/dev/null 2>&1; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+rm -f conf$$ conf$$.exe conf$$.file
+echo >conf$$.file
+if ln -s conf$$.file conf$$ 2>/dev/null; then
+ # We could just check for DJGPP; but this test a) works b) is more generic
+ # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04).
+ if test -f conf$$.exe; then
+ # Don't use ln at all; we don't have any links
+ as_ln_s='cp -p'
+ else
+ as_ln_s='ln -s'
+ fi
+elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+else
+ as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.file
+
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p=:
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+as_executable_p="test -f"
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.
+as_nl='
+'
+IFS=" $as_nl"
+
+# CDPATH.
+$as_unset CDPATH
+
+
+# Name of the host.
+# hostname on some systems (SVR3.2, Linux) returns a bogus exit status,
+# so uname gets run too.
+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+exec 6>&1
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+ac_config_libobj_dir=.
+cross_compiling=no
+subdirs=
+MFLAGS=
+MAKEFLAGS=
+SHELL=${CONFIG_SHELL-/bin/sh}
+
+# Maximum number of lines to put in a shell here document.
+# This variable seems obsolete. It should probably be removed, and
+# only ac_max_sed_lines should be used.
+: ${ac_max_here_lines=38}
+
+# Identity of this package.
+PACKAGE_NAME=
+PACKAGE_TARNAME=
+PACKAGE_VERSION=
+PACKAGE_STRING=
+PACKAGE_BUGREPORT=
+
+ac_unique_file="kernel.c"
+# Factoring default headers for most tests.
+ac_includes_default="\
+#include <stdio.h>
+#if HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#if HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#if STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# if HAVE_STDLIB_H
+# include <stdlib.h>
+# endif
+#endif
+#if HAVE_STRING_H
+# if !STDC_HEADERS && HAVE_MEMORY_H
+# include <memory.h>
+# endif
+# include <string.h>
+#endif
+#if HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#if HAVE_INTTYPES_H
+# include <inttypes.h>
+#else
+# if HAVE_STDINT_H
+# include <stdint.h>
+# endif
+#endif
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif"
+
+ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS oss alsa jack portaudio portmidi fftw CPPFLAGS MORECFLAGS EXT USE_DEBUG_CFLAGS AUDIOSRC MIDISRC STRIPFLAG EXTERNTARGET LIBSUFFIX LDSOFLAGS CC CFLAGS LDFLAGS ac_ct_CC EXEEXT OBJEXT INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA SET_MAKE CPP EGREP ALLOCA LIBOBJS LTLIBOBJS'
+ac_subst_files=''
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datadir='${prefix}/share'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+libdir='${exec_prefix}/lib'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+infodir='${prefix}/info'
+mandir='${prefix}/man'
+
+ac_prev=
+for ac_option
+do
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval "$ac_prev=\$ac_option"
+ ac_prev=
+ continue
+ fi
+
+ ac_optarg=`expr "x$ac_option" : 'x[^=]*=\(.*\)'`
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case $ac_option in
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir=$ac_optarg ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build_alias ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build_alias=$ac_optarg ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file=$ac_optarg ;;
+
+ --config-cache | -C)
+ cache_file=config.cache ;;
+
+ -datadir | --datadir | --datadi | --datad | --data | --dat | --da)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \
+ | --da=*)
+ datadir=$ac_optarg ;;
+
+ -disable-* | --disable-*)
+ ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid feature name: $ac_feature" >&2
+ { (exit 1); exit 1; }; }
+ ac_feature=`echo $ac_feature | sed 's/-/_/g'`
+ eval "enable_$ac_feature=no" ;;
+
+ -enable-* | --enable-*)
+ ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid feature name: $ac_feature" >&2
+ { (exit 1); exit 1; }; }
+ ac_feature=`echo $ac_feature | sed 's/-/_/g'`
+ case $ac_option in
+ *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "enable_$ac_feature='$ac_optarg'" ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix=$ac_optarg ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he | -h)
+ ac_init_help=long ;;
+ -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+ ac_init_help=recursive ;;
+ -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+ ac_init_help=short ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host_alias ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host_alias=$ac_optarg ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir=$ac_optarg ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir=$ac_optarg ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir=$ac_optarg ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir=$ac_optarg ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst \
+ | --locals | --local | --loca | --loc | --lo)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* \
+ | --locals=* | --local=* | --loca=* | --loc=* | --lo=*)
+ localstatedir=$ac_optarg ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir=$ac_optarg ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c | -n)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir=$ac_optarg ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix=$ac_optarg ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix=$ac_optarg ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix=$ac_optarg ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name=$ac_optarg ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir=$ac_optarg ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir=$ac_optarg ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site=$ac_optarg ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir=$ac_optarg ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir=$ac_optarg ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target_alias ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target_alias=$ac_optarg ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers | -V)
+ ac_init_version=: ;;
+
+ -with-* | --with-*)
+ ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid package name: $ac_package" >&2
+ { (exit 1); exit 1; }; }
+ ac_package=`echo $ac_package| sed 's/-/_/g'`
+ case $ac_option in
+ *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "with_$ac_package='$ac_optarg'" ;;
+
+ -without-* | --without-*)
+ ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid package name: $ac_package" >&2
+ { (exit 1); exit 1; }; }
+ ac_package=`echo $ac_package | sed 's/-/_/g'`
+ eval "with_$ac_package=no" ;;
+
+ --x)
+ # Obsolete; use --with-x.
+ with_x=yes ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes=$ac_optarg ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries=$ac_optarg ;;
+
+ -*) { echo "$as_me: error: unrecognized option: $ac_option
+Try \`$0 --help' for more information." >&2
+ { (exit 1); exit 1; }; }
+ ;;
+
+ *=*)
+ ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid variable name: $ac_envvar" >&2
+ { (exit 1); exit 1; }; }
+ ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`
+ eval "$ac_envvar='$ac_optarg'"
+ export $ac_envvar ;;
+
+ *)
+ # FIXME: should be removed in autoconf 3.0.
+ echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+ expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+ echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+ : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+ { echo "$as_me: error: missing argument to $ac_option" >&2
+ { (exit 1); exit 1; }; }
+fi
+
+# Be sure to have absolute paths.
+for ac_var in exec_prefix prefix
+do
+ eval ac_val=$`echo $ac_var`
+ case $ac_val in
+ [\\/$]* | ?:[\\/]* | NONE | '' ) ;;
+ *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2
+ { (exit 1); exit 1; }; };;
+ esac
+done
+
+# Be sure to have absolute paths.
+for ac_var in bindir sbindir libexecdir datadir sysconfdir sharedstatedir \
+ localstatedir libdir includedir oldincludedir infodir mandir
+do
+ eval ac_val=$`echo $ac_var`
+ case $ac_val in
+ [\\/$]* | ?:[\\/]* ) ;;
+ *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2
+ { (exit 1); exit 1; }; };;
+ esac
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+ if test "x$build_alias" = x; then
+ cross_compiling=maybe
+ echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host.
+ If a cross compiler is detected then cross compile mode will be used." >&2
+ elif test "x$build_alias" != "x$host_alias"; then
+ cross_compiling=yes
+ fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then its parent.
+ ac_confdir=`(dirname "$0") 2>/dev/null ||
+$as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$0" : 'X\(//\)[^/]' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$0" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ srcdir=$ac_confdir
+ if test ! -r $srcdir/$ac_unique_file; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r $srcdir/$ac_unique_file; then
+ if test "$ac_srcdir_defaulted" = yes; then
+ { echo "$as_me: error: cannot find sources ($ac_unique_file) in $ac_confdir or .." >&2
+ { (exit 1); exit 1; }; }
+ else
+ { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2
+ { (exit 1); exit 1; }; }
+ fi
+fi
+(cd $srcdir && test -r ./$ac_unique_file) 2>/dev/null ||
+ { echo "$as_me: error: sources are in $srcdir, but \`cd $srcdir' does not work" >&2
+ { (exit 1); exit 1; }; }
+srcdir=`echo "$srcdir" | sed 's%\([^\\/]\)[\\/]*$%\1%'`
+ac_env_build_alias_set=${build_alias+set}
+ac_env_build_alias_value=$build_alias
+ac_cv_env_build_alias_set=${build_alias+set}
+ac_cv_env_build_alias_value=$build_alias
+ac_env_host_alias_set=${host_alias+set}
+ac_env_host_alias_value=$host_alias
+ac_cv_env_host_alias_set=${host_alias+set}
+ac_cv_env_host_alias_value=$host_alias
+ac_env_target_alias_set=${target_alias+set}
+ac_env_target_alias_value=$target_alias
+ac_cv_env_target_alias_set=${target_alias+set}
+ac_cv_env_target_alias_value=$target_alias
+ac_env_CC_set=${CC+set}
+ac_env_CC_value=$CC
+ac_cv_env_CC_set=${CC+set}
+ac_cv_env_CC_value=$CC
+ac_env_CFLAGS_set=${CFLAGS+set}
+ac_env_CFLAGS_value=$CFLAGS
+ac_cv_env_CFLAGS_set=${CFLAGS+set}
+ac_cv_env_CFLAGS_value=$CFLAGS
+ac_env_LDFLAGS_set=${LDFLAGS+set}
+ac_env_LDFLAGS_value=$LDFLAGS
+ac_cv_env_LDFLAGS_set=${LDFLAGS+set}
+ac_cv_env_LDFLAGS_value=$LDFLAGS
+ac_env_CPPFLAGS_set=${CPPFLAGS+set}
+ac_env_CPPFLAGS_value=$CPPFLAGS
+ac_cv_env_CPPFLAGS_set=${CPPFLAGS+set}
+ac_cv_env_CPPFLAGS_value=$CPPFLAGS
+ac_env_CPP_set=${CPP+set}
+ac_env_CPP_value=$CPP
+ac_cv_env_CPP_set=${CPP+set}
+ac_cv_env_CPP_value=$CPP
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat <<_ACEOF
+\`configure' configures this package to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE. See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+ -h, --help display this help and exit
+ --help=short display options specific to this package
+ --help=recursive display the short help of all the included packages
+ -V, --version display version information and exit
+ -q, --quiet, --silent do not print \`checking...' messages
+ --cache-file=FILE cache test results in FILE [disabled]
+ -C, --config-cache alias for \`--cache-file=config.cache'
+ -n, --no-create do not create output files
+ --srcdir=DIR find the sources in DIR [configure dir or \`..']
+
+_ACEOF
+
+ cat <<_ACEOF
+Installation directories:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+ --bindir=DIR user executables [EPREFIX/bin]
+ --sbindir=DIR system admin executables [EPREFIX/sbin]
+ --libexecdir=DIR program executables [EPREFIX/libexec]
+ --datadir=DIR read-only architecture-independent data [PREFIX/share]
+ --sysconfdir=DIR read-only single-machine data [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data [PREFIX/var]
+ --libdir=DIR object code libraries [EPREFIX/lib]
+ --includedir=DIR C header files [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc [/usr/include]
+ --infodir=DIR info documentation [PREFIX/info]
+ --mandir=DIR man documentation [PREFIX/man]
+_ACEOF
+
+ cat <<\_ACEOF
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+
+ cat <<\_ACEOF
+
+Optional Features:
+ --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
+ --enable-FEATURE[=ARG] include FEATURE [ARG=yes]
+ --enable-oss audio via OSS
+ --enable-alsa audio via ALSA
+ --enable-jack audio via JACK
+ --enable-portaudio audio via PortAudio
+ --enable-portmidi MIDI via PortMidi
+ --enable-debug debugging support
+ --enable-static link statically
+ --enable-fftw use FFTW package
+
+Some influential environment variables:
+ CC C compiler command
+ CFLAGS C compiler flags
+ LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
+ nonstandard directory <lib dir>
+ CPPFLAGS C/C++ preprocessor flags, e.g. -I<include dir> if you have
+ headers in a nonstandard directory <include dir>
+ CPP C preprocessor
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+_ACEOF
+fi
+
+if test "$ac_init_help" = "recursive"; then
+ # If there are subdirs, report their specific --help.
+ ac_popdir=`pwd`
+ for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+ test -d $ac_dir || continue
+ ac_builddir=.
+
+if test "$ac_dir" != .; then
+ ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'`
+ # A "../" for each directory in $ac_dir_suffix.
+ ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'`
+else
+ ac_dir_suffix= ac_top_builddir=
+fi
+
+case $srcdir in
+ .) # No --srcdir option. We are building in place.
+ ac_srcdir=.
+ if test -z "$ac_top_builddir"; then
+ ac_top_srcdir=.
+ else
+ ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'`
+ fi ;;
+ [\\/]* | ?:[\\/]* ) # Absolute path.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir ;;
+ *) # Relative path.
+ ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_builddir$srcdir ;;
+esac
+
+# Do not use `cd foo && pwd` to compute absolute paths, because
+# the directories may not exist.
+case `pwd` in
+.) ac_abs_builddir="$ac_dir";;
+*)
+ case "$ac_dir" in
+ .) ac_abs_builddir=`pwd`;;
+ [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";;
+ *) ac_abs_builddir=`pwd`/"$ac_dir";;
+ esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_top_builddir=${ac_top_builddir}.;;
+*)
+ case ${ac_top_builddir}. in
+ .) ac_abs_top_builddir=$ac_abs_builddir;;
+ [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;;
+ *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;;
+ esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_srcdir=$ac_srcdir;;
+*)
+ case $ac_srcdir in
+ .) ac_abs_srcdir=$ac_abs_builddir;;
+ [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;;
+ *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;;
+ esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_top_srcdir=$ac_top_srcdir;;
+*)
+ case $ac_top_srcdir in
+ .) ac_abs_top_srcdir=$ac_abs_builddir;;
+ [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;;
+ *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;;
+ esac;;
+esac
+
+ cd $ac_dir
+ # Check for guested configure; otherwise get Cygnus style configure.
+ if test -f $ac_srcdir/configure.gnu; then
+ echo
+ $SHELL $ac_srcdir/configure.gnu --help=recursive
+ elif test -f $ac_srcdir/configure; then
+ echo
+ $SHELL $ac_srcdir/configure --help=recursive
+ elif test -f $ac_srcdir/configure.ac ||
+ test -f $ac_srcdir/configure.in; then
+ echo
+ $ac_configure --help
+ else
+ echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+ fi
+ cd "$ac_popdir"
+ done
+fi
+
+test -n "$ac_init_help" && exit 0
+if $ac_init_version; then
+ cat <<\_ACEOF
+
+Copyright (C) 2003 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+ exit 0
+fi
+exec 5>config.log
+cat >&5 <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by $as_me, which was
+generated by GNU Autoconf 2.59. Invocation command line was
+
+ $ $0 $@
+
+_ACEOF
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown`
+
+/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+hostinfo = `(hostinfo) 2>/dev/null || echo unknown`
+/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown`
+/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ echo "PATH: $as_dir"
+done
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_sep=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+ for ac_arg
+ do
+ case $ac_arg in
+ -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ continue ;;
+ *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*)
+ ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ case $ac_pass in
+ 1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;;
+ 2)
+ ac_configure_args1="$ac_configure_args1 '$ac_arg'"
+ if test $ac_must_keep_next = true; then
+ ac_must_keep_next=false # Got value, back to normal.
+ else
+ case $ac_arg in
+ *=* | --config-cache | -C | -disable-* | --disable-* \
+ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+ | -with-* | --with-* | -without-* | --without-* | --x)
+ case "$ac_configure_args0 " in
+ "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+ esac
+ ;;
+ -* ) ac_must_keep_next=true ;;
+ esac
+ fi
+ ac_configure_args="$ac_configure_args$ac_sep'$ac_arg'"
+ # Get rid of the leading space.
+ ac_sep=" "
+ ;;
+ esac
+ done
+done
+$as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; }
+$as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; }
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log. We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Be sure not to use single quotes in there, as some shells,
+# such as our DU 5.0 friend, will then `close' the trap.
+trap 'exit_status=$?
+ # Save into config.log some information that might help in debugging.
+ {
+ echo
+
+ cat <<\_ASBOX
+## ---------------- ##
+## Cache variables. ##
+## ---------------- ##
+_ASBOX
+ echo
+ # The following way of writing the cache mishandles newlines in values,
+{
+ (set) 2>&1 |
+ case `(ac_space='"'"' '"'"'; set | grep ac_space) 2>&1` in
+ *ac_space=\ *)
+ sed -n \
+ "s/'"'"'/'"'"'\\\\'"'"''"'"'/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='"'"'\\2'"'"'/p"
+ ;;
+ *)
+ sed -n \
+ "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p"
+ ;;
+ esac;
+}
+ echo
+
+ cat <<\_ASBOX
+## ----------------- ##
+## Output variables. ##
+## ----------------- ##
+_ASBOX
+ echo
+ for ac_var in $ac_subst_vars
+ do
+ eval ac_val=$`echo $ac_var`
+ echo "$ac_var='"'"'$ac_val'"'"'"
+ done | sort
+ echo
+
+ if test -n "$ac_subst_files"; then
+ cat <<\_ASBOX
+## ------------- ##
+## Output files. ##
+## ------------- ##
+_ASBOX
+ echo
+ for ac_var in $ac_subst_files
+ do
+ eval ac_val=$`echo $ac_var`
+ echo "$ac_var='"'"'$ac_val'"'"'"
+ done | sort
+ echo
+ fi
+
+ if test -s confdefs.h; then
+ cat <<\_ASBOX
+## ----------- ##
+## confdefs.h. ##
+## ----------- ##
+_ASBOX
+ echo
+ sed "/^$/d" confdefs.h | sort
+ echo
+ fi
+ test "$ac_signal" != 0 &&
+ echo "$as_me: caught signal $ac_signal"
+ echo "$as_me: exit $exit_status"
+ } >&5
+ rm -f core *.core &&
+ rm -rf conftest* confdefs* conf$$* $ac_clean_files &&
+ exit $exit_status
+ ' 0
+for ac_signal in 1 2 13 15; do
+ trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -rf conftest* confdefs.h
+# AIX cpp loses on an empty file, so make sure it contains at least a newline.
+echo >confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer explicitly selected file to automatically selected ones.
+if test -z "$CONFIG_SITE"; then
+ if test "x$prefix" != xNONE; then
+ CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site"
+ else
+ CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
+ fi
+fi
+for ac_site_file in $CONFIG_SITE; do
+ if test -r "$ac_site_file"; then
+ { echo "$as_me:$LINENO: loading site script $ac_site_file" >&5
+echo "$as_me: loading site script $ac_site_file" >&6;}
+ sed 's/^/| /' "$ac_site_file" >&5
+ . "$ac_site_file"
+ fi
+done
+
+if test -r "$cache_file"; then
+ # Some versions of bash will fail to source /dev/null (special
+ # files actually), so we avoid doing that.
+ if test -f "$cache_file"; then
+ { echo "$as_me:$LINENO: loading cache $cache_file" >&5
+echo "$as_me: loading cache $cache_file" >&6;}
+ case $cache_file in
+ [\\/]* | ?:[\\/]* ) . $cache_file;;
+ *) . ./$cache_file;;
+ esac
+ fi
+else
+ { echo "$as_me:$LINENO: creating cache $cache_file" >&5
+echo "$as_me: creating cache $cache_file" >&6;}
+ >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in `(set) 2>&1 |
+ sed -n 's/^ac_env_\([a-zA-Z_0-9]*\)_set=.*/\1/p'`; do
+ eval ac_old_set=\$ac_cv_env_${ac_var}_set
+ eval ac_new_set=\$ac_env_${ac_var}_set
+ eval ac_old_val="\$ac_cv_env_${ac_var}_value"
+ eval ac_new_val="\$ac_env_${ac_var}_value"
+ case $ac_old_set,$ac_new_set in
+ set,)
+ { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,set)
+ { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5
+echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,);;
+ *)
+ if test "x$ac_old_val" != "x$ac_new_val"; then
+ { echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5
+echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+ { echo "$as_me:$LINENO: former value: $ac_old_val" >&5
+echo "$as_me: former value: $ac_old_val" >&2;}
+ { echo "$as_me:$LINENO: current value: $ac_new_val" >&5
+echo "$as_me: current value: $ac_new_val" >&2;}
+ ac_cache_corrupted=:
+ fi;;
+ esac
+ # Pass precious variables to config.status.
+ if test "$ac_new_set" = set; then
+ case $ac_new_val in
+ *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*)
+ ac_arg=$ac_var=`echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+ *) ac_arg=$ac_var=$ac_new_val ;;
+ esac
+ case " $ac_configure_args " in
+ *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy.
+ *) ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+ esac
+ fi
+done
+if $ac_cache_corrupted; then
+ { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5
+echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+ { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5
+echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+oss=yes
+
+alsa=yes
+
+jack=yes
+
+portaudio=yes
+
+portmidi=yes
+
+fftw=yes
+
+
+
+
+USE_DEBUG_CFLAGS=no
+
+
+
+
+
+
+
+
+# Check whether --enable-alsa or --disable-alsa was given.
+if test "${enable_alsa+set}" = set; then
+ enableval="$enable_alsa"
+ alsa=$enableval
+fi;
+# Check whether --enable-alsa or --disable-alsa was given.
+if test "${enable_alsa+set}" = set; then
+ enableval="$enable_alsa"
+ alsa=$enableval
+fi;
+# Check whether --enable-jack or --disable-jack was given.
+if test "${enable_jack+set}" = set; then
+ enableval="$enable_jack"
+ jack=$enableval
+fi;
+# Check whether --enable-portaudio or --disable-portaudio was given.
+if test "${enable_portaudio+set}" = set; then
+ enableval="$enable_portaudio"
+ portaudio=$enableval
+fi;
+# Check whether --enable-portmidi or --disable-portmidi was given.
+if test "${enable_portmidi+set}" = set; then
+ enableval="$enable_portmidi"
+ portmidi=$enableval
+fi;
+# Check whether --enable-debug or --disable-debug was given.
+if test "${enable_debug+set}" = set; then
+ enableval="$enable_debug"
+ USE_DEBUG_CFLAGS=$enableval
+fi;
+# Check whether --enable-static or --disable-static was given.
+if test "${enable_static+set}" = set; then
+ enableval="$enable_static"
+ static=$enableval
+fi;
+# Check whether --enable-fftw or --disable-fftw was given.
+if test "${enable_fftw+set}" = set; then
+ enableval="$enable_fftw"
+ fftw=$enableval
+fi;
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}gcc"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+ ac_ct_CC=$CC
+ # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="gcc"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ CC=$ac_ct_CC
+else
+ CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}cc"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+ ac_ct_CC=$CC
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="cc"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ CC=$ac_ct_CC
+else
+ CC="$ac_cv_prog_CC"
+fi
+
+fi
+if test -z "$CC"; then
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+ ac_prog_rejected=yes
+ continue
+ fi
+ ac_cv_prog_CC="cc"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+if test $ac_prog_rejected = yes; then
+ # We found a bogon in the path, so make sure we never use it.
+ set dummy $ac_cv_prog_CC
+ shift
+ if test $# != 0; then
+ # We chose a different compiler from the bogus one.
+ # However, it has the same basename, so the bogon will be chosen
+ # first if we set CC to just the basename; use the full file name.
+ shift
+ ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+ fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ for ac_prog in cl
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ test -n "$CC" && break
+ done
+fi
+if test -z "$CC"; then
+ ac_ct_CC=$CC
+ for ac_prog in cl
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="$ac_prog"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ test -n "$ac_ct_CC" && break
+done
+
+ CC=$ac_ct_CC
+fi
+
+fi
+
+
+test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH
+See \`config.log' for more details." >&5
+echo "$as_me: error: no acceptable C compiler found in \$PATH
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+
+# Provide some information about the compiler.
+echo "$as_me:$LINENO:" \
+ "checking for C compiler version" >&5
+ac_compiler=`set X $ac_compile; echo $2`
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler --version </dev/null >&5\"") >&5
+ (eval $ac_compiler --version </dev/null >&5) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler -v </dev/null >&5\"") >&5
+ (eval $ac_compiler -v </dev/null >&5) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler -V </dev/null >&5\"") >&5
+ (eval $ac_compiler -V </dev/null >&5) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.exe b.out"
+# Try to create an executable without -o first, disregard a.out.
+# It will help us diagnose broken compilers, and finding out an intuition
+# of exeext.
+echo "$as_me:$LINENO: checking for C compiler default output file name" >&5
+echo $ECHO_N "checking for C compiler default output file name... $ECHO_C" >&6
+ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+if { (eval echo "$as_me:$LINENO: \"$ac_link_default\"") >&5
+ (eval $ac_link_default) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ # Find the output, starting from the most likely. This scheme is
+# not robust to junk in `.', hence go to wildcards (a.*) only as a last
+# resort.
+
+# Be careful to initialize this variable, since it used to be cached.
+# Otherwise an old cache value of `no' led to `EXEEXT = no' in a Makefile.
+ac_cv_exeext=
+# b.out is created by i960 compilers.
+for ac_file in a_out.exe a.exe conftest.exe a.out conftest a.* conftest.* b.out
+do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj )
+ ;;
+ conftest.$ac_ext )
+ # This is the source file.
+ ;;
+ [ab].out )
+ # We found the default executable, but exeext='' is most
+ # certainly right.
+ break;;
+ *.* )
+ ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ # FIXME: I believe we export ac_cv_exeext for Libtool,
+ # but it would be cool to find out if it's true. Does anybody
+ # maintain Libtool? --akim.
+ export ac_cv_exeext
+ break;;
+ * )
+ break;;
+ esac
+done
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { echo "$as_me:$LINENO: error: C compiler cannot create executables
+See \`config.log' for more details." >&5
+echo "$as_me: error: C compiler cannot create executables
+See \`config.log' for more details." >&2;}
+ { (exit 77); exit 77; }; }
+fi
+
+ac_exeext=$ac_cv_exeext
+echo "$as_me:$LINENO: result: $ac_file" >&5
+echo "${ECHO_T}$ac_file" >&6
+
+# Check the compiler produces executables we can run. If not, either
+# the compiler is broken, or we cross compile.
+echo "$as_me:$LINENO: checking whether the C compiler works" >&5
+echo $ECHO_N "checking whether the C compiler works... $ECHO_C" >&6
+# FIXME: These cross compiler hacks should be removed for Autoconf 3.0
+# If not cross compiling, check that we can run a simple program.
+if test "$cross_compiling" != yes; then
+ if { ac_try='./$ac_file'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ cross_compiling=no
+ else
+ if test "$cross_compiling" = maybe; then
+ cross_compiling=yes
+ else
+ { { echo "$as_me:$LINENO: error: cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+ fi
+ fi
+fi
+echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+
+rm -f a.out a.exe conftest$ac_cv_exeext b.out
+ac_clean_files=$ac_clean_files_save
+# Check the compiler produces executables we can run. If not, either
+# the compiler is broken, or we cross compile.
+echo "$as_me:$LINENO: checking whether we are cross compiling" >&5
+echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6
+echo "$as_me:$LINENO: result: $cross_compiling" >&5
+echo "${ECHO_T}$cross_compiling" >&6
+
+echo "$as_me:$LINENO: checking for suffix of executables" >&5
+echo $ECHO_N "checking for suffix of executables... $ECHO_C" >&6
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ # If both `conftest.exe' and `conftest' are `present' (well, observable)
+# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will
+# work properly (i.e., refer to `conftest.exe'), while it won't with
+# `rm'.
+for ac_file in conftest.exe conftest conftest.*; do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj ) ;;
+ *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ export ac_cv_exeext
+ break;;
+ * ) break;;
+ esac
+done
+else
+ { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+rm -f conftest$ac_cv_exeext
+echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5
+echo "${ECHO_T}$ac_cv_exeext" >&6
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+echo "$as_me:$LINENO: checking for suffix of object files" >&5
+echo $ECHO_N "checking for suffix of object files... $ECHO_C" >&6
+if test "${ac_cv_objext+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.o conftest.obj
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ for ac_file in `(ls conftest.o conftest.obj; ls conftest.*) 2>/dev/null`; do
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg ) ;;
+ *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+ break;;
+ esac
+done
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute suffix of object files: cannot compile
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_objext" >&5
+echo "${ECHO_T}$ac_cv_objext" >&6
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5
+echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6
+if test "${ac_cv_c_compiler_gnu+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+#ifndef __GNUC__
+ choke me
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_compiler_gnu=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_compiler_gnu=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5
+echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6
+GCC=`test $ac_compiler_gnu = yes && echo yes`
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+CFLAGS="-g"
+echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5
+echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6
+if test "${ac_cv_prog_cc_g+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_prog_cc_g=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_prog_cc_g=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5
+echo "${ECHO_T}$ac_cv_prog_cc_g" >&6
+if test "$ac_test_CFLAGS" = set; then
+ CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+ if test "$GCC" = yes; then
+ CFLAGS="-g -O2"
+ else
+ CFLAGS="-g"
+ fi
+else
+ if test "$GCC" = yes; then
+ CFLAGS="-O2"
+ else
+ CFLAGS=
+ fi
+fi
+echo "$as_me:$LINENO: checking for $CC option to accept ANSI C" >&5
+echo $ECHO_N "checking for $CC option to accept ANSI C... $ECHO_C" >&6
+if test "${ac_cv_prog_cc_stdc+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_prog_cc_stdc=no
+ac_save_CC=$CC
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+ char **p;
+ int i;
+{
+ return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+ char *s;
+ va_list v;
+ va_start (v,p);
+ s = g (p, va_arg (v,int));
+ va_end (v);
+ return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has
+ function prototypes and stuff, but not '\xHH' hex character constants.
+ These don't provoke an error unfortunately, instead are silently treated
+ as 'x'. The following induces an error, until -std1 is added to get
+ proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an
+ array size at least. It's necessary to write '\x00'==0 to get something
+ that's true only with -std1. */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1];
+ ;
+ return 0;
+}
+_ACEOF
+# Don't try gcc -ansi; that turns off useful extensions and
+# breaks some systems' header files.
+# AIX -qlanglvl=ansi
+# Ultrix and OSF/1 -std1
+# HP-UX 10.20 and later -Ae
+# HP-UX older versions -Aa -D_HPUX_SOURCE
+# SVR4 -Xc -D__EXTENSIONS__
+for ac_arg in "" -qlanglvl=ansi -std1 -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+ CC="$ac_save_CC $ac_arg"
+ rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_prog_cc_stdc=$ac_arg
+break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext
+done
+rm -f conftest.$ac_ext conftest.$ac_objext
+CC=$ac_save_CC
+
+fi
+
+case "x$ac_cv_prog_cc_stdc" in
+ x|xno)
+ echo "$as_me:$LINENO: result: none needed" >&5
+echo "${ECHO_T}none needed" >&6 ;;
+ *)
+ echo "$as_me:$LINENO: result: $ac_cv_prog_cc_stdc" >&5
+echo "${ECHO_T}$ac_cv_prog_cc_stdc" >&6
+ CC="$CC $ac_cv_prog_cc_stdc" ;;
+esac
+
+# Some people use a C++ compiler to compile C. Since we use `exit',
+# in C++ we need to declare it. In case someone uses the same compiler
+# for both compiling C and C++ we need to have the C++ compiler decide
+# the declaration of exit, since it's the most demanding environment.
+cat >conftest.$ac_ext <<_ACEOF
+#ifndef __cplusplus
+ choke me
+#endif
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ for ac_declaration in \
+ '' \
+ 'extern "C" void std::exit (int) throw (); using std::exit;' \
+ 'extern "C" void std::exit (int); using std::exit;' \
+ 'extern "C" void exit (int) throw ();' \
+ 'extern "C" void exit (int);' \
+ 'void exit (int);'
+do
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_declaration
+#include <stdlib.h>
+int
+main ()
+{
+exit (42);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ :
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+continue
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_declaration
+int
+main ()
+{
+exit (42);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+rm -f conftest*
+if test -n "$ac_declaration"; then
+ echo '#ifdef __cplusplus' >>confdefs.h
+ echo $ac_declaration >>confdefs.h
+ echo '#endif' >>confdefs.h
+fi
+
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+ac_aux_dir=
+for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do
+ if test -f $ac_dir/install-sh; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install-sh -c"
+ break
+ elif test -f $ac_dir/install.sh; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install.sh -c"
+ break
+ elif test -f $ac_dir/shtool; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/shtool install -c"
+ break
+ fi
+done
+if test -z "$ac_aux_dir"; then
+ { { echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&5
+echo "$as_me: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+ac_config_guess="$SHELL $ac_aux_dir/config.guess"
+ac_config_sub="$SHELL $ac_aux_dir/config.sub"
+ac_configure="$SHELL $ac_aux_dir/configure" # This should be Cygnus configure.
+
+# Find a good install program. We prefer a C program (faster),
+# so one script is as good as another. But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AmigaOS /C/install, which installs bootblocks on floppy discs
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# OS/2's system install, which has a completely different semantic
+# ./install, which can be erroneously created by make from ./install.sh.
+echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5
+echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6
+if test -z "$INSTALL"; then
+if test "${ac_cv_path_install+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ # Account for people who put trailing slashes in PATH elements.
+case $as_dir/ in
+ ./ | .// | /cC/* | \
+ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \
+ ?:\\/os2\\/install\\/* | ?:\\/OS2\\/INSTALL\\/* | \
+ /usr/ucb/* ) ;;
+ *)
+ # OSF1 and SCO ODT 3.0 have their own names for install.
+ # Don't use installbsd from OSF since it installs stuff as root
+ # by default.
+ for ac_prog in ginstall scoinst install; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then
+ if test $ac_prog = install &&
+ grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+ # AIX install. It has an incompatible calling convention.
+ :
+ elif test $ac_prog = install &&
+ grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+ # program-specific install script used by HP pwplus--don't use.
+ :
+ else
+ ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c"
+ break 3
+ fi
+ fi
+ done
+ done
+ ;;
+esac
+done
+
+
+fi
+ if test "${ac_cv_path_install+set}" = set; then
+ INSTALL=$ac_cv_path_install
+ else
+ # As a last resort, use the slow shell script. We don't cache a
+ # path for INSTALL within a source directory, because that will
+ # break other packages using the cache if that directory is
+ # removed, or if the path is relative.
+ INSTALL=$ac_install_sh
+ fi
+fi
+echo "$as_me:$LINENO: result: $INSTALL" >&5
+echo "${ECHO_T}$INSTALL" >&6
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+echo "$as_me:$LINENO: checking whether ${MAKE-make} sets \$(MAKE)" >&5
+echo $ECHO_N "checking whether ${MAKE-make} sets \$(MAKE)... $ECHO_C" >&6
+set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y,:./+-,___p_,'`
+if eval "test \"\${ac_cv_prog_make_${ac_make}_set+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.make <<\_ACEOF
+all:
+ @echo 'ac_maketemp="$(MAKE)"'
+_ACEOF
+# GNU make sometimes prints "make[1]: Entering...", which would confuse us.
+eval `${MAKE-make} -f conftest.make 2>/dev/null | grep temp=`
+if test -n "$ac_maketemp"; then
+ eval ac_cv_prog_make_${ac_make}_set=yes
+else
+ eval ac_cv_prog_make_${ac_make}_set=no
+fi
+rm -f conftest.make
+fi
+if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+ SET_MAKE=
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+ SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5
+echo $ECHO_N "checking how to run the C preprocessor... $ECHO_C" >&6
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+ CPP=
+fi
+if test -z "$CPP"; then
+ if test "${ac_cv_prog_CPP+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ # Double quotes because CPP needs to be expanded
+ for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
+ do
+ ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ :
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether non-existent headers
+ # can be detected and how.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ # Broken: success on invalid input.
+continue
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then
+ break
+fi
+
+ done
+ ac_cv_prog_CPP=$CPP
+
+fi
+ CPP=$ac_cv_prog_CPP
+else
+ ac_cv_prog_CPP=$CPP
+fi
+echo "$as_me:$LINENO: result: $CPP" >&5
+echo "${ECHO_T}$CPP" >&6
+ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ :
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether non-existent headers
+ # can be detected and how.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ # Broken: success on invalid input.
+continue
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then
+ :
+else
+ { { echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details." >&5
+echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+echo "$as_me:$LINENO: checking for an ANSI C-conforming const" >&5
+echo $ECHO_N "checking for an ANSI C-conforming const... $ECHO_C" >&6
+if test "${ac_cv_c_const+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+/* FIXME: Include the comments suggested by Paul. */
+#ifndef __cplusplus
+ /* Ultrix mips cc rejects this. */
+ typedef int charset[2];
+ const charset x;
+ /* SunOS 4.1.1 cc rejects this. */
+ char const *const *ccp;
+ char **p;
+ /* NEC SVR4.0.2 mips cc rejects this. */
+ struct point {int x, y;};
+ static struct point const zero = {0,0};
+ /* AIX XL C 1.02.0.0 rejects this.
+ It does not let you subtract one const X* pointer from another in
+ an arm of an if-expression whose if-part is not a constant
+ expression */
+ const char *g = "string";
+ ccp = &g + (g ? g-g : 0);
+ /* HPUX 7.0 cc rejects these. */
+ ++ccp;
+ p = (char**) ccp;
+ ccp = (char const *const *) p;
+ { /* SCO 3.2v4 cc rejects this. */
+ char *t;
+ char const *s = 0 ? (char *) 0 : (char const *) 0;
+
+ *t++ = 0;
+ }
+ { /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */
+ int x[] = {25, 17};
+ const int *foo = &x[0];
+ ++foo;
+ }
+ { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */
+ typedef const int *iptr;
+ iptr p = 0;
+ ++p;
+ }
+ { /* AIX XL C 1.02.0.0 rejects this saying
+ "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */
+ struct s { int j; const int *ap[3]; };
+ struct s *b; b->j = 5;
+ }
+ { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */
+ const int foo = 10;
+ }
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_c_const=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_c_const=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_c_const" >&5
+echo "${ECHO_T}$ac_cv_c_const" >&6
+if test $ac_cv_c_const = no; then
+
+cat >>confdefs.h <<\_ACEOF
+#define const
+_ACEOF
+
+fi
+
+
+echo "$as_me:$LINENO: checking for egrep" >&5
+echo $ECHO_N "checking for egrep... $ECHO_C" >&6
+if test "${ac_cv_prog_egrep+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if echo a | (grep -E '(a|b)') >/dev/null 2>&1
+ then ac_cv_prog_egrep='grep -E'
+ else ac_cv_prog_egrep='egrep'
+ fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_prog_egrep" >&5
+echo "${ECHO_T}$ac_cv_prog_egrep" >&6
+ EGREP=$ac_cv_prog_egrep
+
+
+echo "$as_me:$LINENO: checking for ANSI C header files" >&5
+echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6
+if test "${ac_cv_header_stdc+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_header_stdc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_header_stdc=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+if test $ac_cv_header_stdc = yes; then
+ # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <string.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "memchr" >/dev/null 2>&1; then
+ :
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdlib.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "free" >/dev/null 2>&1; then
+ :
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+ if test "$cross_compiling" = yes; then
+ :
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <ctype.h>
+#if ((' ' & 0x0FF) == 0x020)
+# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#else
+# define ISLOWER(c) \
+ (('a' <= (c) && (c) <= 'i') \
+ || ('j' <= (c) && (c) <= 'r') \
+ || ('s' <= (c) && (c) <= 'z'))
+# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
+#endif
+
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int
+main ()
+{
+ int i;
+ for (i = 0; i < 256; i++)
+ if (XOR (islower (i), ISLOWER (i))
+ || toupper (i) != TOUPPER (i))
+ exit(2);
+ exit (0);
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ :
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+ac_cv_header_stdc=no
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5
+echo "${ECHO_T}$ac_cv_header_stdc" >&6
+if test $ac_cv_header_stdc = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define STDC_HEADERS 1
+_ACEOF
+
+fi
+
+# On IRIX 5.3, sys/types and inttypes.h are conflicting.
+
+
+
+
+
+
+
+
+
+for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \
+ inttypes.h stdint.h unistd.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_Header=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_Header=no"
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+echo "$as_me:$LINENO: checking for pid_t" >&5
+echo $ECHO_N "checking for pid_t... $ECHO_C" >&6
+if test "${ac_cv_type_pid_t+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+if ((pid_t *) 0)
+ return 0;
+if (sizeof (pid_t))
+ return 0;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_type_pid_t=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_type_pid_t=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_type_pid_t" >&5
+echo "${ECHO_T}$ac_cv_type_pid_t" >&6
+if test $ac_cv_type_pid_t = yes; then
+ :
+else
+
+cat >>confdefs.h <<_ACEOF
+#define pid_t int
+_ACEOF
+
+fi
+
+echo "$as_me:$LINENO: checking for size_t" >&5
+echo $ECHO_N "checking for size_t... $ECHO_C" >&6
+if test "${ac_cv_type_size_t+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+if ((size_t *) 0)
+ return 0;
+if (sizeof (size_t))
+ return 0;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_type_size_t=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_type_size_t=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_type_size_t" >&5
+echo "${ECHO_T}$ac_cv_type_size_t" >&6
+if test $ac_cv_type_size_t = yes; then
+ :
+else
+
+cat >>confdefs.h <<_ACEOF
+#define size_t unsigned
+_ACEOF
+
+fi
+
+echo "$as_me:$LINENO: checking whether time.h and sys/time.h may both be included" >&5
+echo $ECHO_N "checking whether time.h and sys/time.h may both be included... $ECHO_C" >&6
+if test "${ac_cv_header_time+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <sys/types.h>
+#include <sys/time.h>
+#include <time.h>
+
+int
+main ()
+{
+if ((struct tm *) 0)
+return 0;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_header_time=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_header_time=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_time" >&5
+echo "${ECHO_T}$ac_cv_header_time" >&6
+if test $ac_cv_header_time = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define TIME_WITH_SYS_TIME 1
+_ACEOF
+
+fi
+
+
+echo "$as_me:$LINENO: checking for ANSI C header files" >&5
+echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6
+if test "${ac_cv_header_stdc+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_header_stdc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_header_stdc=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+if test $ac_cv_header_stdc = yes; then
+ # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <string.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "memchr" >/dev/null 2>&1; then
+ :
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdlib.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "free" >/dev/null 2>&1; then
+ :
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+ if test "$cross_compiling" = yes; then
+ :
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <ctype.h>
+#if ((' ' & 0x0FF) == 0x020)
+# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#else
+# define ISLOWER(c) \
+ (('a' <= (c) && (c) <= 'i') \
+ || ('j' <= (c) && (c) <= 'r') \
+ || ('s' <= (c) && (c) <= 'z'))
+# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
+#endif
+
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int
+main ()
+{
+ int i;
+ for (i = 0; i < 256; i++)
+ if (XOR (islower (i), ISLOWER (i))
+ || toupper (i) != TOUPPER (i))
+ exit(2);
+ exit (0);
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ :
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+ac_cv_header_stdc=no
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5
+echo "${ECHO_T}$ac_cv_header_stdc" >&6
+if test $ac_cv_header_stdc = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define STDC_HEADERS 1
+_ACEOF
+
+fi
+
+
+
+
+
+
+
+
+for ac_header in fcntl.h limits.h malloc.h sys/ioctl.h sys/time.h unistd.h bstring.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+ yes:no: )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+ ac_header_preproc=yes
+ ;;
+ no:yes:* )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+ (
+ cat <<\_ASBOX
+## ------------------------------------------ ##
+## Report this to the AC_PACKAGE_NAME lists. ##
+## ------------------------------------------ ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+if test $ac_cv_c_compiler_gnu = yes; then
+ echo "$as_me:$LINENO: checking whether $CC needs -traditional" >&5
+echo $ECHO_N "checking whether $CC needs -traditional... $ECHO_C" >&6
+if test "${ac_cv_prog_gcc_traditional+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_pattern="Autoconf.*'x'"
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <sgtty.h>
+Autoconf TIOCGETP
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "$ac_pattern" >/dev/null 2>&1; then
+ ac_cv_prog_gcc_traditional=yes
+else
+ ac_cv_prog_gcc_traditional=no
+fi
+rm -f conftest*
+
+
+ if test $ac_cv_prog_gcc_traditional = no; then
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <termio.h>
+Autoconf TCGETA
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "$ac_pattern" >/dev/null 2>&1; then
+ ac_cv_prog_gcc_traditional=yes
+fi
+rm -f conftest*
+
+ fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_prog_gcc_traditional" >&5
+echo "${ECHO_T}$ac_cv_prog_gcc_traditional" >&6
+ if test $ac_cv_prog_gcc_traditional = yes; then
+ CC="$CC -traditional"
+ fi
+fi
+
+echo "$as_me:$LINENO: checking return type of signal handlers" >&5
+echo $ECHO_N "checking return type of signal handlers... $ECHO_C" >&6
+if test "${ac_cv_type_signal+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <sys/types.h>
+#include <signal.h>
+#ifdef signal
+# undef signal
+#endif
+#ifdef __cplusplus
+extern "C" void (*signal (int, void (*)(int)))(int);
+#else
+void (*signal ()) ();
+#endif
+
+int
+main ()
+{
+int i;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_type_signal=void
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_type_signal=int
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_type_signal" >&5
+echo "${ECHO_T}$ac_cv_type_signal" >&6
+
+cat >>confdefs.h <<_ACEOF
+#define RETSIGTYPE $ac_cv_type_signal
+_ACEOF
+
+
+
+for ac_func in vprintf
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+echo "$as_me:$LINENO: checking for _doprnt" >&5
+echo $ECHO_N "checking for _doprnt... $ECHO_C" >&6
+if test "${ac_cv_func__doprnt+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define _doprnt to an innocuous variant, in case <limits.h> declares _doprnt.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define _doprnt innocuous__doprnt
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char _doprnt (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef _doprnt
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char _doprnt ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub__doprnt) || defined (__stub____doprnt)
+choke me
+#else
+char (*f) () = _doprnt;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != _doprnt;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func__doprnt=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func__doprnt=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func__doprnt" >&5
+echo "${ECHO_T}$ac_cv_func__doprnt" >&6
+if test $ac_cv_func__doprnt = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_DOPRNT 1
+_ACEOF
+
+fi
+
+fi
+done
+
+
+
+
+
+
+for ac_func in gettimeofday select socket strerror
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+# The Ultrix 4.2 mips builtin alloca declared by alloca.h only works
+# for constant arguments. Useless!
+echo "$as_me:$LINENO: checking for working alloca.h" >&5
+echo $ECHO_N "checking for working alloca.h... $ECHO_C" >&6
+if test "${ac_cv_working_alloca_h+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <alloca.h>
+int
+main ()
+{
+char *p = (char *) alloca (2 * sizeof (int));
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_working_alloca_h=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_working_alloca_h=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_working_alloca_h" >&5
+echo "${ECHO_T}$ac_cv_working_alloca_h" >&6
+if test $ac_cv_working_alloca_h = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_ALLOCA_H 1
+_ACEOF
+
+fi
+
+echo "$as_me:$LINENO: checking for alloca" >&5
+echo $ECHO_N "checking for alloca... $ECHO_C" >&6
+if test "${ac_cv_func_alloca_works+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#ifdef __GNUC__
+# define alloca __builtin_alloca
+#else
+# ifdef _MSC_VER
+# include <malloc.h>
+# define alloca _alloca
+# else
+# if HAVE_ALLOCA_H
+# include <alloca.h>
+# else
+# ifdef _AIX
+ #pragma alloca
+# else
+# ifndef alloca /* predefined by HP cc +Olibcalls */
+char *alloca ();
+# endif
+# endif
+# endif
+# endif
+#endif
+
+int
+main ()
+{
+char *p = (char *) alloca (1);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_alloca_works=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_alloca_works=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_alloca_works" >&5
+echo "${ECHO_T}$ac_cv_func_alloca_works" >&6
+
+if test $ac_cv_func_alloca_works = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_ALLOCA 1
+_ACEOF
+
+else
+ # The SVR3 libPW and SVR4 libucb both contain incompatible functions
+# that cause trouble. Some versions do not even contain alloca or
+# contain a buggy version. If you still want to use their alloca,
+# use ar to extract alloca.o from them instead of compiling alloca.c.
+
+ALLOCA=alloca.$ac_objext
+
+cat >>confdefs.h <<\_ACEOF
+#define C_ALLOCA 1
+_ACEOF
+
+
+echo "$as_me:$LINENO: checking whether \`alloca.c' needs Cray hooks" >&5
+echo $ECHO_N "checking whether \`alloca.c' needs Cray hooks... $ECHO_C" >&6
+if test "${ac_cv_os_cray+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#if defined(CRAY) && ! defined(CRAY2)
+webecray
+#else
+wenotbecray
+#endif
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "webecray" >/dev/null 2>&1; then
+ ac_cv_os_cray=yes
+else
+ ac_cv_os_cray=no
+fi
+rm -f conftest*
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_os_cray" >&5
+echo "${ECHO_T}$ac_cv_os_cray" >&6
+if test $ac_cv_os_cray = yes; then
+ for ac_func in _getb67 GETB67 getb67; do
+ as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define CRAY_STACKSEG_END $ac_func
+_ACEOF
+
+ break
+fi
+
+ done
+fi
+
+echo "$as_me:$LINENO: checking stack direction for C alloca" >&5
+echo $ECHO_N "checking stack direction for C alloca... $ECHO_C" >&6
+if test "${ac_cv_c_stack_direction+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test "$cross_compiling" = yes; then
+ ac_cv_c_stack_direction=0
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+int
+find_stack_direction ()
+{
+ static char *addr = 0;
+ auto char dummy;
+ if (addr == 0)
+ {
+ addr = &dummy;
+ return find_stack_direction ();
+ }
+ else
+ return (&dummy > addr) ? 1 : -1;
+}
+
+int
+main ()
+{
+ exit (find_stack_direction () < 0);
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_c_stack_direction=1
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+ac_cv_c_stack_direction=-1
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_c_stack_direction" >&5
+echo "${ECHO_T}$ac_cv_c_stack_direction" >&6
+
+cat >>confdefs.h <<_ACEOF
+#define STACK_DIRECTION $ac_cv_c_stack_direction
+_ACEOF
+
+
+fi
+
+
+# audio APIs may accumulate, but there must be only one MIDI API (??)
+AUDIOSRC=""
+MIDISRC="s_midi_none.c"
+
+if test `uname -s` = Linux; then
+ LDFLAGS="-Wl,-export-dynamic "
+ EXT=pd_linux
+ LIBSUFFIX=.so
+ CPPFLAGS="-DDL_OPEN -DPA_USE_OSS -DUNIX -DUNISTD"
+ MORECFLAGS="-fno-strict-aliasing"
+ STRIPFLAG=-s
+ LDSOFLAGS="-shared"
+fi
+
+if test `uname -s` = Darwin; then
+ LDFLAGS=""
+ EXT=pd_darwin
+ LIBSUFFIX=.dylib
+ CPPFLAGS="-DMACOSX -DUNISTD -I/usr/X11R6/include -DPA_USE_COREAUDIO"
+ CPPFLAGS=$CPPFLAGS" -DDL_OPEN" # 0.40
+ MORECFLAGS=""
+ STRIPFLAG=""
+# LDSOFLAGS="-dylib -bundle -flat_namespace -undefined suppress"
+# LDSOFLAGS="-dylib -flat_namespace"
+# Charles Turner told me to use this:
+ LDSOFLAGS="-dynamiclib -Wl,-single_module"
+ EXTERNTARGET=pd_darwin
+### this comes from pd 0.40
+# if test `uname -r` = 7.9.0; then
+# CPPFLAGS=$CPPFLAGS" -DMACOSX3"
+# EXTERNTARGET=d_ppc
+# else
+# CPPFLAGS=$CPPFLAGS" -isysroot /Developer/SDKs/MacOSX10.4u.sdk"
+# MORECFLAGS=$MORECFLAGS" -arch i386 -arch ppc"
+# EXTERNTARGET=d_fat
+# LDFLAGS=$LDFLAGS" -arch i386 -arch ppc"
+# fi
+fi
+
+if test `uname -s | cut -f1 -d_` = CYGWIN; then
+ LDFLAGS="-Wl,-export-dynamic "
+ EXT=pd_linux
+ LIBSUFFIX=.dll
+ CPPFLAGS="-DDL_OPEN -DPA_USE_OSS -DUNIX -DUNISTD"
+ MORECFLAGS="-fno-strict-aliasing"
+ STRIPFLAG=-s
+ LDSOFLAGS="-shared"
+fi
+
+if test `uname -m` = x86_64; then
+ MORECFLAGS=$MORECFLAGS" -fPIC"
+fi
+
+if test "$static" = yes; then LDFLAGS="$LDFLAGS -static"; fi
+
+echo "$as_me:$LINENO: checking for dlopen in -ldl" >&5
+echo $ECHO_N "checking for dlopen in -ldl... $ECHO_C" >&6
+if test "${ac_cv_lib_dl_dlopen+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldl $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char dlopen ();
+int
+main ()
+{
+dlopen ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_dl_dlopen=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_dl_dlopen=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_dl_dlopen" >&5
+echo "${ECHO_T}$ac_cv_lib_dl_dlopen" >&6
+if test $ac_cv_lib_dl_dlopen = yes; then
+ LDFLAGS="$LDFLAGS -ldl"
+else
+ echo "dynamic link support required" || exit 1
+fi
+
+echo "$as_me:$LINENO: checking for sin in -lffm" >&5
+echo $ECHO_N "checking for sin in -lffm... $ECHO_C" >&6
+if test "${ac_cv_lib_ffm_sin+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lffm $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char sin ();
+int
+main ()
+{
+sin ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_ffm_sin=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_ffm_sin=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_ffm_sin" >&5
+echo "${ECHO_T}$ac_cv_lib_ffm_sin" >&6
+if test $ac_cv_lib_ffm_sin = yes; then
+ LDFLAGS="$LDFLAGS -lffm"
+fi
+
+echo "$as_me:$LINENO: checking for sin in -lm" >&5
+echo $ECHO_N "checking for sin in -lm... $ECHO_C" >&6
+if test "${ac_cv_lib_m_sin+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lm $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char sin ();
+int
+main ()
+{
+sin ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_m_sin=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_m_sin=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_m_sin" >&5
+echo "${ECHO_T}$ac_cv_lib_m_sin" >&6
+if test $ac_cv_lib_m_sin = yes; then
+ LDFLAGS="$LDFLAGS -lm"
+else
+ echo "math library required" || exit 1
+fi
+
+echo "$as_me:$LINENO: checking for pthread_create in -lpthread" >&5
+echo $ECHO_N "checking for pthread_create in -lpthread... $ECHO_C" >&6
+if test "${ac_cv_lib_pthread_pthread_create+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lpthread $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char pthread_create ();
+int
+main ()
+{
+pthread_create ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_pthread_pthread_create=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_pthread_pthread_create=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_pthread_pthread_create" >&5
+echo "${ECHO_T}$ac_cv_lib_pthread_pthread_create" >&6
+if test $ac_cv_lib_pthread_pthread_create = yes; then
+ LDFLAGS="$LDFLAGS -lpthread"
+else
+ echo "pthreads required" || exit 1
+fi
+
+
+if test x$oss == xyes; then
+ if test "${ac_cv_header_linux_soundcard_h+set}" = set; then
+ echo "$as_me:$LINENO: checking for linux/soundcard.h" >&5
+echo $ECHO_N "checking for linux/soundcard.h... $ECHO_C" >&6
+if test "${ac_cv_header_linux_soundcard_h+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_linux_soundcard_h" >&5
+echo "${ECHO_T}$ac_cv_header_linux_soundcard_h" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking linux/soundcard.h usability" >&5
+echo $ECHO_N "checking linux/soundcard.h usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <linux/soundcard.h>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking linux/soundcard.h presence" >&5
+echo $ECHO_N "checking linux/soundcard.h presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <linux/soundcard.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+ yes:no: )
+ { echo "$as_me:$LINENO: WARNING: linux/soundcard.h: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: linux/soundcard.h: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: linux/soundcard.h: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: linux/soundcard.h: proceeding with the compiler's result" >&2;}
+ ac_header_preproc=yes
+ ;;
+ no:yes:* )
+ { echo "$as_me:$LINENO: WARNING: linux/soundcard.h: present but cannot be compiled" >&5
+echo "$as_me: WARNING: linux/soundcard.h: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: linux/soundcard.h: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: linux/soundcard.h: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: linux/soundcard.h: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: linux/soundcard.h: see the Autoconf documentation" >&2;}
+ { echo "$as_me:$LINENO: WARNING: linux/soundcard.h: section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: linux/soundcard.h: section \"Present But Cannot Be Compiled\"" >&2;}
+ { echo "$as_me:$LINENO: WARNING: linux/soundcard.h: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: linux/soundcard.h: proceeding with the preprocessor's result" >&2;}
+ { echo "$as_me:$LINENO: WARNING: linux/soundcard.h: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: linux/soundcard.h: in the future, the compiler will take precedence" >&2;}
+ (
+ cat <<\_ASBOX
+## ------------------------------------------ ##
+## Report this to the AC_PACKAGE_NAME lists. ##
+## ------------------------------------------ ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for linux/soundcard.h" >&5
+echo $ECHO_N "checking for linux/soundcard.h... $ECHO_C" >&6
+if test "${ac_cv_header_linux_soundcard_h+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_header_linux_soundcard_h=$ac_header_preproc
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_linux_soundcard_h" >&5
+echo "${ECHO_T}$ac_cv_header_linux_soundcard_h" >&6
+
+fi
+if test $ac_cv_header_linux_soundcard_h = yes; then
+ oss="yes"
+else
+ oss="no"
+fi
+
+
+fi
+
+if test x$alsa == xyes; then
+ echo "$as_me:$LINENO: checking for snd_pcm_info in -lasound" >&5
+echo $ECHO_N "checking for snd_pcm_info in -lasound... $ECHO_C" >&6
+if test "${ac_cv_lib_asound_snd_pcm_info+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lasound $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char snd_pcm_info ();
+int
+main ()
+{
+snd_pcm_info ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_asound_snd_pcm_info=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_asound_snd_pcm_info=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_asound_snd_pcm_info" >&5
+echo "${ECHO_T}$ac_cv_lib_asound_snd_pcm_info" >&6
+if test $ac_cv_lib_asound_snd_pcm_info = yes; then
+ LDFLAGS="$LDFLAGS -lasound" ; alsa="yes"
+else
+ alsa="no"
+fi
+
+fi
+
+if test x$jack == xyes; then
+ echo "$as_me:$LINENO: checking for shm_open in -lrt" >&5
+echo $ECHO_N "checking for shm_open in -lrt... $ECHO_C" >&6
+if test "${ac_cv_lib_rt_shm_open+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lrt $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char shm_open ();
+int
+main ()
+{
+shm_open ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_rt_shm_open=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_rt_shm_open=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_rt_shm_open" >&5
+echo "${ECHO_T}$ac_cv_lib_rt_shm_open" >&6
+if test $ac_cv_lib_rt_shm_open = yes; then
+ LIBS="$LIBS -lrt"
+fi
+
+ echo "$as_me:$LINENO: checking for jack_set_xrun_callback in -ljack" >&5
+echo $ECHO_N "checking for jack_set_xrun_callback in -ljack... $ECHO_C" >&6
+if test "${ac_cv_lib_jack_jack_set_xrun_callback+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ljack $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char jack_set_xrun_callback ();
+int
+main ()
+{
+jack_set_xrun_callback ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_jack_jack_set_xrun_callback=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_jack_jack_set_xrun_callback=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_jack_jack_set_xrun_callback" >&5
+echo "${ECHO_T}$ac_cv_lib_jack_jack_set_xrun_callback" >&6
+if test $ac_cv_lib_jack_jack_set_xrun_callback = yes; then
+ jack=xrun
+else
+ jack=no
+fi
+
+ echo "$as_me:$LINENO: checking for jack_set_error_function in -ljack" >&5
+echo $ECHO_N "checking for jack_set_error_function in -ljack... $ECHO_C" >&6
+if test "${ac_cv_lib_jack_jack_set_error_function+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ljack $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char jack_set_error_function ();
+int
+main ()
+{
+jack_set_error_function ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_jack_jack_set_error_function=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_jack_jack_set_error_function=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_jack_jack_set_error_function" >&5
+echo "${ECHO_T}$ac_cv_lib_jack_jack_set_error_function" >&6
+if test $ac_cv_lib_jack_jack_set_error_function = yes; then
+ jack=yes
+else
+ jack=no
+fi
+
+fi
+
+if test x$portaudio == xyes; then
+ echo "$as_me:$LINENO: checking for Pa_GetDeviceCount in -lportaudio" >&5
+echo $ECHO_N "checking for Pa_GetDeviceCount in -lportaudio... $ECHO_C" >&6
+if test "${ac_cv_lib_portaudio_Pa_GetDeviceCount+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lportaudio $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char Pa_GetDeviceCount ();
+int
+main ()
+{
+Pa_GetDeviceCount ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_portaudio_Pa_GetDeviceCount=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_portaudio_Pa_GetDeviceCount=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_portaudio_Pa_GetDeviceCount" >&5
+echo "${ECHO_T}$ac_cv_lib_portaudio_Pa_GetDeviceCount" >&6
+if test $ac_cv_lib_portaudio_Pa_GetDeviceCount = yes; then
+ LDFLAGS=$LDFLAGS" -lportaudio" ; portaudio=yes
+else
+ portaudio=no
+fi
+
+fi
+
+if test x$portmidi == xyes; then
+ echo "$as_me:$LINENO: checking for Pt_Started in -lporttime" >&5
+echo $ECHO_N "checking for Pt_Started in -lporttime... $ECHO_C" >&6
+if test "${ac_cv_lib_porttime_Pt_Started___+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lporttime $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char Pt_Started ();
+int
+main ()
+{
+Pt_Started ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_porttime_Pt_Started___=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_porttime_Pt_Started___=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_porttime_Pt_Started___" >&5
+echo "${ECHO_T}$ac_cv_lib_porttime_Pt_Started___" >&6
+if test $ac_cv_lib_porttime_Pt_Started___ = yes; then
+ LDFLAGS=$LDFLAGS" -lporttime"
+fi
+
+ echo "$as_me:$LINENO: checking for Pm_Initialize in -lportmidi" >&5
+echo $ECHO_N "checking for Pm_Initialize in -lportmidi... $ECHO_C" >&6
+if test "${ac_cv_lib_portmidi_Pm_Initialize+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lportmidi $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char Pm_Initialize ();
+int
+main ()
+{
+Pm_Initialize ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_portmidi_Pm_Initialize=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_portmidi_Pm_Initialize=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_portmidi_Pm_Initialize" >&5
+echo "${ECHO_T}$ac_cv_lib_portmidi_Pm_Initialize" >&6
+if test $ac_cv_lib_portmidi_Pm_Initialize = yes; then
+ LDFLAGS=$LDFLAGS" -lportmidi" ; portmidi=yes
+else
+ portmidi=no
+fi
+
+fi
+
+if test x$USE_DEBUG_CFLAGS == xyes; then
+ MORECFLAGS=$MORECFLAGS" -O1 -g"
+else
+ MORECFLAGS=$MORECFLAGS" -O3 -funroll-loops -fomit-frame-pointer"
+fi
+
+if test x$oss == xyes; then
+ AUDIOSRC=$AUDIOSRC" s_audio_oss.c"
+ MIDISRC="s_midi_oss.c"
+ CPPFLAGS=$CPPFLAGS" -DUSEAPI_OSS"
+fi
+
+if test x$alsa == xyes; then
+ # the alsa midi is weird, it needs to have another MIDI module at once, so i put it in "audio" instead.
+ AUDIOSRC=$AUDIOSRC" s_audio_alsa.c s_audio_alsamm.c s_midi_alsa.c"
+ CPPFLAGS=$CPPFLAGS" -DPA_USE_ALSA -DUSEAPI_ALSA"
+ LDFLAGS=$LDFLAGS" -lasound"
+fi
+
+if test x$jack == xyes; then
+ AUDIOSRC=$AUDIOSRC" s_audio_jack.c"
+ if test x$jack != xno; then
+ if test `uname -s` = Linux; then
+ if test x$jack == "xyes"; then LDFLAGS=$LDFLAGS" -lrt -ljack"; fi
+ if test x$jack == "xrun"; then LDFLAGS=$LDFLAGS" -lrt -ljack"; fi
+ fi
+ if test `uname -s` = Darwin; then
+ LDFLAGS=$LDFLAGS" -framework Jack" # 0.39
+ LDFLAGS=$LDFLAGS" -weak_framework Jack" # 0.40
+ else
+ LIBS="$LIBS -ljack"
+ fi
+ CPPFLAGS=$CPPFLAGS" -DUSEAPI_JACK"
+ fi
+ if test x$jack == "xrun"; then CPPFLAGS=$CPPFLAGS" -DJACK_XRUN"; fi
+fi
+
+if test x$portaudio == xyes; then
+ CPPFLAGS=$CPPFLAGS" -DUSEAPI_PORTAUDIO -DPA19"
+ AUDIOSRC=$AUDIOSRC" s_audio_portaudio.c"
+ if test `uname -s` = Darwin; then
+ LDFLAGS=$LDFLAGS" -framework CoreAudio -framework AudioUnit -framework AudioToolbox -framework Carbon"
+ fi
+fi
+
+if test x$portmidi == xyes; then
+ MIDISRC="s_midi_pm.c"
+ MIDIFLAGS="-DUSEAPI_PORTMIDI"
+ if test `uname -s` = Darwin; then
+ LDFLAGS=$LDFLAGS" -framework CoreMIDI"
+ fi
+fi
+
+CPPFLAGS=$CPPFLAGS" $MIDIFLAGS"
+
+if test x$fftw == "xyes"; then
+ echo "$as_me:$LINENO: checking for fftwf_forget_wisdom in -lfftw3f" >&5
+echo $ECHO_N "checking for fftwf_forget_wisdom in -lfftw3f... $ECHO_C" >&6
+if test "${ac_cv_lib_fftw3f_fftwf_forget_wisdom_+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lfftw3f $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char fftwf_forget_wisdom ();
+int
+main ()
+{
+fftwf_forget_wisdom ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_fftw3f_fftwf_forget_wisdom_=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_fftw3f_fftwf_forget_wisdom_=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_fftw3f_fftwf_forget_wisdom_" >&5
+echo "${ECHO_T}$ac_cv_lib_fftw3f_fftwf_forget_wisdom_" >&6
+if test $ac_cv_lib_fftw3f_fftwf_forget_wisdom_ = yes; then
+ LDFLAGS=$LDFLAGS" -lfftw3f"
+else
+ fftw=no
+fi
+
+fi
+
+echo "$as_me:$LINENO: checking whether byte ordering is bigendian" >&5
+echo $ECHO_N "checking whether byte ordering is bigendian... $ECHO_C" >&6
+if test "${ac_cv_c_bigendian+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ # See if sys/param.h defines the BYTE_ORDER macro.
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <sys/types.h>
+#include <sys/param.h>
+
+int
+main ()
+{
+#if !BYTE_ORDER || !BIG_ENDIAN || !LITTLE_ENDIAN
+ bogus endian macros
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ # It does; now see whether it defined to BIG_ENDIAN or not.
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <sys/types.h>
+#include <sys/param.h>
+
+int
+main ()
+{
+#if BYTE_ORDER != BIG_ENDIAN
+ not big endian
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_c_bigendian=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_c_bigendian=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+# It does not; compile a test program.
+if test "$cross_compiling" = yes; then
+ # try to guess the endianness by grepping values into an object file
+ ac_cv_c_bigendian=unknown
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+short ascii_mm[] = { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 };
+short ascii_ii[] = { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 };
+void _ascii () { char *s = (char *) ascii_mm; s = (char *) ascii_ii; }
+short ebcdic_ii[] = { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 };
+short ebcdic_mm[] = { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 };
+void _ebcdic () { char *s = (char *) ebcdic_mm; s = (char *) ebcdic_ii; }
+int
+main ()
+{
+ _ascii (); _ebcdic ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ if grep BIGenDianSyS conftest.$ac_objext >/dev/null ; then
+ ac_cv_c_bigendian=yes
+fi
+if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then
+ if test "$ac_cv_c_bigendian" = unknown; then
+ ac_cv_c_bigendian=no
+ else
+ # finding both strings is unlikely to happen, but who knows?
+ ac_cv_c_bigendian=unknown
+ fi
+fi
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+int
+main ()
+{
+ /* Are we little or big endian? From Harbison&Steele. */
+ union
+ {
+ long l;
+ char c[sizeof (long)];
+ } u;
+ u.l = 1;
+ exit (u.c[sizeof (long) - 1] == 1);
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_c_bigendian=no
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+ac_cv_c_bigendian=yes
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_c_bigendian" >&5
+echo "${ECHO_T}$ac_cv_c_bigendian" >&6
+case $ac_cv_c_bigendian in
+ yes)
+ bigendian=yes ;;
+ no)
+ bigendian=no ;;
+ *)
+ bigendian=maybe ;;
+esac
+
+if test x$bigendian = "xyes"; then
+ CPPFLAGS=$CPPFLAGS" -DBIGENDIAN"
+fi
+
+ ac_config_files="$ac_config_files makefile"
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems. If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, don't put newlines in cache variables' values.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+{
+ (set) 2>&1 |
+ case `(ac_space=' '; set | grep ac_space) 2>&1` in
+ *ac_space=\ *)
+ # `set' does not quote correctly, so add quotes (double-quote
+ # substitution turns \\\\ into \\, and sed turns \\ into \).
+ sed -n \
+ "s/'/'\\\\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+ ;;
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n \
+ "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p"
+ ;;
+ esac;
+} |
+ sed '
+ t clear
+ : clear
+ s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+ t end
+ /^ac_cv_env/!s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+ : end' >>confcache
+if diff $cache_file confcache >/dev/null 2>&1; then :; else
+ if test -w $cache_file; then
+ test "x$cache_file" != "x/dev/null" && echo "updating cache $cache_file"
+ cat confcache >$cache_file
+ else
+ echo "not updating unwritable cache $cache_file"
+ fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# VPATH may cause trouble with some makes, so we remove $(srcdir),
+# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=/{
+s/:*\$(srcdir):*/:/;
+s/:*\${srcdir}:*/:/;
+s/:*@srcdir@:*/:/;
+s/^\([^=]*=[ ]*\):*/\1/;
+s/:*$//;
+s/^[^=]*=[ ]*$//;
+}'
+fi
+
+# Transform confdefs.h into DEFS.
+# Protect against shell expansion while executing Makefile rules.
+# Protect against Makefile macro expansion.
+#
+# If the first sed substitution is executed (which looks for macros that
+# take arguments), then we branch to the quote section. Otherwise,
+# look for a macro that doesn't take arguments.
+cat >confdef2opt.sed <<\_ACEOF
+t clear
+: clear
+s,^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\),-D\1=\2,g
+t quote
+s,^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\),-D\1=\2,g
+t quote
+d
+: quote
+s,[ `~#$^&*(){}\\|;'"<>?],\\&,g
+s,\[,\\&,g
+s,\],\\&,g
+s,\$,$$,g
+p
+_ACEOF
+# We use echo to avoid assuming a particular line-breaking character.
+# The extra dot is to prevent the shell from consuming trailing
+# line-breaks from the sub-command output. A line-break within
+# single-quotes doesn't work because, if this script is created in a
+# platform that uses two characters for line-breaks (e.g., DOS), tr
+# would break.
+ac_LF_and_DOT=`echo; echo .`
+DEFS=`sed -n -f confdef2opt.sed confdefs.h | tr "$ac_LF_and_DOT" ' .'`
+rm -f confdef2opt.sed
+
+
+ac_libobjs=
+ac_ltlibobjs=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+ # 1. Remove the extension, and $U if already installed.
+ ac_i=`echo "$ac_i" |
+ sed 's/\$U\././;s/\.o$//;s/\.obj$//'`
+ # 2. Add them.
+ ac_libobjs="$ac_libobjs $ac_i\$U.$ac_objext"
+ ac_ltlibobjs="$ac_ltlibobjs $ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+: ${CONFIG_STATUS=./config.status}
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5
+echo "$as_me: creating $CONFIG_STATUS" >&6;}
+cat >$CONFIG_STATUS <<_ACEOF
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+SHELL=\${CONFIG_SHELL-$SHELL}
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+## --------------------- ##
+## M4sh Initialization. ##
+## --------------------- ##
+
+# Be Bourne compatible
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+ emulate sh
+ NULLCMD=:
+ # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then
+ set -o posix
+fi
+DUALCASE=1; export DUALCASE # for MKS sh
+
+# Support unset when possible.
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+ as_unset=unset
+else
+ as_unset=false
+fi
+
+
+# Work around bugs in pre-3.0 UWIN ksh.
+$as_unset ENV MAIL MAILPATH
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+for as_var in \
+ LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \
+ LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \
+ LC_TELEPHONE LC_TIME
+do
+ if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then
+ eval $as_var=C; export $as_var
+ else
+ $as_unset $as_var
+ fi
+done
+
+# Required to use basename.
+if expr a : '\(a\)' >/dev/null 2>&1; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+
+# Name of the executable.
+as_me=`$as_basename "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)$' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; }
+ /^X\/\(\/\/\)$/{ s//\1/; q; }
+ /^X\/\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+
+
+# PATH needs CR, and LINENO needs CR and PATH.
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ echo "#! /bin/sh" >conf$$.sh
+ echo "exit 0" >>conf$$.sh
+ chmod +x conf$$.sh
+ if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then
+ PATH_SEPARATOR=';'
+ else
+ PATH_SEPARATOR=:
+ fi
+ rm -f conf$$.sh
+fi
+
+
+ as_lineno_1=$LINENO
+ as_lineno_2=$LINENO
+ as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
+ test "x$as_lineno_1" != "x$as_lineno_2" &&
+ test "x$as_lineno_3" = "x$as_lineno_2" || {
+ # Find who we are. Look in the path if we contain no path at all
+ # relative or not.
+ case $0 in
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+done
+
+ ;;
+ esac
+ # We did not find ourselves, most probably we were run as `sh COMMAND'
+ # in which case we are not to be found in the path.
+ if test "x$as_myself" = x; then
+ as_myself=$0
+ fi
+ if test ! -f "$as_myself"; then
+ { { echo "$as_me:$LINENO: error: cannot find myself; rerun with an absolute path" >&5
+echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2;}
+ { (exit 1); exit 1; }; }
+ fi
+ case $CONFIG_SHELL in
+ '')
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for as_base in sh bash ksh sh5; do
+ case $as_dir in
+ /*)
+ if ("$as_dir/$as_base" -c '
+ as_lineno_1=$LINENO
+ as_lineno_2=$LINENO
+ as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
+ test "x$as_lineno_1" != "x$as_lineno_2" &&
+ test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then
+ $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; }
+ $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; }
+ CONFIG_SHELL=$as_dir/$as_base
+ export CONFIG_SHELL
+ exec "$CONFIG_SHELL" "$0" ${1+"$@"}
+ fi;;
+ esac
+ done
+done
+;;
+ esac
+
+ # Create $as_me.lineno as a copy of $as_myself, but with $LINENO
+ # uniformly replaced by the line number. The first 'sed' inserts a
+ # line-number line before each line; the second 'sed' does the real
+ # work. The second script uses 'N' to pair each line-number line
+ # with the numbered line, and appends trailing '-' during
+ # substitution so that $LINENO is not a special case at line end.
+ # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the
+ # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-)
+ sed '=' <$as_myself |
+ sed '
+ N
+ s,$,-,
+ : loop
+ s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3,
+ t loop
+ s,-$,,
+ s,^['$as_cr_digits']*\n,,
+ ' >$as_me.lineno &&
+ chmod +x $as_me.lineno ||
+ { { echo "$as_me:$LINENO: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&5
+echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2;}
+ { (exit 1); exit 1; }; }
+
+ # Don't try to exec as it changes $[0], causing all sort of problems
+ # (the dirname of $[0] is not the place where we might find the
+ # original and so on. Autoconf is especially sensible to this).
+ . ./$as_me.lineno
+ # Exit status is that of the last command.
+ exit
+}
+
+
+case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in
+ *c*,-n*) ECHO_N= ECHO_C='
+' ECHO_T=' ' ;;
+ *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;;
+ *) ECHO_N= ECHO_C='\c' ECHO_T= ;;
+esac
+
+if expr a : '\(a\)' >/dev/null 2>&1; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+rm -f conf$$ conf$$.exe conf$$.file
+echo >conf$$.file
+if ln -s conf$$.file conf$$ 2>/dev/null; then
+ # We could just check for DJGPP; but this test a) works b) is more generic
+ # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04).
+ if test -f conf$$.exe; then
+ # Don't use ln at all; we don't have any links
+ as_ln_s='cp -p'
+ else
+ as_ln_s='ln -s'
+ fi
+elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+else
+ as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.file
+
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p=:
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+as_executable_p="test -f"
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.
+as_nl='
+'
+IFS=" $as_nl"
+
+# CDPATH.
+$as_unset CDPATH
+
+exec 6>&1
+
+# Open the log real soon, to keep \$[0] and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling. Logging --version etc. is OK.
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+} >&5
+cat >&5 <<_CSEOF
+
+This file was extended by $as_me, which was
+generated by GNU Autoconf 2.59. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ $ $0 $@
+
+_CSEOF
+echo "on `(hostname || uname -n) 2>/dev/null | sed 1q`" >&5
+echo >&5
+_ACEOF
+
+# Files that config.status was made for.
+if test -n "$ac_config_files"; then
+ echo "config_files=\"$ac_config_files\"" >>$CONFIG_STATUS
+fi
+
+if test -n "$ac_config_headers"; then
+ echo "config_headers=\"$ac_config_headers\"" >>$CONFIG_STATUS
+fi
+
+if test -n "$ac_config_links"; then
+ echo "config_links=\"$ac_config_links\"" >>$CONFIG_STATUS
+fi
+
+if test -n "$ac_config_commands"; then
+ echo "config_commands=\"$ac_config_commands\"" >>$CONFIG_STATUS
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+
+ac_cs_usage="\
+\`$as_me' instantiates files from templates according to the
+current configuration.
+
+Usage: $0 [OPTIONS] [FILE]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number, then exit
+ -q, --quiet do not print progress messages
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+
+Configuration files:
+$config_files
+
+Report bugs to <bug-autoconf@gnu.org>."
+_ACEOF
+
+cat >>$CONFIG_STATUS <<_ACEOF
+ac_cs_version="\\
+config.status
+configured by $0, generated by GNU Autoconf 2.59,
+ with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\"
+
+Copyright (C) 2003 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+srcdir=$srcdir
+INSTALL="$INSTALL"
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+# If no file are specified by the user, then we need to provide default
+# value. By we need to know if files were specified by the user.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=*)
+ ac_option=`expr "x$1" : 'x\([^=]*\)='`
+ ac_optarg=`expr "x$1" : 'x[^=]*=\(.*\)'`
+ ac_shift=:
+ ;;
+ -*)
+ ac_option=$1
+ ac_optarg=$2
+ ac_shift=shift
+ ;;
+ *) # This is not an option, so the user has probably given explicit
+ # arguments.
+ ac_option=$1
+ ac_need_defaults=false;;
+ esac
+
+ case $ac_option in
+ # Handling of the options.
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ ac_cs_recheck=: ;;
+ --version | --vers* | -V )
+ echo "$ac_cs_version"; exit 0 ;;
+ --he | --h)
+ # Conflict between --help and --header
+ { { echo "$as_me:$LINENO: error: ambiguous option: $1
+Try \`$0 --help' for more information." >&5
+echo "$as_me: error: ambiguous option: $1
+Try \`$0 --help' for more information." >&2;}
+ { (exit 1); exit 1; }; };;
+ --help | --hel | -h )
+ echo "$ac_cs_usage"; exit 0 ;;
+ --debug | --d* | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ $ac_shift
+ CONFIG_FILES="$CONFIG_FILES $ac_optarg"
+ ac_need_defaults=false;;
+ --header | --heade | --head | --hea )
+ $ac_shift
+ CONFIG_HEADERS="$CONFIG_HEADERS $ac_optarg"
+ ac_need_defaults=false;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil | --si | --s)
+ ac_cs_silent=: ;;
+
+ # This is an error.
+ -*) { { echo "$as_me:$LINENO: error: unrecognized option: $1
+Try \`$0 --help' for more information." >&5
+echo "$as_me: error: unrecognized option: $1
+Try \`$0 --help' for more information." >&2;}
+ { (exit 1); exit 1; }; } ;;
+
+ *) ac_config_targets="$ac_config_targets $1" ;;
+
+ esac
+ shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+ exec 6>/dev/null
+ ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF
+if \$ac_cs_recheck; then
+ echo "running $SHELL $0 " $ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6
+ exec $SHELL $0 $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+fi
+
+_ACEOF
+
+
+
+
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+for ac_config_target in $ac_config_targets
+do
+ case "$ac_config_target" in
+ # Handling of arguments.
+ "makefile" ) CONFIG_FILES="$CONFIG_FILES makefile" ;;
+ *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5
+echo "$as_me: error: invalid argument: $ac_config_target" >&2;}
+ { (exit 1); exit 1; }; };;
+ esac
+done
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used. Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+fi
+
+# Have a temporary directory for convenience. Make it in the build tree
+# simply because there is no reason to put it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Create a temporary directory, and hook for its removal unless debugging.
+$debug ||
+{
+ trap 'exit_status=$?; rm -rf $tmp && exit $exit_status' 0
+ trap '{ (exit 1); exit 1; }' 1 2 13 15
+}
+
+# Create a (secure) tmp directory for tmp files.
+
+{
+ tmp=`(umask 077 && mktemp -d -q "./confstatXXXXXX") 2>/dev/null` &&
+ test -n "$tmp" && test -d "$tmp"
+} ||
+{
+ tmp=./confstat$$-$RANDOM
+ (umask 077 && mkdir $tmp)
+} ||
+{
+ echo "$me: cannot create a temporary directory in ." >&2
+ { (exit 1); exit 1; }
+}
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<_ACEOF
+
+#
+# CONFIG_FILES section.
+#
+
+# No need to generate the scripts if there are no CONFIG_FILES.
+# This happens for instance when ./config.status config.h
+if test -n "\$CONFIG_FILES"; then
+ # Protect against being on the right side of a sed subst in config.status.
+ sed 's/,@/@@/; s/@,/@@/; s/,;t t\$/@;t t/; /@;t t\$/s/[\\\\&,]/\\\\&/g;
+ s/@@/,@/; s/@@/@,/; s/@;t t\$/,;t t/' >\$tmp/subs.sed <<\\CEOF
+s,@SHELL@,$SHELL,;t t
+s,@PATH_SEPARATOR@,$PATH_SEPARATOR,;t t
+s,@PACKAGE_NAME@,$PACKAGE_NAME,;t t
+s,@PACKAGE_TARNAME@,$PACKAGE_TARNAME,;t t
+s,@PACKAGE_VERSION@,$PACKAGE_VERSION,;t t
+s,@PACKAGE_STRING@,$PACKAGE_STRING,;t t
+s,@PACKAGE_BUGREPORT@,$PACKAGE_BUGREPORT,;t t
+s,@exec_prefix@,$exec_prefix,;t t
+s,@prefix@,$prefix,;t t
+s,@program_transform_name@,$program_transform_name,;t t
+s,@bindir@,$bindir,;t t
+s,@sbindir@,$sbindir,;t t
+s,@libexecdir@,$libexecdir,;t t
+s,@datadir@,$datadir,;t t
+s,@sysconfdir@,$sysconfdir,;t t
+s,@sharedstatedir@,$sharedstatedir,;t t
+s,@localstatedir@,$localstatedir,;t t
+s,@libdir@,$libdir,;t t
+s,@includedir@,$includedir,;t t
+s,@oldincludedir@,$oldincludedir,;t t
+s,@infodir@,$infodir,;t t
+s,@mandir@,$mandir,;t t
+s,@build_alias@,$build_alias,;t t
+s,@host_alias@,$host_alias,;t t
+s,@target_alias@,$target_alias,;t t
+s,@DEFS@,$DEFS,;t t
+s,@ECHO_C@,$ECHO_C,;t t
+s,@ECHO_N@,$ECHO_N,;t t
+s,@ECHO_T@,$ECHO_T,;t t
+s,@LIBS@,$LIBS,;t t
+s,@oss@,$oss,;t t
+s,@alsa@,$alsa,;t t
+s,@jack@,$jack,;t t
+s,@portaudio@,$portaudio,;t t
+s,@portmidi@,$portmidi,;t t
+s,@fftw@,$fftw,;t t
+s,@CPPFLAGS@,$CPPFLAGS,;t t
+s,@MORECFLAGS@,$MORECFLAGS,;t t
+s,@EXT@,$EXT,;t t
+s,@USE_DEBUG_CFLAGS@,$USE_DEBUG_CFLAGS,;t t
+s,@AUDIOSRC@,$AUDIOSRC,;t t
+s,@MIDISRC@,$MIDISRC,;t t
+s,@STRIPFLAG@,$STRIPFLAG,;t t
+s,@EXTERNTARGET@,$EXTERNTARGET,;t t
+s,@LIBSUFFIX@,$LIBSUFFIX,;t t
+s,@LDSOFLAGS@,$LDSOFLAGS,;t t
+s,@CC@,$CC,;t t
+s,@CFLAGS@,$CFLAGS,;t t
+s,@LDFLAGS@,$LDFLAGS,;t t
+s,@ac_ct_CC@,$ac_ct_CC,;t t
+s,@EXEEXT@,$EXEEXT,;t t
+s,@OBJEXT@,$OBJEXT,;t t
+s,@INSTALL_PROGRAM@,$INSTALL_PROGRAM,;t t
+s,@INSTALL_SCRIPT@,$INSTALL_SCRIPT,;t t
+s,@INSTALL_DATA@,$INSTALL_DATA,;t t
+s,@SET_MAKE@,$SET_MAKE,;t t
+s,@CPP@,$CPP,;t t
+s,@EGREP@,$EGREP,;t t
+s,@ALLOCA@,$ALLOCA,;t t
+s,@LIBOBJS@,$LIBOBJS,;t t
+s,@LTLIBOBJS@,$LTLIBOBJS,;t t
+CEOF
+
+_ACEOF
+
+ cat >>$CONFIG_STATUS <<\_ACEOF
+ # Split the substitutions into bite-sized pieces for seds with
+ # small command number limits, like on Digital OSF/1 and HP-UX.
+ ac_max_sed_lines=48
+ ac_sed_frag=1 # Number of current file.
+ ac_beg=1 # First line for current file.
+ ac_end=$ac_max_sed_lines # Line after last line for current file.
+ ac_more_lines=:
+ ac_sed_cmds=
+ while $ac_more_lines; do
+ if test $ac_beg -gt 1; then
+ sed "1,${ac_beg}d; ${ac_end}q" $tmp/subs.sed >$tmp/subs.frag
+ else
+ sed "${ac_end}q" $tmp/subs.sed >$tmp/subs.frag
+ fi
+ if test ! -s $tmp/subs.frag; then
+ ac_more_lines=false
+ else
+ # The purpose of the label and of the branching condition is to
+ # speed up the sed processing (if there are no `@' at all, there
+ # is no need to browse any of the substitutions).
+ # These are the two extra sed commands mentioned above.
+ (echo ':t
+ /@[a-zA-Z_][a-zA-Z_0-9]*@/!b' && cat $tmp/subs.frag) >$tmp/subs-$ac_sed_frag.sed
+ if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds="sed -f $tmp/subs-$ac_sed_frag.sed"
+ else
+ ac_sed_cmds="$ac_sed_cmds | sed -f $tmp/subs-$ac_sed_frag.sed"
+ fi
+ ac_sed_frag=`expr $ac_sed_frag + 1`
+ ac_beg=$ac_end
+ ac_end=`expr $ac_end + $ac_max_sed_lines`
+ fi
+ done
+ if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds=cat
+ fi
+fi # test -n "$CONFIG_FILES"
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+for ac_file in : $CONFIG_FILES; do test "x$ac_file" = x: && continue
+ # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+ case $ac_file in
+ - | *:- | *:-:* ) # input from stdin
+ cat >$tmp/stdin
+ ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'`
+ ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;;
+ *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'`
+ ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;;
+ * ) ac_file_in=$ac_file.in ;;
+ esac
+
+ # Compute @srcdir@, @top_srcdir@, and @INSTALL@ for subdirectories.
+ ac_dir=`(dirname "$ac_file") 2>/dev/null ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_file" : 'X\(//\)[^/]' \| \
+ X"$ac_file" : 'X\(//\)$' \| \
+ X"$ac_file" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$ac_file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ { if $as_mkdir_p; then
+ mkdir -p "$ac_dir"
+ else
+ as_dir="$ac_dir"
+ as_dirs=
+ while test ! -d "$as_dir"; do
+ as_dirs="$as_dir $as_dirs"
+ as_dir=`(dirname "$as_dir") 2>/dev/null ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ done
+ test ! -n "$as_dirs" || mkdir $as_dirs
+ fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5
+echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;}
+ { (exit 1); exit 1; }; }; }
+
+ ac_builddir=.
+
+if test "$ac_dir" != .; then
+ ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'`
+ # A "../" for each directory in $ac_dir_suffix.
+ ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'`
+else
+ ac_dir_suffix= ac_top_builddir=
+fi
+
+case $srcdir in
+ .) # No --srcdir option. We are building in place.
+ ac_srcdir=.
+ if test -z "$ac_top_builddir"; then
+ ac_top_srcdir=.
+ else
+ ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'`
+ fi ;;
+ [\\/]* | ?:[\\/]* ) # Absolute path.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir ;;
+ *) # Relative path.
+ ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_builddir$srcdir ;;
+esac
+
+# Do not use `cd foo && pwd` to compute absolute paths, because
+# the directories may not exist.
+case `pwd` in
+.) ac_abs_builddir="$ac_dir";;
+*)
+ case "$ac_dir" in
+ .) ac_abs_builddir=`pwd`;;
+ [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";;
+ *) ac_abs_builddir=`pwd`/"$ac_dir";;
+ esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_top_builddir=${ac_top_builddir}.;;
+*)
+ case ${ac_top_builddir}. in
+ .) ac_abs_top_builddir=$ac_abs_builddir;;
+ [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;;
+ *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;;
+ esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_srcdir=$ac_srcdir;;
+*)
+ case $ac_srcdir in
+ .) ac_abs_srcdir=$ac_abs_builddir;;
+ [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;;
+ *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;;
+ esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_top_srcdir=$ac_top_srcdir;;
+*)
+ case $ac_top_srcdir in
+ .) ac_abs_top_srcdir=$ac_abs_builddir;;
+ [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;;
+ *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;;
+ esac;;
+esac
+
+
+ case $INSTALL in
+ [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;;
+ *) ac_INSTALL=$ac_top_builddir$INSTALL ;;
+ esac
+
+ # Let's still pretend it is `configure' which instantiates (i.e., don't
+ # use $as_me), people would be surprised to read:
+ # /* config.h. Generated by config.status. */
+ if test x"$ac_file" = x-; then
+ configure_input=
+ else
+ configure_input="$ac_file. "
+ fi
+ configure_input=$configure_input"Generated from `echo $ac_file_in |
+ sed 's,.*/,,'` by configure."
+
+ # First look for the input files in the build tree, otherwise in the
+ # src tree.
+ ac_file_inputs=`IFS=:
+ for f in $ac_file_in; do
+ case $f in
+ -) echo $tmp/stdin ;;
+ [\\/$]*)
+ # Absolute (can't be DOS-style, as IFS=:)
+ test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5
+echo "$as_me: error: cannot find input file: $f" >&2;}
+ { (exit 1); exit 1; }; }
+ echo "$f";;
+ *) # Relative
+ if test -f "$f"; then
+ # Build tree
+ echo "$f"
+ elif test -f "$srcdir/$f"; then
+ # Source tree
+ echo "$srcdir/$f"
+ else
+ # /dev/null tree
+ { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5
+echo "$as_me: error: cannot find input file: $f" >&2;}
+ { (exit 1); exit 1; }; }
+ fi;;
+ esac
+ done` || { (exit 1); exit 1; }
+
+ if test x"$ac_file" != x-; then
+ { echo "$as_me:$LINENO: creating $ac_file" >&5
+echo "$as_me: creating $ac_file" >&6;}
+ rm -f "$ac_file"
+ fi
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF
+ sed "$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s,@configure_input@,$configure_input,;t t
+s,@srcdir@,$ac_srcdir,;t t
+s,@abs_srcdir@,$ac_abs_srcdir,;t t
+s,@top_srcdir@,$ac_top_srcdir,;t t
+s,@abs_top_srcdir@,$ac_abs_top_srcdir,;t t
+s,@builddir@,$ac_builddir,;t t
+s,@abs_builddir@,$ac_abs_builddir,;t t
+s,@top_builddir@,$ac_top_builddir,;t t
+s,@abs_top_builddir@,$ac_abs_top_builddir,;t t
+s,@INSTALL@,$ac_INSTALL,;t t
+" $ac_file_inputs | (eval "$ac_sed_cmds") >$tmp/out
+ rm -f $tmp/stdin
+ if test x"$ac_file" != x-; then
+ mv $tmp/out $ac_file
+ else
+ cat $tmp/out
+ rm -f $tmp/out
+ fi
+
+done
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+
+{ (exit 0); exit 0; }
+_ACEOF
+chmod +x $CONFIG_STATUS
+ac_clean_files=$ac_clean_files_save
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded. So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status. When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+ ac_cs_success=:
+ ac_config_status_args=
+ test "$silent" = yes &&
+ ac_config_status_args="$ac_config_status_args --quiet"
+ exec 5>/dev/null
+ $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+ exec 5>>config.log
+ # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+ # would make configure fail if this is the last instruction.
+ $ac_cs_success || { (exit 1); exit 1; }
+fi
+
+
diff --git a/desiredata/src/configure.in b/desiredata/src/configure.in
new file mode 100644
index 00000000..752551ec
--- /dev/null
+++ b/desiredata/src/configure.in
@@ -0,0 +1,213 @@
+# This file is part of DesireData
+# If you want to build Thomas Grill's devel_0_39, you need to use scons instead.
+#
+# ./configure is not a source file (not written by someone), it's generated from
+# ./configure.in, but it's still put in the CVS and releases so that people don't
+# have to have autoconf installed.
+
+AC_INIT(kernel.c)
+AC_SUBST(oss, yes)
+AC_SUBST(alsa, yes)
+AC_SUBST(jack, yes)
+AC_SUBST(portaudio, yes)
+AC_SUBST(portmidi, yes)
+AC_SUBST(fftw, yes)
+AC_SUBST(CPPFLAGS)
+AC_SUBST(MORECFLAGS)
+AC_SUBST(EXT)
+AC_SUBST(USE_DEBUG_CFLAGS, no)
+AC_SUBST(AUDIOSRC)
+AC_SUBST(MIDISRC)
+AC_SUBST(STRIPFLAG)
+AC_SUBST(EXTERNTARGET)
+AC_SUBST(LIBSUFFIX)
+AC_SUBST(LDSOFLAGS)
+
+dnl Checks for features.
+AC_ARG_ENABLE(alsa, [ --enable-oss audio via OSS], alsa=$enableval)
+AC_ARG_ENABLE(alsa, [ --enable-alsa audio via ALSA], alsa=$enableval)
+AC_ARG_ENABLE(jack, [ --enable-jack audio via JACK], jack=$enableval)
+AC_ARG_ENABLE(portaudio,[ --enable-portaudio audio via PortAudio], portaudio=$enableval)
+AC_ARG_ENABLE(portmidi, [ --enable-portmidi MIDI via PortMidi], portmidi=$enableval)
+AC_ARG_ENABLE(debug, [ --enable-debug debugging support], USE_DEBUG_CFLAGS=$enableval)
+AC_ARG_ENABLE(static, [ --enable-static link statically], static=$enableval)
+AC_ARG_ENABLE(fftw, [ --enable-fftw use FFTW package], fftw=$enableval)
+
+dnl Checks for programs.
+AC_PROG_CC
+AC_PROG_INSTALL
+AC_PROG_MAKE_SET
+AC_PROG_CPP
+
+dnl Checks for typedefs, structures, and compiler characteristics.
+AC_C_CONST
+AC_TYPE_PID_T
+AC_TYPE_SIZE_T
+AC_HEADER_TIME
+
+dnl Checks for header files.
+AC_HEADER_STDC
+AC_CHECK_HEADERS(fcntl.h limits.h malloc.h sys/ioctl.h sys/time.h unistd.h bstring.h)
+
+dnl Checks for library functions.
+AC_PROG_GCC_TRADITIONAL
+AC_TYPE_SIGNAL
+AC_FUNC_VPRINTF
+AC_CHECK_FUNCS(gettimeofday select socket strerror)
+AC_FUNC_ALLOCA
+
+# audio APIs may accumulate, but there must be only one MIDI API (??)
+AUDIOSRC=""
+MIDISRC="s_midi_none.c"
+
+if test `uname -s` = Linux; then
+ LDFLAGS="-Wl,-export-dynamic "
+ EXT=pd_linux
+ LIBSUFFIX=.so
+ CPPFLAGS="-DDL_OPEN -DPA_USE_OSS -DUNIX -DUNISTD"
+ MORECFLAGS="-fno-strict-aliasing"
+ STRIPFLAG=-s
+ LDSOFLAGS="-shared"
+fi
+
+if test `uname -s` = Darwin; then
+ LDFLAGS=""
+ EXT=pd_darwin
+ LIBSUFFIX=.dylib
+ CPPFLAGS="-DMACOSX -DUNISTD -I/usr/X11R6/include -DPA_USE_COREAUDIO"
+ CPPFLAGS=$CPPFLAGS" -DDL_OPEN" # 0.40
+ MORECFLAGS=""
+ STRIPFLAG=""
+# LDSOFLAGS="-dylib -bundle -flat_namespace -undefined suppress"
+# LDSOFLAGS="-dylib -flat_namespace"
+# Charles Turner told me to use this:
+ LDSOFLAGS="-dynamiclib -Wl,-single_module"
+ EXTERNTARGET=pd_darwin
+### this comes from pd 0.40
+# if test `uname -r` = 7.9.0; then
+# CPPFLAGS=$CPPFLAGS" -DMACOSX3"
+# EXTERNTARGET=d_ppc
+# else
+# CPPFLAGS=$CPPFLAGS" -isysroot /Developer/SDKs/MacOSX10.4u.sdk"
+# MORECFLAGS=$MORECFLAGS" -arch i386 -arch ppc"
+# EXTERNTARGET=d_fat
+# LDFLAGS=$LDFLAGS" -arch i386 -arch ppc"
+# fi
+fi
+
+if test `uname -s | cut -f1 -d_` = CYGWIN; then
+ LDFLAGS="-Wl,-export-dynamic "
+ EXT=pd_linux
+ LIBSUFFIX=.dll
+ CPPFLAGS="-DDL_OPEN -DPA_USE_OSS -DUNIX -DUNISTD"
+ MORECFLAGS="-fno-strict-aliasing"
+ STRIPFLAG=-s
+ LDSOFLAGS="-shared"
+fi
+
+if test `uname -m` = x86_64; then
+ MORECFLAGS=$MORECFLAGS" -fPIC"
+fi
+
+if test "$static" = yes; then LDFLAGS="$LDFLAGS -static"; fi
+
+dnl Checking for `dlopen' function in -ldl:
+AC_CHECK_LIB(dl, dlopen,LDFLAGS="$LDFLAGS -ldl", echo "dynamic link support required" || exit 1)
+dnl Checking for `sin' function in -lffm (ffm is the fast math library on the alpha)
+AC_CHECK_LIB(ffm, sin,LDFLAGS="$LDFLAGS -lffm")
+dnl Checking for `sin' function in -lm:
+AC_CHECK_LIB(m, sin,LDFLAGS="$LDFLAGS -lm", echo "math library required" || exit 1)
+dnl Checking for `pthread_create' function in -pthread
+AC_CHECK_LIB(pthread, pthread_create,LDFLAGS="$LDFLAGS -lpthread", echo "pthreads required" || exit 1)
+
+if test x$oss = xyes; then
+ AC_CHECK_HEADER(linux/soundcard.h,oss="yes",oss="no")
+fi
+
+dnl This should be fixed so Pd can use ALSA shared libraries where appropriate.
+if test x$alsa = xyes; then
+ AC_CHECK_LIB(asound,snd_pcm_info,LDFLAGS="$LDFLAGS -lasound" ; alsa="yes",alsa="no")
+fi
+
+if test x$jack = xyes; then
+ AC_CHECK_LIB(rt,shm_open,LIBS="$LIBS -lrt")
+ AC_CHECK_LIB(jack,jack_set_xrun_callback,jack=xrun,jack=no)
+ AC_CHECK_LIB(jack,jack_set_error_function,jack=yes,jack=no)
+fi
+
+dnl This should be fixed so Pd can use ALSA shared libraries where appropriate.
+if test x$portaudio = xyes; then
+ AC_CHECK_LIB(portaudio,Pa_GetDeviceCount,LDFLAGS=$LDFLAGS" -lportaudio" ; portaudio=yes,portaudio=no)
+fi
+
+if test x$portmidi = xyes; then
+ AC_CHECK_LIB(porttime,Pt_Started ,LDFLAGS=$LDFLAGS" -lporttime")
+ AC_CHECK_LIB(portmidi,Pm_Initialize,LDFLAGS=$LDFLAGS" -lportmidi" ; portmidi=yes,portmidi=no)
+fi
+
+if test x$USE_DEBUG_CFLAGS = xyes; then
+ MORECFLAGS=$MORECFLAGS" -O1 -g"
+else
+ MORECFLAGS=$MORECFLAGS" -O3 -funroll-loops -fomit-frame-pointer"
+fi
+
+if test x$oss = xyes; then
+ AUDIOSRC=$AUDIOSRC" s_audio_oss.c"
+ MIDISRC="s_midi_oss.c"
+ CPPFLAGS=$CPPFLAGS" -DUSEAPI_OSS"
+fi
+
+if test x$alsa = xyes; then
+ # the alsa midi is weird, it needs to have another MIDI module at once, so i put it in "audio" instead.
+ AUDIOSRC=$AUDIOSRC" s_audio_alsa.c s_audio_alsamm.c s_midi_alsa.c"
+ CPPFLAGS=$CPPFLAGS" -DPA_USE_ALSA -DUSEAPI_ALSA"
+ LDFLAGS=$LDFLAGS" -lasound"
+fi
+
+if test x$jack = xyes; then
+ AUDIOSRC=$AUDIOSRC" s_audio_jack.c"
+ if test x$jack != xno; then
+ if test `uname -s` = Linux; then
+ if test x$jack = "xyes"; then LDFLAGS=$LDFLAGS" -lrt -ljack"; fi
+ if test x$jack = "xrun"; then LDFLAGS=$LDFLAGS" -lrt -ljack"; fi
+ fi
+ if test `uname -s` = Darwin; then
+ LDFLAGS=$LDFLAGS" -framework Jack" # 0.39
+ LDFLAGS=$LDFLAGS" -weak_framework Jack" # 0.40
+ else
+ LIBS="$LIBS -ljack"
+ fi
+ CPPFLAGS=$CPPFLAGS" -DUSEAPI_JACK"
+ fi
+ if test x$jack = "xrun"; then CPPFLAGS=$CPPFLAGS" -DJACK_XRUN"; fi
+fi
+
+if test x$portaudio = xyes; then
+ CPPFLAGS=$CPPFLAGS" -DUSEAPI_PORTAUDIO -DPA19"
+ AUDIOSRC=$AUDIOSRC" s_audio_portaudio.c"
+ if test `uname -s` = Darwin; then
+ LDFLAGS=$LDFLAGS" -framework CoreAudio -framework AudioUnit -framework AudioToolbox -framework Carbon"
+ fi
+fi
+
+if test x$portmidi = xyes; then
+ MIDISRC="s_midi_pm.c"
+ MIDIFLAGS="-DUSEAPI_PORTMIDI"
+ if test `uname -s` = Darwin; then
+ LDFLAGS=$LDFLAGS" -framework CoreMIDI"
+ fi
+fi
+
+CPPFLAGS=$CPPFLAGS" $MIDIFLAGS"
+
+if test x$fftw = "xyes"; then
+ AC_CHECK_LIB(fftw3f, fftwf_forget_wisdom ,LDFLAGS=$LDFLAGS" -lfftw3f",fftw=no)
+fi
+
+AC_C_BIGENDIAN(bigendian=yes,bigendian=no,bigendian=maybe)
+if test x$bigendian = "xyes"; then
+ CPPFLAGS=$CPPFLAGS" -DBIGENDIAN"
+fi
+
+AC_OUTPUT(makefile)
+
diff --git a/desiredata/src/cvs-switch-user b/desiredata/src/cvs-switch-user
new file mode 100755
index 00000000..99cfc7c0
--- /dev/null
+++ b/desiredata/src/cvs-switch-user
@@ -0,0 +1,5 @@
+echo $1@pure-data.cvs.sourceforge.net:/cvsroot/pure-data > CVS/Root
+for file in $(find -name Root)
+do
+ cp CVS/Root $file
+done
diff --git a/desiredata/src/d_fftroutine.c b/desiredata/src/d_fftroutine.c
new file mode 100644
index 00000000..4a44ee61
--- /dev/null
+++ b/desiredata/src/d_fftroutine.c
@@ -0,0 +1,999 @@
+/*****************************************************************************/
+/* */
+/* Fast Fourier Transform */
+/* Network Abstraction, Definitions */
+/* Kevin Peterson, MIT Media Lab, EMS */
+/* UROP - Fall '86 */
+/* REV: 6/12/87(KHP) - To incorporate link list of different sized networks */
+/* */
+/*****************************************************************************/
+
+/*****************************************************************************/
+/* added debug option 5/91 brown@nadia */
+/* change sign at AAA */
+/* */
+/* Fast Fourier Transform */
+/* FFT Network Interaction and Support Modules */
+/* Kevin Peterson, MIT Media Lab, EMS */
+/* UROP - Fall '86 */
+/* REV: 6/12/87(KHP) - Generalized to one procedure call with typed I/O */
+/* */
+/*****************************************************************************/
+
+/* Overview:
+
+ My realization of the FFT involves a representation of a network of
+ "butterfly" elements that takes a set of 'N' sound samples as input and
+ computes the discrete Fourier transform. This network consists of a
+ series of stages (log2 N), each stage consisting of N/2 parallel butterfly
+ elements. Consecutive stages are connected by specific, predetermined flow
+ paths, (see Oppenheim, Schafer for details) and each butterfly element has
+ an associated multiplicative coefficient.
+
+ FFT NETWORK:
+ -----------
+ ____ _ ____ _ ____ _ ____ _ ____
+ o--| |o-| |-o| |o-| |-o| |o-| |-o| |o-| |-o| |--o
+ |reg1| | | |W^r1| | | |reg1| | | |W^r1| | | |reg1|
+ | | | | | | | | | | | | | | | | | | .....
+ | | | | | | | | | | | | | | | | | |
+ o--|____|o-| |-o|____|o-| |-o|____|o-| |-o|____|o-| |-o|____|--o
+ | | | | | | | |
+ | | | | | | | |
+ ____ | | ____ | | ____ | | ____ | | ____
+ o--| |o-| |-o| |o-| |-o| |o-| |-o| |o-| |-o| |--o
+ |reg2| | | |W^r2| | | |reg2| | | |W^r2| | | |reg2|
+ | | | | | | | | | | | | | | | | | | .....
+ | | | | | | | | | | | | | | | | | |
+ o--|____|o-| |-o|____|o-| |-o|____|o-| |-o|____|o-| |-o|____|--o
+ | | | | | | | |
+ | | | | | | | |
+ : : : : : : : : :
+ : : : : : : : : :
+ : : : : : : : : :
+ : : : : : : : : :
+ : : : : : : : : :
+
+ ____ | | ____ | | ____ | | ____ | | ____
+ o--| |o-| |-o| |o-| |-o| |o-| |-o| |o-| |-o| |--o
+ |reg | | | |W^r | | | |reg | | | |W^r | | | |reg |
+ | N/2| | | | N/2| | | | N/2| | | | N/2| | | | N/2| .....
+ | | | | | | | | | | | | | | | | | |
+ o--|____|o-|_|-o|____|o-|_|-o|____|o-|_|-o|____|o-|_|-o|____|--o
+
+ ^ ^ ^ ^
+ Initial | Bttrfly | Rd/Wrt | Bttrfly | Rd/Wrt
+ Buffer | | Register | | Register
+ |____________|____________|____________|
+ |
+ |
+ Interconnect
+ Paths
+
+ The use of "in-place" computation permits one to use only one set of
+ registers realized by an array of complex number structures. To describe
+ the coefficients for each butterfly I am using a two dimensional array
+ (stage, butterfly) of complex numbers. The predetermined stage connections
+ will be described in a two dimensional array of indicies. These indicies
+ will be used to determine the order of reading at each stage of the
+ computation.
+*/
+
+
+/*****************************************************************************/
+/* INCLUDE FILES */
+/*****************************************************************************/
+
+#include <stdio.h>
+#include <math.h>
+#include <stdlib.h>
+
+ /* the following is needed only to declare pd_fft() as exportable in MSW */
+#include "m_pd.h"
+
+/* some basic definitions */
+#ifndef BOOL
+#define BOOL int
+#define TRUE 1
+#define FALSE 0
+#endif
+
+#define SAMPLE float /* data type used in calculation */
+
+#define SHORT_SIZE sizeof(short)
+#define INT_SIZE sizeof(int)
+#define FLOAT_SIZE sizeof(float)
+#define SAMPLE_SIZE sizeof(SAMPLE)
+#define PNTR_SIZE sizeof(char *)
+
+#define PI 3.1415927
+#define TWO_PI 6.2831854
+
+/* type definitions for I/O buffers */
+#define REAL 0 /* real only */
+#define IMAG 2 /* imaginary only */
+#define RECT 8 /* real and imaginary */
+#define MAG 16 /* magnitude only */
+#define PHASE 32 /* phase only */
+#define POLAR 64 /* magnitude and phase*/
+
+/* scale definitions for I/O buffers */
+#define LINEAR 0
+#define DB 1 /* 20log10 */
+
+/* transform direction definition */
+#define FORWARD 1 /* Forward FFT */
+#define INVERSE 2 /* Inverse FFT */
+
+/* window type definitions */
+#define HANNING 1
+#define RECTANGULAR 0
+
+
+
+/* network structure definition */
+
+typedef struct Tfft_net {
+ int n;
+ int stages;
+ int bps;
+ int direction;
+ int window_type;
+ int *load_index;
+ SAMPLE *window, *inv_window;
+ SAMPLE *regr;
+ SAMPLE *regi;
+ SAMPLE **indexpr;
+ SAMPLE **indexpi;
+ SAMPLE **indexqr;
+ SAMPLE **indexqi;
+ SAMPLE *coeffr, *inv_coeffr;
+ SAMPLE *coeffi, *inv_coeffi;
+ struct Tfft_net *next;
+} FFT_NET;
+
+
+void cfft(int trnsfrm_dir, int npnt, int window,
+ float *source_buf, int source_form, int source_scale,
+ float *result_buf, int result_form, int result_scale, int debug);
+
+
+/*****************************************************************************/
+/* GLOBAL DECLARATIONS */
+/*****************************************************************************/
+
+static FFT_NET *firstnet;
+
+/* prototypes */
+
+void net_alloc(FFT_NET *fft_net);
+void net_dealloc(FFT_NET *fft_net);
+int power_of_two(int n);
+void create_hanning(SAMPLE *window, int n, SAMPLE scale);
+void create_rectangular(SAMPLE *window, int n, SAMPLE scale);
+void short_to_float(short *short_buf, float *float_buf, int n);
+void load_registers(FFT_NET *fft_net, float *buf, int buf_form,
+ int buf_scale, int trnsfrm_dir);
+void compute_fft(FFT_NET *fft_net);
+void store_registers(FFT_NET *fft_net, float *buf, int buf_form,
+ int buf_scale, int debug);
+void build_fft_network(FFT_NET *fft_net, int n, int window_type);
+
+/*****************************************************************************/
+/* GENERALIZED FAST FOURIER TRANSFORM MODULE */
+/*****************************************************************************/
+
+void cfft(int trnsfrm_dir, int npnt, int window,
+ float *source_buf, int source_form, int source_scale,
+ float *result_buf, int result_form, int result_scale, int debug)
+
+/* modifies: result_buf
+ effects: Computes npnt FFT specified by form, scale, and dir parameters.
+ Source samples (single precision float) are taken from soure_buf and
+ the transfrmd representation is stored in result_buf (single precision
+ float). The parameters are defined as follows:
+
+ trnsfrm_dir = FORWARD | INVERSE
+ npnt = 2^k for some any positive integer k
+ window = HANNING | RECTANGULAR
+ (RECT = real and imag parts, POLAR = magnitude and phase)
+ source_form = REAL | IMAG | RECT | POLAR
+ result_form = REAL | IMAG | RECT | MAG | PHASE | POLAR
+ xxxxxx_scale= LINEAR | DB ( 20log10 |mag| )
+
+ The input/output buffers are stored in a form appropriate to the type.
+ For example: REAL => {real, real, real ...},
+ MAG => {mag, mag, mag, ... },
+ RECT => {real, imag, real, imag, ... },
+ POLAR => {mag, phase, mag, phase, ... }.
+
+ To look at the magnitude (in db) of a 1024 point FFT of a real time
+ signal we have:
+
+ fft(FORWARD, 1024, RECTANGULAR, input, REAL, LINEAR, output, MAG, DB)
+
+ All possible input and output combinations are possible given the
+ choice of type and scale parameters.
+*/
+
+{
+ FFT_NET *thisnet = (FFT_NET *)0;
+ FFT_NET *lastnet = (FFT_NET *)0;
+
+ /* A linked list of fft networks of different sizes is maintained to
+ avoid building with every call. The network is built on the first
+ call but reused for subsequent calls requesting the same size
+ transformation.
+ */
+
+ thisnet=firstnet;
+ while (thisnet) {
+ if (!(thisnet->n == npnt) || !(thisnet->window_type == window)) {
+ /* current net doesn't match size or window type */
+ lastnet=thisnet;
+ thisnet=thisnet->next;
+ continue; /* keep looking */
+ }
+
+ else { /* network matches desired size */
+ load_registers(thisnet, source_buf, source_form, source_scale,
+ trnsfrm_dir);
+ compute_fft(thisnet); /* do transformation */
+ store_registers(thisnet, result_buf, result_form, result_scale,debug);
+ return;
+ }
+ }
+
+ /* none of existing networks match required size*/
+
+ if (lastnet) { /* add new network to end of list */
+ thisnet = (FFT_NET *)malloc(sizeof(FFT_NET)); /* allocate */
+ thisnet->next = 0;
+ lastnet->next = thisnet; /* add to end of list */
+ }
+ else { /* first network to be created */
+ thisnet=firstnet=(FFT_NET *)malloc(sizeof(FFT_NET)); /* alloc. */
+ thisnet->next = 0;
+ }
+
+ /* build new network and compute transformation */
+ build_fft_network(thisnet, npnt, window);
+ load_registers(thisnet, source_buf, source_form, source_scale,
+ trnsfrm_dir);
+ compute_fft(thisnet);
+ store_registers(thisnet, result_buf, result_form, result_scale,debug);
+ return;
+}
+
+void fft_clear(void)
+
+/* effects: Deallocates all preserved FFT networks. Should be used when
+ finished with all computations.
+*/
+
+{
+ FFT_NET *thisnet, *nextnet;
+
+ if (firstnet) {
+ thisnet=firstnet;
+ do {
+ nextnet = thisnet->next;
+ net_dealloc(thisnet);
+ free((char *)thisnet);
+ } while (thisnet = nextnet);
+ }
+}
+
+
+/*****************************************************************************/
+/* NETWORK CONSTRUCTION */
+/*****************************************************************************/
+
+void build_fft_network(FFT_NET *fft_net, int n, int window_type)
+
+
+/* modifies:fft_net
+ effects: Constructs the fft network as described in fft.h. Butterfly
+ coefficients, read/write indicies, bit reversed load indicies,
+ and array allocations are computed.
+*/
+
+{
+ int cntr, i, j, s;
+ int stages, bps;
+ int **p, **q, *pp, *qp;
+ SAMPLE two_pi_div_n = TWO_PI / n;
+
+
+ /* network definition */
+ fft_net->n = n;
+ fft_net->bps = bps = n/2;
+ for (i = 0, j = n; j > 1; j >>= 1, i++);
+ fft_net->stages = stages = i;
+ fft_net->direction = FORWARD;
+ fft_net->window_type = window_type;
+ fft_net->next = (FFT_NET *)0;
+
+ /* allocate registers, index, coefficient arrays */
+ net_alloc(fft_net);
+
+
+ /* create appropriate windows */
+ if (window_type==HANNING) {
+ create_hanning(fft_net->window, n, 1.);
+ create_hanning(fft_net->inv_window, n, 1./n);
+ }
+ else {
+ create_rectangular(fft_net->window, n, 1.);
+ create_rectangular(fft_net->inv_window, n, 1./n);
+ }
+
+
+ /* calculate butterfly coefficients */ {
+
+ int num_diff_coeffs, power_inc, power;
+ SAMPLE *coeffpr = fft_net->coeffr;
+ SAMPLE *coeffpi = fft_net->coeffi;
+ SAMPLE *inv_coeffpr = fft_net->inv_coeffr;
+ SAMPLE *inv_coeffpi = fft_net->inv_coeffi;
+
+ /* stage one coeffs are 1 + 0j */
+ for (i = 0; i < bps; i++) {
+ *coeffpr = *inv_coeffpr = 1.;
+ *coeffpi = *inv_coeffpi = 0.;
+ coeffpr++; inv_coeffpr++;
+ coeffpi++; inv_coeffpi++;
+ }
+
+ /* stage 2 to last stage coeffs need calculation */
+ /* (1<<r <=> 2^r */
+ for (s = 2; s <= stages; s++) {
+
+ num_diff_coeffs = n / (1 << (stages - s + 1));
+ power_inc = 1 << (stages -s);
+ cntr = 0;
+
+ for (i = bps/num_diff_coeffs; i > 0; i--) {
+
+ power = 0;
+
+ for (j = num_diff_coeffs; j > 0; j--) {
+ *coeffpr = cos(two_pi_div_n*power);
+ *inv_coeffpr = cos(two_pi_div_n*power);
+/* AAA change these signs */ *coeffpi = -sin(two_pi_div_n*power);
+/* change back */ *inv_coeffpi = sin(two_pi_div_n*power);
+ power += power_inc;
+ coeffpr++; inv_coeffpr++;
+ coeffpi++; inv_coeffpi++;
+ }
+ }
+ }
+ }
+
+ /* calculate network indicies: stage exchange indicies are
+ calculated and then used as offset values from the base
+ register locations. The final addresses are then stored in
+ fft_net.
+ */ {
+
+ int index, inc;
+ SAMPLE **indexpr = fft_net->indexpr;
+ SAMPLE **indexpi = fft_net->indexpi;
+ SAMPLE **indexqr = fft_net->indexqr;
+ SAMPLE **indexqi = fft_net->indexqi;
+ SAMPLE *regr = fft_net->regr;
+ SAMPLE *regi = fft_net->regi;
+
+
+ /* allocate temporary 2d stage exchange index, 1d temp
+ load index */
+ p = (int **)malloc(stages * PNTR_SIZE);
+ q = (int **)malloc(stages * PNTR_SIZE);
+
+ for (s = 0; s < stages; s++) {
+ p[s] = (int *)malloc(bps * INT_SIZE);
+ q[s] = (int *)malloc(bps * INT_SIZE);
+ }
+
+ /* calculate stage exchange indicies: */
+ for (s = 0; s < stages; s++) {
+ pp = p[s];
+ qp = q[s];
+ inc = 1 << s;
+ cntr = 1 << (stages-s-1);
+ i = j = index = 0;
+
+ do {
+ do {
+ qp[i] = index + inc;
+ pp[i++] = index++;
+ } while (++j < inc);
+ index = qp[i-1] + 1;
+ j = 0;
+ } while (--cntr);
+ }
+
+ /* compute actual address values using indicies as offsets */
+ for (s = 0; s < stages; s++) {
+ for (i = 0; i < bps; i++) {
+ *indexpr++ = regr + p[s][i];
+ *indexpi++ = regi + p[s][i];
+ *indexqr++ = regr + q[s][i];
+ *indexqi++ = regi + q[s][i];
+ }
+ }
+ }
+
+
+ /* calculate load indicies (bit reverse ordering) */
+ /* bit reverse ordering achieved by passing normal
+ order indicies backwards through the network */
+
+ /* init to normal order indicies */ {
+ int *load_index,*load_indexp;
+ int *temp_indexp, *temp_index;
+ temp_index=temp_indexp=(int *)malloc(n * INT_SIZE);
+
+ i = 0; j = n;
+ load_index = load_indexp = fft_net->load_index;
+
+ while (j--)
+ *load_indexp++ = i++;
+
+ /* pass indicies backwards through net */
+ for (s = stages - 1; s > 0; s--) {
+ pp = p[s];
+ qp = q[s];
+
+ for (i = 0; i < bps; i++) {
+ temp_index[pp[i]]=load_index[2*i];
+ temp_index[qp[i]]=load_index[2*i+1];
+ }
+ j = n;
+ load_indexp = load_index;
+ temp_indexp = temp_index;
+ while (j--)
+ *load_indexp++ = *temp_indexp++;
+ }
+
+ /* free all temporary arrays */
+ free((char *)temp_index);
+ for (s = 0; s < stages; s++) {
+ free((char *)p[s]);free((char *)q[s]);
+ }
+ free((char *)p);free((char *)q);
+ }
+}
+
+
+
+/*****************************************************************************/
+/* REGISTER LOAD AND STORE */
+/*****************************************************************************/
+
+void load_registers(FFT_NET *fft_net, float *buf, int buf_form,
+ int buf_scale, int trnsfrm_dir)
+
+/* effects: Multiplies the input buffer with the appropriate window and
+ stores the resulting values in the initial registers of the
+ network. Input buffer must contain values appropriate to form.
+ For RECT, the buffer contains real num. followed by imag num,
+ and for POLAR, it contains magnitude followed by phase. Pure
+ inputs are listed normally. Both LINEAR and DB scales are
+ interpreted.
+*/
+
+{
+ int *load_index = fft_net->load_index;
+ SAMPLE *window;
+ int index, i = 0;
+
+ if (trnsfrm_dir==FORWARD) window = fft_net->window;
+ else if (trnsfrm_dir==INVERSE) window = fft_net->inv_window;
+ else {
+ fprintf(stderr, "load_registers:illegal transform direction\n");
+ exit(0);
+ }
+ fft_net->direction = trnsfrm_dir;
+
+ switch(buf_scale) {
+ case LINEAR: {
+
+ switch (buf_form) {
+ case REAL: { /* pure REAL */
+ while (i < fft_net->n) {
+ index = load_index[i];
+ fft_net->regr[i]=(SAMPLE)buf[index] * window[index];
+ fft_net->regi[i]=0.;
+ i++;
+ }
+ } break;
+
+ case IMAG: { /* pure IMAGinary */
+ while (i < fft_net->n) {
+ index = load_index[i];
+ fft_net->regr[i]=0;
+ fft_net->regi[i]=(SAMPLE)buf[index] * window[index];
+ i++;
+ }
+ } break;
+
+ case RECT: { /* both REAL and IMAGinary */
+ while (i < fft_net->n) {
+ index = load_index[i];
+ fft_net->regr[i]=(SAMPLE)buf[index*2] * window[index];
+ fft_net->regi[i]=(SAMPLE)buf[index*2+1] * window[index];
+ i++;
+ }
+ } break;
+
+ case POLAR: { /* magnitude followed by phase */
+ while (i < fft_net->n) {
+ index = load_index[i];
+ fft_net->regr[i]=(SAMPLE)(buf[index*2] * cos(buf[index*2+1]))
+ * window[index];
+ fft_net->regi[i]=(SAMPLE)(buf[index*2] * sin(buf[index*2+1]))
+ * window[index];
+ i++;
+ }
+ } break;
+
+ default: {
+ fprintf(stderr, "load_registers:illegal input form\n");
+ exit(0);
+ } break;
+ }
+ } break;
+
+ case DB: {
+
+ switch (buf_form) {
+ case REAL: { /* log pure REAL */
+ while (i < fft_net->n) {
+ index = load_index[i];
+ fft_net->regr[i]=(SAMPLE)pow(10., (1./20.)*buf[index])
+ * window[index]; /* window scaling after linearization */
+ fft_net->regi[i]=0.;
+ i++;
+ }
+ } break;
+
+ case IMAG: { /* log pure IMAGinary */
+ while (i < fft_net->n) {
+ index = load_index[i];
+ fft_net->regr[i]=0.;
+ fft_net->regi[i]=(SAMPLE)pow(10., (1./20.)*buf[index])
+ * window[index];
+ i++;
+ }
+ } break;
+
+ case RECT: { /* log REAL and log IMAGinary */
+ while (i < fft_net->n) {
+ index = load_index[i];
+ fft_net->regr[i]=(SAMPLE)pow(10., (1./20.)*buf[index*2])
+ * window[index];
+ fft_net->regi[i]=(SAMPLE)pow(10., (1./20.)*buf[index*2+1])
+ * window[index];
+ i++;
+ }
+ } break;
+
+ case POLAR: { /* log mag followed by phase */
+ while (i < fft_net->n) {
+ index = load_index[i];
+ fft_net->regr[i]=(SAMPLE)(pow(10., (1./20.)*buf[index*2])
+ * cos(buf[index*2+1])) * window[index];
+ fft_net->regi[i]=(SAMPLE)(pow(10., (1./20.)*buf[index*2])
+ * sin(buf[index*2+1])) * window[index];
+ i++;
+ }
+ } break;
+
+ default: {
+ fprintf(stderr, "load_registers:illegal input form\n");
+ exit(0);
+ } break;
+ }
+ } break;
+
+ default: {
+ fprintf(stderr, "load_registers:illegal input scale\n");
+ exit(0);
+ } break;
+ }
+}
+
+
+void store_registers(FFT_NET *fft_net, float *buf, int buf_form,
+ int buf_scale, int debug)
+
+/* modifies: buf
+ effects: Writes the final contents of the network registers into buf in
+ either linear or db scale, polar or rectangular form. If any of
+ the pure forms(REAL, IMAG, MAG, or PHASE) are used then only the
+ corresponding part of the registers is stored in buf.
+*/
+
+{
+ int i;
+ SAMPLE real, imag;
+ int n;
+
+ i = 0;
+ n = fft_net->n;
+
+ switch (buf_scale) {
+ case LINEAR: {
+
+ switch (buf_form) {
+ case REAL: { /* pure REAL */
+ do {
+ *buf++ = (float)fft_net->regr[i];
+ } while (++i < n);
+ } break;
+
+ case IMAG: { /* pure IMAGinary */
+ do {
+ *buf++ = (float)fft_net->regi[i];
+ } while (++i < n);
+ } break;
+
+ case RECT: { /* both REAL and IMAGinary */
+ do {
+ *buf++ = (float)fft_net->regr[i];
+ *buf++ = (float)fft_net->regi[i];
+ } while (++i < n);
+ } break;
+
+ case MAG: { /* magnitude only */
+ do {
+ real = fft_net->regr[i];
+ imag = fft_net->regi[i];
+ *buf++ = (float)sqrt(real*real+imag*imag);
+ } while (++i < n);
+ } break;
+
+ case PHASE: { /* phase only */
+ do {
+ real = fft_net->regr[i];
+ imag = fft_net->regi[i];
+ if (real > .00001)
+ *buf++ = (float)atan2(imag, real);
+ else { /* deal with bad case */
+ if (imag > 0){ *buf++ = PI / 2.;
+ if(debug) fprintf(stderr,"real=0 and imag > 0\n");}
+ else if (imag < 0){ *buf++ = -PI / 2.;
+ if(debug) fprintf(stderr,"real=0 and imag < 0\n");}
+ else { *buf++ = 0;
+ if(debug) fprintf(stderr,"real=0 and imag=0\n");}
+ }
+ } while (++i < n);
+ } break;
+
+ case POLAR: { /* magnitude and phase */
+ do {
+ real = fft_net->regr[i];
+ imag = fft_net->regi[i];
+ *buf++ = (float)sqrt(real*real+imag*imag);
+ if (real) /* a hack to avoid div by zero */
+ *buf++ = (float)atan2(imag, real);
+ else { /* deal with bad case */
+ if (imag > 0) *buf++ = PI / 2.;
+ else if (imag < 0) *buf++ = -PI / 2.;
+ else *buf++ = 0;
+ }
+ } while (++i < n);
+ } break;
+
+ default: {
+ fprintf(stderr, "store_registers:illegal output form\n");
+ exit(0);
+ } break;
+ }
+ } break;
+
+ case DB: {
+
+ switch (buf_form) {
+ case REAL: { /* real only */
+ do {
+ *buf++ = (float)20.*log10(fft_net->regr[i]);
+ } while (++i < n);
+ } break;
+
+ case IMAG: { /* imag only */
+ do {
+ *buf++ = (float)20.*log10(fft_net->regi[i]);
+ } while (++i < n);
+ } break;
+
+ case RECT: { /* real and imag */
+ do {
+ *buf++ = (float)20.*log10(fft_net->regr[i]);
+ *buf++ = (float)20.*log10(fft_net->regi[i]);
+ } while (++i < n);
+ } break;
+
+ case MAG: { /* magnitude only */
+ do {
+ real = fft_net->regr[i];
+ imag = fft_net->regi[i];
+ *buf++ = (float)20.*log10(sqrt(real*real+imag*imag));
+ } while (++i < n);
+ } break;
+
+ case PHASE: { /* phase only */
+ do {
+ real = fft_net->regr[i];
+ imag = fft_net->regi[i];
+ if (real)
+ *buf++ = (float)atan2(imag, real);
+ else { /* deal with bad case */
+ if (imag > 0) *buf++ = PI / 2.;
+ else if (imag < 0) *buf++ = -PI / 2.;
+ else *buf++ = 0;
+ }
+ } while (++i < n);
+ } break;
+
+ case POLAR: { /* magnitude and phase */
+ do {
+ real = fft_net->regr[i];
+ imag = fft_net->regi[i];
+ *buf++ = (float)20.*log10(sqrt(real*real+imag*imag));
+ if (real)
+ *buf++ = (float)atan2(imag, real);
+ else { /* deal with bad case */
+ if (imag > 0) *buf++ = PI / 2.;
+ else if (imag < 0) *buf++ = -PI / 2.;
+ else *buf++ = 0;
+ }
+ } while (++i < n);
+ } break;
+
+ default: {
+ fprintf(stderr, "store_registers:illegal output form\n");
+ exit(0);
+ } break;
+ }
+ } break;
+
+ default: {
+ fprintf(stderr, "store_registers:illegal output scale\n");
+ exit(0);
+ } break;
+ }
+}
+
+
+
+/*****************************************************************************/
+/* COMPUTE TRANSFORMATION */
+/*****************************************************************************/
+
+void compute_fft(FFT_NET *fft_net)
+
+
+/* modifies: fft_net
+ effects: Passes the values (already loaded) in the registers through
+ the network, multiplying with appropriate coefficients at each
+ stage. The fft result will be in the registers at the end of
+ the computation. The direction of the transformation is indicated
+ by the network flag 'direction'. The form of the computation is:
+
+ X(pn) = X(p) + C*X(q)
+ X(qn) = X(p) - C*X(q)
+
+ where X(pn,qn) represents the output of the registers at each stage.
+ The calculations are actually done in place. Register pointers are
+ used to speed up the calculations.
+
+ Register and coefficient addresses involved in the calculations
+ are stored sequentially and are accessed as such. fft_net->indexp,
+ indexq contain pointers to the relevant addresses, and fft_net->coeffs,
+ inv_coeffs points to the appropriate coefficients at each stage of the
+ computation.
+*/
+
+{
+ SAMPLE **xpr, **xpi, **xqr, **xqi, *cr, *ci;
+ int i;
+ SAMPLE tpr, tpi, tqr, tqi;
+ int bps = fft_net->bps;
+ int cnt = bps * (fft_net->stages - 1);
+
+ /* predetermined register addresses and coefficients */
+ xpr = fft_net->indexpr;
+ xpi = fft_net->indexpi;
+ xqr = fft_net->indexqr;
+ xqi = fft_net->indexqi;
+
+ if (fft_net->direction==FORWARD) { /* FORWARD FFT coefficients */
+ cr = fft_net->coeffr;
+ ci = fft_net->coeffi;
+ }
+ else { /* INVERSE FFT coefficients */
+ cr = fft_net->inv_coeffr;
+ ci = fft_net->inv_coeffi;
+ }
+
+ /* stage one coefficients are 1 + 0j so C*X(q)=X(q) */
+ /* bps mults can be avoided */
+
+ for (i = 0; i < bps; i++) {
+
+ /* add X(p) and X(q) */
+ tpr = **xpr + **xqr;
+ tpi = **xpi + **xqi;
+ tqr = **xpr - **xqr;
+ tqi = **xpi - **xqi;
+
+ /* exchange register with temp */
+ **xpr = tpr;
+ **xpi = tpi;
+ **xqr = tqr;
+ **xqi = tqi;
+
+ /* next set of register for calculations: */
+ xpr++; xpi++; xqr++; xqi++; cr++; ci++;
+
+ }
+
+ for (i = 0; i < cnt; i++) {
+
+ /* mult X(q) by coeff C */
+ tqr = **xqr * *cr - **xqi * *ci;
+ tqi = **xqr * *ci + **xqi * *cr;
+
+ /* exchange register with temp */
+ **xqr = tqr;
+ **xqi = tqi;
+
+ /* add X(p) and X(q) */
+ tpr = **xpr + **xqr;
+ tpi = **xpi + **xqi;
+ tqr = **xpr - **xqr;
+ tqi = **xpi - **xqi;
+
+ /* exchange register with temp */
+ **xpr = tpr;
+ **xpi = tpi;
+ **xqr = tqr;
+ **xqi = tqi;
+ /* next set of register for calculations: */
+ xpr++; xpi++; xqr++; xqi++; cr++; ci++;
+ }
+}
+
+
+/****************************************************************************/
+/* SUPPORT MODULES */
+/****************************************************************************/
+
+void net_alloc(FFT_NET *fft_net)
+
+
+/* effects: Allocates appropriate two dimensional arrays and assigns
+ correct internal pointers.
+*/
+
+{
+
+ int stages, bps, n;
+
+ n = fft_net->n;
+ stages = fft_net->stages;
+ bps = fft_net->bps;
+
+
+ /* two dimensional arrays with elements stored sequentially */
+
+ fft_net->load_index = (int *)malloc(n * INT_SIZE);
+ fft_net->regr = (SAMPLE *)malloc(n * SAMPLE_SIZE);
+ fft_net->regi = (SAMPLE *)malloc(n * SAMPLE_SIZE);
+ fft_net->coeffr = (SAMPLE *)malloc(stages*bps*SAMPLE_SIZE);
+ fft_net->coeffi = (SAMPLE *)malloc(stages*bps*SAMPLE_SIZE);
+ fft_net->inv_coeffr = (SAMPLE *)malloc(stages*bps*SAMPLE_SIZE);
+ fft_net->inv_coeffi = (SAMPLE *)malloc(stages*bps*SAMPLE_SIZE);
+ fft_net->indexpr = (SAMPLE **)malloc(stages * bps * PNTR_SIZE);
+ fft_net->indexpi = (SAMPLE **)malloc(stages * bps * PNTR_SIZE);
+ fft_net->indexqr = (SAMPLE **)malloc(stages * bps * PNTR_SIZE);
+ fft_net->indexqi = (SAMPLE **)malloc(stages * bps * PNTR_SIZE);
+
+ /* one dimensional load window */
+ fft_net->window = (SAMPLE *)malloc(n * SAMPLE_SIZE);
+ fft_net->inv_window = (SAMPLE *)malloc(n * SAMPLE_SIZE);
+}
+
+void net_dealloc(FFT_NET *fft_net)
+
+
+/* effects: Deallocates given FFT network.
+*/
+
+{
+
+ free((char *)fft_net->load_index);
+ free((char *)fft_net->regr);
+ free((char *)fft_net->regi);
+ free((char *)fft_net->coeffr);
+ free((char *)fft_net->coeffi);
+ free((char *)fft_net->inv_coeffr);
+ free((char *)fft_net->inv_coeffi);
+ free((char *)fft_net->indexpr);
+ free((char *)fft_net->indexpi);
+ free((char *)fft_net->indexqr);
+ free((char *)fft_net->indexqi);
+ free((char *)fft_net->window);
+ free((char *)fft_net->inv_window);
+}
+
+
+BOOL power_of_two(int n)
+
+/* effects: Returns TRUE if n is a power of two, otherwise FALSE.
+*/
+
+{
+ int i;
+
+ for (i = n; i > 1; i >>= 1)
+ if (i & 1) return FALSE; /* more than one bit high */
+ return TRUE;
+}
+
+
+void create_hanning(SAMPLE *window, int n, SAMPLE scale)
+
+/* effects: Fills the buffer window with a hanning window of the appropriate
+ size scaled by scale.
+*/
+
+{
+ SAMPLE a, pi_div_n = PI/n;
+ int k;
+
+ for (k=1; k <= n; k++) {
+ a = sin(k * pi_div_n);
+ *window++ = scale * a * a;
+ }
+}
+
+
+void create_rectangular(SAMPLE *window, int n, SAMPLE scale)
+
+/* effects: Fills the buffer window with a rectangular window of the
+ appropriate size of height scale.
+*/
+
+{
+ while (n--)
+ *window++ = scale;
+}
+
+
+void short_to_float(short *short_buf, float *float_buf, int n)
+
+/* effects; Converts short_buf to floats and stores them in float_buf.
+*/
+
+{
+ while (n--) {
+ *float_buf++ = (float)*short_buf++;
+ }
+}
+
+
+/* here's the meat: */
+
+void pd_fft(float *buf, int npoints, int inverse)
+{
+ double renorm;
+ float *fp;
+ int i;
+ renorm = (inverse ? npoints : 1.);
+ cfft((inverse ? INVERSE : FORWARD), npoints, RECTANGULAR,
+ buf, RECT, LINEAR, buf, RECT, LINEAR, 0);
+ for (i = npoints << 1, fp = buf; i--; fp++) *fp *= renorm;
+}
diff --git a/desiredata/src/d_mayer_fft.c b/desiredata/src/d_mayer_fft.c
new file mode 100644
index 00000000..74ee1c76
--- /dev/null
+++ b/desiredata/src/d_mayer_fft.c
@@ -0,0 +1,422 @@
+/*
+** FFT and FHT routines
+** Copyright 1988, 1993; Ron Mayer
+**
+** mayer_fht(fz,n);
+** Does a hartley transform of "n" points in the array "fz".
+** mayer_fft(n,real,imag)
+** Does a fourier transform of "n" points of the "real" and
+** "imag" arrays.
+** mayer_ifft(n,real,imag)
+** Does an inverse fourier transform of "n" points of the "real"
+** and "imag" arrays.
+** mayer_realfft(n,real)
+** Does a real-valued fourier transform of "n" points of the
+** "real" array. The real part of the transform ends
+** up in the first half of the array and the imaginary part of the
+** transform ends up in the second half of the array.
+** mayer_realifft(n,real)
+** The inverse of the realfft() routine above.
+**
+**
+** NOTE: This routine uses at least 2 patented algorithms, and may be
+** under the restrictions of a bunch of different organizations.
+** Although I wrote it completely myself, it is kind of a derivative
+** of a routine I once authored and released under the GPL, so it
+** may fall under the free software foundation's restrictions;
+** it was worked on as a Stanford Univ project, so they claim
+** some rights to it; it was further optimized at work here, so
+** I think this company claims parts of it. The patents are
+** held by R. Bracewell (the FHT algorithm) and O. Buneman (the
+** trig generator), both at Stanford Univ.
+** If it were up to me, I'd say go do whatever you want with it;
+** but it would be polite to give credit to the following people
+** if you use this anywhere:
+** Euler - probable inventor of the fourier transform.
+** Gauss - probable inventor of the FFT.
+** Hartley - probable inventor of the hartley transform.
+** Buneman - for a really cool trig generator
+** Mayer(me) - for authoring this particular version and
+** including all the optimizations in one package.
+** Thanks,
+** Ron Mayer; mayer@acuson.com
+**
+*/
+
+/* This is a slightly modified version of Mayer's contribution; write
+* msp@ucsd.edu for the original code. Kudos to Mayer for a fine piece
+* of work. -msp
+*/
+
+#ifdef MSW
+#pragma warning( disable : 4305 ) /* uncast const double to float */
+#pragma warning( disable : 4244 ) /* uncast double to float */
+#pragma warning( disable : 4101 ) /* unused local variables */
+#endif
+
+/* the following is needed only to declare pd_fft() as exportable in MSW */
+#include "m_pd.h"
+
+#define REAL float
+#define GOOD_TRIG
+
+#ifdef GOOD_TRIG
+#else
+#define FAST_TRIG
+#endif
+
+#if defined(GOOD_TRIG)
+#define FHT_SWAP(a,b,t) {(t)=(a);(a)=(b);(b)=(t);}
+#define TRIG_VARS \
+ int t_lam=0;
+#define TRIG_INIT(k,c,s) \
+ { \
+ int i; \
+ for (i=2 ; i<=k ; i++) \
+ {coswrk[i]=costab[i];sinwrk[i]=sintab[i];} \
+ t_lam = 0; \
+ c = 1; \
+ s = 0; \
+ }
+#define TRIG_NEXT(k,c,s) \
+ { \
+ int i,j; \
+ (t_lam)++; \
+ for (i=0 ; !((1<<i)&t_lam) ; i++); \
+ i = k-i; \
+ s = sinwrk[i]; \
+ c = coswrk[i]; \
+ if (i>1) \
+ { \
+ for (j=k-i+2 ; (1<<j)&t_lam ; j++); \
+ j = k - j; \
+ sinwrk[i] = halsec[i] * (sinwrk[i-1] + sinwrk[j]); \
+ coswrk[i] = halsec[i] * (coswrk[i-1] + coswrk[j]); \
+ } \
+ }
+#define TRIG_RESET(k,c,s)
+#endif
+
+#if defined(FAST_TRIG)
+#define TRIG_VARS \
+ REAL t_c,t_s;
+#define TRIG_INIT(k,c,s) \
+ { \
+ t_c = costab[k]; \
+ t_s = sintab[k]; \
+ c = 1; \
+ s = 0; \
+ }
+#define TRIG_NEXT(k,c,s) \
+ { \
+ REAL t = c; \
+ c = t*t_c - s*t_s; \
+ s = t*t_s + s*t_c; \
+ }
+#define TRIG_RESET(k,c,s)
+#endif
+
+static REAL halsec[20]=
+ {
+ 0,
+ 0,
+ .54119610014619698439972320536638942006107206337801,
+ .50979557910415916894193980398784391368261849190893,
+ .50241928618815570551167011928012092247859337193963,
+ .50060299823519630134550410676638239611758632599591,
+ .50015063602065098821477101271097658495974913010340,
+ .50003765191554772296778139077905492847503165398345,
+ .50000941253588775676512870469186533538523133757983,
+ .50000235310628608051401267171204408939326297376426,
+ .50000058827484117879868526730916804925780637276181,
+ .50000014706860214875463798283871198206179118093251,
+ .50000003676714377807315864400643020315103490883972,
+ .50000000919178552207366560348853455333939112569380,
+ .50000000229794635411562887767906868558991922348920,
+ .50000000057448658687873302235147272458812263401372
+ };
+static REAL costab[20]=
+ {
+ .00000000000000000000000000000000000000000000000000,
+ .70710678118654752440084436210484903928483593768847,
+ .92387953251128675612818318939678828682241662586364,
+ .98078528040323044912618223613423903697393373089333,
+ .99518472667219688624483695310947992157547486872985,
+ .99879545620517239271477160475910069444320361470461,
+ .99969881869620422011576564966617219685006108125772,
+ .99992470183914454092164649119638322435060646880221,
+ .99998117528260114265699043772856771617391725094433,
+ .99999529380957617151158012570011989955298763362218,
+ .99999882345170190992902571017152601904826792288976,
+ .99999970586288221916022821773876567711626389934930,
+ .99999992646571785114473148070738785694820115568892,
+ .99999998161642929380834691540290971450507605124278,
+ .99999999540410731289097193313960614895889430318945,
+ .99999999885102682756267330779455410840053741619428
+ };
+static REAL sintab[20]=
+ {
+ 1.0000000000000000000000000000000000000000000000000,
+ .70710678118654752440084436210484903928483593768846,
+ .38268343236508977172845998403039886676134456248561,
+ .19509032201612826784828486847702224092769161775195,
+ .09801714032956060199419556388864184586113667316749,
+ .04906767432741801425495497694268265831474536302574,
+ .02454122852291228803173452945928292506546611923944,
+ .01227153828571992607940826195100321214037231959176,
+ .00613588464915447535964023459037258091705788631738,
+ .00306795676296597627014536549091984251894461021344,
+ .00153398018628476561230369715026407907995486457522,
+ .00076699031874270452693856835794857664314091945205,
+ .00038349518757139558907246168118138126339502603495,
+ .00019174759731070330743990956198900093346887403385,
+ .00009587379909597734587051721097647635118706561284,
+ .00004793689960306688454900399049465887274686668768
+ };
+static REAL coswrk[20]=
+ {
+ .00000000000000000000000000000000000000000000000000,
+ .70710678118654752440084436210484903928483593768847,
+ .92387953251128675612818318939678828682241662586364,
+ .98078528040323044912618223613423903697393373089333,
+ .99518472667219688624483695310947992157547486872985,
+ .99879545620517239271477160475910069444320361470461,
+ .99969881869620422011576564966617219685006108125772,
+ .99992470183914454092164649119638322435060646880221,
+ .99998117528260114265699043772856771617391725094433,
+ .99999529380957617151158012570011989955298763362218,
+ .99999882345170190992902571017152601904826792288976,
+ .99999970586288221916022821773876567711626389934930,
+ .99999992646571785114473148070738785694820115568892,
+ .99999998161642929380834691540290971450507605124278,
+ .99999999540410731289097193313960614895889430318945,
+ .99999999885102682756267330779455410840053741619428
+ };
+static REAL sinwrk[20]=
+ {
+ 1.0000000000000000000000000000000000000000000000000,
+ .70710678118654752440084436210484903928483593768846,
+ .38268343236508977172845998403039886676134456248561,
+ .19509032201612826784828486847702224092769161775195,
+ .09801714032956060199419556388864184586113667316749,
+ .04906767432741801425495497694268265831474536302574,
+ .02454122852291228803173452945928292506546611923944,
+ .01227153828571992607940826195100321214037231959176,
+ .00613588464915447535964023459037258091705788631738,
+ .00306795676296597627014536549091984251894461021344,
+ .00153398018628476561230369715026407907995486457522,
+ .00076699031874270452693856835794857664314091945205,
+ .00038349518757139558907246168118138126339502603495,
+ .00019174759731070330743990956198900093346887403385,
+ .00009587379909597734587051721097647635118706561284,
+ .00004793689960306688454900399049465887274686668768
+ };
+
+
+#define SQRT2_2 0.70710678118654752440084436210484
+#define SQRT2 2*0.70710678118654752440084436210484
+
+void mayer_fht(REAL *fz, int n)
+{
+/* REAL a,b;
+REAL c1,s1,s2,c2,s3,c3,s4,c4;
+ REAL f0,g0,f1,g1,f2,g2,f3,g3; */
+ int k,k1,k2,k3,k4,kx;
+ REAL *fi,*fn,*gi;
+ TRIG_VARS;
+
+ for (k1=1,k2=0;k1<n;k1++)
+ {
+ REAL aa;
+ for (k=n>>1; (!((k2^=k)&k)); k>>=1);
+ if (k1>k2)
+ {
+ aa=fz[k1];fz[k1]=fz[k2];fz[k2]=aa;
+ }
+ }
+ for ( k=0 ; (1<<k)<n ; k++ );
+ k &= 1;
+ if (k==0)
+ {
+ for (fi=fz,fn=fz+n;fi<fn;fi+=4)
+ {
+ REAL f0,f1,f2,f3;
+ f1 = fi[0 ]-fi[1 ];
+ f0 = fi[0 ]+fi[1 ];
+ f3 = fi[2 ]-fi[3 ];
+ f2 = fi[2 ]+fi[3 ];
+ fi[2 ] = (f0-f2);
+ fi[0 ] = (f0+f2);
+ fi[3 ] = (f1-f3);
+ fi[1 ] = (f1+f3);
+ }
+ }
+ else
+ {
+ for (fi=fz,fn=fz+n,gi=fi+1;fi<fn;fi+=8,gi+=8)
+ {
+ REAL bs1,bc1,bs2,bc2,bs3,bc3,bs4,bc4,
+ bg0,bf0,bf1,bg1,bf2,bg2,bf3,bg3;
+ bc1 = fi[0 ] - gi[0 ];
+ bs1 = fi[0 ] + gi[0 ];
+ bc2 = fi[2 ] - gi[2 ];
+ bs2 = fi[2 ] + gi[2 ];
+ bc3 = fi[4 ] - gi[4 ];
+ bs3 = fi[4 ] + gi[4 ];
+ bc4 = fi[6 ] - gi[6 ];
+ bs4 = fi[6 ] + gi[6 ];
+ bf1 = (bs1 - bs2);
+ bf0 = (bs1 + bs2);
+ bg1 = (bc1 - bc2);
+ bg0 = (bc1 + bc2);
+ bf3 = (bs3 - bs4);
+ bf2 = (bs3 + bs4);
+ bg3 = SQRT2*bc4;
+ bg2 = SQRT2*bc3;
+ fi[4 ] = bf0 - bf2;
+ fi[0 ] = bf0 + bf2;
+ fi[6 ] = bf1 - bf3;
+ fi[2 ] = bf1 + bf3;
+ gi[4 ] = bg0 - bg2;
+ gi[0 ] = bg0 + bg2;
+ gi[6 ] = bg1 - bg3;
+ gi[2 ] = bg1 + bg3;
+ }
+ }
+ if (n<16) return;
+
+ do
+ {
+ REAL s1,c1;
+ int ii;
+ k += 2;
+ k1 = 1 << k;
+ k2 = k1 << 1;
+ k4 = k2 << 1;
+ k3 = k2 + k1;
+ kx = k1 >> 1;
+ fi = fz;
+ gi = fi + kx;
+ fn = fz + n;
+ do
+ {
+ REAL g0,f0,f1,g1,f2,g2,f3,g3;
+ f1 = fi[0 ] - fi[k1];
+ f0 = fi[0 ] + fi[k1];
+ f3 = fi[k2] - fi[k3];
+ f2 = fi[k2] + fi[k3];
+ fi[k2] = f0 - f2;
+ fi[0 ] = f0 + f2;
+ fi[k3] = f1 - f3;
+ fi[k1] = f1 + f3;
+ g1 = gi[0 ] - gi[k1];
+ g0 = gi[0 ] + gi[k1];
+ g3 = SQRT2 * gi[k3];
+ g2 = SQRT2 * gi[k2];
+ gi[k2] = g0 - g2;
+ gi[0 ] = g0 + g2;
+ gi[k3] = g1 - g3;
+ gi[k1] = g1 + g3;
+ gi += k4;
+ fi += k4;
+ } while (fi<fn);
+ TRIG_INIT(k,c1,s1);
+ for (ii=1;ii<kx;ii++)
+ {
+ REAL c2,s2;
+ TRIG_NEXT(k,c1,s1);
+ c2 = c1*c1 - s1*s1;
+ s2 = 2*(c1*s1);
+ fn = fz + n;
+ fi = fz +ii;
+ gi = fz +k1-ii;
+ do
+ {
+ REAL a,b,g0,f0,f1,g1,f2,g2,f3,g3;
+ b = s2*fi[k1] - c2*gi[k1];
+ a = c2*fi[k1] + s2*gi[k1];
+ f1 = fi[0 ] - a;
+ f0 = fi[0 ] + a;
+ g1 = gi[0 ] - b;
+ g0 = gi[0 ] + b;
+ b = s2*fi[k3] - c2*gi[k3];
+ a = c2*fi[k3] + s2*gi[k3];
+ f3 = fi[k2] - a;
+ f2 = fi[k2] + a;
+ g3 = gi[k2] - b;
+ g2 = gi[k2] + b;
+ b = s1*f2 - c1*g3;
+ a = c1*f2 + s1*g3;
+ fi[k2] = f0 - a;
+ fi[0 ] = f0 + a;
+ gi[k3] = g1 - b;
+ gi[k1] = g1 + b;
+ b = c1*g2 - s1*f3;
+ a = s1*g2 + c1*f3;
+ gi[k2] = g0 - a;
+ gi[0 ] = g0 + a;
+ fi[k3] = f1 - b;
+ fi[k1] = f1 + b;
+ gi += k4;
+ fi += k4;
+ } while (fi<fn);
+ }
+ TRIG_RESET(k,c1,s1);
+ } while (k4<n);
+}
+
+void mayer_fft(int n, REAL *real, REAL *imag)
+{
+ REAL a,b,c,d;
+ REAL q,r,s,t;
+ int i,j,k;
+ for (i=1,j=n-1,k=n/2;i<k;i++,j--) {
+ a = real[i]; b = real[j]; q=a+b; r=a-b;
+ c = imag[i]; d = imag[j]; s=c+d; t=c-d;
+ real[i] = (q+t)*.5; real[j] = (q-t)*.5;
+ imag[i] = (s-r)*.5; imag[j] = (s+r)*.5;
+ }
+ mayer_fht(real,n);
+ mayer_fht(imag,n);
+}
+
+void mayer_ifft(int n, REAL *real, REAL *imag)
+{
+ REAL a,b,c,d;
+ REAL q,r,s,t;
+ int i,j,k;
+ mayer_fht(real,n);
+ mayer_fht(imag,n);
+ for (i=1,j=n-1,k=n/2;i<k;i++,j--) {
+ a = real[i]; b = real[j]; q=a+b; r=a-b;
+ c = imag[i]; d = imag[j]; s=c+d; t=c-d;
+ imag[i] = (s+r)*0.5; imag[j] = (s-r)*0.5;
+ real[i] = (q-t)*0.5; real[j] = (q+t)*0.5;
+ }
+}
+
+void mayer_realfft(int n, REAL *real)
+{
+ REAL a,b;
+ int i,j,k;
+ mayer_fht(real,n);
+ for (i=1,j=n-1,k=n/2;i<k;i++,j--) {
+ a = real[i];
+ b = real[j];
+ real[j] = (a-b)*0.5;
+ real[i] = (a+b)*0.5;
+ }
+}
+
+void mayer_realifft(int n, REAL *real)
+{
+ REAL a,b;
+ int i,j,k;
+ for (i=1,j=n-1,k=n/2;i<k;i++,j--) {
+ a = real[i];
+ b = real[j];
+ real[j] = (a-b);
+ real[i] = (a+b);
+ }
+ mayer_fht(real,n);
+}
diff --git a/desiredata/src/d_soundfile.c b/desiredata/src/d_soundfile.c
new file mode 100644
index 00000000..2a281869
--- /dev/null
+++ b/desiredata/src/d_soundfile.c
@@ -0,0 +1,2059 @@
+/* Copyright (c) 1997-1999 Miller Puckette.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* this file contains, first, a collection of soundfile access routines, a
+sort of soundfile library. Second, the "soundfiler" object is defined which
+uses the routines to read or write soundfiles, synchronously, from garrays.
+These operations are not to be done in "real time" as they may have to wait
+for disk accesses (even the write routine.) Finally, the realtime objects
+readsf~ and writesf~ are defined which confine disk operations to a separate
+thread so that they can be used in real time. The readsf~ and writesf~
+objects use Posix-like threads. */
+
+/* threaded soundfiler by Tim Blechmann */
+// #define THREADED_SF
+
+#ifndef MSW
+#include <unistd.h>
+#include <fcntl.h>
+#endif
+#include <pthread.h>
+#ifdef MSW
+#include <io.h>
+#endif
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+#define PD_PLUSPLUS_FACE
+#include "desire.h"
+#define a_symbol a_w.w_symbol
+#define a_float a_w.w_float
+
+#define MAXSFCHANS 64
+
+#ifdef _LARGEFILE64_SOURCE
+# define open open64
+# define lseek lseek64
+#endif
+
+static bool debug=0;
+
+#define EAT_ARG(ATYPE,VAR) if (argc<1 || argv->a_type != ATYPE) goto usage; else {VAR = *argv++; argc--;}
+
+/***************** soundfile header structures ************************/
+
+typedef unsigned short uint16;
+typedef unsigned int uint32; /* long isn't 32-bit on amd64 */
+
+#define FORMAT_WAVE 0
+#define FORMAT_AIFF 1
+#define FORMAT_NEXT 2
+
+/* the NeXTStep sound header structure; can be big or little endian */
+
+struct t_nextstep {
+ char fileid[4]; /* magic number '.snd' if file is big-endian */
+ uint32 onset; /* byte offset of first sample */
+ uint32 length; /* length of sound in bytes */
+ uint32 format; /* format; see below */
+ uint32 sr; /* sample rate */
+ uint32 nchans; /* number of channels */
+ char info[4]; /* comment */
+};
+
+#define NS_FORMAT_LINEAR_16 3
+#define NS_FORMAT_LINEAR_24 4
+#define NS_FORMAT_FLOAT 6
+#define SCALE (1./(1024. * 1024. * 1024. * 2.))
+
+/* the WAVE header. All Wave files are little endian. We assume
+ the "fmt" chunk comes first which is usually the case but perhaps not
+ always; same for AIFF and the "COMM" chunk. */
+
+struct t_wave {
+ char fileid[4]; /* chunk id 'RIFF' */
+ uint32 chunksize; /* chunk size */
+ char waveid[4]; /* wave chunk id 'WAVE' */
+ char fmtid[4]; /* format chunk id 'fmt ' */
+ uint32 fmtchunksize; /* format chunk size */
+ uint16 fmttag; /* format tag (WAV_INT etc) */
+ uint16 nchannels; /* number of channels */
+ uint32 samplespersec; /* sample rate in hz */
+ uint32 navgbytespersec; /* average bytes per second */
+ uint16 nblockalign; /* number of bytes per frame */
+ uint16 nbitspersample; /* number of bits in a sample */
+ char datachunkid[4]; /* data chunk id 'data' */
+ uint32 datachunksize; /* length of data chunk */
+};
+
+struct t_fmt { /* format chunk */
+ uint16 fmttag; /* format tag, 1 for PCM */
+ uint16 nchannels; /* number of channels */
+ uint32 samplespersec; /* sample rate in hz */
+ uint32 navgbytespersec; /* average bytes per second */
+ uint16 nblockalign; /* number of bytes per frame */
+ uint16 nbitspersample; /* number of bits in a sample */
+};
+
+struct t_wavechunk { /* ... and the last two items */
+ char id[4]; /* data chunk id, e.g., 'data' or 'fmt ' */
+ uint32 size; /* length of data chunk */
+};
+
+#define WAV_INT 1
+#define WAV_FLOAT 3
+
+typedef unsigned char byte;
+
+/* the AIFF header. I'm assuming AIFC is compatible but don't really know that. */
+
+struct t_datachunk {
+ char id[4]; // data chunk id 'SSND'
+ uint32 size; // length of data chunk
+ uint32 offset; // additional offset in bytes
+ uint32 block; // block size
+};
+
+struct t_comm {
+ uint16 nchannels; // number of channels
+ uint16 nframeshi; // # of sample frames (hi)
+ uint16 nframeslo; // # of sample frames (lo)
+ uint16 bitspersamp; // bits per sample
+ byte samprate[10];// sample rate, 80-bit float!
+};
+
+/* this version is more convenient for writing them out: */
+struct t_aiff {
+ char fileid[4]; // chunk id 'FORM'
+ uint32 chunksize; // chunk size
+ char aiffid[4]; // aiff chunk id 'AIFF'
+ char fmtid[4]; // format chunk id 'COMM'
+ uint32 fmtchunksize; // format chunk size, 18
+ uint16 nchannels; // number of channels
+ uint16 nframeshi; // # of sample frames (hi)
+ uint16 nframeslo; // # of sample frames (lo)
+ uint16 bitspersamp; // bits per sample
+ byte samprate[10]; // sample rate, 80-bit float!
+};
+
+struct t_param {
+ int bytespersample;
+ int bigendian;
+ int nchannels;
+ long bytelimit;
+ int bytesperchannel() {return bytespersample * nchannels;}
+};
+
+#define AIFFHDRSIZE 38 /* probably not what sizeof() gives */
+#define AIFFPLUS (AIFFHDRSIZE + 16) /* header size including SSND chunk hdr */
+#define WHDR1 sizeof(t_nextstep)
+#define WHDR2 (sizeof(t_wave) > WHDR1 ? sizeof (t_wave) : WHDR1)
+#define WRITEHDRSIZE (AIFFPLUS > WHDR2 ? AIFFPLUS : WHDR2)
+#define READHDRSIZE (16 > WHDR2 + 2 ? 16 : WHDR2 + 2)
+
+#ifdef MSW
+#include <fcntl.h>
+#define BINCREATE (_O_WRONLY | _O_CREAT | _O_TRUNC | _O_BINARY)
+#else
+#define BINCREATE (O_WRONLY | O_CREAT | O_TRUNC)
+#endif
+
+/* this routine returns 1 if the high order byte comes at the lower
+address on our architecture (big-endianness.). It's 1 for Motorola, 0 for Intel: */
+
+extern int garray_ambigendian();
+
+/* byte swappers */
+
+static uint32 swap4(uint32 n, int doit) {
+ if (doit) return ((n & 0xff) << 24) | ((n & 0xff00) << 8) | ((n & 0xff0000) >> 8) | ((n & 0xff000000) >> 24);
+ else return n;
+}
+
+static uint16 swap2(uint32 n, int doit) {
+ if (doit) return ((n & 0xff) << 8) | ((n & 0xff00) >> 8);
+ else return n;
+}
+
+static void swapstring(char *foo, int doit) {
+ if (doit) {
+ char a = foo[0], b = foo[1], c = foo[2], d = foo[3];
+ foo[0] = d; foo[1] = c; foo[2] = b; foo[3] = a;
+ }
+}
+
+/******************** soundfile access routines **********************/
+/* This routine opens a file, looks for either a nextstep or "wave" header,
+* seeks to end of it, and fills in bytes per sample and number of channels.
+* Only 2- and 3-byte fixed-point samples and 4-byte floating point samples
+* are supported. If "headersize" is nonzero, the
+* caller should supply the number of channels, endinanness, and bytes per
+* sample; the header is ignored. Otherwise, the routine tries to read the
+* header and fill in the properties.
+*/
+
+int open_soundfile_via_fd(int fd, int headersize, t_param *p, long skipframes) {
+ int swap, sysrtn;
+ errno = 0;
+ t_param q;
+ q.bytelimit = 0x7fffffff;
+ if (headersize >= 0) { /* header detection overridden */
+ q = *p;
+ } else {
+ char buf[MAXPDSTRING];
+ int bytesread = read(fd, buf, READHDRSIZE);
+ int format;
+ if (bytesread < 4) goto badheader;
+ if (!strncmp(buf, ".snd", 4)) {format = FORMAT_NEXT; q.bigendian = 1;}
+ else if (!strncmp(buf, "dns.", 4)) {format = FORMAT_NEXT; q.bigendian = 0;}
+ else if (!strncmp(buf, "RIFF", 4)) {
+ if (bytesread < 12 || strncmp(buf + 8, "WAVE", 4)) goto badheader;
+ format = FORMAT_WAVE; q.bigendian = 0;
+ }
+ else if (!strncmp(buf, "FORM", 4)) {
+ if (bytesread < 12 || strncmp(buf + 8, "AIFF", 4)) goto badheader;
+ format = FORMAT_AIFF; q.bigendian = 1;
+ } else goto badheader;
+ swap = (q.bigendian != garray_ambigendian());
+ if (format == FORMAT_NEXT) { /* nextstep header */
+ if (bytesread < (int)sizeof(t_nextstep)) goto badheader;
+ q.nchannels = swap4(((t_nextstep *)buf)->nchans, swap);
+ format = swap4(((t_nextstep *)buf)->format, swap);
+ headersize = swap4(((t_nextstep *)buf)->onset, swap);
+ if (format == NS_FORMAT_LINEAR_16) q.bytespersample = 2;
+ else if (format == NS_FORMAT_LINEAR_24) q.bytespersample = 3;
+ else if (format == NS_FORMAT_FLOAT) q.bytespersample = 4;
+ else goto badheader;
+ q.bytelimit = 0x7fffffff;
+ } else if (format == FORMAT_WAVE) { /* wave header */
+ /* This is awful. You have to skip over chunks,
+ except that if one happens to be a "fmt" chunk, you want to
+ find out the format from that one. The case where the
+ "fmt" chunk comes after the audio isn't handled. */
+ headersize = 12;
+ if (bytesread < 20) goto badheader;
+ /* First we guess a number of channels, etc., in case there's
+ no "fmt" chunk to follow. */
+ q.nchannels = 1;
+ q.bytespersample = 2;
+ /* copy the first chunk header to beginnning of buffer. */
+ memcpy(buf, buf + headersize, sizeof(t_wavechunk));
+ /* read chunks in loop until we get to the data chunk */
+ while (strncmp(((t_wavechunk *)buf)->id, "data", 4)) {
+ long chunksize = swap4(((t_wavechunk *)buf)->size, swap), seekto = headersize + chunksize + 8, seekout;
+ if (!strncmp(((t_wavechunk *)buf)->id, "fmt ", 4)) {
+ long commblockonset = headersize + 8;
+ seekout = lseek(fd, commblockonset, SEEK_SET);
+ if (seekout != commblockonset) goto badheader;
+ if (read(fd, buf, sizeof(t_fmt)) < (int) sizeof(t_fmt)) goto badheader;
+ q.nchannels = swap2(((t_fmt *)buf)->nchannels, swap);
+ format = swap2(((t_fmt *)buf)->nbitspersample, swap);
+ if (format == 16) q.bytespersample = 2;
+ else if (format == 24) q.bytespersample = 3;
+ else if (format == 32) q.bytespersample = 4;
+ else goto badheader;
+ }
+ seekout = lseek(fd, seekto, SEEK_SET);
+ if (seekout != seekto) goto badheader;
+ if (read(fd, buf, sizeof(t_wavechunk)) < (int) sizeof(t_wavechunk)) goto badheader;
+ headersize = seekto;
+ }
+ q.bytelimit = swap4(((t_wavechunk *)buf)->size, swap);
+ headersize += 8;
+ } else {
+ /* AIFF. same as WAVE; actually predates it. Disgusting. */
+ headersize = 12;
+ if (bytesread < 20) goto badheader;
+ /* First we guess a number of channels, etc., in case there's no COMM block to follow. */
+ q.nchannels = 1;
+ q.bytespersample = 2;
+ /* copy the first chunk header to beginnning of buffer. */
+ memcpy(buf, buf + headersize, sizeof(t_datachunk));
+ /* read chunks in loop until we get to the data chunk */
+ while (strncmp(((t_datachunk *)buf)->id, "SSND", 4)) {
+ long chunksize = swap4(((t_datachunk *)buf)->size, swap), seekto = headersize + chunksize + 8, seekout;
+ if (!strncmp(((t_datachunk *)buf)->id, "COMM", 4)) {
+ long commblockonset = headersize + 8;
+ seekout = lseek(fd, commblockonset, SEEK_SET);
+ if (seekout != commblockonset) goto badheader;
+ if (read(fd, buf, sizeof(t_comm)) < (int) sizeof(t_comm)) goto badheader;
+ q.nchannels = swap2(((t_comm *)buf)->nchannels, swap);
+ format = swap2(((t_comm *)buf)->bitspersamp, swap);
+ if (format == 16) q.bytespersample = 2;
+ else if (format == 24) q.bytespersample = 3;
+ else goto badheader;
+ }
+ seekout = lseek(fd, seekto, SEEK_SET);
+ if (seekout != seekto) goto badheader;
+ if (read(fd, buf, sizeof(t_datachunk)) < (int) sizeof(t_datachunk)) goto badheader;
+ headersize = seekto;
+ }
+ q.bytelimit = swap4(((t_datachunk *)buf)->size, swap);
+ headersize += 8;
+ }
+ }
+ /* seek past header and any sample frames to skip */
+ sysrtn = lseek(fd, q.bytesperchannel() * skipframes + headersize, 0);
+ if (sysrtn != q.bytesperchannel() * skipframes + headersize) return -1;
+ q.bytelimit -= q.bytesperchannel() * skipframes;
+ if (q.bytelimit < 0) q.bytelimit = 0;
+ *p = q;
+ return fd;
+badheader:
+ /* the header wasn't recognized. We're threadable here so let's not print out the error... */
+ errno = EIO;
+ return -1;
+}
+
+/* open a soundfile, using open_via_path(). This is used by readsf~ in
+ a not-perfectly-threadsafe way. LATER replace with a thread-hardened version of open_soundfile_via_canvas() */
+static int open_soundfile(const char *dirname, const char *filename, int headersize, t_param *p, long skipframes) {
+ char *buf, *bufptr;
+ int fd = open_via_path2(dirname, filename, "", &buf, &bufptr, 1);
+ if (fd < 0) return -1;
+ free(buf);
+ return open_soundfile_via_fd(fd, headersize, p, skipframes);
+}
+
+/* open a soundfile, using open_via_canvas(). This is used by readsf~ in
+ a not-perfectly-threadsafe way. LATER replace with a thread-hardened version of open_soundfile_via_canvas() */
+static int open_soundfile_via_canvas(t_canvas *canvas, const char *filename, int headersize, t_param *p, long skipframes) {
+ char *buf, *bufptr;
+ int fd = canvas_open2(canvas, filename, "", &buf, &bufptr, 1);
+ if (fd < 0) return -1;
+ free(buf);
+ return open_soundfile_via_fd(fd, headersize, p, skipframes);
+}
+
+static void soundfile_xferin(int sfchannels, int nvecs, float **vecs,
+ long itemsread, unsigned char *buf, int nitems, int bytespersample, int bigendian) {
+ unsigned char *sp, *sp2;
+ int nchannels = (sfchannels < nvecs ? sfchannels : nvecs);
+ int bytesperframe = bytespersample * sfchannels;
+ sp = buf;
+ for (int i=0; i < nchannels; i++, sp += bytespersample) {
+ int j;
+ sp2=sp;
+ float *fp=vecs[i] + itemsread;
+ #define LOOP for (j=0; j<nitems; j++, sp2 += bytesperframe, fp++)
+ if (bytespersample == 2) {
+ if (bigendian) LOOP {*fp = SCALE * ((sp2[0]<<24) | (sp2[1]<<16));}
+ else LOOP {*fp = SCALE * ((sp2[1]<<24) | (sp2[0]<<16));}
+ } else if (bytespersample == 3) {
+ if (bigendian) LOOP {*fp = SCALE * ((sp2[0]<<24) | (sp2[1]<<16) | (sp2[2]<<8));}
+ else LOOP {*fp = SCALE * ((sp2[2]<<24) | (sp2[1]<<16) | (sp2[0]<<8));}
+ } else if (bytespersample == 4) {
+ if (bigendian) LOOP {*(long *)fp = (sp2[0]<<24) | (sp2[1]<<16) | (sp2[2]<<8) | sp2[3];}
+ else LOOP {*(long *)fp = (sp2[3]<<24) | (sp2[2]<<16) | (sp2[1]<<8) | sp2[0];}
+ }
+ #undef LOOP
+ }
+ /* zero out other outputs */
+ for (int i=sfchannels; i < nvecs; i++) {
+ float *fp=vecs[i];
+ for (int j=nitems; j--; ) *fp++ = 0;
+ }
+}
+
+/* soundfiler_write ...
+ usage: write [flags] filename table ...
+ flags: -nframes <frames> -skip <frames> -bytes <bytes per sample> -normalize -nextstep -wave -big -little
+ the routine which actually does the work should LATER also be called from garray_write16.
+ Parse arguments for writing. The "obj" argument is only for flagging
+ errors. For streaming to a file the "normalize", "onset" and "nframes"
+ arguments shouldn't be set but the calling routine flags this. */
+static int soundfiler_writeargparse(void *obj, int *p_argc, t_atom **p_argv, t_symbol **p_filesym,
+int *p_filetype, int *p_bytespersamp, int *p_swap, int *p_bigendian,
+int *p_normalize, long *p_onset, long *p_nframes, float *p_rate) {
+ int argc = *p_argc;
+ t_atom *argv = *p_argv;
+ int bytespersample = 2, bigendian = 0, endianness = -1, swap, filetype = -1, normalize = 0;
+ long onset = 0, nframes = 0x7fffffff;
+ t_symbol *filesym;
+ float rate = -1;
+ while (argc > 0 && argv->a_type == A_SYMBOL && *argv->a_symbol->name == '-') {
+ char *flag = argv->a_symbol->name + 1;
+ argc--; argv++;
+ if (!strcmp(flag, "skip")) {
+ EAT_ARG(A_FLOAT,onset); if (onset<0) goto usage;
+ } else if (!strcmp(flag, "nframes")) {
+ EAT_ARG(A_FLOAT,nframes); if (nframes<0) goto usage;
+ } else if (!strcmp(flag, "bytes")) {
+ EAT_ARG(A_FLOAT,bytespersample); if (bytespersample<2 || bytespersample>4) goto usage;
+ } else if (!strcmp(flag, "normalize")) {normalize = 1;
+ } else if (!strcmp(flag, "wave")) {filetype = FORMAT_WAVE;
+ } else if (!strcmp(flag, "nextstep")) {filetype = FORMAT_NEXT;
+ } else if (!strcmp(flag, "aiff")) {filetype = FORMAT_AIFF;
+ } else if (!strcmp(flag, "big")) {endianness = 1;
+ } else if (!strcmp(flag, "little")) {endianness = 0;
+ } else if (!strcmp(flag, "r") || !strcmp(flag, "rate")) {
+ EAT_ARG(A_FLOAT,rate); if (rate<0) goto usage;
+ } else goto usage;
+ }
+ if (!argc || argv->a_type != A_SYMBOL) goto usage;
+ filesym = argv->a_symbol;
+ /* check if format not specified and fill in */
+ if (filetype < 0) {
+ const char *s = filesym->name + strlen(filesym->name);
+ if (strlen(filesym->name) >= 5 && !strcasecmp(s-4, ".aif" )) filetype = FORMAT_AIFF;
+ if (strlen(filesym->name) >= 6 && !strcasecmp(s-5, ".aiff")) filetype = FORMAT_AIFF;
+ if (strlen(filesym->name) >= 5 && !strcasecmp(s-4, ".snd" )) filetype = FORMAT_NEXT;
+ if (strlen(filesym->name) >= 4 && !strcasecmp(s-3, ".au" )) filetype = FORMAT_NEXT;
+ if (filetype < 0) filetype = FORMAT_WAVE;
+ }
+ /* don't handle AIFF floating point samples */
+ if (bytespersample == 4) {
+ if (filetype == FORMAT_AIFF) {
+ error("AIFF floating-point file format unavailable");
+ goto usage;
+ }
+ }
+ /* for WAVE force little endian; for nextstep use machine native */
+ if (filetype == FORMAT_WAVE) {
+ bigendian = 0;
+ if (endianness == 1) error("WAVE file forced to little endian");
+ } else if (filetype == FORMAT_AIFF) {
+ bigendian = 1;
+ if (endianness == 0) error("AIFF file forced to big endian");
+ } else if (endianness == -1) {
+ bigendian = garray_ambigendian();
+ } else bigendian = endianness;
+ swap = (bigendian != garray_ambigendian());
+ argc--; argv++;
+ *p_argc = argc;
+ *p_argv = argv;
+ *p_filesym = filesym;
+ *p_filetype = filetype;
+ *p_bytespersamp = bytespersample;
+ *p_swap = swap;
+ *p_normalize = normalize;
+ *p_onset = onset;
+ *p_nframes = nframes;
+ *p_bigendian = bigendian;
+ *p_rate = rate;
+ return 0;
+usage:
+ return -1;
+}
+
+static bool strcaseends(const char *a, const char *b) {return strcasecmp(a+strlen(a)-strlen(b),b)==0;}
+
+static int create_soundfile(t_canvas *canvas, const char *filename, int filetype, int nframes, int bytespersample,
+int bigendian, int nchannels, int swap, float samplerate) {
+ char filenamebuf[strlen(filename)+10];
+ char headerbuf[WRITEHDRSIZE];
+ int fd, headersize = 0;
+ strcpy(filenamebuf, filename);
+ if (filetype == FORMAT_NEXT) {
+ t_nextstep *nexthdr = (t_nextstep *)headerbuf;
+ if (!strcaseends(filenamebuf,".snd")) strcat(filenamebuf, ".snd");
+ if (bigendian) strncpy(nexthdr->fileid, bigendian?".snd":"dns.", 4);
+ nexthdr->onset = swap4(sizeof(*nexthdr), swap);
+ nexthdr->length = 0;
+ nexthdr->format = swap4(bytespersample == 3 ? NS_FORMAT_LINEAR_24 : bytespersample == 4 ? NS_FORMAT_FLOAT : NS_FORMAT_LINEAR_16, swap);
+ nexthdr->sr = swap4((size_t)samplerate, swap);
+ nexthdr->nchans = swap4((size_t)nchannels, swap);
+ strcpy(nexthdr->info, "Pd ");
+ swapstring(nexthdr->info, swap);
+ headersize = sizeof(t_nextstep);
+ } else if (filetype == FORMAT_AIFF) {
+ long datasize = nframes * nchannels * bytespersample;
+ long longtmp;
+ static unsigned char dogdoo[] = {0x40, 0x0e, 0xac, 0x44, 0, 0, 0, 0, 0, 0, 'S', 'S', 'N', 'D'};
+ t_aiff *aiffhdr = (t_aiff *)headerbuf;
+ if (!strcaseends(filenamebuf,".aif") && !strcaseends(filenamebuf,".aiff")) strcat(filenamebuf, ".aif");
+ strncpy(aiffhdr->fileid, "FORM", 4);
+ aiffhdr->chunksize = swap4(datasize + sizeof(*aiffhdr) + 4, swap);
+ strncpy(aiffhdr->aiffid, "AIFF", 4);
+ strncpy(aiffhdr->fmtid, "COMM", 4);
+ aiffhdr->fmtchunksize = swap4(18, swap);
+ aiffhdr->nchannels = swap2(nchannels, swap);
+ longtmp = swap4(nframes, swap);
+ memcpy(&aiffhdr->nframeshi, &longtmp, 4);
+ aiffhdr->bitspersamp = swap2(8 * bytespersample, swap);
+ memcpy(aiffhdr->samprate, dogdoo, sizeof(dogdoo));
+ longtmp = swap4(datasize, swap);
+ memcpy(aiffhdr->samprate + sizeof(dogdoo), &longtmp, 4);
+ memset(aiffhdr->samprate + sizeof(dogdoo) + 4, 0, 8);
+ headersize = AIFFPLUS;
+ /* fix by matju for hfeli, 2007.07.04, but really, dogdoo should be removed */
+ while (samplerate >= 0x10000) {aiffhdr->samprate[1]++; samplerate/=2;}
+ aiffhdr->samprate[2] = (long)samplerate>>8;
+ aiffhdr->samprate[3] = (long)samplerate;
+ } else { /* WAVE format */
+ long datasize = nframes * nchannels * bytespersample;
+ if (!strcaseends(filenamebuf,".wav")) strcat(filenamebuf, ".wav");
+ t_wave *wavehdr = (t_wave *)headerbuf;
+ strncpy(wavehdr->fileid, "RIFF", 4);
+ wavehdr->chunksize = swap4(datasize + sizeof(*wavehdr) - 8, swap);
+ strncpy(wavehdr->waveid, "WAVE", 4);
+ strncpy(wavehdr->fmtid, "fmt ", 4);
+ wavehdr->fmtchunksize = swap4(16, swap);
+ wavehdr->fmttag = swap2((bytespersample == 4 ? WAV_FLOAT : WAV_INT), swap);
+ wavehdr->nchannels = swap2(nchannels, swap);
+ wavehdr->samplespersec = swap4(size_t(samplerate), swap);
+ wavehdr->navgbytespersec = swap4((int)(samplerate * nchannels * bytespersample), swap);
+ wavehdr->nblockalign = swap2(nchannels * bytespersample, swap);
+ wavehdr->nbitspersample = swap2(8 * bytespersample, swap);
+ strncpy(wavehdr->datachunkid, "data", 4);
+ wavehdr->datachunksize = swap4(datasize, swap);
+ headersize = sizeof(t_wave);
+ }
+ char *buf2 = canvas_makefilename(canvas, filenamebuf,0,0);
+ sys_bashfilename(buf2,buf2);
+ if ((fd = open(buf2, BINCREATE, 0666)) < 0) {free(buf2); return -1;}
+ if (write(fd, headerbuf, headersize) < headersize) {
+ close (fd);
+ return -1;
+ }
+ return fd;
+}
+
+static void soundfile_finishwrite(void *obj, char *filename, int fd,
+int filetype, long nframes, long itemswritten, int bytesperframe, int swap) {
+ if (itemswritten < nframes) {
+ if (nframes < 0x7fffffff)
+ error("soundfiler_write: %d out of %d bytes written", itemswritten, nframes);
+ /* try to fix size fields in header */
+ if (filetype == FORMAT_WAVE) {
+ long datasize = itemswritten * bytesperframe, v;
+ if (lseek(fd, ((char *)(&((t_wave *)0)->chunksize)) - (char *)0, SEEK_SET) == 0) goto baddonewrite;
+ v = swap4(datasize + sizeof(t_wave) - 8, swap);
+ if (write(fd, (char *)&v, 4) < 4) goto baddonewrite;
+ if (lseek(fd, ((char *)(&((t_wave *)0)->datachunksize)) - (char *)0, SEEK_SET) == 0) goto baddonewrite;
+ v = swap4(datasize, swap);
+ if (write(fd, (char *)&v, 4) < 4) goto baddonewrite;
+ }
+ if (filetype == FORMAT_AIFF) {
+ long v;
+ if (lseek(fd, ((char *)(&((t_aiff *)0)->nframeshi)) - (char *)0, SEEK_SET) == 0) goto baddonewrite;
+ v = swap4(itemswritten, swap);
+ if (write(fd, (char *)&v,4) < 4) goto baddonewrite;
+ if (lseek(fd, ((char *)(&((t_aiff *)0)->chunksize)) - (char *)0, SEEK_SET) == 0) goto baddonewrite;
+ v = swap4(itemswritten*bytesperframe+AIFFHDRSIZE, swap);
+ if (write(fd, (char *)&v,4) < 4) goto baddonewrite;
+ if (lseek(fd, (AIFFHDRSIZE+4), SEEK_SET) == 0) goto baddonewrite;
+ v = swap4(itemswritten*bytesperframe, swap);
+ if (write(fd, (char *)&v,4) < 4) goto baddonewrite;
+ }
+ if (filetype == FORMAT_NEXT) {
+ /* do it the lazy way: just set the size field to 'unknown size'*/
+ uint32 nextsize = 0xffffffff;
+ if (lseek(fd, 8, SEEK_SET) == 0) goto baddonewrite;
+ if (write(fd, &nextsize, 4) < 4) goto baddonewrite;
+ }
+ }
+ return;
+baddonewrite:
+ error("%s: %s", filename, strerror(errno));
+}
+
+static void soundfile_xferout(int nchannels, float **vecs, unsigned char *buf, int nitems, long onset, int bytespersample,
+int bigendian, float normalfactor) {
+ unsigned char *sp=buf, *sp2;
+ float *fp;
+ int bytesperframe = bytespersample * nchannels;
+ #define LOOP for (int j=0; j<nitems; j++, sp2 += bytesperframe, fp++)
+ for (int i = 0; i < nchannels; i++, sp += bytespersample) {
+ sp2 = sp; fp = vecs[i] + onset;
+ if (bytespersample == 2) {
+ float ff = normalfactor * 32768.;
+ if (bigendian) LOOP {
+ int xx = clip(int(32768. + *fp * ff) - 0x8000,-0x7fff,+0x7fff);
+ sp2[0] = xx>>8; sp2[1] = xx;
+ } else LOOP {
+ int xx = clip(int(32768. + *fp * ff) - 0x8000,-0x7fff,+0x7fff);
+ sp2[1] = xx>>8; sp2[0] = xx;
+ }
+ } else if (bytespersample == 3) {
+ float ff = normalfactor * 8388608.;
+ if (bigendian) LOOP {
+ int xx = clip(int(8388608. + *fp * ff) - 0x800000,-0x7fffff,+0x7fffff);
+ sp2[0] = xx>>16; sp2[1] = xx>>8; sp2[2] = xx;
+ } else LOOP {
+ int xx = clip(int(8388608. + *fp * ff) - 0x800000,-0x7fffff,+0x7fffff);
+ sp2[2] = xx>>16; sp2[1] = xx>>8; sp2[0] = xx;
+ }
+ } else if (bytespersample == 4) {
+ if (bigendian) LOOP {
+ float f2 = *fp * normalfactor; long xx = *(long *)&f2;
+ sp2[0] = xx >> 24; sp2[1] = xx >> 16; sp2[2] = xx >> 8; sp2[3] = xx;
+ } else LOOP {
+ float f2 = *fp * normalfactor; long xx = *(long *)&f2;
+ sp2[3] = xx >> 24; sp2[2] = xx >> 16; sp2[1] = xx >> 8; sp2[0] = xx;
+ }
+ }
+ }
+ #undef LOOP
+}
+
+/* ------- soundfiler - reads and writes soundfiles to/from "garrays" ---- */
+
+#define DEFMAXSIZE (16*1024*1024*4) /* default maximum 16 million floats per channel */
+#define SAMPBUFSIZE 1024
+
+static t_class *soundfiler_class;
+
+struct t_soundfiler : t_object {t_canvas *canvas;};
+
+#ifdef THREADED_SF
+#include <sched.h>
+#if (_POSIX_MEMLOCK - 0) >= 200112L
+#include <sys/mman.h>
+#else
+#define munlockall() /* ignore */
+#define mlockall() /* ignore */
+#endif /* _POSIX_MEMLOCK */
+
+static pthread_t sf_thread_id; /* id of soundfiler thread */
+
+struct t_sfprocess {
+ void (*process)(t_soundfiler *,t_symbol *, int, t_atom *); /* function to call */
+ t_soundfiler *x;
+ int argc;
+ t_atom *argv;
+ struct t_sfprocess *next; /* next object in queue */
+ pthread_mutex_t mutex;
+};
+
+/* this is the queue for all soundfiler objects */
+struct t_sfqueue {
+ t_sfprocess *begin;
+ t_sfprocess *end;
+ pthread_mutex_t mutex;
+ pthread_cond_t cond;
+};
+
+static t_sfqueue *soundfiler_queue;
+
+/* we fill the queue */
+void soundfiler_queue_add(void (* process) (t_soundfiler *,t_symbol *,int,t_atom *), void * x, int argc, t_atom * argv) {
+ /* preparing entry */
+ t_sfprocess * last_entry = (t_sfprocess*)getbytes(sizeof(t_sfprocess));
+ if (debug) post("adding process to queue");
+ pthread_mutex_init(&(last_entry->mutex), NULL);
+ pthread_mutex_lock(&(last_entry->mutex));
+ last_entry->process = process;
+ last_entry->x = (t_soundfiler *)x;
+ last_entry->argc = argc;
+ last_entry->argv = (t_atom *)copybytes(argv, argc * sizeof(t_atom));
+ last_entry->next = NULL;
+ pthread_mutex_unlock(&(last_entry->mutex));
+ /* add new entry to queue */
+ pthread_mutex_lock(&(soundfiler_queue->mutex));
+ if (soundfiler_queue->begin==NULL) {
+ soundfiler_queue->begin=last_entry;
+ soundfiler_queue->end=last_entry;
+ } else {
+ pthread_mutex_lock(&(soundfiler_queue->end->mutex));
+ soundfiler_queue->end->next=last_entry;
+ pthread_mutex_unlock(&(soundfiler_queue->end->mutex));
+ soundfiler_queue->end=last_entry;
+ }
+ if ( soundfiler_queue->begin == soundfiler_queue->end ) {
+ if (debug) post("signaling");
+ pthread_mutex_unlock(&(soundfiler_queue->mutex));
+ /* and signal the helper thread */
+ pthread_cond_signal(&(soundfiler_queue->cond));
+ } else {
+ if (debug) post("not signaling");
+ pthread_mutex_unlock(&(soundfiler_queue->mutex));
+ }
+ return;
+}
+
+/* global soundfiler thread ... sleeping until signaled */
+void soundfiler_thread() {
+ t_sfprocess *me;
+ t_sfprocess *next;
+ if (debug) post("soundfiler_thread ID: %d", pthread_self());
+ while (1) {
+ if (debug) post("Soundfiler sleeping");
+ pthread_cond_wait(&soundfiler_queue->cond, &soundfiler_queue->mutex);
+ if (debug) post("Soundfiler awake");
+ /* work on the queue */
+ while (soundfiler_queue->begin!=NULL) {
+ post("soundfiler: locked queue");
+ /* locking process */
+ pthread_mutex_lock(&(soundfiler_queue->begin->mutex));
+ me = soundfiler_queue->begin;
+ pthread_mutex_unlock(&(me->mutex));
+ pthread_mutex_unlock(&(soundfiler_queue->mutex));
+ if (debug) post("soundfiler: mutex unlocked, running process");
+ /* running the specific function */
+ me->process(me->x, NULL, me->argc, me->argv);
+ if (debug) post("soundfiler: process done, locking mutex");
+ pthread_mutex_lock(&(soundfiler_queue->mutex));
+ pthread_mutex_lock(&(me->mutex));
+ free(me->argv);
+ /* the process struct */
+ next=me->next;
+ soundfiler_queue->begin=next;
+ free(me);
+ }
+ soundfiler_queue->end=NULL;
+ }
+}
+
+extern int sys_hipriority; /* real-time flag, true if priority boosted */
+
+/* create soundfiler thread */
+void sys_start_sfthread() {
+ pthread_attr_t sf_attr;
+ struct sched_param sf_param;
+ int status;
+ // initialize queue
+ soundfiler_queue = (t_sfqueue *)getbytes(sizeof(t_sfqueue));
+ pthread_mutex_init(&soundfiler_queue->mutex,NULL);
+ pthread_cond_init(&soundfiler_queue->cond,NULL);
+ soundfiler_queue->begin=soundfiler_queue->end=NULL;
+/* pthread_mutex_unlock(&(soundfiler_queue->mutex)); */
+ // initialize thread
+ pthread_attr_init(&sf_attr);
+ sf_param.sched_priority=sched_get_priority_min(SCHED_OTHER);
+ pthread_attr_setschedparam(&sf_attr,&sf_param);
+/* pthread_attr_setinheritsched(&sf_attr,PTHREAD_EXPLICIT_SCHED); */
+#ifdef UNIX
+ if (sys_hipriority == 1 && getuid() == 0) {
+ sf_param.sched_priority=sched_get_priority_min(SCHED_RR);
+ pthread_attr_setschedpolicy(&sf_attr,SCHED_RR);
+ } else {
+/* pthread_attr_setschedpolicy(&sf_attr,SCHED_OTHER); */
+/* sf_param.sched_priority=sched_get_priority_min(SCHED_OTHER); */
+ }
+#endif /* UNIX */
+ //start thread
+ status = pthread_create(&sf_thread_id, &sf_attr, (void *(*)(void *)) soundfiler_thread,NULL);
+ if (status != 0) error("Couldn't create soundfiler thread: %d",status);
+ else post("global soundfiler thread launched, priority: %d", sf_param.sched_priority);
+}
+
+static void soundfiler_t_write( t_soundfiler *x, t_symbol *s, int argc, t_atom *argv);
+static void soundfiler_t_write_addq(t_soundfiler *x, t_symbol *s, int argc, t_atom *argv) {
+ soundfiler_queue_add(soundfiler_t_write,(void *)x,argc, argv);
+}
+static void soundfiler_t_read( t_soundfiler *x, t_symbol *s, int argc, t_atom *argv);
+static void soundfiler_t_read_addq(t_soundfiler *x, t_symbol *s, int argc, t_atom *argv) {
+ soundfiler_queue_add(soundfiler_t_read,(void *)x,argc, argv);
+}
+
+/* soundfiler_read
+ usage: read [flags] filename table ...
+ flags: -skip <frames> ... frames to skip in file
+ -nframes <frames> -onset <frames> ... onset in table to read into (NOT DONE YET)
+ -raw <headersize channels bytes endian> -resize -maxsize <max-size>
+ TB: adapted for threaded use */
+static t_int soundfiler_read_update_garray(t_int *w);
+static t_int soundfiler_read_update_graphics(t_int *w);
+static t_int soundfiler_read_output(t_int *w);
+static void soundfiler_t_read(t_soundfiler *x, t_symbol *s, int argc, t_atom *argv) {
+ t_param p;
+ int headersize = -1;
+ p.nchannels = 0; p.bytespersample = 0; p.bigendian = 0;
+ int resize = 0, i, j;
+ long skipframes = 0, nframes = 0, finalsize = 0, maxsize = DEFMAXSIZE, itemsread = 0;
+ p.bytelimit = 0x7fffffff;
+ int fd = -1;
+ char endianness, *filename;
+ t_garray *garrays[MAXSFCHANS];
+ t_float *vecs[MAXSFCHANS]; /* the old array */
+ t_float *nvecs[MAXSFCHANS]; /* the new array */
+ int vecsize[MAXSFCHANS]; /* the old array size */
+ char sampbuf[SAMPBUFSIZE];
+ int bufframes, nitems;
+ FILE *fp;
+ pthread_cond_t resume_after_callback = PTHREAD_COND_INITIALIZER;
+ pthread_mutex_t resume_after_callback_mutex = PTHREAD_MUTEX_INITIALIZER; /* dummy */
+ t_int* outargs;
+ while (argc > 0 && argv->a_type == A_SYMBOL && *argv->a_symbol->name == '-') {
+ char *flag = argv->a_symbol->name + 1;
+ argc--; argv++;
+ if (!strcmp(flag, "skip")) {
+ EAT_ARG(A_FLOAT,skipframes); if (skipframes<0) goto usage;
+ } else if (!strcmp(flag, "nframes")) {
+ EAT_ARG(A_FLOAT,nframes); if (nframes<0) goto usage;
+ } else if (!strcmp(flag, "raw")) {
+ EAT_ARG(A_FLOAT,headersize); if (headersize<0) goto usage;
+ EAT_ARG(A_FLOAT,p.nchannels); if (p.nchannels<1) goto usage;
+ EAT_ARG(A_FLOAT,p.bytespersample); if (p.bytespersample<2 || p.bytespersample>4) goto usage;
+ EAT_ARG(A_SYMBOL,endianness); if (endianness!='b' && endianness!='l' && endianness!='n') goto usage;
+ if (endianness == 'b') p.bigendian = 1;
+ else if (endianness == 'l') p.bigendian = 0;
+ else p.bigendian = garray_ambigendian();
+ } else if (!strcmp(flag, "resize")) {
+ resize = 1;
+ } else if (!strcmp(flag, "maxsize")) {
+ EAT_ARG(A_FLOAT,maxsize); if (maxsize<0) goto usage;
+ resize = 1; /* maxsize implies resize. */
+ } else goto usage;
+ }
+ if (argc < 2 || argc > MAXSFCHANS + 1 || argv[0].a_type != A_SYMBOL) goto usage;
+ filename = argv[0].a_symbol->name;
+ argc--; argv++;
+ for (int i=0; i<argc; i++) {
+ if (argv[i].a_type != A_SYMBOL) goto usage;
+ garrays[i] = (t_garray *)pd_findbyclass(argv[i].a_symbol, garray_class);
+ if (!garrays[i]) {
+ error("%s: no such table", argv[i].a_symbol->name);
+ goto done;
+ } else if (!garray_getfloatarray(garrays[i], &vecsize[i], &vecs[i]))
+ error("%s: bad template for tabwrite", argv[i].a_symbol->name);
+ if (finalsize && finalsize != vecsize[i] && !resize) {
+ post("soundfiler_read: arrays have different lengths; resizing...");
+ resize = 1;
+ }
+ finalsize = vecsize[i];
+ }
+ fd = open_soundfile(canvas_getdir(x->canvas)->name, filename, headersize, &p, skipframes);
+ if (fd < 0) {
+ error("soundfiler_read: %s: %s", filename, (errno == EIO ? "unknown or bad header format" : strerror(errno)));
+ goto done;
+ }
+ if (resize) {
+ /* figure out what to resize to */
+ long poswas, eofis, framesinfile;
+ poswas = lseek(fd, 0, SEEK_CUR);
+ eofis = lseek(fd, 0, SEEK_END);
+ if (poswas < 0 || eofis < 0) {error("lseek failed"); goto done;}
+ lseek(fd, poswas, SEEK_SET);
+ framesinfile = (eofis - poswas) / p.bytesperchannel();
+ if (framesinfile > maxsize) {
+ error("soundfiler_read: truncated to %d elements", maxsize);
+ framesinfile = maxsize;
+ }
+ framesinfile = min(framesinfile, p.bytelimit / p.bytesperchannel());
+ finalsize = framesinfile;
+ }
+ if (!finalsize) finalsize = 0x7fffffff;
+ finalsize = min(finalsize, p.bytelimit / p.bytesperchannel());
+ fp = fdopen(fd, "rb");
+ bufframes = SAMPBUFSIZE / p.bytesperchannel();
+ if (debug) {
+ post("buffers: %d", argc);
+ post("channels: %d", p.nchannels);
+ }
+ munlockall();
+ /* allocate memory for new array */
+ if (resize)
+ for (int i=0; i<argc; i++) {
+ nvecs[i] = (float *)getalignedbytes(finalsize * sizeof(t_float));
+ /* if we are out of memory, free it again and quit */
+ if (nvecs[i]==0) {
+ error("resize failed");
+ /* if the resizing fails, we'll have to free all arrays again */
+ for (j=0; j!=i;++j) freealignedbytes (nvecs[i],finalsize * sizeof(t_float));
+ goto done;
+ }
+ }
+ else
+ for (int i=0; i<argc; i++) {
+ nvecs[i] = (float *)getalignedbytes(vecsize[i] * sizeof(t_float));
+ /* if we are out of memory, free it again and quit */
+ if (nvecs[i]==0) {
+ error("resize failed");
+ /* if the resizing fails, we'll have to free all arrays again */
+ for (j=0; j!=i;++j) freealignedbytes (nvecs[i],vecsize[i] * sizeof(t_float));
+ goto done;
+ }
+ }
+ if(i > p.nchannels) memset(nvecs[i],0,vecsize[i] * sizeof(t_float));
+ if (debug) post("transfer soundfile");
+ for (itemsread = 0; itemsread < finalsize; ) {
+ int thisread = finalsize - itemsread;
+ thisread = (thisread > bufframes ? bufframes : thisread);
+ nitems = fread(sampbuf, p.bytesperchannel(), thisread, fp);
+ if (nitems <= 0) break;
+ soundfile_xferin(p.nchannels, argc, nvecs, itemsread, (unsigned char *)sampbuf, nitems, p.bytespersample, p.bigendian);
+ itemsread += nitems;
+ }
+ if (debug) post("zeroing remaining elements");
+ /* zero out remaining elements of vectors */
+ for (int i=0; i<argc; i++) for (int j=itemsread; j<finalsize; j++) nvecs[i][j] = 0;
+ /* set idle callback to switch pointers */
+ if (debug) post("locked");
+ for (int i=0; i<argc; i++) {
+ t_int *w = (t_int*)getbytes(4*sizeof(t_int));
+ w[0] = (t_int)(garrays[i]);
+ w[1] = (t_int)nvecs[i];
+ w[2] = (t_int)finalsize;
+ w[3] = (t_int)(&resume_after_callback);
+ sys_callback(&soundfiler_read_update_garray, w, 4);
+ pthread_cond_wait(&resume_after_callback, &resume_after_callback_mutex);
+ }
+ if (debug) post("unlocked, doing graphics updates");
+ /* do all graphics updates. run this in the main thread via callback */
+ for (int i=0; i<argc; i++) {
+ t_int *w = (t_int*)getbytes(2*sizeof(t_int));
+ w[0] = (t_int)(garrays[i]);
+ w[1] = (t_int)finalsize;
+ sys_callback(&soundfiler_read_update_graphics, w, 2);
+ }
+ /* free the old arrays */
+ for (int i=0; i<argc; i++) freealignedbytes(vecs[i], vecsize[i] * sizeof(t_float));
+ fclose(fp);
+ fd = -1;
+ goto done;
+usage:
+ error("usage: read [flags] filename tablename...");
+ post("flags: -skip <n> -nframes <n> -resize -maxsize <n> ...");
+ post("-raw <headerbytes> <channels> <bytespersample> <endian (b, l, or n)>.");
+done:
+ if (fd>=0) close(fd);
+ mlockall(MCL_FUTURE);
+ outargs = (t_int*)getbytes(2*sizeof(t_int));
+ outargs[0] = (t_int)x->outlet;
+ outargs[1] = (t_int)itemsread;
+ sys_callback(&soundfiler_read_output, outargs, 2);
+}
+
+/* idle callback for threadsafe synchronisation */
+static t_int soundfiler_read_update_garray(t_int *w) {
+ t_garray *garray = (t_garray*)w[0];
+ t_int nvec = w[1];
+ t_int finalsize = w[2];
+ pthread_cond_t *conditional = (pthread_cond_t*) w[3];
+ t_array *a = garray_getarray(garray);
+ a->vec = (char *) nvec;
+ a->n = finalsize;
+ if (garray->usedindsp) canvas_update_dsp();
+ /* signal helper thread */
+ pthread_cond_broadcast(conditional);
+ return 0;
+}
+
+static t_int soundfiler_read_update_graphics(t_int *w) {
+ t_garray *garray = (t_garray*) w[0];
+ t_canvas *gl;
+ int n = w[1];
+ /* if this is the only array in the graph, reset the graph's coordinates */
+ if (debug) post("redraw array %p", garray);
+ gl = garray->canvas;
+ if (gl->list == garray && !garray->next) {
+ vmess(gl, gensym("bounds"), "ffff", 0., gl->y1, double(n > 1 ? n-1 : 1), gl->y2);
+ /* close any dialogs that might have the wrong info now... */
+ } else garray_redraw(garray);
+ return 0;
+}
+
+static t_int soundfiler_read_output(t_int * w) {
+ t_outlet* outlet = (t_outlet*) w[0];
+ float itemsread = (float) w[1];
+ if (debug) post("bang %p", outlet);
+ outlet_float (outlet, itemsread);
+ return 0;
+}
+
+/* this is broken out from soundfiler_write below so garray_write can call it too... not done yet though. */
+long soundfiler_t_dowrite(void *obj, t_canvas *canvas, int argc, t_atom *argv) {
+ int bytespersample, bigendian, swap, filetype, normalize, nchannels;
+ long onset, nframes, itemswritten = 0;
+ t_garray *garrays[MAXSFCHANS];
+ t_float *vecs[MAXSFCHANS];
+ char sampbuf[SAMPBUFSIZE];
+ int bufframes;
+ int fd = -1;
+ float normfactor, biggest = 0, samplerate;
+ t_symbol *filesym;
+ if (soundfiler_writeargparse(obj, &argc, &argv, &filesym, &filetype,
+ &bytespersample, &swap, &bigendian, &normalize, &onset, &nframes, &samplerate))
+ goto usage;
+ nchannels = argc;
+ if (nchannels < 1 || nchannels > MAXSFCHANS) goto usage;
+ if (samplerate < 0) samplerate = sys_getsr();
+ for (int i=0; i<nchannels; i++) {
+ int vecsize;
+ if (argv[i].a_type != A_SYMBOL) goto usage;
+ if (!(garrays[i] = (t_garray *)pd_findbyclass(argv[i].a_symbol, garray_class))) {
+ error("%s: no such table", argv[i].a_symbol->name);
+ goto fail;
+ }
+ else if (!garray_getfloatarray(garrays[i], &vecsize, &vecs[i]))
+ error("%s: bad template for tabwrite", argv[i].a_symbol->name);
+ if (nframes > vecsize - onset)
+ nframes = vecsize - onset;
+ for (int j=0; j<vecsize; j++) {
+ if (+vecs[i][j] > biggest) biggest = +vecs[i][j];
+ else if (-vecs[i][j] > biggest) biggest = -vecs[i][j];
+ }
+ }
+ if (nframes <= 0) {
+ error("soundfiler_write: no samples at onset %ld", onset);
+ goto fail;
+ }
+ if ((fd = create_soundfile(canvas, filesym->name, filetype, nframes, bytespersample, bigendian, nchannels, swap, samplerate)) < 0) {
+ post("%s: %s", filesym->name, strerror(errno));
+ goto fail;
+ }
+ if (!normalize) {
+ if ((bytespersample != 4) && (biggest > 1)) {
+ post("%s: normalizing max amplitude %f to 1", filesym->name, biggest);
+ normalize = 1;
+ } else post("%s: biggest amplitude = %f", filesym->name, biggest);
+ }
+ if (normalize) normfactor = (biggest > 0 ? 32767./(32768. * biggest) : 1);
+ else normfactor = 1;
+ bufframes = SAMPBUFSIZE / (nchannels * bytespersample);
+ for (itemswritten = 0; itemswritten < nframes; ) {
+ int thiswrite = nframes - itemswritten, nbytes;
+ thiswrite = (thiswrite > bufframes ? bufframes : thiswrite);
+ soundfile_xferout(argc, vecs, (unsigned char *)sampbuf, thiswrite, onset, bytespersample, bigendian, normfactor);
+ nbytes = write(fd, sampbuf, nchannels * bytespersample * thiswrite);
+ if (nbytes < nchannels * bytespersample * thiswrite) {
+ post("%s: %s", filesym->name, strerror(errno));
+ if (nbytes > 0) itemswritten += nbytes / (nchannels * bytespersample);
+ break;
+ }
+ itemswritten += thiswrite;
+ onset += thiswrite;
+ }
+ if (fd >= 0) {
+ soundfile_finishwrite(obj, filesym->name, fd, filetype, nframes, itemswritten, nchannels * bytespersample, swap);
+ close (fd);
+ }
+ return itemswritten;
+usage:
+ error("usage: write [flags] filename tablename...");
+ post("flags: -skip <n> -nframes <n> -bytes <n> -wave -aiff -nextstep ...");
+ post("-big -little -normalize");
+ post("(defaults to a 16-bit wave file).");
+fail:
+ if (fd >= 0) close(fd);
+ return 0;
+}
+
+static void soundfiler_t_write(t_soundfiler *x, t_symbol *s, int argc, t_atom *argv) {
+ long bozo = soundfiler_t_dowrite(x, x->canvas, argc, argv);
+ sys_lock();
+ outlet_float(x->outlet, (float)bozo);
+ sys_lock();
+}
+
+static void soundfiler_t_resize(t_soundfiler *x, t_symbol *s, int argc, t_atom *argv);
+static void soundfiler_t_resize_addq(t_soundfiler *x, t_symbol *s, int argc, t_atom *argv) {
+ soundfiler_queue_add(soundfiler_t_resize,(void *)x,argc, argv);
+}
+
+/* TB: soundfiler_t_resize ... usage: resize table size; adapted from garray_resize */
+static void soundfiler_t_resize(t_soundfiler *y, t_symbol *s, int argc, t_atom *argv) {
+ int was, elemsize; /* array contains was elements of size elemsize */
+ t_float *vec; /* old array */
+ t_canvas *gl;
+ int n; /* resize of n elements */
+ char *nvec; /* new array */
+ t_garray *x = (t_garray *)pd_findbyclass(argv[0].a_symbol, garray_class);
+ t_array *a = garray_getarray(x);
+ if (!x) {error("%s: no such table", argv[0].a_symbol->name); goto usage;}
+ vec = (t_float*) a->vec;
+ was = a->n;
+ if ((argv+1)->a_type == A_FLOAT) {
+ n = (int) (argv+1)->a_float;
+ } else goto usage;
+ if (n == was) return;
+ if (n < 1) n = 1;
+ elemsize = template_findbyname(a->templatesym)->t_n * sizeof(t_word);
+ munlockall();
+ if (was > n) {
+ nvec = (char *)copyalignedbytes(a->vec, was * elemsize);
+ } else {
+ nvec = (char *)getalignedbytes(n * elemsize);
+ memcpy (nvec, a->vec, was * elemsize);
+ memset(nvec + was*elemsize, 0, (n - was) * elemsize);
+ }
+ if (!nvec) {error("array resize failed: out of memory"); mlockall(MCL_FUTURE); return;}
+ /* TB: we'll have to be sure that no one is accessing the array */
+ sys_lock();
+ a->vec = nvec;
+ a->n = n;
+ if (x->usedindsp) canvas_update_dsp();
+ sys_unlock();
+ /* if this is the only array in the graph, reset the graph's coordinates */
+ gl = x->canvas;
+ if (gl->list == x && !x->next) {
+ vmess(gl, gensym("bounds"), "ffff", 0., gl->y1, (double)(n > 1 ? n-1 : 1), gl->y2);
+ /* close any dialogs that might have the wrong info now... */
+ } else garray_redraw(x);
+ freealignedbytes (vec, was * elemsize);
+ mlockall(MCL_FUTURE);
+ sys_lock();
+ outlet_float(y->outlet, (float)atom_getintarg(1,argc,argv));
+ sys_unlock();
+ return;
+usage:
+ error("usage: resize tablename size");
+}
+
+static void soundfiler_t_const(t_soundfiler *x, t_symbol *s, int argc, t_atom *argv);
+static void soundfiler_t_const_addq(t_soundfiler *x, t_symbol *s, int argc, t_atom *argv) {
+ soundfiler_queue_add(soundfiler_t_const,(void *)x,argc, argv);
+}
+
+/* TB: soundfiler_t_const ... usage: const table value */
+static void soundfiler_t_const(t_soundfiler *y, t_symbol *s, int argc, t_atom *argv) {
+ int size, elemsize; /* array contains was elements of size elemsize */
+ t_float *vec; /* old array */
+ t_canvas *gl;
+ int val; /* value */
+ char *nvec; /* new array */
+ t_garray * x = (t_garray *)pd_findbyclass(argv[0].a_symbol, garray_class);
+ t_array *a = garray_getarray(x);
+ if (!x) {error("%s: no such table", argv[0].a_symbol->name); goto usage;}
+ vec = (t_float*) a->vec;
+ size = a->n;
+ if ((argv+1)->a_type == A_FLOAT) {
+ val = (int) (argv+1)->a_float;
+ } else goto usage;
+ elemsize = template_findbyname(a->templatesym)->t_n * sizeof(t_word);
+ /* allocating memory */
+ munlockall();
+ nvec = (char *)getalignedbytes(size * elemsize);
+ if (!nvec) {
+ error("array resize failed: out of memory");
+ mlockall(MCL_FUTURE);
+ return;
+ }
+ /* setting array */
+ for (int i=0; i!=size; ++i) nvec[i]=val;
+ /* TB: we'll have to be sure that no one is accessing the array */
+ sys_lock();
+ a->vec = nvec;
+ if (x->usedindsp) canvas_update_dsp();
+ sys_unlock();
+ /* if this is the only array in the graph, reset the graph's coordinates */
+ gl = x->canvas;
+ if (gl->list == x && !x->next) {
+ vmess(gl, gensym("bounds"), "ffff", 0., gl->y1, (double)(size > 1 ? size-1 : 1), gl->y2);
+ /* close any dialogs that might have the wrong info now... */
+ } else garray_redraw(x);
+ freealignedbytes (vec, size * elemsize);
+ mlockall(MCL_FUTURE);
+ sys_lock();
+ outlet_float(y->outlet, size);
+ sys_unlock();
+ return;
+ usage:
+ error("usage: const tablename value");
+}
+
+#endif /* THREADED_SF */
+
+static t_soundfiler *soundfiler_new() {
+ t_soundfiler *x = (t_soundfiler *)pd_new(soundfiler_class);
+ x->canvas = canvas_getcurrent();
+ outlet_new(x,&s_float);
+#ifdef THREADED_SF
+ post("warning: threaded soundfiler is not synchronous");
+#endif /* THREADED_SF */
+ return x;
+}
+
+/* soundfiler_read ...
+ usage: read [flags] filename table ...
+ flags: -skip <frames> ... frames to skip in file
+ -nframes <frames> -onset <frames> ... onset in table to read into (NOT DONE YET)
+ -raw <headersize channels bytes endian> -resize -maxsize <max-size> */
+static void soundfiler_read(t_soundfiler *x, t_symbol *s, int argc, t_atom *argv) {
+ t_param p;
+ p.bytespersample = 0;
+ p.bigendian = 0;
+ p.nchannels = 0;
+ p.bytelimit = 0x7fffffff;
+ int headersize = -1, resize = 0;
+ long skipframes = 0, nframes = 0, finalsize = 0, maxsize = DEFMAXSIZE, itemsread = 0;
+ int fd = -1;
+ char endianness, *filename;
+ t_garray *garrays[MAXSFCHANS];
+ t_float *vecs[MAXSFCHANS];
+ char sampbuf[SAMPBUFSIZE];
+ int bufframes, nitems;
+ FILE *fp;
+ while (argc > 0 && argv->a_type == A_SYMBOL && *argv->a_symbol->name == '-') {
+ char *flag = argv->a_symbol->name + 1;
+ argc--; argv++;
+ if (!strcmp(flag, "skip")) {
+ EAT_ARG(A_FLOAT,skipframes); if (skipframes<0) goto usage;
+ } else if (!strcmp(flag, "nframes")) {
+ EAT_ARG(A_FLOAT,nframes); if (nframes<0) goto usage;
+ } else if (!strcmp(flag, "raw")) {
+ EAT_ARG(A_FLOAT,headersize); if (headersize<0) goto usage;
+ EAT_ARG(A_FLOAT,p.nchannels); if (p.nchannels<1) goto usage;
+ EAT_ARG(A_FLOAT,p.bytespersample); if (p.bytespersample<2 || p.bytespersample>4) goto usage;
+ EAT_ARG(A_SYMBOL,endianness); if (endianness!='b' && endianness!='l' && endianness!='n') goto usage;
+ if (endianness == 'b') p.bigendian = 1;
+ else if (endianness == 'l') p.bigendian = 0;
+ else p.bigendian = garray_ambigendian();
+ } else if (!strcmp(flag, "resize")) {
+ resize = 1;
+ } else if (!strcmp(flag, "maxsize")) {
+ EAT_ARG(A_FLOAT,maxsize); if (maxsize<0) goto usage;
+ resize = 1; /* maxsize implies resize. */
+ } else goto usage;
+ }
+ if (argc < 2 || argc > MAXSFCHANS + 1 || argv[0].a_type != A_SYMBOL) goto usage;
+ filename = argv[0].a_symbol->name;
+ argc--; argv++;
+ for (int i=0; i<argc; i++) {
+ int vecsize;
+ if (argv[i].a_type != A_SYMBOL) goto usage;
+ garrays[i] = (t_garray *)pd_findbyclass(argv[i].a_symbol, garray_class);
+ if (!garrays) {
+ error("%s: no such table", argv[i].a_symbol->name);
+ goto done;
+ } else if (!garray_getfloatarray(garrays[i], &vecsize, &vecs[i]))
+ error("%s: bad template for tabwrite", argv[i].a_symbol->name);
+ if (finalsize && finalsize != vecsize && !resize) {
+ post("soundfiler_read: arrays have different lengths; resizing...");
+ resize = 1;
+ }
+ finalsize = vecsize;
+ }
+ fd = open_soundfile_via_canvas(x->canvas, filename, headersize, &p, skipframes);
+ if (fd < 0) {
+ error("soundfiler_read: %s: %s", filename, (errno == EIO ? "unknown or bad header format" : strerror(errno)));
+ goto done;
+ }
+ if (resize) {
+ /* figure out what to resize to */
+ long poswas, eofis, framesinfile;
+ poswas = lseek(fd, 0, SEEK_CUR);
+ eofis = lseek(fd, 0, SEEK_END);
+ if (poswas < 0 || eofis < 0) {error("lseek failed"); goto done;}
+ lseek(fd, poswas, SEEK_SET);
+ framesinfile = (eofis - poswas) / (p.nchannels * p.bytespersample);
+ if (framesinfile > maxsize) {
+ error("soundfiler_read: truncated to %d elements", maxsize);
+ framesinfile = maxsize;
+ }
+ framesinfile = min(framesinfile, p.bytelimit / (p.nchannels * p.bytespersample));
+ finalsize = framesinfile;
+ for (int i=0; i<argc; i++) {
+ int vecsize;
+ garray_resize(garrays[i], finalsize);
+ /* for sanity's sake let's clear the save-in-patch flag here */
+ garray_setsaveit(garrays[i], 0);
+ garray_getfloatarray(garrays[i], &vecsize, &vecs[i]);
+ /* if the resize failed, garray_resize reported the error */
+ if (vecsize != framesinfile) {error("resize failed"); goto done;}
+ }
+ }
+ if (!finalsize) finalsize = 0x7fffffff;
+ finalsize = min(finalsize, p.bytelimit / (p.nchannels * p.bytespersample));
+ fp = fdopen(fd, "rb");
+ bufframes = SAMPBUFSIZE / (p.nchannels * p.bytespersample);
+ for (itemsread = 0; itemsread < finalsize; ) {
+ int thisread = finalsize - itemsread;
+ thisread = min(thisread,bufframes);
+ nitems = fread(sampbuf, p.nchannels * p.bytespersample, thisread, fp);
+ if (nitems <= 0) break;
+ soundfile_xferin(p.nchannels, argc, vecs, itemsread, (unsigned char *)sampbuf, nitems, p.bytespersample, p.bigendian);
+ itemsread += nitems;
+ }
+ /* zero out remaining elements of vectors */
+ for (int i=0; i<argc; i++) {
+ int vecsize; garray_getfloatarray(garrays[i], &vecsize, &vecs[i]);
+ for (int j=itemsread; j<vecsize; j++) vecs[i][j]=0;
+ }
+ /* zero out vectors in excess of number of channels */
+ for (int i=p.nchannels; i<argc; i++) {
+ int vecsize; float *foo; garray_getfloatarray(garrays[i], &vecsize, &foo);
+ for (int j=0; j<vecsize; j++) foo[j]=0;
+ }
+ /* do all graphics updates */
+ for (int i=0; i<argc; i++) garray_redraw(garrays[i]);
+ fclose(fp);
+ fd = -1;
+ goto done;
+usage:
+ error("usage: read [flags] filename tablename...");
+ post("flags: -skip <n> -nframes <n> -resize -maxsize <n> ...");
+ post("-raw <headerbytes> <channels> <bytespersample> <endian (b, l, or n)>.");
+done:
+ if (fd >= 0) close (fd);
+ outlet_float(x->outlet, (float)itemsread);
+}
+
+/* this is broken out from soundfiler_write below so garray_write can
+ call it too... not done yet though. */
+long soundfiler_dowrite(void *obj, t_canvas *canvas, int argc, t_atom *argv) {
+ int bytespersample, bigendian, swap, filetype, normalize, nchannels;
+ long onset, nframes, itemswritten = 0;
+ t_garray *garrays[MAXSFCHANS];
+ t_float *vecs[MAXSFCHANS];
+ char sampbuf[SAMPBUFSIZE];
+ int bufframes;
+ int fd = -1;
+ float normfactor, biggest = 0, samplerate;
+ t_symbol *filesym;
+ if (soundfiler_writeargparse(obj, &argc, &argv, &filesym, &filetype,
+ &bytespersample, &swap, &bigendian, &normalize, &onset, &nframes,
+ &samplerate))
+ goto usage;
+ nchannels = argc;
+ if (nchannels < 1 || nchannels > MAXSFCHANS) goto usage;
+ if (samplerate < 0) samplerate = sys_getsr();
+ for (int i=0; i<nchannels; i++) {
+ int vecsize;
+ if (argv[i].a_type != A_SYMBOL) goto usage;
+ if (!(garrays[i] = (t_garray *)pd_findbyclass(argv[i].a_symbol, garray_class))) {
+ error("%s: no such table", argv[i].a_symbol->name);
+ goto fail;
+ }
+ else if (!garray_getfloatarray(garrays[i], &vecsize, &vecs[i]))
+ error("%s: bad template for tabwrite", argv[i].a_symbol->name);
+ nframes = min(nframes, vecsize - onset);
+ for (int j=0; j<vecsize; j++) {
+ if (+vecs[i][j] > biggest) biggest = +vecs[i][j];
+ else if (-vecs[i][j] > biggest) biggest = -vecs[i][j];
+ }
+ }
+ if (nframes <= 0) {
+ error("soundfiler_write: no samples at onset %ld", onset);
+ goto fail;
+ }
+ if ((fd = create_soundfile(canvas, filesym->name, filetype, nframes, bytespersample, bigendian, nchannels, swap, samplerate)) < 0) {
+ post("%s: %s", filesym->name, strerror(errno));
+ goto fail;
+ }
+ if (!normalize) {
+ if ((bytespersample != 4) && (biggest > 1)) {
+ post("%s: normalizing max amplitude %f to 1", filesym->name, biggest);
+ normalize = 1;
+ } else post("%s: biggest amplitude = %f", filesym->name, biggest);
+ }
+ if (normalize) normfactor = (biggest > 0 ? 32767./(32768. * biggest) : 1); else normfactor = 1;
+ bufframes = SAMPBUFSIZE / (nchannels * bytespersample);
+ for (itemswritten = 0; itemswritten < nframes; ) {
+ int thiswrite = nframes - itemswritten, nbytes;
+ thiswrite = (thiswrite > bufframes ? bufframes : thiswrite);
+ soundfile_xferout(argc, vecs, (unsigned char *)sampbuf, thiswrite, onset, bytespersample, bigendian, normfactor);
+ nbytes = write(fd, sampbuf, nchannels * bytespersample * thiswrite);
+ if (nbytes < nchannels * bytespersample * thiswrite) {
+ post("%s: %s", filesym->name, strerror(errno));
+ if (nbytes > 0) itemswritten += nbytes / (nchannels * bytespersample);
+ break;
+ }
+ itemswritten += thiswrite;
+ onset += thiswrite;
+ }
+ if (fd >= 0) {
+ soundfile_finishwrite(obj, filesym->name, fd, filetype, nframes, itemswritten, nchannels * bytespersample, swap);
+ close (fd);
+ }
+ return itemswritten;
+usage:
+ error("usage: write [flags] filename tablename...");
+ post("flags: -skip <n> -nframes <n> -bytes <n> -wave -aiff -nextstep ...");
+ post("-big -little -normalize");
+ post("(defaults to a 16-bit wave file).");
+fail:
+ if (fd >= 0) close(fd);
+ return 0;
+}
+
+static void soundfiler_write(t_soundfiler *x, t_symbol *s, int argc, t_atom *argv) {
+ long bozo = soundfiler_dowrite(x, x->canvas, argc, argv);
+ outlet_float(x->outlet, (float)bozo);
+}
+
+static void soundfiler_setup() {
+ t_class *c = soundfiler_class = class_new2("soundfiler", (t_newmethod)soundfiler_new, 0, sizeof(t_soundfiler), 0, "");
+#ifdef THREADED_SF
+ class_addmethod2(c, (t_method)soundfiler_t_read_addq, "read", "*");
+/* class_addmethod2(c, (t_method)soundfiler_t_write_addq, "write", "*"); */
+ class_addmethod2(c, (t_method)soundfiler_t_resize_addq, "resize", "*");
+ class_addmethod2(c, (t_method)soundfiler_t_const_addq, "const", "*");
+#else
+ class_addmethod2(c, (t_method)soundfiler_read, "read", "*");
+#endif /* THREADED_SF */
+ class_addmethod2(c, (t_method)soundfiler_write, "write", "*");
+}
+
+/************************* readsf object ******************************/
+
+/* READSF uses the Posix threads package; for the moment we're Linux
+only although this should be portable to the other platforms.
+
+Each instance of readsf~ owns a "child" thread for doing the unix (MSW?) file
+reading. The parent thread signals the child each time:
+ (1) a file wants opening or closing;
+ (2) we've eaten another 1/16 of the shared buffer (so that the
+ child thread should check if it's time to read some more.)
+The child signals the parent whenever a read has completed. Signalling
+is done by setting "conditions" and putting data in mutex-controlled common
+areas.
+*/
+
+#define MAXBYTESPERSAMPLE 4
+#define MAXVECSIZE 128
+
+#define READSIZE 65536
+#define WRITESIZE 65536
+#define DEFBUFPERCHAN 262144
+#define MINBUFSIZE (4 * READSIZE)
+#define MAXBUFSIZE 16777216 /* arbitrary; just don't want to hang malloc */
+
+#define REQUEST_NOTHING 0
+#define REQUEST_OPEN 1
+#define REQUEST_CLOSE 2
+#define REQUEST_QUIT 3
+#define REQUEST_BUSY 4
+
+#define STATE_IDLE 0
+#define STATE_STARTUP 1
+#define STATE_STREAM 2
+
+static t_class *readsf_class;
+
+struct t_readsf : t_object {
+ t_canvas *canvas;
+ t_clock *clock;
+ char *buf; /* soundfile buffer */
+ int bufsize; /* buffer size in bytes */
+ int noutlets; /* number of audio outlets */
+ t_sample *(outvec[MAXSFCHANS]); /* audio vectors */
+ int vecsize; /* vector size for transfers */
+ t_outlet *bangout; /* bang-on-done outlet */
+ int state; /* opened, running, or idle */
+ float insamplerate; /* sample rate of input signal if known */
+ /* parameters to communicate with subthread */
+ int requestcode; /* pending request from parent to I/O thread */
+ char *filename; /* file to open (string is permanently allocated) */
+ int fileerror; /* slot for "errno" return */
+ int skipheaderbytes; /* size of header we'll skip */
+ t_param p;
+ float samplerate; /* sample rate of soundfile */
+ long onsetframes; /* number of sample frames to skip */
+ int fd; /* filedesc */
+ int fifosize; /* buffer size appropriately rounded down */
+ int fifohead; /* index of next byte to get from file */
+ int fifotail; /* index of next byte the ugen will read */
+ int eof; /* true if fifohead has stopped changing */
+ int sigcountdown; /* counter for signalling child for more data */
+ int sigperiod; /* number of ticks per signal */
+ int filetype; /* writesf~ only; type of file to create */
+ int itemswritten; /* writesf~ only; items writen */
+ int swap; /* writesf~ only; true if byte swapping */
+ float f; /* writesf~ only; scalar for signal inlet */
+ pthread_mutex_t mutex;
+ pthread_cond_t requestcondition;
+ pthread_cond_t answercondition;
+ pthread_t childthread;
+};
+
+
+/************** the child thread which performs file I/O ***********/
+
+#if 1
+#define sfread_cond_wait pthread_cond_wait
+#define sfread_cond_signal pthread_cond_signal
+#else
+#include <sys/time.h> /* debugging version... */
+#include <sys/types.h>
+static void readsf_fakewait(pthread_mutex_t *b) {
+ struct timeval timout;
+ timout.tv_sec = 0;
+ timout.tv_usec = 1000000;
+ pthread_mutex_unlock(b);
+ select(0, 0, 0, 0, &timout);
+ pthread_mutex_lock(b);
+}
+
+#define sfread_cond_wait(a,b) readsf_fakewait(b)
+#define sfread_cond_signal(a)
+#endif
+
+static void *readsf_child_main(void *zz) {
+ t_readsf *x = (t_readsf *)zz;
+ pthread_mutex_lock(&x->mutex);
+ while (1) {
+ int fd, fifohead;
+ char *buf;
+ if (x->requestcode == REQUEST_NOTHING) {
+ sfread_cond_signal(&x->answercondition);
+ sfread_cond_wait(&x->requestcondition, &x->mutex);
+ } else if (x->requestcode == REQUEST_OPEN) {
+ int sysrtn, wantbytes;
+ /* copy file stuff out of the data structure so we can
+ relinquish the mutex while we're in open_soundfile(). */
+ long onsetframes = x->onsetframes;
+ t_param p;
+ p.bytelimit = 0x7fffffff;
+ int skipheaderbytes = x->skipheaderbytes;
+ p.bytespersample = x->p.bytespersample;
+ p.bigendian = x->p.bigendian;
+ /* alter the request code so that an ensuing "open" will get noticed. */
+ x->requestcode = REQUEST_BUSY;
+ x->fileerror = 0;
+ /* if there's already a file open, close it */
+ if (x->fd >= 0) {
+ fd = x->fd;
+ pthread_mutex_unlock(&x->mutex);
+ close (fd);
+ pthread_mutex_lock(&x->mutex);
+ x->fd = -1;
+ if (x->requestcode != REQUEST_BUSY) goto lost;
+ }
+ /* open the soundfile with the mutex unlocked */
+ pthread_mutex_unlock(&x->mutex);
+ fd = open_soundfile(canvas_getdir(x->canvas)->name, x->filename, skipheaderbytes, &p, onsetframes);
+ pthread_mutex_lock(&x->mutex);
+ /* copy back into the instance structure. */
+ x->p = p;
+ x->fd = fd;
+ if (fd < 0) {
+ x->fileerror = errno;
+ x->eof = 1;
+ goto lost;
+ }
+ /* check if another request has been made; if so, field it */
+ if (x->requestcode != REQUEST_BUSY) goto lost;
+ x->fifohead = 0;
+ /* set fifosize from bufsize. fifosize must be a multiple of the number of bytes eaten for each DSP
+ tick. We pessimistically assume MAXVECSIZE samples per tick since that could change. There could be a
+ problem here if the vector size increases while a soundfile is being played... */
+ x->fifosize = x->bufsize - (x->bufsize % (x->p.bytesperchannel() * MAXVECSIZE));
+ /* arrange for the "request" condition to be signalled 16 times per buffer */
+ x->sigcountdown = x->sigperiod = x->fifosize / (16 * x->p.bytesperchannel() * x->vecsize);
+ /* in a loop, wait for the fifo to get hungry and feed it */
+ while (x->requestcode == REQUEST_BUSY) {
+ int fifosize = x->fifosize;
+ if (x->eof) break;
+ if (x->fifohead >= x->fifotail) {
+ /* if the head is >= the tail, we can immediately read to the end of the fifo. Unless, that is, we
+ would read all the way to the end of the buffer and the "tail" is zero; this would fill the buffer completely
+ which isn't allowed because you can't tell a completely full buffer from an empty one. */
+ if (x->fifotail || (fifosize - x->fifohead > READSIZE)) {
+ wantbytes = min(min(fifosize - x->fifohead, READSIZE),(int)x->p.bytelimit);
+ } else {
+ sfread_cond_signal(&x->answercondition);
+ sfread_cond_wait(&x->requestcondition, &x->mutex);
+ continue;
+ }
+ } else {
+ /* otherwise check if there are at least READSIZE bytes to read. If not, wait and loop back. */
+ wantbytes = x->fifotail - x->fifohead - 1;
+ if (wantbytes < READSIZE) {
+ sfread_cond_signal(&x->answercondition);
+ sfread_cond_wait(&x->requestcondition, &x->mutex);
+ continue;
+ } else wantbytes = READSIZE;
+ wantbytes = min(wantbytes,(int)x->p.bytelimit);
+ }
+ fd = x->fd;
+ buf = x->buf;
+ fifohead = x->fifohead;
+ pthread_mutex_unlock(&x->mutex);
+ sysrtn = read(fd, buf + fifohead, wantbytes);
+ pthread_mutex_lock(&x->mutex);
+ if (x->requestcode != REQUEST_BUSY) break;
+ if (sysrtn < 0) {x->fileerror = errno; break;}
+ else if (sysrtn == 0) {x->eof = 1; break;}
+ else {
+ x->fifohead += sysrtn;
+ x->p.bytelimit -= sysrtn;
+ if (x->p.bytelimit <= 0) {x->eof = 1; break;}
+ if (x->fifohead == fifosize) x->fifohead = 0;
+ }
+ /* signal parent in case it's waiting for data */
+ sfread_cond_signal(&x->answercondition);
+ }
+ lost:
+ if (x->requestcode == REQUEST_BUSY) x->requestcode = REQUEST_NOTHING;
+ /* fell out of read loop: close file if necessary, set EOF and signal once more */
+ if (x->fd >= 0) {
+ fd = x->fd;
+ pthread_mutex_unlock(&x->mutex);
+ close (fd);
+ pthread_mutex_lock(&x->mutex);
+ x->fd = -1;
+ }
+ sfread_cond_signal(&x->answercondition);
+ } else if (x->requestcode == REQUEST_CLOSE || x->requestcode == REQUEST_QUIT) {
+ if (x->fd >= 0) {
+ fd = x->fd;
+ pthread_mutex_unlock(&x->mutex);
+ close (fd);
+ pthread_mutex_lock(&x->mutex);
+ x->fd = -1;
+ }
+ x->requestcode = REQUEST_NOTHING;
+ sfread_cond_signal(&x->answercondition);
+ }
+ if (x->requestcode == REQUEST_QUIT) break;
+ }
+ pthread_mutex_unlock(&x->mutex);
+ return 0;
+}
+
+/******** the object proper runs in the calling (parent) thread ****/
+
+static void readsf_tick(t_readsf *x);
+
+static void *readsf_new(t_floatarg fnchannels, t_floatarg fbufsize) {
+ int nchannels = int(fnchannels), bufsize = int(fbufsize);
+ if (nchannels < 1) nchannels = 1;
+ else if (nchannels > MAXSFCHANS) nchannels = MAXSFCHANS;
+ if (bufsize <= 0) bufsize = DEFBUFPERCHAN * nchannels;
+ else if (bufsize < MINBUFSIZE) bufsize = MINBUFSIZE;
+ else if (bufsize > MAXBUFSIZE) bufsize = MAXBUFSIZE;
+ char *buf = (char *)getbytes(bufsize);
+ if (!buf) return 0;
+ t_readsf *x = (t_readsf *)pd_new(readsf_class);
+ for (int i=0; i<nchannels; i++) outlet_new(x,gensym("signal"));
+ x->noutlets = nchannels;
+ x->bangout = outlet_new(x,&s_bang);
+ pthread_mutex_init(&x->mutex, 0);
+ pthread_cond_init(&x->requestcondition, 0);
+ pthread_cond_init(&x->answercondition, 0);
+ x->vecsize = MAXVECSIZE;
+ x->state = STATE_IDLE;
+ x->clock = clock_new(x, (t_method)readsf_tick);
+ x->canvas = canvas_getcurrent();
+ x->p.bytespersample = 2;
+ x->p.nchannels = 1;
+ x->fd = -1;
+ x->buf = buf;
+ x->bufsize = bufsize;
+ x->fifosize = x->fifohead = x->fifotail = x->requestcode = 0;
+ pthread_create(&x->childthread, 0, readsf_child_main, x);
+ return x;
+}
+
+static void readsf_tick(t_readsf *x) {outlet_bang(x->bangout);}
+
+static t_int *readsf_perform(t_int *w) {
+ t_readsf *x = (t_readsf *)(w[1]);
+ int vecsize = x->vecsize, noutlets = x->noutlets;
+ if (x->state == STATE_STREAM) {
+ int wantbytes;
+ pthread_mutex_lock(&x->mutex);
+ wantbytes = vecsize * x->p.bytesperchannel();
+ while (!x->eof && x->fifohead >= x->fifotail && x->fifohead < x->fifotail + wantbytes-1) {
+ sfread_cond_signal(&x->requestcondition);
+ sfread_cond_wait(&x->answercondition, &x->mutex);
+ }
+ if (x->eof && x->fifohead >= x->fifotail && x->fifohead < x->fifotail + wantbytes-1) {
+ if (x->fileerror) {
+ error("dsp: %s: %s", x->filename, x->fileerror == EIO ? "unknown or bad header format" : strerror(x->fileerror));
+ }
+ clock_delay(x->clock, 0);
+ x->state = STATE_IDLE;
+ /* if there's a partial buffer left, copy it out. */
+ int xfersize = (x->fifohead - x->fifotail + 1) / x->p.bytesperchannel();
+ if (xfersize) {
+ soundfile_xferin(x->p.nchannels, noutlets, x->outvec, 0,
+ (unsigned char *)(x->buf + x->fifotail), xfersize, x->p.bytespersample, x->p.bigendian);
+ vecsize -= xfersize;
+ }
+ /* then zero out the (rest of the) output */
+ for (int i=0; i<noutlets; i++) {
+ float *fp = x->outvec[i] + xfersize;
+ for (int j=vecsize; j--; ) *fp++ = 0;
+ }
+ sfread_cond_signal(&x->requestcondition);
+ pthread_mutex_unlock(&x->mutex);
+ return w+2;
+ }
+ soundfile_xferin(x->p.nchannels, noutlets, x->outvec, 0, (unsigned char *)(x->buf + x->fifotail), vecsize, x->p.bytespersample, x->p.bigendian);
+ x->fifotail += wantbytes;
+ if (x->fifotail >= x->fifosize) x->fifotail = 0;
+ if ((--x->sigcountdown) <= 0) {
+ sfread_cond_signal(&x->requestcondition);
+ x->sigcountdown = x->sigperiod;
+ }
+ pthread_mutex_unlock(&x->mutex);
+ } else {
+ for (int i=0; i<noutlets; i++) {
+ float *fp = x->outvec[i];
+ for (int j=vecsize; j--; ) *fp++=0;
+ }
+ }
+ return w+2;
+}
+
+static void readsf_start(t_readsf *x) {
+ /* start making output. If we're in the "startup" state change
+ to the "running" state. */
+ if (x->state == STATE_STARTUP) x->state = STATE_STREAM;
+ else error("readsf: start requested with no prior 'open'");
+}
+
+static void readsf_stop(t_readsf *x) {
+ /* LATER rethink whether you need the mutex just to set a variable? */
+ pthread_mutex_lock(&x->mutex);
+ x->state = STATE_IDLE;
+ x->requestcode = REQUEST_CLOSE;
+ sfread_cond_signal(&x->requestcondition);
+ pthread_mutex_unlock(&x->mutex);
+}
+
+static void readsf_float(t_readsf *x, t_floatarg f) {
+ if (f != 0) readsf_start(x); else readsf_stop(x);
+}
+
+/* open method. Called as: open filename [skipframes headersize channels bytespersample endianness]
+ (if headersize is zero, header is taken to be automatically detected; thus, use the special "-1" to mean a truly headerless file.) */
+static void readsf_open(t_readsf *x, t_symbol *s, int argc, t_atom *argv) {
+ t_symbol *filesym = atom_getsymbolarg(0, argc, argv);
+ t_float onsetframes = atom_getfloatarg(1, argc, argv);
+ t_float headerbytes = atom_getfloatarg(2, argc, argv);
+ t_float channels = atom_getfloatarg(3, argc, argv);
+ t_float bytespersample = atom_getfloatarg(4, argc, argv);
+ t_symbol *endian = atom_getsymbolarg(5, argc, argv);
+ if (!*filesym->name) return;
+ pthread_mutex_lock(&x->mutex);
+ x->requestcode = REQUEST_OPEN;
+ x->filename = filesym->name;
+ x->fifotail = 0;
+ x->fifohead = 0;
+ if (*endian->name == 'b') x->p.bigendian = 1;
+ else if (*endian->name == 'l') x->p.bigendian = 0;
+ else if (*endian->name) error("endianness neither 'b' nor 'l'");
+ else x->p.bigendian = garray_ambigendian();
+ x->onsetframes = max(long(onsetframes),0L);
+ x->skipheaderbytes = int(headerbytes > 0 ? headerbytes : headerbytes == 0 ? -1 : 0);
+ x->p.nchannels = max(int(channels),1);
+ x->p.bytespersample = max(int(bytespersample),2);
+ x->eof = 0;
+ x->fileerror = 0;
+ x->state = STATE_STARTUP;
+ sfread_cond_signal(&x->requestcondition);
+ pthread_mutex_unlock(&x->mutex);
+}
+
+static void readsf_dsp(t_readsf *x, t_signal **sp) {
+ int i, noutlets = x->noutlets;
+ pthread_mutex_lock(&x->mutex);
+ x->vecsize = sp[0]->n;
+ x->sigperiod = (x->fifosize / (x->p.bytesperchannel() * x->vecsize));
+ for (i = 0; i < noutlets; i++) x->outvec[i] = sp[i]->v;
+ pthread_mutex_unlock(&x->mutex);
+ dsp_add(readsf_perform, 1, x);
+}
+
+static void readsf_print(t_readsf *x) {
+ post("state %d", x->state);
+ post("fifo head %d", x->fifohead);
+ post("fifo tail %d", x->fifotail);
+ post("fifo size %d", x->fifosize);
+ post("fd %d", x->fd);
+ post("eof %d", x->eof);
+}
+
+static void readsf_free(t_readsf *x) {
+ /* request QUIT and wait for acknowledge */
+ void *threadrtn;
+ pthread_mutex_lock(&x->mutex);
+ x->requestcode = REQUEST_QUIT;
+ sfread_cond_signal(&x->requestcondition);
+ while (x->requestcode != REQUEST_NOTHING) {
+ sfread_cond_signal(&x->requestcondition);
+ sfread_cond_wait(&x->answercondition, &x->mutex);
+ }
+ pthread_mutex_unlock(&x->mutex);
+ if (pthread_join(x->childthread, &threadrtn)) error("readsf_free: join failed");
+ pthread_cond_destroy(&x->requestcondition);
+ pthread_cond_destroy(&x->answercondition);
+ pthread_mutex_destroy(&x->mutex);
+ free(x->buf);
+ clock_free(x->clock);
+}
+
+static void readsf_setup() {
+ t_class *c = readsf_class = class_new2("readsf~", (t_newmethod)readsf_new, (t_method)readsf_free, sizeof(t_readsf), 0, "FF");
+ class_addfloat(c, (t_method)readsf_float);
+ class_addmethod2(c, (t_method)readsf_start, "start","");
+ class_addmethod2(c, (t_method)readsf_stop, "stop","");
+ class_addmethod2(c, (t_method)readsf_dsp, "dsp","");
+ class_addmethod2(c, (t_method)readsf_open, "open","*");
+ class_addmethod2(c, (t_method)readsf_print, "print","");
+}
+
+/******************************* writesf *******************/
+
+static t_class *writesf_class;
+typedef t_readsf t_writesf; /* just re-use the structure */
+
+/************** the child thread which performs file I/O ***********/
+
+static void *writesf_child_main(void *zz) {
+ t_writesf *x = (t_writesf*)zz;
+ pthread_mutex_lock(&x->mutex);
+ while (1) {
+ if (x->requestcode == REQUEST_NOTHING) {
+ sfread_cond_signal(&x->answercondition);
+ sfread_cond_wait(&x->requestcondition, &x->mutex);
+ } else if (x->requestcode == REQUEST_OPEN) {
+ int fd, sysrtn, writebytes;
+ /* copy file stuff out of the data structure so we can relinquish the mutex while we're in open_soundfile(). */
+ int filetype = x->filetype;
+ char *filename = x->filename;
+ t_canvas *canvas = x->canvas;
+ float samplerate = x->samplerate;
+ /* alter the request code so that an ensuing "open" will get noticed. */
+ x->requestcode = REQUEST_BUSY;
+ x->fileerror = 0;
+ /* if there's already a file open, close it. This should never happen since
+ writesf_open() calls stop if needed and then waits until we're idle. */
+ if (x->fd >= 0) {
+ int bytesperframe = x->p.bytesperchannel();
+ char *filename = x->filename;
+ int fd = x->fd;
+ int filetype = x->filetype;
+ int itemswritten = x->itemswritten;
+ int swap = x->swap;
+ pthread_mutex_unlock(&x->mutex);
+ soundfile_finishwrite(x, filename, fd, filetype, 0x7fffffff, itemswritten, bytesperframe, swap);
+ close (fd);
+ pthread_mutex_lock(&x->mutex);
+ x->fd = -1;
+ if (x->requestcode != REQUEST_BUSY) continue;
+ }
+ /* open the soundfile with the mutex unlocked */
+ pthread_mutex_unlock(&x->mutex);
+ fd = create_soundfile(canvas, filename, filetype, 0,
+ x->p.bytespersample, x->p.bigendian, x->p.nchannels, garray_ambigendian() != x->p.bigendian, samplerate);
+ pthread_mutex_lock(&x->mutex);
+ if (fd < 0) {
+ x->fd = -1;
+ x->eof = 1;
+ x->fileerror = errno;
+ x->requestcode = REQUEST_NOTHING;
+ continue;
+ }
+ /* check if another request has been made; if so, field it */
+ if (x->requestcode != REQUEST_BUSY) continue;
+ x->fd = fd;
+ x->fifotail = 0;
+ x->itemswritten = 0;
+ x->swap = garray_ambigendian() != x->p.bigendian;
+ /* in a loop, wait for the fifo to have data and write it to disk */
+ while (x->requestcode == REQUEST_BUSY || (x->requestcode == REQUEST_CLOSE && x->fifohead != x->fifotail)) {
+ int fifosize = x->fifosize, fifotail;
+ char *buf = x->buf;
+ /* if the head is < the tail, we can immediately write
+ from tail to end of fifo to disk; otherwise we hold off
+ writing until there are at least WRITESIZE bytes in the
+ buffer */
+ if (x->fifohead < x->fifotail || x->fifohead >= x->fifotail + WRITESIZE
+ || (x->requestcode == REQUEST_CLOSE && x->fifohead != x->fifotail)) {
+ writebytes = (x->fifohead < x->fifotail ? fifosize : x->fifohead) - x->fifotail;
+ if (writebytes > READSIZE) writebytes = READSIZE;
+ } else {
+ sfread_cond_signal(&x->answercondition);
+ sfread_cond_wait(&x->requestcondition,&x->mutex);
+ continue;
+ }
+ fifotail = x->fifotail;
+ fd = x->fd;
+ pthread_mutex_unlock(&x->mutex);
+ sysrtn = write(fd, buf + fifotail, writebytes);
+ pthread_mutex_lock(&x->mutex);
+ if (x->requestcode != REQUEST_BUSY && x->requestcode != REQUEST_CLOSE) break;
+ if (sysrtn < writebytes) {x->fileerror = errno; break;}
+ else {
+ x->fifotail += sysrtn;
+ if (x->fifotail == fifosize) x->fifotail = 0;
+ }
+ x->itemswritten += sysrtn / x->p.bytesperchannel();
+ /* signal parent in case it's waiting for data */
+ sfread_cond_signal(&x->answercondition);
+ }
+ } else if (x->requestcode == REQUEST_CLOSE || x->requestcode == REQUEST_QUIT) {
+ if (x->fd >= 0) {
+ int bytesperframe = x->p.bytesperchannel();
+ char *filename = x->filename;
+ int fd = x->fd;
+ int filetype = x->filetype;
+ int itemswritten = x->itemswritten;
+ int swap = x->swap;
+ pthread_mutex_unlock(&x->mutex);
+ soundfile_finishwrite(x, filename, fd, filetype, 0x7fffffff, itemswritten, bytesperframe, swap);
+ close(fd);
+ pthread_mutex_lock(&x->mutex);
+ x->fd = -1;
+ }
+ x->requestcode = REQUEST_NOTHING;
+ sfread_cond_signal(&x->answercondition);
+ }
+ if (x->requestcode == REQUEST_QUIT) break;
+ }
+ pthread_mutex_unlock(&x->mutex);
+ return 0;
+}
+
+/******** the object proper runs in the calling (parent) thread ****/
+
+static void *writesf_new(t_floatarg fnchannels, t_floatarg fbufsize) {
+ int nchannels = int(fnchannels), bufsize = int(fbufsize), i;
+ if (nchannels < 1) nchannels = 1;
+ else if (nchannels > MAXSFCHANS) nchannels = MAXSFCHANS;
+ if (bufsize <= 0) bufsize = DEFBUFPERCHAN * nchannels;
+ else if (bufsize < MINBUFSIZE) bufsize = MINBUFSIZE;
+ else if (bufsize > MAXBUFSIZE) bufsize = MAXBUFSIZE;
+ char *buf = (char *)getbytes(bufsize);
+ if (!buf) return 0;
+ t_writesf *x = (t_writesf *)pd_new(writesf_class);
+ for (i = 1; i < nchannels; i++) inlet_new(x,x, &s_signal, &s_signal);
+ x->f = 0;
+ x->p.nchannels = nchannels;
+ pthread_mutex_init(&x->mutex, 0);
+ pthread_cond_init(&x->requestcondition, 0);
+ pthread_cond_init(&x->answercondition, 0);
+ x->vecsize = MAXVECSIZE;
+ x->insamplerate = x->samplerate = 0;
+ x->state = STATE_IDLE;
+ x->clock = 0; /* no callback needed here */
+ x->canvas = canvas_getcurrent();
+ x->p.bytespersample = 2;
+ x->fd = -1;
+ x->buf = buf;
+ x->bufsize = bufsize;
+ x->fifosize = x->fifohead = x->fifotail = x->requestcode = 0;
+ pthread_create(&x->childthread, 0, writesf_child_main, x);
+ return x;
+}
+
+static t_int *writesf_perform(t_int *w) {
+ t_writesf *x = (t_writesf *)(w[1]);
+ if (x->state == STATE_STREAM) {
+ int wantbytes;
+ pthread_mutex_lock(&x->mutex);
+ wantbytes = x->vecsize * x->p.bytesperchannel();
+ while (x->fifotail > x->fifohead && x->fifotail < x->fifohead + wantbytes + 1) {
+ sfread_cond_signal(&x->requestcondition);
+ sfread_cond_wait(&x->answercondition, &x->mutex);
+ /* resync local cariables -- bug fix thanks to Shahrokh */
+ wantbytes = x->vecsize * x->p.bytesperchannel();
+ }
+ soundfile_xferout(x->p.nchannels, x->outvec, (unsigned char *)(x->buf + x->fifohead), x->vecsize, 0, x->p.bytespersample, x->p.bigendian, 1.);
+ x->fifohead += wantbytes;
+ if (x->fifohead >= x->fifosize) x->fifohead = 0;
+ if ((--x->sigcountdown) <= 0) {
+ sfread_cond_signal(&x->requestcondition);
+ x->sigcountdown = x->sigperiod;
+ }
+ pthread_mutex_unlock(&x->mutex);
+ }
+ return w+2;
+}
+
+static void writesf_start(t_writesf *x) {
+ /* start making output. If we're in the "startup" state change to the "running" state. */
+ if (x->state == STATE_STARTUP) x->state = STATE_STREAM;
+ else error("writesf: start requested with no prior 'open'");
+}
+
+static void writesf_stop(t_writesf *x) {
+ /* LATER rethink whether you need the mutex just to set a Svariable? */
+ pthread_mutex_lock(&x->mutex);
+ x->state = STATE_IDLE;
+ x->requestcode = REQUEST_CLOSE;
+ sfread_cond_signal(&x->requestcondition);
+ pthread_mutex_unlock(&x->mutex);
+}
+
+/* open method. Called as: open [args] filename with args as in soundfiler_writeargparse(). */
+static void writesf_open(t_writesf *x, t_symbol *s, int argc, t_atom *argv) {
+ t_symbol *filesym;
+ int filetype, bytespersample, swap, bigendian, normalize;
+ long onset, nframes;
+ float samplerate;
+ if (x->state != STATE_IDLE) writesf_stop(x);
+ if (soundfiler_writeargparse(x, &argc, &argv, &filesym, &filetype, &bytespersample, &swap, &bigendian,
+ &normalize, &onset, &nframes, &samplerate)) {
+ error("writesf~: usage: open [-bytes [234]] [-wave,-nextstep,-aiff] ...");
+ post("... [-big,-little] [-rate ####] filename");
+ return;
+ }
+ if (normalize || onset || (nframes != 0x7fffffff))
+ error("normalize/onset/nframes argument to writesf~: ignored");
+ if (argc) error("extra argument(s) to writesf~: ignored");
+ pthread_mutex_lock(&x->mutex);
+ while (x->requestcode != REQUEST_NOTHING) {
+ sfread_cond_signal(&x->requestcondition);
+ sfread_cond_wait(&x->answercondition, &x->mutex);
+ }
+ x->p.bytespersample = max(bytespersample,2);
+ x->swap = swap;
+ x->p.bigendian = bigendian;
+ x->filename = filesym->name;
+ x->filetype = filetype;
+ x->itemswritten = 0;
+ x->requestcode = REQUEST_OPEN;
+ x->fifotail = 0;
+ x->fifohead = 0;
+ x->eof = 0;
+ x->fileerror = 0;
+ x->state = STATE_STARTUP;
+ x->samplerate = samplerate>0 ? samplerate : x->insamplerate>0 ? x->insamplerate : sys_getsr();
+ /* set fifosize from bufsize. fifosize must be a multiple of the number of bytes eaten for each DSP tick. */
+ x->fifosize = x->bufsize - x->bufsize % (x->p.bytesperchannel() * MAXVECSIZE);
+ /* arrange for the "request" condition to be signalled 16 times per buffer */
+ x->sigcountdown = x->sigperiod = x->fifosize / (16 * x->p.bytesperchannel() * x->vecsize);
+ sfread_cond_signal(&x->requestcondition);
+ pthread_mutex_unlock(&x->mutex);
+}
+
+static void writesf_dsp(t_writesf *x, t_signal **sp) {
+ int ninlets = x->p.nchannels;
+ pthread_mutex_lock(&x->mutex);
+ x->vecsize = sp[0]->n;
+ x->sigperiod = x->fifosize / (x->p.bytesperchannel() * x->vecsize);
+ for (int i=0; i<ninlets; i++) x->outvec[i] = sp[i]->v;
+ x->insamplerate = sp[0]->sr;
+ pthread_mutex_unlock(&x->mutex);
+ dsp_add(writesf_perform, 1, x);
+}
+
+static void writesf_print(t_writesf *x) {
+ post("state %d", x->state);
+ post("fifo head %d", x->fifohead);
+ post("fifo tail %d", x->fifotail);
+ post("fifo size %d", x->fifosize);
+ post("fd %d", x->fd);
+ post("eof %d", x->eof);
+}
+
+static void writesf_free(t_writesf *x) {
+ /* request QUIT and wait for acknowledge */
+ void *threadrtn;
+ pthread_mutex_lock(&x->mutex);
+ x->requestcode = REQUEST_QUIT;
+ /* post("stopping writesf thread..."); */
+ sfread_cond_signal(&x->requestcondition);
+ while (x->requestcode != REQUEST_NOTHING) {
+ /* post("signalling..."); */
+ sfread_cond_signal(&x->requestcondition);
+ sfread_cond_wait(&x->answercondition, &x->mutex);
+ }
+ pthread_mutex_unlock(&x->mutex);
+ if (pthread_join(x->childthread, &threadrtn)) error("writesf_free: join failed");
+ /* post("... done."); */
+ pthread_cond_destroy(&x->requestcondition);
+ pthread_cond_destroy(&x->answercondition);
+ pthread_mutex_destroy(&x->mutex);
+ free(x->buf);
+}
+
+static void writesf_setup() {
+ t_class *c = writesf_class = class_new2("writesf~", (t_newmethod)writesf_new, (t_method)writesf_free, sizeof(t_writesf), 0, "FF");
+ class_addmethod2(c, (t_method)writesf_start, "start", "");
+ class_addmethod2(c, (t_method)writesf_stop, "stop", "");
+ class_addmethod2(c, (t_method)writesf_dsp, "dsp", "");
+ class_addmethod2(c, (t_method)writesf_open, "open", "*");
+ class_addmethod2(c, (t_method)writesf_print, "print", "");
+ CLASS_MAINSIGNALIN(c, t_writesf, f);
+}
+
+/* ------------------------ global setup routine ------------------------- */
+
+void d_soundfile_setup() {
+ if (sizeof(uint16)!=2) bug("uint16 should really be 16 bits");
+ if (sizeof(uint32)!=4) bug("uint32 should really be 32 bits");
+ soundfiler_setup();
+ readsf_setup();
+ writesf_setup();
+}
diff --git a/desiredata/src/d_ugen.c b/desiredata/src/d_ugen.c
new file mode 100644
index 00000000..4835b49d
--- /dev/null
+++ b/desiredata/src/d_ugen.c
@@ -0,0 +1,1016 @@
+/* Copyright (c) 1997-1999 Miller Puckette.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* These routines build a copy of the DSP portion of a graph, which is
+ then sorted into a linear list of DSP operations which are added to
+ the DSP duty cycle called by the scheduler. Once that's been done,
+ we delete the copy. The DSP objects are represented by "ugenbox"
+ structures which are parallel to the DSP objects in the graph and
+ have vectors of siginlets and sigoutlets which record their
+ interconnections.
+*/
+
+/* hacked to run subpatches with different power-of-2 samplerates - mfg.gfd.uil IOhannes */
+
+#define PD_PLUSPLUS_FACE
+#include "desire.h"
+#include <stdlib.h>
+#include <stdarg.h>
+
+/* T.Grill - include SIMD functionality */
+#include "m_simd.h"
+
+extern t_class *vinlet_class, *voutlet_class, *canvas_class;
+t_sample *obj_findsignalscalar(t_object *x, int m);
+static int ugen_loud;
+static t_int *dsp_chain;
+static int dsp_chainsize;
+struct _vinlet;
+struct _voutlet;
+
+extern "C" {
+void vinlet_dspprolog( struct _vinlet *x, t_signal **parentsigs, int myvecsize, int calcsize, int phase, int period, int frequency,
+ int downsample, int upsample, int reblock, int switched);
+void voutlet_dspprolog(struct _voutlet *x, t_signal **parentsigs, int myvecsize, int calcsize, int phase, int period, int frequency,
+ int downsample, int upsample, int reblock, int switched);
+void voutlet_dspepilog(struct _voutlet *x, t_signal **parentsigs, int myvecsize, int calcsize, int phase, int period, int frequency,
+ int downsample, int upsample, int reblock, int switched);
+};
+
+/* zero out a vector */
+t_int *zero_perform(t_int *w) {
+ t_float *out = (t_float *)w[1];
+ int n = int(w[2]);
+ while (n--) *out++ = 0;
+ return w+3;
+}
+
+t_int *zero_perf8(t_int *w) {
+ t_float *out = (t_float *)w[1];
+ int n = int(w[2]);
+ for (; n; n -= 8, out += 8) {
+ out[0] = 0; out[1] = 0;
+ out[2] = 0; out[3] = 0;
+ out[4] = 0; out[5] = 0;
+ out[6] = 0; out[7] = 0;
+ }
+ return w+3;
+}
+
+void dsp_add_zero(t_sample *out, int n) {
+ if (n&7) dsp_add(zero_perform, 2, out, n);
+ else if(SIMD_CHECK1(n,out)) dsp_add(zero_perf_simd, 2, out, n);
+ else dsp_add(zero_perf8, 2, out, n);
+}
+
+/* ---------------------------- block~ ----------------------------- */
+/* The "block~ object maintains the containing canvas's DSP computation,
+calling it at a super- or sub-multiple of the containing canvas's
+calling frequency. The block~'s creation arguments specify block size
+and overlap. Block~ does no "dsp" computation in its own right, but it
+adds prolog and epilog code before and after the canvas's unit generators.
+
+A subcanvas need not have a block~ at all; if there's none, its
+ugens are simply put on the list without any prolog or epilog code.
+
+Block~ may be invoked as switch~, in which case it also acts to switch the
+subcanvas on and off. The overall order of scheduling for a subcanvas
+is thus,
+
+ inlet and outlet prologue code (1)
+ block prologue (2)
+ the objects in the subcanvas, including inlets and outlets
+ block epilogue (2)
+ outlet epilogue code (2)
+
+where (1) means, "if reblocked" and (2) means, "if reblocked or switched".
+
+If we're reblocked, the inlet prolog and outlet epilog code takes care of
+overlapping and buffering to deal with vector size changes. If we're switched
+but not reblocked, the inlet prolog is not needed, and the output epilog is
+ONLY run when the block is switched off; in this case the epilog code simply
+copies zeros to all signal outlets.
+*/
+
+static int dsp_phase;
+static t_class *block_class;
+
+struct t_block : t_object {
+ int vecsize; /* size of audio signals in this block */
+ int calcsize; /* number of samples actually to compute */
+ int overlap;
+ int phase; /* from 0 to period-1; when zero we run the block */
+ int period; /* submultiple of containing canvas */
+ int frequency; /* supermultiple of comtaining canvas */
+ int count; /* number of times parent block has called us */
+ int chainonset; /* beginning of code in DSP chain */
+ int blocklength; /* length of dspchain for this block */
+ int epiloglength; /* length of epilog */
+ char switched; /* true if we're acting as a a switch */
+ char switchon; /* true if we're switched on */
+ char reblock; /* true if inlets and outlets are reblocking */
+ int upsample; /* IOhannes: upsampling-factor */
+ int downsample; /* IOhannes: downsampling-factor */
+ int x_return; /* stop right after this block (for one-shots) */
+};
+
+static void block_set(t_block *x, t_floatarg fvecsize, t_floatarg foverlap, t_floatarg fupsample);
+
+static void *block_new(t_floatarg fcalcsize, t_floatarg foverlap, t_floatarg fupsample) /* IOhannes */ {
+ t_block *x = (t_block *)pd_new(block_class);
+ x->phase = 0;
+ x->period = 1;
+ x->frequency = 1;
+ x->switched = 0;
+ x->switchon = 1;
+ block_set(x, fcalcsize, foverlap, fupsample);
+ return x;
+}
+
+static void block_set(t_block *x, t_floatarg fcalcsize, t_floatarg foverlap, t_floatarg fupsample) {
+ int upsample, downsample; /* IOhannes */
+ int calcsize = (int)fcalcsize;
+ int overlap = (int)foverlap;
+ int dspstate = canvas_suspend_dsp();
+ if (overlap < 1) overlap = 1;
+ if (calcsize < 0) calcsize = 0; /* this means we'll get it from parent later. */
+ /* IOhannes { */
+ if (fupsample <= 0) upsample = downsample = 1;
+ else if (fupsample >= 1) {
+ upsample = (int)fupsample;
+ downsample = 1;
+ } else {
+ downsample = int(1.0 / fupsample);
+ upsample = 1;
+ }
+ /* } IOhannes */
+ /* vecsize is smallest power of 2 large enough to hold calcsize */
+ int vecsize = 0;
+ if (calcsize) {
+ vecsize = (1 << ilog2(calcsize));
+ if (vecsize != calcsize) vecsize *= 2;
+ }
+ if (vecsize && vecsize != (1 << ilog2(vecsize))) {error("block~: vector size not a power of 2"); vecsize = 64;}
+ if ( overlap != (1 << ilog2(overlap))) {error("block~: overlap not a power of 2"); overlap = 1;}
+ /* IOhannes { */
+ if (downsample != (1 << ilog2(downsample))) {error("block~: downsampling not a power of 2"); downsample = 1;}
+ if ( upsample != (1 << ilog2( upsample))) {error("block~: upsampling not a power of 2"); upsample = 1;}
+ /* } IOhannes */
+ x->calcsize = calcsize;
+ x->vecsize = vecsize;
+ x->overlap = overlap;
+ /* IOhannes { */
+ x->upsample = upsample;
+ x->downsample = downsample;
+ /* } IOhannes */
+ canvas_resume_dsp(dspstate);
+}
+
+static void *switch_new(t_floatarg fvecsize, t_floatarg foverlap, t_floatarg fupsample) /* IOhannes */ {
+ t_block *x = (t_block *)(block_new(fvecsize, foverlap, fupsample)); /* IOhannes */
+ x->switched = 1;
+ x->switchon = 0;
+ return x;
+}
+
+static void block_float(t_block *x, t_floatarg f) {
+ if (x->switched) x->switchon = f!=0;
+}
+
+static void block_bang(t_block *x) {
+ if (x->switched && !x->switchon) {
+ x->x_return = 1;
+ for (t_int *ip = dsp_chain + x->chainonset; ip; ) ip = t_perfroutine(*ip)(ip);
+ x->x_return = 0;
+ } else error("bang to block~ or on-state switch~ has no effect");
+}
+
+#define PROLOGCALL 2
+#define EPILOGCALL 2
+
+static t_int *block_prolog(t_int *w) {
+ t_block *x = (t_block *)w[1];
+ int phase = x->phase;
+ /* if we're switched off, jump past the epilog code */
+ if (!x->switchon) return w+x->blocklength;
+ if (phase) {
+ phase++;
+ if (phase == x->period) phase = 0;
+ x->phase = phase;
+ return w+x->blocklength; /* skip block; jump past epilog */
+ } else {
+ x->count = x->frequency;
+ x->phase = (x->period > 1 ? 1 : 0);
+ return w+PROLOGCALL; /* beginning of block is next ugen */
+ }
+}
+
+static t_int *block_epilog(t_int *w) {
+ t_block *x = (t_block *)w[1];
+ int count = x->count - 1;
+ if (x->x_return) return 0;
+ if (!x->reblock) return w+x->epiloglength+EPILOGCALL;
+ if (count) {
+ x->count = count;
+ return w - (x->blocklength - (PROLOGCALL + EPILOGCALL)); /* go to ugen after prolog */
+ } else return w+EPILOGCALL;
+}
+
+static void block_dsp(t_block *x, t_signal **sp) {/* do nothing here */}
+
+void block_tilde_setup() {
+ block_class = class_new2("block~", (t_newmethod)block_new, 0, sizeof(t_block), 0,"FFF");
+ class_addcreator2("switch~",(t_newmethod)switch_new,"FFF");
+ class_addmethod2(block_class, (t_method)block_set,"set","FFF");
+ class_addmethod2(block_class, (t_method)block_dsp,"dsp","");
+ class_addfloat(block_class, block_float);
+ class_addbang(block_class, block_bang);
+}
+
+/* ------------------ DSP call list ----------------------- */
+
+static t_int dsp_done(t_int *w) {return 0;}
+
+void dsp_add(t_perfroutine f, int n, ...) {
+ va_list ap;
+ va_start(ap, n);
+ int newsize = dsp_chainsize + n+1;
+ dsp_chain = (t_int *)resizebytes(dsp_chain, dsp_chainsize * sizeof (t_int), newsize * sizeof (t_int));
+ dsp_chain[dsp_chainsize-1] = (t_int)f;
+ for (int i=0; i<n; i++) dsp_chain[dsp_chainsize + i] = va_arg(ap, t_int);
+ dsp_chain[newsize-1] = (t_int)dsp_done;
+ dsp_chainsize = newsize;
+ va_end(ap);
+}
+
+/* at Guenter's suggestion, here's a vectorized version */
+void dsp_addv(t_perfroutine f, int n, t_int *vec) {
+ int newsize = dsp_chainsize + n+1;
+ dsp_chain = (t_int *)resizebytes(dsp_chain, dsp_chainsize * sizeof (t_int), newsize * sizeof (t_int));
+ dsp_chain[dsp_chainsize-1] = (t_int)f;
+ for (int i=0; i<n; i++) dsp_chain[dsp_chainsize + i] = vec[i];
+ dsp_chain[newsize-1] = (t_int)dsp_done;
+ dsp_chainsize = newsize;
+}
+
+void dsp_tick() {
+ if (dsp_chain) {
+ for (t_int *ip = dsp_chain; ip; ) ip = ((t_perfroutine)*ip)(ip);
+ dsp_phase++;
+ }
+}
+
+/* ---------------- signals ---------------------------- */
+
+int ilog2(int n) {
+ int r = -1;
+ if (n <= 0) return 0;
+ while (n) {
+ r++;
+ n >>= 1;
+ }
+ return r;
+}
+
+/* list of signals which can be reused, sorted by buffer size */
+static t_signal *signal_freelist[MAXLOGSIG+1];
+/* list of reusable "borrowed" signals (which don't own sample buffers) */
+static t_signal *signal_freeborrowed;
+/* list of all signals allocated (not including "borrowed" ones) */
+static t_signal *signal_usedlist;
+
+/* call this when DSP is stopped to free all the signals */
+void signal_cleanup() {
+ t_signal *sig;
+ while ((sig = signal_usedlist)) {
+ signal_usedlist = sig->nextused;
+ if (!sig->isborrowed) {
+#ifndef VECTORALIGNMENT
+ free(sig->v);
+#else
+ freealignedbytes(sig->v, sig->vecsize * sizeof (*sig->v));
+#endif
+ }
+ free(sig);
+ }
+ for (int i=0; i<=MAXLOGSIG; i++) signal_freelist[i] = 0;
+ signal_freeborrowed = 0;
+}
+
+/* mark the signal "reusable." */
+extern "C" void signal_makereusable(t_signal *sig) {
+ int logn = ilog2(sig->vecsize);
+#if 1
+ for (t_signal *s5 = signal_freeborrowed; s5; s5 = s5->nextfree) {if (s5 == sig) {bug("signal_free 3"); return;}}
+ for (t_signal *s5 = signal_freelist[logn]; s5; s5 = s5->nextfree) {if (s5 == sig) {bug("signal_free 4"); return;}}
+#endif
+ if (ugen_loud) post("free %lx: %d", sig, sig->isborrowed);
+ if (sig->isborrowed) {
+ /* if the signal is borrowed, decrement the borrowed-from signal's reference count, possibly marking it reusable too */
+ t_signal *s2 = sig->borrowedfrom;
+ if ((s2 == sig) || !s2) bug("signal_free");
+ s2->refcount--;
+ if (!s2->refcount) signal_makereusable(s2);
+ sig->nextfree = signal_freeborrowed;
+ signal_freeborrowed = sig;
+ } else {
+ /* if it's a real signal (not borrowed), put it on the free list so we can reuse it. */
+ if (signal_freelist[logn] == sig) bug("signal_free 2");
+ sig->nextfree = signal_freelist[logn];
+ signal_freelist[logn] = sig;
+ }
+}
+
+/* reclaim or make an audio signal. If n is zero, return a "borrowed"
+ signal whose buffer and size will be obtained later via signal_setborrowed(). */
+t_signal *signal_new(int n, float sr) {
+ int vecsize = 0;
+ t_signal *ret, **whichlist;
+ int logn = ilog2(n);
+ if (n) {
+ if ((vecsize = (1<<logn)) != n) vecsize *= 2;
+ if (logn > MAXLOGSIG) bug("signal buffer too large");
+ whichlist = signal_freelist + logn;
+ } else whichlist = &signal_freeborrowed;
+ /* first try to reclaim one from the free list */
+ ret = *whichlist;
+ if (ret) *whichlist = ret->nextfree;
+ else {
+ /* LATER figure out what to do for out-of-space here! */
+ ret = (t_signal *)t_getbytes(sizeof *ret);
+ if (n) {
+#ifndef VECTORALIGNMENT
+ ret->v = (t_sample *)getbytes(vecsize * sizeof (*ret->v));
+#else
+ /* T.Grill - make signal vectors aligned! */
+ ret->v = (t_sample *)getalignedbytes(vecsize * sizeof (*ret->v));
+#endif
+ ret->isborrowed = 0;
+ } else {
+ ret->v = 0;
+ ret->isborrowed = 1;
+ }
+ ret->nextused = signal_usedlist;
+ signal_usedlist = ret;
+ }
+ ret->n = n;
+ ret->vecsize = vecsize;
+ ret->sr = sr;
+ ret->refcount = 0;
+ ret->borrowedfrom = 0;
+ if (ugen_loud) post("new %lx: %d", ret, ret->isborrowed);
+ return ret;
+}
+
+static t_signal *signal_newlike(const t_signal *sig) {return signal_new(sig->n, sig->sr);}
+
+extern "C" void signal_setborrowed(t_signal *sig, t_signal *sig2) {
+ if (!sig->isborrowed || sig->borrowedfrom) bug("signal_setborrowed");
+ if (sig == sig2) bug("signal_setborrowed 2");
+ sig->borrowedfrom = sig2;
+ sig->v = sig2->v;
+ sig->n = sig2->n;
+ sig->vecsize = sig2->vecsize;
+}
+
+int signal_compatible(t_signal *s1, t_signal *s2) {return s1->n == s2->n && s1->sr == s2->sr;}
+
+/* ------------------ ugen ("unit generator") sorting ----------------- */
+
+struct t_ugenbox {
+ struct t_siginlet *in; int nin;
+ struct t_sigoutlet *out; int nout;
+ int u_phase;
+ t_ugenbox *next;
+ t_object *obj;
+ int done;
+};
+
+struct t_siginlet {
+ int nconnect;
+ int ngot;
+ t_signal *signal;
+};
+
+struct t_sigoutconnect {
+ t_ugenbox *who;
+ int inno;
+ t_sigoutconnect *next;
+};
+
+struct t_sigoutlet {
+ int nconnect;
+ int nsent;
+ t_signal *signal;
+ t_sigoutconnect *connections;
+};
+
+struct t_dspcontext {
+ t_ugenbox *ugenlist;
+ t_dspcontext *parentcontext;
+ int ninlets;
+ int noutlets;
+ t_signal **iosigs;
+ float srate;
+ int vecsize; /* vector size, power of two */
+ int calcsize; /* number of elements to calculate */
+ char toplevel; /* true if "iosigs" is invalid. */
+ char reblock; /* true if we have to reblock inlets/outlets */
+ char switched; /* true if we're switched */
+};
+
+static int ugen_sortno = 0;
+static t_dspcontext *ugen_currentcontext;
+
+void ugen_stop() {
+ if (dsp_chain) {
+ free(dsp_chain);
+ dsp_chain = 0;
+ }
+ signal_cleanup();
+}
+
+void ugen_start() {
+ ugen_stop();
+ ugen_sortno++;
+ dsp_chain = (t_int *)getbytes(sizeof(*dsp_chain));
+ dsp_chain[0] = (t_int)dsp_done;
+ dsp_chainsize = 1;
+ if (ugen_currentcontext) bug("ugen_start");
+}
+
+int ugen_getsortno() {return ugen_sortno;}
+
+#if 0
+void glob_foo(void *dummy, t_symbol *s, int argc, t_atom *argv) {
+ int i, count;
+ t_signal *sig;
+ for (count = 0, sig = signal_usedlist; sig; count++, sig = sig->nextused) {}
+ post("used signals %d", count);
+ for (i = 0; i < MAXLOGSIG; i++) {
+ for (count = 0, sig = signal_freelist[i]; sig; count++, sig = sig->nextfree) {}
+ if (count) post("size %d: free %d", (1 << i), count);
+ }
+ for (count = 0, sig = signal_freeborrowed; sig; count++, sig = sig->nextfree) {}
+ post("free borrowed %d", count);
+ ugen_loud = argc;
+}
+#endif
+
+/* start building the graph for a canvas */
+extern "C" t_dspcontext *ugen_start_graph(int toplevel, t_signal **sp, int ninlets, int noutlets) {
+ t_dspcontext *dc = (t_dspcontext *)getbytes(sizeof(*dc));
+ if (ugen_loud) post("ugen_start_graph...");
+ dc->ugenlist = 0;
+ dc->toplevel = toplevel;
+ dc->iosigs = sp;
+ dc->ninlets = ninlets;
+ dc->noutlets = noutlets;
+ dc->parentcontext = ugen_currentcontext;
+ ugen_currentcontext = dc;
+ return dc;
+}
+
+/* first the canvas calls this to create all the boxes... */
+extern "C" void ugen_add(t_dspcontext *dc, t_object *obj) {
+ t_ugenbox *x = (t_ugenbox *)getbytes(sizeof *x);
+ int i;
+ t_sigoutlet *uout;
+ t_siginlet *uin;
+ x->next = dc->ugenlist;
+ dc->ugenlist = x;
+ x->obj = obj;
+ x->nin = obj_nsiginlets(obj);
+ x->in = (t_siginlet *)getbytes(x->nin * sizeof (*x->in));
+ for (uin = x->in, i = x->nin; i--; uin++) uin->nconnect = 0;
+ x->nout = obj_nsigoutlets(obj);
+ x->out = (t_sigoutlet *)getbytes(x->nout * sizeof (*x->out));
+ for (uout = x->out, i = x->nout; i--; uout++) uout->connections = 0, uout->nconnect = 0;
+}
+
+/* and then this to make all the connections. */
+extern "C" void ugen_connect(t_dspcontext *dc, t_object *x1, int outno, t_object *x2, int inno) {
+ t_ugenbox *u1, *u2;
+ int sigoutno = obj_sigoutletindex(x1, outno);
+ int siginno = obj_siginletindex(x2, inno);
+ if (ugen_loud) post("%s -> %s: %d->%d", class_getname(x1->ob_pd), class_getname(x2->ob_pd), outno, inno);
+ for (u1 = dc->ugenlist; u1 && u1->obj != x1; u1 = u1->next);
+ for (u2 = dc->ugenlist; u2 && u2->obj != x2; u2 = u2->next);
+ if (!u1 || !u2 || siginno < 0) {
+ pd_error(u1->obj, "signal outlet connect to nonsignal inlet (ignored)");
+ return;
+ }
+ if (sigoutno < 0 || sigoutno >= u1->nout || siginno >= u2->nin) {
+ bug("ugen_connect %s %s %d %d (%d %d)",
+ class_getname(x1->ob_pd), class_getname(x2->ob_pd), sigoutno, siginno, u1->nout, u2->nin);
+ }
+ t_sigoutlet *uout = u1->out + sigoutno;
+ t_siginlet * uin = u2->in + siginno;
+ /* add a new connection to the outlet's list */
+ t_sigoutconnect *oc = (t_sigoutconnect *)getbytes(sizeof *oc);
+ oc->next = uout->connections;
+ uout->connections = oc;
+ oc->who = u2;
+ oc->inno = siginno;
+ /* update inlet and outlet counts */
+ uout->nconnect++;
+ uin->nconnect++;
+}
+
+/* get the index of a ugenbox or -1 if it's not on the list */
+static int ugen_index(t_dspcontext *dc, t_ugenbox *x) {
+ int ret=0;
+ for (t_ugenbox *u = dc->ugenlist; u; u = u->next, ret++) if (u == x) return ret;
+ return -1;
+}
+
+/* put a ugenbox on the chain, recursively putting any others on that this one might uncover. */
+static void ugen_doit(t_dspcontext *dc, t_ugenbox *u) {
+ t_sigoutlet *uout;
+ t_siginlet *uin;
+ t_sigoutconnect *oc;
+ t_class *klass = pd_class(u->obj);
+ int i, n;
+ /* suppress creating new signals for the outputs of signal
+ inlets and subpatchs; except in the case we're an inlet and "blocking"
+ is set. We don't yet know if a subcanvas will be "blocking" so there
+ we delay new signal creation, which will be handled by calling
+ signal_setborrowed in the ugen_done_graph routine below. */
+ int nonewsigs = klass==canvas_class || klass==vinlet_class && !dc->reblock;
+ /* when we encounter a subcanvas or a signal outlet, suppress freeing
+ the input signals as they may be "borrowed" for the super or sub
+ patch; same exception as above, but also if we're "switched" we
+ have to do a copy rather than a borrow. */
+ int nofreesigs = klass==canvas_class || klass==voutlet_class && !(dc->reblock || dc->switched);
+ t_signal **insig, **outsig, **sig, *s1, *s2, *s3;
+ t_ugenbox *u2;
+ if (ugen_loud) post("doit %s %d %d", class_getname(klass), nofreesigs, nonewsigs);
+ for (i = 0, uin = u->in; i < u->nin; i++, uin++) {
+ if (!uin->nconnect) {
+ t_sample *scalar;
+ s3 = signal_new(dc->vecsize, dc->srate);
+ /* post("%s: unconnected signal inlet set to zero", class_getname(u->obj->ob_pd)); */
+ if ((scalar = obj_findsignalscalar(u->obj, i))) dsp_add_scalarcopy(scalar, s3->v, s3->n);
+ else dsp_add_zero(s3->v, s3->n);
+ uin->signal = s3;
+ s3->refcount = 1;
+ }
+ }
+ insig = (t_signal **)getbytes((u->nin + u->nout) * sizeof(t_signal *));
+ outsig = insig + u->nin;
+ for (sig = insig, uin = u->in, i = u->nin; i--; sig++, uin++) {
+ int newrefcount;
+ *sig = uin->signal;
+ newrefcount = --(*sig)->refcount;
+ /* if the reference count went to zero, we free the signal now,
+ unless it's a subcanvas or outlet; these might keep the
+ signal around to send to objects connected to them. In this
+ case we increment the reference count; the corresponding decrement
+ is in sig_makereusable(). */
+ if (nofreesigs) (*sig)->refcount++;
+ else if (!newrefcount) signal_makereusable(*sig);
+ }
+ for (sig = outsig, uout = u->out, i = u->nout; i--; sig++, uout++) {
+ /* similarly, for outlets of subcanvases we delay creating
+ them; instead we create "borrowed" ones so that the refcount
+ is known. The subcanvas replaces the fake signal with one showing
+ where the output data actually is, to avoid having to copy it.
+ For any other object, we just allocate a new output vector;
+ since we've already freed the inputs the objects might get called "in place." */
+ *sig = uout->signal = nonewsigs ?
+ signal_new(0, dc->srate) :
+ signal_new(dc->vecsize, dc->srate);
+ (*sig)->refcount = uout->nconnect;
+ }
+ /* now call the DSP scheduling routine for the ugen. This routine must fill in "borrowed"
+ signal outputs in case it's either a subcanvas or a signal inlet. */
+ mess1(u->obj, gensym("dsp"), insig);
+ /* if any output signals aren't connected to anyone, free them now; otherwise they'll either
+ get freed when the reference count goes back to zero, or even later as explained above. */
+ for (sig = outsig, uout = u->out, i = u->nout; i--; sig++, uout++) {
+ if (!(*sig)->refcount) signal_makereusable(*sig);
+ }
+ if (ugen_loud) {
+ if (u->nin+u->nout==0) post("put %s %d", class_getname(u->obj->ob_pd), ugen_index(dc,u));
+ else if (u->nin+u->nout==1) post("put %s %d (%lx)", class_getname(u->obj->ob_pd), ugen_index(dc,u),sig[0]);
+ else if (u->nin+u->nout==2) post("put %s %d (%lx %lx)", class_getname(u->obj->ob_pd), ugen_index(dc,u),sig[0],sig[1]);
+ else post("put %s %d (%lx %lx %lx ...)", class_getname(u->obj->ob_pd), ugen_index(dc,u),sig[0],sig[1],sig[2]);
+ }
+ /* pass it on and trip anyone whose last inlet was filled */
+ for (uout = u->out, i = u->nout; i--; uout++) {
+ s1 = uout->signal;
+ for (oc = uout->connections; oc; oc = oc->next) {
+ u2 = oc->who;
+ uin = &u2->in[oc->inno];
+ /* if there's already someone here, sum the two */
+ s2 = uin->signal;
+ if (s2) {
+ s1->refcount--;
+ s2->refcount--;
+ if (!signal_compatible(s1, s2)) {pd_error(u->obj, "%s: incompatible signal inputs", class_getname(u->obj->ob_pd)); return;}
+ s3 = signal_newlike(s1);
+ dsp_add_plus(s1->v, s2->v, s3->v, s1->n);
+ uin->signal = s3;
+ s3->refcount = 1;
+ if (!s1->refcount) signal_makereusable(s1);
+ if (!s2->refcount) signal_makereusable(s2);
+ } else uin->signal = s1;
+ uin->ngot++;
+ if (uin->ngot < uin->nconnect) goto notyet;
+ if (u2->nin > 1) for (uin = u2->in, n = u2->nin; n--; uin++) if (uin->ngot < uin->nconnect) goto notyet;
+ ugen_doit(dc, u2);
+ notyet: ;
+ }
+ }
+ free(insig);
+ u->done = 1;
+}
+
+/* once the DSP graph is built, we call this routine to sort it. This routine also deletes the graph; later we might
+ want to leave the graph around, in case the user is editing the DSP network, to save having to recreate it all the
+ time. But not today. */
+extern "C" void ugen_done_graph(t_dspcontext *dc) {
+ t_sigoutlet *uout;
+ t_siginlet *uin;
+ int i, n;
+ t_block *blk;
+ int period, frequency, phase, vecsize, calcsize;
+ float srate;
+ int reblock = 0, switched;
+ int downsample = 1, upsample = 1; /* IOhannes */
+ /* debugging printout */
+ if (ugen_loud) {
+ post("ugen_done_graph...");
+ for (t_ugenbox *u = dc->ugenlist; u; u = u->next) {
+ post("ugen: %s", class_getname(u->obj->ob_pd));
+ for (uout = u->out, i = 0; i < u->nout; uout++, i++)
+ for (t_sigoutconnect *oc = uout->connections; oc; oc = oc->next) {
+ post("... out %d to %s, index %d, inlet %d", i, class_getname(oc->who->obj->ob_pd), ugen_index(dc, oc->who), oc->inno);
+ }
+ }
+ }
+ /* search for an object of class "block~" */
+ blk = 0;
+ for (t_ugenbox *u = dc->ugenlist; u; u = u->next) {
+ t_pd *zz = u->obj;
+ if (pd_class(zz) == block_class) {
+ if (blk) pd_error(blk, "conflicting block~ objects in same page");
+ else blk = (t_block *)zz;
+ }
+ }
+ t_dspcontext *parent_context = dc->parentcontext;
+ float parent_srate = parent_context ? parent_context->srate : sys_getsr();
+ int parent_vecsize = parent_context ? parent_context->vecsize : sys_getblksize();
+ if (blk) {
+ int realoverlap;
+ vecsize = blk->vecsize; if (!vecsize) vecsize = parent_vecsize;
+ calcsize = blk->calcsize;if (!calcsize) calcsize = vecsize;
+ realoverlap = blk->overlap; if (realoverlap > vecsize) realoverlap = vecsize;
+ /* IOhannes { */
+ downsample = blk->downsample;
+ upsample = blk->upsample;
+ if (downsample > parent_vecsize) downsample=parent_vecsize;
+ period = (vecsize * downsample) / (parent_vecsize * realoverlap * upsample);
+ frequency = (parent_vecsize * realoverlap * upsample) / (vecsize * downsample);
+ /* } IOhannes*/
+ phase = blk->phase;
+ srate = parent_srate * realoverlap * upsample / downsample;
+ /* IOhannes */
+ if (period < 1) period = 1;
+ if (frequency < 1) frequency = 1;
+ blk->frequency = frequency;
+ blk->period = period;
+ blk->phase = dsp_phase & (period - 1);
+ if (!parent_context || realoverlap!=1 || vecsize!=parent_vecsize || downsample!=1 || upsample!=1) /* IOhannes */
+ reblock = 1;
+ switched = blk->switched;
+ } else {
+ srate = parent_srate;
+ vecsize = parent_vecsize;
+ calcsize = parent_context ? parent_context->calcsize : vecsize;
+ downsample = upsample = 1;/* IOhannes */
+ period = frequency = 1;
+ phase = 0;
+ if (!parent_context) reblock = 1;
+ switched = 0;
+ }
+ dc->reblock = reblock;
+ dc->switched = switched;
+ dc->srate = srate;
+ dc->vecsize = vecsize;
+ dc->calcsize = calcsize;
+ /* if we're reblocking or switched, we now have to create output signals to fill in for the "borrowed" ones we
+ have now. This is also possibly true even if we're not blocked/switched, in the case that there was a
+ signal loop. But we don't know this yet. */
+ if (dc->iosigs && (switched || reblock)) {
+ t_signal **sigp;
+ for (i = 0, sigp = dc->iosigs + dc->ninlets; i < dc->noutlets; i++, sigp++) {
+ if ((*sigp)->isborrowed && !(*sigp)->borrowedfrom) {
+ signal_setborrowed(*sigp, signal_new(parent_vecsize, parent_srate));
+ (*sigp)->refcount++;
+ if (ugen_loud) post("set %lx->%lx", *sigp, (*sigp)->borrowedfrom);
+ }
+ }
+ }
+ if (ugen_loud) post("reblock %d, switched %d", reblock, switched);
+ /* schedule prologs for inlets and outlets. If the "reblock" flag is set, an inlet will put code on the DSP chain
+ to copy its input into an internal buffer here, before any unit generators' DSP code gets scheduled. If we don't
+ "reblock", inlets will need to get pointers to their corresponding inlets/outlets on the box we're inside,
+ if any. Outlets will also need pointers, unless we're switched, in which case outlet epilog code will kick in. */
+ for (t_ugenbox *u = dc->ugenlist; u; u = u->next) {
+ t_pd *zz = u->obj;
+ t_signal **outsigs = dc->iosigs;
+ if (outsigs) outsigs += dc->ninlets;
+ if (pd_class(zz) == vinlet_class)
+ vinlet_dspprolog((struct _vinlet *)zz, dc->iosigs, vecsize, calcsize, dsp_phase, period, frequency,
+ downsample, upsample, reblock, switched);
+ else if (pd_class(zz) == voutlet_class)
+ voutlet_dspprolog((struct _voutlet *)zz, outsigs, vecsize, calcsize, dsp_phase, period, frequency,
+ downsample, upsample, reblock, switched);
+ }
+ int chainblockbegin = dsp_chainsize; /* DSP chain onset before block prolog code */
+ if (blk && (reblock || switched)) { /* add the block DSP prolog */
+ dsp_add(block_prolog, 1, blk);
+ blk->chainonset = dsp_chainsize - 1;
+ }
+ /* Initialize for sorting */
+ for (t_ugenbox *u = dc->ugenlist; u; u = u->next) {
+ u->done = 0;
+ for (uout = u->out, i = u->nout; i--; uout++) uout->nsent = 0;
+ for (uin = u->in, i = u->nin; i--; uin++) uin->ngot = 0, uin->signal = 0;
+ }
+ /* Do the sort */
+ for (t_ugenbox *u = dc->ugenlist; u; u = u->next) {
+ /* check that we have no connected signal inlets */
+ if (u->done) continue;
+ for (uin = u->in, i = u->nin; i--; uin++)
+ if (uin->nconnect) goto next;
+ ugen_doit(dc, u);
+ next: ;
+ }
+ /* check for a DSP loop, which is evidenced here by the presence of ugens not yet scheduled. */
+ for (t_ugenbox *u = dc->ugenlist; u; u = u->next) if (!u->done) {
+ t_signal **sigp;
+ pd_error(u->obj, "DSP loop detected (some tilde objects not scheduled)");
+ /* this might imply that we have unfilled "borrowed" outputs which we'd better fill in now. */
+ for (i = 0, sigp = dc->iosigs + dc->ninlets; i < dc->noutlets; i++, sigp++) {
+ if ((*sigp)->isborrowed && !(*sigp)->borrowedfrom) {
+ t_signal *s3 = signal_new(parent_vecsize, parent_srate);
+ signal_setborrowed(*sigp, s3);
+ (*sigp)->refcount++;
+ dsp_add_zero(s3->v, s3->n);
+ if (ugen_loud) post("oops, belatedly set %lx->%lx", *sigp, (*sigp)->borrowedfrom);
+ }
+ }
+ break; /* don't need to keep looking. */
+ }
+ /* add block DSP epilog */
+ if (blk && (reblock || switched)) dsp_add(block_epilog, 1, blk);
+ int chainblockend = dsp_chainsize; /* and after block epilog code */
+ /* add epilogs for outlets. */
+ for (t_ugenbox *u = dc->ugenlist; u; u = u->next) {
+ t_pd *zz = u->obj;
+ if (pd_class(zz) == voutlet_class) {
+ t_signal **iosigs = dc->iosigs;
+ if (iosigs) iosigs += dc->ninlets;
+ voutlet_dspepilog((struct _voutlet *)zz, iosigs, vecsize, calcsize, dsp_phase, period, frequency,
+ downsample, upsample, reblock, switched);
+ }
+ }
+ int chainafterall = dsp_chainsize; /* and after signal outlet epilog */
+ if (blk) {
+ blk->blocklength = chainblockend - chainblockbegin;
+ blk->epiloglength = chainafterall - chainblockend;
+ blk->reblock = reblock;
+ }
+ if (ugen_loud) {
+ t_int *ip;
+ if (!dc->parentcontext)
+ for (i = dsp_chainsize, ip = dsp_chain; i--; ip++) post("chain %lx", *ip);
+ post("... ugen_done_graph done.");
+ }
+ /* now delete everything. */
+ while (dc->ugenlist) {
+ for (uout = dc->ugenlist->out, n = dc->ugenlist->nout; n--; uout++) {
+ t_sigoutconnect *oc = uout->connections, *oc2;
+ while (oc) {
+ oc2 = oc->next;
+ free(oc);
+ oc = oc2;
+ }
+ }
+ free(dc->ugenlist->out);
+ free(dc->ugenlist->in);
+ t_ugenbox *u = dc->ugenlist;
+ dc->ugenlist = u->next;
+ free(u);
+ }
+ if (ugen_currentcontext == dc) ugen_currentcontext = dc->parentcontext;
+ else bug("ugen_currentcontext");
+ free(dc);
+}
+
+t_signal *ugen_getiosig(int index, int inout) {
+ if (!ugen_currentcontext) bug("ugen_getiosig");
+ if (ugen_currentcontext->toplevel) return 0;
+ if (inout) index += ugen_currentcontext->ninlets;
+ return ugen_currentcontext->iosigs[index];
+}
+
+/* resampling code originally by Johannes Zmlnig in 2001 */
+/* also "block-resampling" added by Johannes in 2004.09 */
+/* --------------------- up/down-sampling --------------------- */
+/* LATER: add some downsampling-filters for HOLD and LINEAR */
+
+t_int *downsampling_perform_0(t_int *w) {
+ t_float *in = (t_float *)w[1]; /* original signal */
+ t_float *out = (t_float *)w[2]; /* downsampled signal */
+ int down = int(w[3]); /* downsampling factor */
+ int parent = int(w[4]); /* original vectorsize */
+ int n=parent/down;
+ while(n--) {
+ *out++=*in;
+ in+=down;
+ }
+ return w+5;
+}
+
+t_int *downsampling_perform_block(t_int *w) {
+ /* the downsampled vector is exactly the first part of the parent vector
+ * the rest of the parent is just skipped
+ * cool for FFT-data, where you only want to process the significant (1st) part of the vector
+ */
+ t_float *in = (t_float *)w[1]; /* original signal */
+ t_float *out = (t_float *)w[2]; /* downsampled signal */
+ int down = int(w[3]); /* downsampling factor */
+ int parent = int(w[4]); /* original vectorsize */
+ int n=parent/down;
+ while(n--) *out++=*in++;
+ return w+5;
+}
+
+t_int *upsampling_perform_0(t_int *w) {
+ t_float *in = (t_float *)w[1]; /* original signal */
+ t_float *out = (t_float *)w[2]; /* upsampled signal */
+ int up = int(w[3]); /* upsampling factor */
+ int parent = int(w[4]); /* original vectorsize */
+ int n=parent*up;
+ t_float *dummy = out;
+ while(n--) *out++=0;
+ n = parent;
+ out = dummy;
+ while(n--) {*out=*in++; out+=up;}
+ return w+5;
+}
+
+t_int *upsampling_perform_hold(t_int *w) {
+ t_float *in = (t_float *)w[1]; /* original signal */
+ t_float *out = (t_float *)w[2]; /* upsampled signal */
+ int up = int(w[3]); /* upsampling factor */
+ int parent = int(w[4]); /* original vectorsize */
+ int i=up;
+ t_float *dum_out = out;
+ t_float *dum_in = in;
+ while (i--) {
+ int n = parent;
+ out = dum_out+i;
+ in = dum_in;
+ while(n--) {*out=*in++; out+=up;}
+ }
+ return w+5;
+}
+
+t_int *upsampling_perform_linear(t_int *w) {
+ t_resample *x= (t_resample *)w[1];
+ t_float *in = (t_float *)w[2]; /* original signal */
+ t_float *out = (t_float *)w[3]; /* upsampled signal */
+ const int up = int(w[4]); /* upsampling factor */
+ const int parent = int(w[5]); /* original vectorsize */
+ const int length = parent*up;
+ t_float *fp;
+ t_float a=*x->buffer, b=*in;
+ const t_float up_inv = (t_float)1.0/up;
+ t_float findex = 0.f;
+ for (int n=0; n<length; n++) {
+ const int index = int(findex+=up_inv);
+ t_float frac=findex-index;
+ if(frac==0.)frac=1.;
+ *out++ = frac * b + (1.-frac) * a;
+ fp=in+index;
+ b=*fp;
+ // do we still need the last sample of the previous pointer for interpolation ?
+ a=(index)?*(fp-1):a;
+ }
+ *x->buffer = a;
+ return w+6;
+}
+
+t_int *upsampling_perform_block(t_int *w) {
+ /* 1st part of the upsampled signal-vector will be the original one
+ * 2nd part of the upsampled signal-vector is just 0
+ * cool for FFT-data, where you only want to process the significant (1st) part of the vector */
+ t_float *in = (t_float *)w[1]; /* original signal */
+ t_float *out = (t_float *)w[2]; /* upsampled signal */
+ int up = (int)w[3]; /* upsampling factor */
+ int parent = (int)w[4]; /* original vectorsize */
+ int i=parent;
+ int n=parent*(up-1);
+ while (i--) *out++=*in++;
+ while (n--) *out++=0.f;
+ return w+5;
+}
+
+/* ----------------------- public -------------------------------- */
+/* utils */
+
+void resample_init(t_resample *x) {
+ x->method=0;
+ x->downsample=x->upsample=1;
+ x->n = x->coefsize = x->bufsize = 0;
+ x->v = x->coeffs = x->buffer = 0;
+}
+void resample_free(t_resample *x) {
+ if (x->n) free(x->v);
+ if (x->coefsize) free(x->coeffs);
+ if (x->bufsize) free(x->buffer);
+ x->n = x->coefsize = x->bufsize = 0;
+ x->v = x->coeffs = x->buffer = 0;
+}
+void resample_dsp(t_resample *x, t_sample* in, int insize, t_sample* out, int outsize, int method) {
+ if (insize == outsize) {bug("nothing to be done"); return;}
+ if (insize > outsize) { /* downsampling */
+ if (insize % outsize) {error("bad downsampling factor"); return;}
+ switch (method) {
+ case RESAMPLE_BLOCK: dsp_add(downsampling_perform_block, 4, in, out, insize/outsize, insize); break;
+ default: dsp_add(downsampling_perform_0, 4, in, out, insize/outsize, insize);
+ }
+ } else { /* upsampling */
+ if (outsize % insize) {error("bad upsampling factor"); return;}
+ switch (method) {
+ case RESAMPLE_HOLD: dsp_add(upsampling_perform_hold, 4, in, out, outsize/insize, insize); break;
+ case RESAMPLE_LINEAR:
+ if (x->bufsize != 1) {
+ free(x->buffer);
+ x->bufsize = 1;
+ x->buffer = (t_float *)t_getbytes(x->bufsize*sizeof(*x->buffer));
+ }
+ dsp_add(upsampling_perform_linear, 5, x, in, out, outsize/insize, insize);
+ break;
+ case RESAMPLE_BLOCK: dsp_add(upsampling_perform_block, 4, in, out, outsize/insize, insize); break;
+ default: dsp_add(upsampling_perform_0, 4, in, out, outsize/insize, insize);
+ }
+ }
+}
+void resamplefrom_dsp(t_resample *x, t_sample *in, int insize, int outsize, int method) {
+ if (insize==outsize) { free(x->v); x->n = 0; x->v = in; return;}
+ if (x->n != outsize) {
+ free(x->v);
+ x->v = (t_float *)t_getbytes(outsize * sizeof(*x->v));
+ x->n = outsize;
+ }
+ resample_dsp(x, in, insize, x->v, x->n, method);
+}
+void resampleto_dsp(t_resample *x, t_sample *out, int insize, int outsize, int method) {
+ if (insize==outsize) {if (x->n) free(x->v); x->n = 0; x->v = out; return;}
+ if (x->n != insize) {
+ free(x->v);
+ x->v = (t_float *)t_getbytes(insize * sizeof(*x->v));
+ x->n = insize;
+ }
+ resample_dsp(x, x->v, x->n, out, outsize, method);
+}
+
+/* ------------------------ samplerate~ -------------------------- */
+
+static t_class *samplerate_tilde_class;
+struct t_samplerate : t_object {
+ t_canvas *canvas;
+};
+extern "C" void *canvas_getblock(t_class *blockclass, t_canvas **canvasp);
+static void samplerate_tilde_bang(t_samplerate *x) {
+ float srate = sys_getsr();
+ t_canvas *canvas = x->canvas;
+ while (canvas) {
+ t_block *b = (t_block *)canvas_getblock(block_class, &canvas);
+ if (b) srate *= float(b->upsample) / float(b->downsample);
+ }
+ outlet_float(x->ob_outlet, srate);
+}
+static void *samplerate_tilde_new(t_symbol *s) {
+ t_samplerate *x = (t_samplerate *)pd_new(samplerate_tilde_class);
+ outlet_new(x,&s_float);
+ x->canvas = canvas_getcurrent();
+ return x;
+}
+static void samplerate_tilde_setup() {
+ samplerate_tilde_class = class_new2("samplerate~",samplerate_tilde_new,0,sizeof(t_samplerate),0,"");
+ class_addbang(samplerate_tilde_class, samplerate_tilde_bang);
+}
+
+/* -------------------- setup routine -------------------------- */
+
+void d_ugen_setup () {
+ block_tilde_setup();
+ samplerate_tilde_setup();
+}
diff --git a/desiredata/src/defaults.ddrc b/desiredata/src/defaults.ddrc
new file mode 100644
index 00000000..fdee7d78
--- /dev/null
+++ b/desiredata/src/defaults.ddrc
@@ -0,0 +1,193 @@
+look {
+ TextBox {
+ bgedit #ffffff
+ }
+ View {
+ language english
+ }
+ Client {
+ console 666
+ }
+ Box {
+ extrapix 1
+ }
+ Canvas {
+ pointer_sense 5
+ bgedit #dddddd
+ bgrun #ffffff
+ grid #ffffff
+ buttonbar 1
+ compbg #ffffff
+ compfg #000000
+ compselectbg #000000
+ compselectfg #ffffff
+ crosshair #ff14ff
+ hairsnap 1
+ hairstate 1
+ gridstate 1
+ grid_size 20
+ snap_grid 1
+ showcomp 10
+ statusbar 1
+ menubar 1
+ scrollbar 0
+ }
+ Comment {
+ bg #cccccc
+ fg #000000
+ frame1 #ffffff
+ frame2 #888888
+ frame3 #cccccc
+ }
+ FutureWire {
+ dash #ee0012
+ }
+ SelRect {
+ rect #ff12ff
+ }
+ Slider {
+ bg #ccebff
+ }
+ TextBox {
+ bgedit {#ffffff}
+ fg {#000000}
+ }
+ View {
+ bg #ffffff
+ fg #000000
+ font {Courier -12}
+ frame1 #99cccc
+ frame2 #668888
+ frame3 #000000
+ selectframe #0080ff
+ tooltip 1
+ }
+ Box {
+ iowidth 7
+ minobjwidth 21
+ inletfg #000000
+ outletfg #000000
+ iopos -1
+ }
+ Wire {
+ dspfg #890098
+ fg #888888
+ fg2 #ee0000
+ thick 1
+ wirearrow 1
+ }
+ KeyboardDialog {
+ font {Courier -10}
+ }
+ Console {
+ font {Courier -10}
+ }
+}
+key {
+ Canvas {
+ Array {}
+ bng Alt+b
+ cnv Alt+c
+ Comment Ctrl+5
+ Graph {}
+ hradio Alt+i
+ hsl Alt+h
+ Message Ctrl+2
+ Number Ctrl+3
+ nbx Alt+n
+ Object Ctrl+1
+ Pdwindow {}
+ Symbol Ctrl+4
+ tgl Alt+t
+ vu Alt+u
+ vradio Alt+d
+ vsl Alt+v
+ about {}
+ audio_off Ctrl+period
+ audio_on Ctrl+slash
+ class_browser {}
+ close Ctrl+w
+ copy Ctrl+c
+ crosshair {}
+ cut Ctrl+x
+ decr_scale Ctrl+UNDERSCORE
+ decr_zoom Ctrl+minus
+ dropper Alt+y
+ duplicate Ctrl+d
+ editmodeswitch Ctrl+e
+ find Ctrl+f
+ find_again Ctrl+g
+ find_last_error {}
+ font_bomb Ctrl+F
+ incr_scale Ctrl+PLUS
+ incr_zoom Ctrl+equal
+ key_nav_down Ctrl+down
+ key_nav_down_shift Ctrl+DOWN
+ key_nav_ioselect Ctrl+tab
+ key_nav_left Ctrl+left
+ key_nav_left_shift Ctrl+LEFT
+ key_nav_right Ctrl+right
+ key_nav_right_shift Ctrl+RIGHT
+ key_nav_up Ctrl+up
+ key_nav_up_shift Ctrl+UP
+ latency_meter {}
+ load_meter {}
+ new_file Ctrl+n
+ open_file Ctrl+o
+ parentwindow {}
+ paste Ctrl+v
+ paths {}
+ popup_help {}
+ popup_open {}
+ popup_properties {}
+ print Ctrl+p
+ quit Ctrl+q
+ redo Ctrl+Z
+ redraw {}
+ reload Ctrl+r
+ save Ctrl+s
+ save_as Ctrl+S
+ select_all Ctrl+a
+ text_editor Ctrl+t
+ tidy_up {}
+ undo Ctrl+z
+ insert_object Ctrl+i
+ chain_object Ctrl+6
+ clear_wires Ctrl+k
+ auto_wire Ctrl+j
+ subpatcherize Alt+s
+ clear_selection Ctrl+A
+ auto_test Ctrl+grave
+ runcommand Alt+x
+ keyprefix Ctrl+QUESTION
+ macro_toggle Alt+m
+ macro_play Ctrl+m
+ macro_copy Ctrl+M
+ id_toggle Ctrl+semicolon
+ }
+ Client {
+ Canvas Alt+c
+ about {}
+ audio_off Ctrl+period
+ audio_on Ctrl+slash
+ audio_settings {}
+ class_browser {}
+ client_class_tree Ctrl+grave
+ client_prefs Ctrl+l
+ find Ctrl+f
+ find_again Ctrl+g
+ find_last_error {}
+ font_bomb {}
+ latency_meter {}
+ load_meter {}
+ midi_settings {}
+ new_file Ctrl+n
+ open_file Ctrl+o
+ paths {}
+ server_prefs Ctrl+p
+ quit Ctrl+q
+ send_message Ctrl+m
+ test_audio_and_midi {}
+ text_editor Ctrl+t
+ }
+}
diff --git a/desiredata/src/desire.c b/desiredata/src/desire.c
new file mode 100644
index 00000000..cc04ad5e
--- /dev/null
+++ b/desiredata/src/desire.c
@@ -0,0 +1,7332 @@
+/* $Id: desire.c,v 1.1.2.217.2.235 2007-08-21 19:50:25 matju Exp $
+
+ This file is part of DesireData.
+ Copyright (c) 2004-2007 by Mathieu Bouchard.
+ Portions Copyright (c) 1997-2005 Miller Puckette, Günter Geiger, Krzysztof Czaja,
+ Johannes Zmoelnig, Thomas Musil, Joseph Sarlo, etc.
+ The remains of IEMGUI Copyright (c) 2000-2001 Thomas Musil (IEM KUG Graz Austria)
+ For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ WARRANTIES, see the file, "LICENSE.txt," in this distribution.
+*/
+
+#define PD_PLUSPLUS_FACE
+#include "m_pd.h"
+#include "desire.h"
+#include "s_stuff.h"
+#include <ctype.h>
+#include <math.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "m_simd.h"
+#include <errno.h>
+#include <sys/time.h>
+#include <sstream>
+#include <map>
+
+#ifdef MSW
+#include <io.h>
+#define snprintf _snprintf
+#else
+#include <unistd.h>
+#endif
+
+/*
+#define sys_vgui(args...) do { \
+ fprintf(stderr,"\e[0;1;31m"); \
+ L fprintf(stderr,args); \
+ fprintf(stderr,"\e[0m"); \
+ sys_vgui(args); } while(0)
+*/
+
+#define foreach(ITER,COLL) for(typeof(COLL.begin()) ITER = COLL.begin(); ITER != (COLL).end(); ITER++)
+
+#define boxes_each(CHILD,BOXES) for(t_gobj *CHILD=(BOXES)->first(); CHILD; CHILD=CHILD->next())
+#define canvas_each(CHILD,CANVAS) for(t_gobj *CHILD=(CANVAS)->boxes->first(); CHILD; CHILD=CHILD->next())
+#define canvas_wires_each(WIRE,TRAV,CANVAS) \
+ for (t_outconnect *WIRE=(t_outconnect *)666; WIRE==(t_outconnect *)666; ) \
+ for (t_linetraverser TRAV(CANVAS); (WIRE=linetraverser_next(&TRAV)); )
+
+#undef SET
+#define SET(attr,value) do {gobj_changed(x,#attr); x->attr = (value);} while(0)
+
+#define a_float a_w.w_float
+#define a_symbol a_w.w_symbol
+
+#define CLAMP(_var,_min,_max) do { if (_var<_min) _var=_min; else if (_var>_max) _var=_max; } while(0)
+#define IS_A_FLOAT(atom,index) ((atom+index)->a_type == A_FLOAT)
+#define IS_A_SYMBOL(atom,index) ((atom+index)->a_type == A_SYMBOL)
+
+int imin(int a, int b) {return a<b?a:b;}
+int imax(int a, int b) {return a>b?a:b;}
+t_symbol *s_empty, *s_pd, *s_Pd;
+
+std::ostream &operator << (std::ostream &str, t_pd *self) {
+ t_binbuf *b;
+ if (self->_class->patchable && (b = ((t_text *)self)->binbuf)) {
+ char *buf; int bufn;
+ binbuf_gettext(b,&buf,&bufn);
+ str << "[" << buf << "]";
+ free(buf);
+ } else str << "<" << self->_class->name->name << ":" << std::hex << (long)self << ">";
+ return str;
+}
+
+//--------------------------------------------------------------------------
+
+t_class *boxes_class;
+
+struct t_boxes : t_gobj {
+ typedef std::map<int,t_gobj *> M;
+ typedef std::pair<int,t_gobj *> KV;
+private:
+ std::map<int,t_gobj *> map;
+public:
+ void invariant () {size();}
+ t_boxes() {}
+ size_t size() {
+ size_t n=0;
+ boxes_each(g,this) n++;
+ if (map.size()!=n) post("map size=%d list size=%d",map.size(),n);
+ return n;
+ }
+ t_gobj *first() {return map.begin() != map.end() ? map.begin()->second : 0;}
+ t_gobj *last() {M::iterator iter = map.end(); iter--; return iter->second;}
+ t_gobj *next(t_gobj *x) {
+ M::iterator iter = map.begin();
+ while (iter->second != x) iter++;
+ iter++;
+ return iter == map.end() ? 0 : iter->second;
+ }
+ void add(t_gobj *x) {map.insert(KV(x->dix->index,x)); invariant();}
+ void remove(int i) {map.erase(i); invariant();}
+ void remove_by_value(t_gobj *x) {map.erase(x->dix->index); invariant();}
+};
+
+t_boxes *boxes_new() {
+ t_boxes *self = (t_boxes *)pd_new(boxes_class);
+ new(self) t_boxes;
+ return self;
+}
+
+void boxes_notice(t_boxes *self, t_gobj *origin, int argc, t_atom *argv) {
+}
+
+void boxes_free(t_boxes *self) {self->~t_boxes();}
+
+t_gobj *_gobj::next() {return dix->canvas->boxes->next(this);}
+
+//--------------------------------------------------------------------------
+
+t_class *gop_filtre_class;
+
+struct t_gop_filtre : t_gobj {
+ t_canvas *canvas;
+};
+
+// test for half-open interval membership
+bool inside (int x, int x0, int x1) {return x0<=x && x<x1;}
+
+/* this method is always called when a canvas is in gop mode so we don't check for this */
+/* it doesn't filtre out all that needs to be filtred out, but does not filtre out anything that has to stay */
+void gop_filtre_notice(t_gop_filtre *self,t_gobj *origin, int argc, t_atom *argv) {
+ /* here, assume that the canvas *is* a gop; else we wouldn't be in this method. */
+ t_object *o = (t_object *)origin;
+ t_canvas *c = self->canvas;
+ if (0/* check for messagebox, comment, but you can't check for objectboxes in general */) return;
+ if (c->goprect) {
+ if (!inside(o->x, c->xmargin, c->xmargin + c->pixwidth )) return;
+ if (!inside(o->y, c->ymargin, c->ymargin + c->pixheight)) return;
+ }
+ gobj_changed3(self,origin,argc,argv);
+}
+
+t_gobj *gop_filtre_new(t_canvas *canvas) {
+ t_gop_filtre *self = (t_gop_filtre *)pd_new(gop_filtre_class);
+ new(self) t_gop_filtre;
+ self->canvas = canvas;
+ gobj_subscribe(canvas->boxes,self);
+ return self;
+}
+
+void gop_filtre_free(t_boxes *self) {}
+
+//--------------------------------------------------------------------------
+// t_appendix: an extension to t_gobj made by matju so that all t_gobj's may have new fields
+// without sacrificing binary compat with externals compiled for PureMSP.
+
+typedef t_hash<t_symbol *, t_arglist *> t_visual;
+
+t_appendix *appendix_new (t_gobj *master) {
+ //fprintf(stderr,"appendix_new %p\n",master);
+ t_appendix *self = (t_appendix *)malloc(sizeof(t_appendix));
+ self->canvas = 0;
+ self->nobs = 0;
+ self->obs = 0;
+ self->visual = new t_visual(1);
+ self->index = 0;
+ self->elapsed = 0;
+ return self;
+}
+
+void appendix_save (t_gobj *master, t_binbuf *b) {
+ t_visual *h = master->dix->visual;
+ //fprintf(stderr,"appendix_save %p size=%ld\n",master,hash_size(h));
+ if (!h->size()) return;
+ t_symbol *k;
+ t_arglist *v;
+ int i=0;
+ binbuf_addv(b,"t","#V");
+ hash_foreach(k,v,h) {
+ t_arglist *al = (t_arglist *)v;
+ binbuf_addv(b,"s",k);
+ binbuf_add(b,al->c,al->v);
+ if (size_t(i+1)==h->size()) binbuf_addv(b, ";"); else binbuf_addv(b,"t",",");
+ i++;
+ }
+}
+
+void appendix_free (t_gobj *master) {
+ t_appendix *self = master->dix;
+ t_symbol *k;
+ t_arglist *v;
+ if (self->visual) {
+ hash_foreach(k,v,self->visual) free(v);
+ delete self->visual;
+ }
+ free(self);
+}
+
+/* subscribing N spies takes N*N time, but it's not important for now */
+/* subscription could become just a special use of t_outlet in the future, or sometimes become implied. */
+/* perhaps use [bindelem] here? */
+void gobj_subscribe(t_gobj *self, t_gobj *observer) {
+ t_appendix *d = self->dix;
+ for (size_t i=0; i<d->nobs; i++) if (d->obs[i]) return;
+ d->obs=(t_gobj **)realloc(d->obs,sizeof(t_gobj *)*(1+d->nobs));
+ d->obs[d->nobs++] = observer;
+ t_onsubscribe ons = self->_class->onsubscribe;
+ ons(self,observer);
+ //post("x%p has %d observers",self,(int)d->nobs);
+}
+
+void gobj_unsubscribe (t_gobj *self, t_gobj *observer) {
+ t_appendix *d = self->dix;
+ size_t i;
+ for (i=0; i<d->nobs; i++) if (d->obs[i]) break;
+ if (i==d->nobs) return;
+ d->nobs--;
+ for (; i<d->nobs; i++) d->obs[i] = d->obs[i+1];
+ // should have something like onunsubscribe too, to handle delete?... or just use onsubscribe differently.
+}
+
+void gobj_setcanvas (t_gobj *self, t_canvas *c) {
+ if (self->dix->canvas == c) return;
+ if (self->dix->canvas) gobj_unsubscribe(self,self->dix->canvas);
+ self->dix->canvas = c;
+ if (self->dix->canvas) gobj_subscribe(self,self->dix->canvas);
+}
+
+/* for future use */
+t_canvas *gobj_canvas (t_gobj *self) {return self->dix->canvas;}
+
+// if !k then suppose all of the object might have changed.
+void gobj_changed (t_gobj *self, const char *k) {
+ int dirty = k ? (1<<class_getfieldindex(self->_class,k)) : -1;
+ t_atom argv[1];
+ SETFLOAT(argv,(float)dirty);
+ gobj_changed3(self,self,1,argv);
+}
+//#define gobj_changed(SELF,K) do {L; gobj_changed(SELF,K);} while(0)
+
+// if only a float is sent, it's a bitset of at most 25 elements
+// else it may mean whatever else...
+void gobj_changed2 (t_gobj *self, int argc, t_atom *argv) {
+ gobj_changed3(self,self,argc,argv);
+}
+
+void gobj_changed3 (t_gobj *self, t_gobj *origin, int argc, t_atom *argv) {
+ t_appendix *d = self->dix;
+ std::ostringstream s;
+ for (int i=0; i<argc; i++) s << " " << &argv[i];
+ //fprintf(stderr,"gobj_changed3 self=%lx origin=%lx args=%s\n",(long)self,(long)origin,s.str().data());
+ /* TRACE THE DIFFERENTIAL UPLOAD REQUESTS */
+ //std::cerr << "gobj_changed3 self=" << self << " origin=" << origin << " args={" << s.str().data()+(!!argc) << "}\n";
+ if (!d) {post("gobj_changed3: no appendix in %p",self); return;}
+ for (size_t i=0; i<d->nobs; i++) {
+ t_gobj *obs = d->obs[i];
+ t_notice ice = obs->_class->notice;
+ if (ice) ice(obs,origin,argc,argv);
+ else post("null func ptr for class %s",self->_class->name->name);
+ }
+}
+
+//--------------------------------------------------------------------------
+// some simple ringbuffer-style queue
+// when this becomes too small, use a bigger constant or a better impl.
+
+#define QUEUE_SIZE 16384
+struct t_queue {
+ int start,len;
+ t_pd *o[QUEUE_SIZE];
+};
+
+t_queue *queue_new () {
+ t_queue *self = (t_queue *)getbytes(sizeof(t_queue));
+ self->start = self->len = 0;
+ return self;
+}
+
+static bool debug_queue=0;
+
+static void pd_print (t_pd *self, char *header) {
+ if (self->_class->gobj && (object_table->get(self)&1)==0) {printf("%s %p dead\n",header,self); return;}
+ if (self->_class->patchable) {
+ t_binbuf *b = ((t_text *)self)->binbuf;
+ if (b) {
+ char *buf; int bufn;
+ binbuf_gettext(b,&buf,&bufn);
+ printf("%s %p [%.*s]\n",header,self,bufn,buf);
+ return;
+ }
+ }
+ printf("%s %p (%s)\n",header,self,self->_class->name->name);
+}
+
+void queue_put (t_queue *self, t_pd *stuff) {
+ if (debug_queue) pd_print(stuff,"queue_put");
+ if (self->len==QUEUE_SIZE) {bug("queue full"); return;}
+ self->o[(self->start+self->len)%QUEUE_SIZE] = stuff;
+ self->len++;
+ if (debug_queue) post("queue_put: items in queue: %d",self->len);
+}
+
+void *queue_get (t_queue *self) {
+ t_pd *stuff = self->o[self->start];
+ self->start = (self->start+1)%QUEUE_SIZE;
+ self->len--;
+ if (debug_queue) {post("queue_get: items in queue: %d",self->len); pd_print(stuff,"queue_get");}
+ return stuff;
+}
+
+#define queue_each(i,self) \
+ for (int i=self->start; i!=(self->start+self->len)%QUEUE_SIZE; i=(i+1)%QUEUE_SIZE)
+
+void queue_free (t_queue *self) {
+ abort();
+ free(self);
+}
+
+int queue_empty (t_queue *self) {return self->len==0;}
+int queue_full (t_queue *self) {return self->len==QUEUE_SIZE;}
+
+//--------------------------------------------------------------------------
+// reply system:
+
+struct t_reply : t_gobj {
+ short serial;
+ void *answer;
+};
+
+t_class *reply_class;
+
+static t_reply *reply_new (short serial, void *answer) {
+ t_reply *self = (t_reply *)pd_new(reply_class);
+ self->dix = appendix_new(self);
+ self->serial = serial;
+ self->answer = answer;
+ return self;
+}
+
+static void reply_send (t_reply *self) {
+ sys_vgui("serial %ld x%lx\n",(long)self->serial,(long)self->answer);
+}
+
+static void reply_free (t_reply *self) {}
+
+//--------------------------------------------------------------------------
+// update manager:
+
+struct t_dirtyentry {
+ long fields;
+ size_t start,end;
+ t_dirtyentry() {}
+};
+
+typedef t_hash <t_gobj *, t_dirtyentry *> t_dirtyset;
+
+struct t_manager : t_text {
+ t_queue *q;
+ t_clock *clock;
+ t_binbuf *b; /* reusable, for processing messages from the gui */
+ t_dirtyset *dirty;
+};
+
+static t_class *manager_class;
+t_manager *manager;
+
+void manager_call (void *foo) {
+ t_manager *self = (t_manager *)foo;
+ while (!queue_empty(self->q)) {
+ t_gobj *o = (t_gobj *)queue_get(self->q);
+ if (!o) continue; /* cancelled notice */
+ //fprintf(stderr,"manager_call, o->_class=%s\n",o->_class->c_name->name);
+ if (o->_class == reply_class) {
+ reply_send((t_reply *)o);
+ pd_free(o);
+ } else {
+ if (self->dirty->exists(o)) {
+ pd_upload(o);
+ self->dirty->del(o);
+ }
+ }
+ }
+ clock_delay(self->clock,50);
+}
+
+void manager_notice (t_gobj *self_, t_gobj *origin, int argc, t_atom *argv) {
+ t_manager *self = (t_manager *)self_;
+ if (!self->dirty->exists(origin)) {
+ //std::cerr << "manager_notice:";
+ //for (int i=0; i<argc; i++) std::cerr << " " << &argv[i];
+ //std::cerr << "\n";
+ queue_put(self->q,origin);
+ self->dirty->set(origin,0);
+ }
+}
+
+t_manager *manager_new (t_symbol *s, int argc, t_atom *argv) {
+ t_manager *self = (t_manager *)pd_new(manager_class);
+ self->q = queue_new();
+ self->clock = clock_new(self,(t_method)manager_call);
+ self->b = binbuf_new();
+ clock_delay(self->clock,0);
+ self->dirty = new t_dirtyset(127);
+ return self;
+}
+
+void manager_free (t_manager *self) {
+ clock_free(self->clock);
+ queue_free(self->q);
+ binbuf_free(self->b);
+ pd_free(self);
+}
+
+extern "C" void manager_anything (t_manager *self, t_symbol *s, int argc, t_atom *argv) {
+ binbuf_clear(self->b);
+ binbuf_addv(self->b,"s",s);
+ binbuf_add(self->b,argc,argv);
+ binbuf_eval(self->b,0,0,0);
+}
+
+//--------------------------------------------------------------------------
+/*
+IOhannes changed the canvas_restore, so that it might accept $args as well
+(like "pd $0_test") so you can make multiple & distinguishable templates.
+*/
+
+#define CANVAS_DEFCANVASWIDTH 450
+#define CANVAS_DEFCANVASHEIGHT 300
+
+#ifdef __APPLE__
+#define CANVAS_DEFCANVASYLOC 22
+#else
+#define CANVAS_DEFCANVASYLOC 0
+#endif
+
+extern short next_object;
+extern t_pd *newest;
+t_class *canvas_class;
+int canvas_dspstate; /* whether DSP is on or off */
+t_canvas *canvas_whichfind; /* last canvas we did a find in */
+std::map<t_canvas *,int> windowed_canvases; /* where int is dummy */
+static void canvas_setbounds(t_canvas *x, t_floatarg x1, t_floatarg y1, t_floatarg x2, t_floatarg y2);
+static t_symbol *canvas_newfilename = &s_;
+static t_symbol *canvas_newdirectory = &s_;
+static int canvas_newargc;
+static t_atom *canvas_newargv;
+
+/* add a canvas the list of "root" canvases (toplevels without parents.) */
+/* should those two functions still exist? */
+static void canvas_addtolist(t_canvas *x) {
+ windowed_canvases.insert(std::pair<t_canvas *,int>(x,42));
+ if (x->havewindow) gobj_subscribe(x,manager);
+}
+static void canvas_takeofflist(t_canvas *x) {windowed_canvases.erase(x);}
+
+/* if there's an old one lying around free it here.
+ This happens if an abstraction is loaded but never gets as far as calling canvas_new(). */
+void canvas_setargs(int argc, t_atom *argv) {
+ if (canvas_newargv) free(canvas_newargv);
+ canvas_newargc = argc;
+ canvas_newargv = (t_atom *)copybytes(argv, argc * sizeof(t_atom));
+}
+
+void glob_setfilename(void *self, t_symbol *filesym, t_symbol *dirsym) {
+ canvas_newfilename = filesym;
+ canvas_newdirectory = dirsym;
+}
+
+t_canvas *canvas_getcurrent () {return ((t_canvas *)pd_findbyclass(&s__X, canvas_class));}
+
+t_canvasenvironment *canvas_getenv(t_canvas *x) {
+ while (!x->env) x = x->dix->canvas;
+ return x->env;
+}
+
+int canvas_getdollarzero () {
+ t_canvas *x = canvas_getcurrent();
+ t_canvasenvironment *env = x ? canvas_getenv(x) : 0;
+ return env ? env->dollarzero : 0;
+}
+
+t_symbol *canvas_realizedollar(t_canvas *x, t_symbol *s) {
+ if (strchr(s->name,'$')) {
+ t_canvasenvironment *env = canvas_getenv(x);
+ pd_pushsym(x);
+ t_symbol *ret = binbuf_realizedollsym(s, env->argc, env->argv, 1);
+ pd_popsym(x);
+ return ret;
+ }
+ return s;
+}
+
+t_symbol *canvas_getcurrentdir () {return canvas_getenv(canvas_getcurrent())->dir;}
+t_symbol *canvas_getdir(t_canvas *x) {return canvas_getenv( x)->dir;}
+
+char *canvas_makefilename(t_canvas *x, char *file, char *result, int resultsize) {
+ char *dir = canvas_getenv(x)->dir->name;
+ if (file[0] == '/' || (file[0] && file[1] == ':') || !*dir) {
+ if (!result) return strdup(file);
+ strncpy(result, file, resultsize);
+ result[resultsize-1] = 0;
+ } else {
+ if (result) {snprintf(result,resultsize,"%s/%s",dir,file); result[resultsize-1] = 0;}
+ else asprintf(&result, "%s/%s",dir,file);
+ }
+ return result;
+}
+
+static void canvas_rename(t_canvas *x, t_symbol *s, t_symbol *dir) {
+ t_symbol *bs = canvas_makebindsym(x->name);
+ if (x->name!=s_Pd) pd_unbind(x, bs);
+ SET(name,s);
+ if (x->name!=s_Pd) pd_bind(x, bs);
+ if (dir && dir != &s_) {
+ canvas_getenv(x)->dir = dir;
+ gobj_changed(x,"dir");
+ }
+}
+
+/* --------------- traversing the set of lines in a canvas ----------- */
+
+t_linetraverser::t_linetraverser(t_canvas *canvas) {linetraverser_start(this,canvas);}
+
+void linetraverser_start(t_linetraverser *t, t_canvas *x) {
+ t->from = 0;
+ t->canvas = x;
+ t->next = 0;
+ t->nextoutno = t->nout = 0;
+}
+
+t_outconnect *linetraverser_next(t_linetraverser *t) {
+ t_outconnect *rval = t->next;
+ while (!rval) {
+ int outno = t->nextoutno;
+ while (outno == t->nout) {
+ t_object *ob = 0;
+ t_gobj *y = t->from ? t->from->next() : t->canvas->boxes->first();
+ for (; y; y = y->next()) if ((ob = pd_checkobject(y))) break;
+ if (!ob) return 0;
+ t->from = ob;
+ t->nout = obj_noutlets(ob);
+ outno = 0;
+ }
+ t->nextoutno = outno + 1;
+ rval = obj_starttraverseoutlet(t->from, &t->outletp, outno);
+ t->outlet = outno;
+ }
+ t->next = obj_nexttraverseoutlet(rval, &t->to, &t->inletp, &t->inlet);
+ t->nin = obj_ninlets(t->to);
+ if (!t->nin) bug("linetraverser_next");
+ return rval;
+}
+
+/* -------------------- the canvas object -------------------------- */
+static int hack = 1;
+
+static t_canvas *canvas_new2() {
+ t_canvas *x = (t_canvas *)pd_new(canvas_class);
+ /* zero out every field except "pd" and "dix" */
+ memset(((char *)x) + sizeof(t_gobj), 0, sizeof(*x) - sizeof(t_gobj));
+ x->xlabel = (t_symbol **)getbytes(0);
+ x->ylabel = (t_symbol **)getbytes(0);
+ // only manage this canvas if it's not one of the 3 invisible builtin canvases
+ x->boxes = boxes_new();
+ return x;
+}
+
+static void canvas_vis(t_canvas *x, t_floatarg f);
+
+/* make a new canvas. It will either be a "root" canvas or else it appears as
+ a "text" object in another window (canvas_getcurrent() tells us which.) */
+static t_canvas *canvas_new(void *self, t_symbol *sel, int argc, t_atom *argv) {
+ t_canvas *x = canvas_new2();
+ t_canvas *owner = canvas_getcurrent();
+ t_symbol *s = &s_;
+ int width = CANVAS_DEFCANVASWIDTH, xloc = 0;
+ int height = CANVAS_DEFCANVASHEIGHT, yloc = CANVAS_DEFCANVASYLOC;
+ int vis=0, font = owner?owner->font:10;
+ if (!owner) canvas_addtolist(x);
+ /* toplevel vs subwindow */
+ if (argc==5) pd_scanargs(argc,argv,"iiiii", &xloc,&yloc,&width,&height,&font);
+ else if (argc==6) pd_scanargs(argc,argv,"iiiisi",&xloc,&yloc,&width,&height,&s,&vis);
+ /* (otherwise assume we're being created from the menu.) */
+ if (canvas_newdirectory->name[0]) {
+ static long dollarzero = 1000;
+ t_canvasenvironment *env = x->env = (t_canvasenvironment *)getbytes(sizeof(*x->env));
+ if (!canvas_newargv) canvas_newargv = (t_atom *)getbytes(0);
+ env->dir = canvas_newdirectory;
+ env->argc = canvas_newargc;
+ env->argv = canvas_newargv;
+ env->dollarzero = dollarzero++;
+ env->path = 0;
+ canvas_newdirectory = &s_;
+ canvas_newargc = 0;
+ canvas_newargv = 0;
+ } else x->env = 0;
+
+ if (yloc < CANVAS_DEFCANVASYLOC) yloc = CANVAS_DEFCANVASYLOC;
+ if (xloc < 0) xloc = 0;
+ x->x1 = 0; x->y1 = 0;
+ x->x2 = 1; x->y2 = 1;
+ canvas_setbounds(x, xloc, yloc, xloc + width, yloc + height);
+ gobj_setcanvas(x,owner);
+ x->name = *s->name ? s : canvas_newfilename ? canvas_newfilename : s_Pd;
+ if (x->name != s_Pd) pd_bind(x, canvas_makebindsym(x->name));
+ x->goprect = 0; /* no GOP rectangle unless it's turned on later */
+ /* cancel "vis" flag if we're a subpatch of an abstraction inside another patch.
+ A separate mechanism prevents the toplevel abstraction from showing up. */
+ if (vis && gensym("#X")->thing && gensym("#X")->thing->_class == canvas_class) {
+ t_canvas *z = (t_canvas *)(gensym("#X")->thing);
+ while (z && !z->env) z = z->dix->canvas;
+ if (z && canvas_isabstraction(z) && z->dix->canvas) vis = 0;
+ }
+ if (vis) canvas_vis(x,vis);
+ x->font = 10 /*sys_nearestfontsize(font)*/;
+ pd_pushsym(x);
+ newest = x;
+ return x;
+}
+
+void canvas_setgraph(t_canvas *x, int flag, int nogoprect);
+
+static void canvas_coords(t_canvas *x, t_symbol *s, int argc, t_atom *argv) {
+ pd_scanargs(argc,argv,"ffffii*",&x->x1,&x->y1,&x->x2,&x->y2,&x->pixwidth,&x->pixheight);
+ if (argc <= 7) canvas_setgraph(x, atom_getintarg(6, argc, argv), 1);
+ else {
+ canvas_setgraph(x, atom_getintarg(6, argc, argv), 0);
+ SET(xmargin, atom_getintarg(7, argc, argv));
+ SET(ymargin, atom_getintarg(8, argc, argv));
+ }
+ gobj_changed(x,0);
+}
+
+template <class T> void swap(T &a, T &b) {T c=a; a=b; b=c;}
+
+#define CANVAS_DEFGRAPHWIDTH 200
+#define CANVAS_DEFGRAPHHEIGHT 140
+/* make a new canvas and add it to this canvas. It will appear as a "graph", not a text object. */
+static t_canvas *canvas_addcanvas(t_canvas *g, t_symbol *sym,
+float x1, float y1, float x2, float y2,
+float px1, float py1, float px2, float py2) {
+ static int gcount = 0;
+ int menu = 0;
+ t_canvas *x = canvas_new2();
+ if (!*sym->name) {
+ sym = symprintf("graph%d", ++gcount);
+ menu = 1;
+ } else if (!strncmp(sym->name,"graph",5)) {
+ int zz = atoi(sym->name+5);
+ if (zz>gcount) gcount = zz;
+ }
+ /* in 0.34 and earlier, the pixel rectangle and the y bounds were reversed; this would behave the same,
+ except that the dialog window would be confusing. The "correct" way is to have "py1" be the value
+ that is higher on the screen. */
+ if (py2 < py1) {swap(y1,y2); swap(py1,py2);}
+ if (x1 == x2 || y1 == y2) {x1=0; x2=100; y1=1; y2=-1;}
+ if (px1 >= px2 || py1 >= py2) {
+ px1=100; px2=px1+CANVAS_DEFGRAPHWIDTH;
+ py1=20; py2=py1+CANVAS_DEFGRAPHHEIGHT;
+ }
+ x->name = sym;
+ SET(x1,x1); SET(y1,y1); SET(x,short(px1)); SET(pixwidth ,int(px2-px1));
+ SET(x2,x2); SET(y2,y2); SET(y,short(py1)); SET(pixheight,int(py2-py1));
+ x->font = (canvas_getcurrent() ? canvas_getcurrent()->font : 42 /*sys_defaultfont*/);
+ x->screenx1 = x->screeny1 = 0; x->screenx2 = 450; x->screeny2 = 300;
+ if (x->name != s_Pd) pd_bind(x, canvas_makebindsym(x->name));
+ gobj_setcanvas(x,g);
+ x->gop = 1;
+ x->goprect = 0;
+ x->binbuf = binbuf_new();
+ binbuf_addv(x->binbuf,"t","graph");
+ if (!menu) pd_pushsym(x);
+ canvas_add(g,x);
+ return x;
+}
+
+static void canvas_canvas(t_canvas *g, t_symbol *s, int argc, t_atom *argv) {
+ t_symbol *sym;
+ float x1,y1,x2,y2,px1,py1,px2,py2;
+ pd_scanargs(argc,argv,"sffffffff",&sym,&x1,&y1,&x2,&y2,&px1,&py1,&px2,&py2);
+ canvas_addcanvas(g, sym, x1, y1, x2, y2, px1, py1, px2, py2);
+}
+
+static void canvas_redraw(t_canvas *x) {
+ gobj_changed(x,0);
+ canvas_each(y,x) if (y->_class==canvas_class) canvas_redraw((t_canvas *)y); else gobj_changed(y,0);
+}
+
+/* This is sent from the GUI to inform a toplevel that its window has been moved or resized. */
+static void canvas_setbounds(t_canvas *x, t_floatarg x1, t_floatarg y1, t_floatarg x2, t_floatarg y2) {
+ int heightwas = int(y2-y1);
+ if (x->screenx1 == x1 && x->screeny1 == y1 &&
+ x->screenx2 == x2 && x->screeny2 == y2) return;
+ x->screenx1 = int(x1); x->screeny1 = int(y1);
+ x->screenx2 = int(x2); x->screeny2 = int(y2);
+ if (!x->gop && x->y2 < x->y1) {
+ /* if it's flipped so that y grows upward, fix so that zero is bottom edge and redraw.
+ This is only appropriate if we're a regular "text" object on the parent. */
+ float diff = x->y1 - x->y2;
+ x->y1 = heightwas * diff;
+ x->y2 = x->y1 - diff;
+ canvas_redraw(x);
+ }
+}
+
+t_symbol *canvas_makebindsym(t_symbol *s) {return symprintf("pd-%s",s->name);}
+
+static void canvas_vis(t_canvas *x, t_floatarg f) {
+ int hadwindow = x->havewindow;
+ SET(havewindow,!!f);
+ if (hadwindow && !x->havewindow) gobj_unsubscribe(x,manager);
+ if (!hadwindow && x->havewindow) gobj_subscribe(x,manager);
+}
+
+/* we call this on a non-toplevel canvas to "open" it into its own window. */
+static void canvas_menu_open(t_canvas *x) {
+ if (canvas_isvisible(x) && !canvas_istoplevel(x)) {
+ if (!x->dix->canvas) {error("this works only on subpatch or abstraction"); return;}
+ SET(havewindow,1);
+ }
+}
+
+int canvas_isvisible(t_canvas *x) {return gstack_empty() && canvas_getcanvas(x)->havewindow;}
+
+/* we consider a graph "toplevel" if it has its own window or if it appears as a box in its parent window
+ so that we don't draw the actual contents there. */
+int canvas_istoplevel(t_canvas *x) {return x->havewindow || !x->gop;}
+
+static void canvas_free(t_canvas *x) {
+ int dspstate = canvas_suspend_dsp();
+ if (canvas_whichfind == x) canvas_whichfind = 0;
+ t_gobj *y;
+ while ((y = x->boxes->first())) canvas_delete(x, y);
+ canvas_vis(x, 0);
+ if (x->name != s_Pd) pd_unbind(x,canvas_makebindsym(x->name));
+ if (x->env) {
+ free(x->env->argv);
+ free(x->env);
+ }
+ canvas_resume_dsp(dspstate);
+ free(x->xlabel);
+ free(x->ylabel);
+ if (!x->dix->canvas) canvas_takeofflist(x);
+}
+
+/* kill all lines for one inlet or outlet */
+void canvas_deletelinesforio(t_canvas *x, t_text *text, t_inlet *inp, t_outlet *outp) {
+ canvas_wires_each(oc,t,x)
+ if ((t.from == text && t.outletp == outp) ||
+ (t.to == text && t.inletp == inp))
+ obj_disconnect(t.from, t.outlet, t.to, t.inlet);
+}
+void canvas_deletelinesfor(t_canvas *x, t_text *text) {
+ canvas_wires_each(oc,t,x)
+ if (t.from == text || t.to == text)
+ obj_disconnect(t.from, t.outlet, t.to, t.inlet);
+}
+
+static void canvas_resortinlets(t_canvas *x);
+static void canvas_resortoutlets(t_canvas *x);
+static void canvas_push(t_canvas *x, t_floatarg f) {pd_pushsym(x);}
+/* assuming that this only ever gets called on toplevel canvases (?) */
+static void canvas_pop(t_canvas *x, t_floatarg fvis) {
+ pd_popsym(x); canvas_resortinlets(x); canvas_resortoutlets(x);
+ if (fvis) canvas_vis(x, 1);
+}
+/* called by m_class.c */
+extern "C" void canvas_popabstraction(t_canvas *x) {
+ pd_set_newest(x);
+ pd_popsym(x); canvas_resortinlets(x); canvas_resortoutlets(x);
+}
+
+void canvas_objfor(t_canvas *gl, t_text *x, int argc, t_atom *argv);
+
+void canvas_restore(t_canvas *x, t_symbol *s, int argc, t_atom *argv) {
+ if (argc > 3) {
+ t_atom *ap=argv+3;
+ if (ap->a_type == A_SYMBOL) {
+ t_canvasenvironment *e = canvas_getenv(canvas_getcurrent());
+ canvas_rename(x, binbuf_realizedollsym(ap->a_symbol, e->argc, e->argv, 1), 0);
+ }
+ }
+ canvas_pop(x,0); /* 0 means "don't touch" here. */
+ t_pd *z = gensym("#X")->thing;
+ if (!z) {error("out of context"); return;}
+ if (z->_class != canvas_class) {error("wasn't a canvas"); return;}
+ gobj_setcanvas(x,(t_canvas *)z);
+ canvas_objfor((t_canvas *)z, x, argc, argv);
+ newest = x;
+}
+
+static void canvas_loadbang(t_canvas *x);
+
+static void canvas_loadbangabstractions(t_canvas *x) {
+ canvas_each(y,x) if (y->_class == canvas_class) {
+ t_canvas *z = (t_canvas *)y;
+ if (canvas_isabstraction(z)) canvas_loadbang(z); else canvas_loadbangabstractions(z);
+ }
+}
+
+void canvas_loadbangsubpatches(t_canvas *x) {
+ t_symbol *s = gensym("loadbang");
+ canvas_each(y,x) if (y->_class == canvas_class) {
+ t_canvas *z = (t_canvas *)y;
+ if (!canvas_isabstraction(z)) canvas_loadbangsubpatches(z);
+ }
+ canvas_each(y,x) if ((y->_class != canvas_class) && zgetfn(y,s)) pd_vmess(y,s,"");
+}
+
+static void canvas_loadbang(t_canvas *x) {
+ canvas_loadbangabstractions(x);
+ canvas_loadbangsubpatches(x);
+}
+
+/* When you ask a canvas its size the result is 2 pixels more than what you gave it to open it;
+ perhaps there's a 1-pixel border all around it or something. Anyway, we just add the 2 pixels back here;
+ seems we have to do this for linux but not MSW; not sure about MacOS. */
+#ifdef MSW
+#define HORIZBORDER 0
+#define VERTBORDER 0
+#else
+#define HORIZBORDER 2
+#define VERTBORDER 2
+#endif
+
+static void canvas_relocate(t_canvas *x, t_symbol *canvasgeom, t_symbol *topgeom) {
+ int cxpix, cypix, cw, ch, txpix, typix, tw, th;
+ if (sscanf(canvasgeom->name, "%dx%d+%d+%d", &cw, &ch, &cxpix, &cypix) < 4 ||
+ sscanf( topgeom->name, "%dx%d+%d+%d", &tw, &th, &txpix, &typix) < 4)
+ bug("canvas_relocate");
+ /* for some reason this is initially called with cw=ch=1 so we just suppress that here. */
+ if (cw>5 && ch>5) canvas_setbounds(x, txpix, typix, txpix + cw - HORIZBORDER, typix + ch - VERTBORDER);
+}
+
+void pd_set_newest (t_pd *x) {newest = x;}
+
+static void *subcanvas_new(t_symbol *s) {
+ t_atom a[6];
+ t_canvas *z = canvas_getcurrent();
+ if (!*s->name) s = gensym("/SUBPATCH/");
+ SETFLOAT(a, 0);
+ SETFLOAT(a+1, CANVAS_DEFCANVASYLOC);
+ SETFLOAT(a+2, CANVAS_DEFCANVASWIDTH);
+ SETFLOAT(a+3, CANVAS_DEFCANVASHEIGHT);
+ SETSYMBOL(a+4, s);
+ SETFLOAT(a+5, 1);
+ t_canvas *x = canvas_new(0, 0, 6, a);
+ gobj_setcanvas(x,z);
+ canvas_pop(x, 1);
+ return x;
+}
+
+static void canvas_rename_method(t_canvas *x, t_symbol *s, int ac, t_atom *av) {
+ if (ac && av->a_type == A_SYMBOL) canvas_rename(x, av->a_symbol, 0);
+ else if (ac && av->a_type == A_DOLLSYM) {
+ t_canvasenvironment *e = canvas_getenv(x);
+ pd_pushsym(x);
+ canvas_rename(x, binbuf_realizedollsym(av->a_symbol, e->argc, e->argv, 1), 0);
+ pd_popsym(x);
+ } else canvas_rename(x, gensym("Pd"), 0);
+}
+
+/* ------------------ table ---------------------------*/
+
+static t_garray *graph_array(t_canvas *gl, t_symbol *s, t_symbol *tmpl, t_floatarg f, t_floatarg saveit);
+
+static int tabcount = 0;
+
+static void *table_new(t_symbol *s, t_floatarg f) {
+ t_atom a[9];
+ t_canvas *z = canvas_getcurrent();
+ if (s == &s_) s = symprintf("table%d", tabcount++);
+ if (f <= 1) f = 100;
+ SETFLOAT(a, 0);
+ SETFLOAT(a+1, CANVAS_DEFCANVASYLOC);
+ SETFLOAT(a+2, 600);
+ SETFLOAT(a+3, 400);
+ SETSYMBOL(a+4, s);
+ SETFLOAT(a+5, 0);
+ t_canvas *x = canvas_new(0,0,6,a);
+ gobj_setcanvas(x,z);
+ /* create a graph for the table */
+ t_canvas *gl = canvas_addcanvas(x, &s_, 0, -1, (f > 1 ? f-1 : 1), 1, 50, 350, 550, 50);
+ graph_array(gl, s, &s_float, f, 0);
+ canvas_pop(x, 0);
+ return x;
+}
+
+/* return true if the "canvas" object is an abstraction (so we don't save its contents, fogr example.) */
+int canvas_isabstraction(t_canvas *x) {return x->env!=0;}
+
+/* return true if the "canvas" object is a "table". */
+int canvas_istable(t_canvas *x) {
+ t_atom *argv = x->binbuf ? binbuf_getvec( x->binbuf) : 0;
+ int argc = x->binbuf ? binbuf_getnatom(x->binbuf) : 0;
+ return argc && argv[0].a_type == A_SYMBOL && argv[0].a_symbol == gensym("table");
+}
+
+/* return true if the "canvas" object should be treated as a text
+ object. This is true for abstractions but also for "table"s... */
+/* JMZ: add a flag to gop-abstractions to hide the title */
+static int canvas_showtext(t_canvas *x) {
+ t_atom *argv = x->binbuf? binbuf_getvec( x->binbuf) : 0;
+ int argc = x->binbuf? binbuf_getnatom(x->binbuf) : 0;
+ int isarray = argc && argv[0].a_type == A_SYMBOL && argv[0].a_symbol == gensym("graph");
+ return x->hidetext ? 0 : !isarray;
+}
+
+/* get the document containing this canvas */
+t_canvas *canvas_getrootfor(t_canvas *x) {
+ if (!x->dix->canvas || canvas_isabstraction(x)) return x;
+ return canvas_getrootfor(x->dix->canvas);
+}
+
+/* ------------------------- DSP chain handling ------------------------- */
+
+typedef struct _dspcontext t_dspcontext;
+
+extern void ugen_start ();
+extern void ugen_stop ();
+extern "C" t_dspcontext *ugen_start_graph(int toplevel, t_signal **sp, int ninlets, int noutlets);
+extern "C" void ugen_add(t_dspcontext *dc, t_object *x);
+extern "C" void ugen_connect(t_dspcontext *dc, t_object *from, int outlet, t_object *to, int inlet);
+extern "C" void ugen_done_graph(t_dspcontext *dc);
+
+/* schedule one canvas for DSP. This is called below for all "root"
+ canvases, but is also called from the "dsp" method for sub-
+ canvases, which are treated almost like any other tilde object. */
+static void canvas_dodsp(t_canvas *x, int toplevel, t_signal **sp) {
+ t_object *ob;
+ t_symbol *dspsym = gensym("dsp");
+ /* create a new "DSP graph" object to use in sorting this canvas.
+ If we aren't toplevel, there are already other dspcontexts around. */
+ t_dspcontext *dc = ugen_start_graph(toplevel, sp, obj_nsiginlets(x), obj_nsigoutlets(x));
+ /* find all the "dsp" boxes and add them to the graph */
+ canvas_each(y,x) if ((ob = pd_checkobject(y)) && zgetfn(y,dspsym)) ugen_add(dc, ob);
+ /* ... and all dsp interconnections */
+ canvas_wires_each(oc,t,x)
+ if (obj_issignaloutlet(t.from, t.outlet))
+ ugen_connect(dc, t.from, t.outlet, t.to, t.inlet);
+ /* finally, sort them and add them to the DSP chain */
+ ugen_done_graph(dc);
+}
+
+static void canvas_dsp(t_canvas *x, t_signal **sp) {canvas_dodsp(x, 0, sp);}
+
+/* this routine starts DSP for all root canvases. */
+static void canvas_start_dsp() {
+ if (canvas_dspstate) ugen_stop();
+ else sys_gui("pdtk_pd_dsp 1\n");
+ ugen_start();
+ //timeval v0,v1; gettimeofday(&v0,0);
+ foreach(x,windowed_canvases) canvas_dodsp(x->first,1,0);
+ //gettimeofday(&v1,0); printf("canvas_start_dsp took %ld us\n",(v1.tv_sec-v0.tv_sec)*1000000+(v1.tv_usec-v0.tv_usec));
+ canvas_dspstate = 1;
+}
+
+/*static*/ void canvas_stop_dsp() {
+ if (canvas_dspstate) {
+ ugen_stop();
+ sys_gui("pdtk_pd_dsp 0\n");
+ canvas_dspstate = 0;
+ }
+}
+
+/* DSP can be suspended before, and resumed after, operations which might affect the DSP chain.
+ For example, we suspend before loading and resume afterwards, so that DSP doesn't get resorted for every DSP object in the patch. */
+int canvas_suspend_dsp () {
+ int rval = canvas_dspstate;
+ if (rval) canvas_stop_dsp();
+ return rval;
+}
+void canvas_resume_dsp(int oldstate) {if (oldstate) canvas_start_dsp();}
+/* this is equivalent to suspending and resuming in one step. */
+void canvas_update_dsp () {if (canvas_dspstate) canvas_start_dsp();}
+
+extern "C" void glob_dsp(void *self, t_symbol *s, int argc, t_atom *argv) {
+ if (argc) {
+ int newstate = atom_getintarg(0, argc, argv);
+ if (newstate && !canvas_dspstate) {
+ canvas_start_dsp();
+ sys_set_audio_state(1);
+ } else if (!newstate && canvas_dspstate) {
+ sys_set_audio_state(0);
+ canvas_stop_dsp();
+ }
+ } else post("dsp state %d", canvas_dspstate);
+}
+
+extern "C" void *canvas_getblock(t_class *blockclass, t_canvas **canvasp) {
+ t_canvas *canvas = *canvasp;
+ void *ret = 0;
+ canvas_each(g,canvas) if (g->_class == blockclass) ret = g;
+ *canvasp = canvas->dix->canvas;
+ return ret;
+}
+
+/******************* redrawing data *********************/
+
+static t_float slot_getcoord(t_slot *f, t_template *, t_word *wp, int loud);
+static void slot_setcoord(t_slot *f, t_template *, t_word *wp, float pix, int loud);
+static t_float slot_cvttocoord(t_slot *f, float val);
+static t_template *template_new(t_symbol *sym, int argc, t_atom *argv);
+static void template_free(t_template *x);
+static int template_match(t_template *x1, t_template *x2);
+static int template_find_field(t_template *x, t_symbol*name, int*p_onset, int*p_type, t_symbol **p_arraytype);
+static t_float template_getfloat( t_template *x, t_symbol *fieldname, t_word *wp, int loud);
+static void template_setfloat( t_template *x, t_symbol *fieldname, t_word *wp, t_float f, int loud);
+static t_symbol *template_getsymbol(t_template *x, t_symbol *fieldname, t_word *wp, int loud);
+static void template_setsymbol(t_template *x, t_symbol *fieldname, t_word *wp, t_symbol *s, int loud);
+static t_template *gtemplate_get(t_gtemplate *x);
+static t_template *template_findbyname(t_symbol *s);
+static t_canvas *template_findcanvas(t_template *tmpl);
+static void template_notify(t_template *, t_symbol *s, int argc, t_atom *argv);
+
+/* find the template defined by a canvas, and redraw all elements for that */
+void canvas_redrawallfortemplatecanvas(t_canvas *x, int action) {
+ t_template *tmpl;
+ t_symbol *s1 = gensym("struct");
+ canvas_each(g,x) {
+ t_object *ob = pd_checkobject(g);
+ if (!ob || /* ob->type != T_OBJECT || */ binbuf_getnatom(ob->binbuf) < 2) continue;
+ t_atom *argv = binbuf_getvec(ob->binbuf);
+ if (argv[0].a_type != A_SYMBOL || argv[1].a_type != A_SYMBOL || argv[0].a_symbol != s1)
+ continue;
+ tmpl = template_findbyname(argv[1].a_symbol);
+ //canvas_redrawallfortemplate(tmpl, action);
+ }
+ //canvas_redrawallfortemplate(0, action);
+}
+
+//#define canvas_each2(CHILD,CANVAS) for(CHILD=&(CANVAS)->list; *CHILD; CHILD=&(*CHILD)->next())
+/* just a raw remove, no other business */
+/* doesn't work (why?) */
+static t_gobj *canvas_remove_nth(t_canvas *x, int n) {
+/*
+ t_gobj **y;
+ canvas_each2(y,x) {
+ fprintf(stderr,"n=%i *y=%p\n",n,*y);
+ if (!n) {
+ t_gobj *z = *y;
+ *y = z->next();
+ z->next() = 0;
+ return z;
+ } else n--;
+ }
+ return 0;
+*/
+}
+
+/* just a raw insert, no other business */
+/* doesn't work (why?) */
+static void canvas_insert_nth(t_canvas *x, int n, t_gobj *nu) {
+/*
+ t_gobj **y;
+ canvas_each2(y,x) if (!n) {
+ t_gobj *z = *y;
+ *y = nu;
+ nu->next() = z;
+ return;
+ } else n--;
+ *y = nu;
+*/
+}
+
+void canvas_disconnect(t_canvas *x, float from_, float outlet, float to_, float inlet) {
+ int ifrom=(int)from_, ito=int(to_);
+ t_gobj *from=0, *to=0;
+ canvas_each(gfrom,x) if (gfrom->dix->index == ifrom) {from=gfrom; break;}
+ canvas_each( gto,x) if ( gto->dix->index == ito) { to= gto; break;}
+ if (!from || !to) goto bad;
+ obj_disconnect((t_object *)from, int(outlet), (t_object *)to, int(inlet));
+ return;
+bad:
+ post("dumb.");
+}
+
+static t_binbuf *canvas_cut_wires(t_canvas *x, t_gobj *o);
+static void canvas_paste_wires(t_canvas *x, t_binbuf *buf);
+
+/* recursively check for abstractions to reload as result of a save.
+ Don't reload the one we just saved ("except") though. */
+/* LATER try to do the same trick for externs. */
+static void canvas_doreload(t_canvas *gl, t_symbol *name, t_symbol *dir, t_gobj *except) {
+ int i=0, nobj = gl->boxes->size();
+ for (t_gobj *g = gl->boxes->first(); g && i < nobj; i++) {
+ if (g != except && g->_class == canvas_class) {
+ t_canvas *c = (t_canvas *)g;
+ if (canvas_isabstraction(c) && c->name==name && canvas_getdir(c) == dir) {
+ /* we're going to remake the object, so "g" will go stale. Get its index here, and afterwards restore g.
+ Also, the replacement will be at the end of the list, so we don't do g = g->next() in this case. */
+ int j = g->dix->index;
+ int hadwindow = gl->havewindow;
+ if (!hadwindow) canvas_vis(canvas_getcanvas(gl), 1);
+ t_binbuf *buf = canvas_cut_wires(gl,g);
+ gl->boxes->remove(j);
+ //MISSING: remake the object here.
+ canvas_paste_wires(gl,buf);
+ if (!hadwindow) canvas_vis(canvas_getcanvas(gl), 0);
+ continue;
+ }
+ canvas_doreload(c,name,dir,except);
+ }
+ g = g->next();
+ }
+}
+
+void canvas_reload(t_symbol *name, t_symbol *dir, t_gobj *except) {
+ foreach(x,windowed_canvases) canvas_doreload(x->first, name, dir, except);
+}
+
+/* ------------------------ event handling ------------------------ */
+
+/* set a canvas up as a graph-on-parent.
+ Set reasonable defaults for any missing paramters and redraw things if necessary. */
+void canvas_setgraph(t_canvas *x, int flag, int nogoprect) {
+ if (!flag && x->gop) {
+ x->gop = 0;
+ } else if (flag) {
+ if (x->pixwidth <= 0) x->pixwidth = CANVAS_DEFGRAPHWIDTH;
+ if (x->pixheight <= 0) x->pixheight = CANVAS_DEFGRAPHHEIGHT;
+ SET(gop,1);
+ SET(hidetext,!!(flag&2));
+ if (!nogoprect && !x->goprect) canvas_each(g,x) if (pd_checkobject(g)) {SET(goprect,1); break;}
+ if (canvas_isvisible(x) && x->goprect) gobj_changed(x,0);
+ }
+}
+
+/* keep me */
+static int canvas_isconnected (t_canvas *x, t_text *ob1, int n1, t_text *ob2, int n2) {
+ canvas_wires_each(oc,t,x)
+ if (t.from == ob1 && t.outlet == n1 && t.to == ob2 && t.inlet == n2) return 1;
+ return 0;
+}
+
+/* ----------------------------- window stuff ----------------------- */
+
+void canvas_close(t_canvas *x) {
+ if (x->dix->canvas) canvas_vis(x, 0); else pd_free(x);
+}
+
+static int canvas_find_index1, canvas_find_index2;
+static t_binbuf *canvas_findbuf;
+int binbuf_match(t_binbuf *inbuf, t_binbuf *searchbuf);
+
+/* find an atom or string of atoms */
+static int canvas_dofind(t_canvas *x, int *myindex1p) {
+ int myindex1 = *myindex1p, myindex2=0;
+ if (myindex1 >= canvas_find_index1) {
+ canvas_each(y,x) {
+ t_object *ob = pd_checkobject(y);
+ if (ob && binbuf_match(ob->ob_binbuf, canvas_findbuf)) {
+ if (myindex1 > canvas_find_index1 ||
+ (myindex1 == canvas_find_index1 && myindex2 > canvas_find_index2)) {
+ canvas_find_index1 = myindex1;
+ canvas_find_index2 = myindex2;
+ vmess(x,gensym("menu-open"),"");
+ return 1;
+ }
+ }
+ myindex2++;
+ }
+ }
+ myindex2=0;
+ canvas_each(y,x) {
+ if (y->_class == canvas_class) {
+ (*myindex1p)++;
+ if (canvas_dofind((t_canvas *)y, myindex1p)) return 1;
+ }
+ myindex2++;
+ }
+ return 0;
+}
+
+static void canvas_find_parent(t_canvas *x) {
+ if (x->dix->canvas) canvas_vis(canvas_getcanvas(x->dix->canvas), 1);
+}
+
+static int canvas_dofinderror(t_canvas *gl, void *error_object) {
+ canvas_each(g,gl) {
+ if (g==error_object) {
+ /* got it... now show it. */
+ canvas_vis(canvas_getcanvas(gl), 1);
+ return 1;
+ } else if (g->_class == canvas_class) {
+ if (canvas_dofinderror((t_canvas *)g, error_object)) return 1;
+ }
+ }
+ return 0;
+}
+
+void canvas_finderror(void *error_object) {
+ foreach(x,windowed_canvases) if (canvas_dofinderror(x->first, error_object)) return;
+ post("... sorry, I couldn't find the source of that error.");
+}
+
+extern t_class *text_class;
+extern t_class *dummy_class;
+
+static int is_dummy (t_text *x) {return x->_class==dummy_class;}
+
+long canvas_base_o_index(void);
+
+void canvas_connect(t_canvas *x, t_floatarg ffrom, t_floatarg foutlet, t_floatarg fto,t_floatarg finlet) {
+ int base = canvas_base_o_index();
+ int ifrom=base+int(ffrom), outlet=(int)foutlet;
+ int ito=base+int(fto), inlet=(int)finlet;
+ t_gobj *gfrom=0, *gto=0;
+ t_object *from=0, *to=0;
+ t_outconnect *oc;
+ if (ifrom<0) goto bad;
+ if (ito <0) goto bad;
+ canvas_each(zfrom,x) if (zfrom->dix->index == ifrom) {gfrom=zfrom; break;}
+ if (!gfrom) goto bad;
+ canvas_each( zto,x) if ( zto->dix->index == ito) { gto= zto; break;}
+ if (!gto) goto bad;
+ from = pd_checkobject(gfrom);
+ to = pd_checkobject( gto);
+ if (!from || !to) goto bad;
+ /* if object creation failed, make dummy inlets or outlets as needed */
+ if (is_dummy(from)) while (outlet >= obj_noutlets(from)) outlet_new(from, &s_);
+ if (is_dummy(to)) while ( inlet >= obj_ninlets(to)) inlet_new(to,to,&s_,&s_);
+ if (!(oc = obj_connect(from,outlet,to,inlet))) goto bad;
+ pd_set_newest(oc);
+ gobj_setcanvas(oc,x);
+ oc->dix->index = x->next_w_index++;
+ return;
+bad:
+ post("%s %d %d %d %d (%s->%s) connection failed", x->name->name,ifrom,outlet,ito,inlet,
+ from ? class_getname(from->_class) : "???",
+ to ? class_getname( to->_class) : "???");
+}
+
+#define ARRAYPAGESIZE 1000 /* this should match the page size in u_main.tk */
+/* aux routine to bash leading '#' to '$' for dialogs in u_main.tk which can't send symbols
+ starting with '$' (because the Pd message interpreter would change them!) */
+static t_symbol *sharptodollar(t_symbol *s) {
+ if (*s->name != '#') return s;
+ return symprintf("$%s",s->name+1);
+}
+
+/* --------- "pure" arrays with scalars for elements. --------------- */
+
+/* Pure arrays have no a priori graphical capabilities.
+They are instantiated by "garrays" below or can be elements of other
+scalars (g_scalar.c); their graphical behavior is defined accordingly. */
+
+t_class *array_class;
+
+static t_array *array_new(t_symbol *templatesym, t_gpointer *parent) {
+ t_array *x = (t_array *)pd_new(array_class);
+ t_template *t = template_findbyname(templatesym);
+ x->templatesym = templatesym;
+ x->n = 1;
+ x->elemsize = sizeof(t_word) * t->n;
+ /* aligned allocation */
+ x->vec = (char *)getalignedbytes(x->elemsize);
+ /* note here we blithely copy a gpointer instead of "setting" a new one; this gpointer isn't accounted for
+ and needn't be since we'll be deleted before the thing pointed to gets deleted anyway; see array_free. */
+ x->gp = *parent;
+ word_init((t_word *)x->vec, t, parent);
+ return x;
+}
+
+void array_resize(t_array *x, int n) {
+ t_template *t = template_findbyname(x->templatesym);
+ if (n < 1) n = 1;
+ int oldn = x->n;
+ int elemsize = sizeof(t_word) * t->n;
+ x->vec = (char *)resizealignedbytes(x->vec, oldn * elemsize, n * elemsize);
+ x->n = n;
+ if (n > oldn) {
+ char *cp = x->vec + elemsize * oldn;
+ for (int i = n-oldn; i--; cp += elemsize) {
+ t_word *wp = (t_word *)cp;
+ word_init(wp, t, &x->gp);
+ }
+ }
+}
+
+static void array_resize_and_redraw(t_array *array, int n) {
+/* what was that for??? */
+ array_resize(array,n);
+ gobj_changed(array,0);
+}
+
+void word_free(t_word *wp, t_template *t);
+
+static void array_free(t_array *x) {
+ t_template *scalartemplate = template_findbyname(x->templatesym);
+ for (int i=0; i < x->n; i++) word_free((t_word *)(x->vec + x->elemsize*i), scalartemplate);
+ freealignedbytes(x->vec, x->elemsize * x->n);
+}
+
+/* --------------------- graphical arrays (garrays) ------------------- */
+
+t_class *garray_class;
+
+static t_pd *garray_arraytemplatecanvas;
+
+/* create invisible, built-in canvases to determine the templates for floats
+and float-arrays. */
+
+void pd_eval_text2(char *s) {pd_eval_text(s,strlen(s));}
+
+extern "C" void garray_init () {
+ hack = 0; /* invisible canvases must be, uh, invisible */
+ if (garray_arraytemplatecanvas) return;
+ t_binbuf *b = binbuf_new();
+ glob_setfilename(0, gensym("_float"), gensym("."));
+ pd_eval_text2(
+ "#N canvas 0 0 458 153 10;\n"
+ "#X obj 43 31 struct _float_array array z float float style float linewidth float color;\n"
+ "#X obj 43 70 plot z color linewidth 0 0 1 style;\n");
+ vmess(s__X.thing, gensym("pop"), "i", 0);
+ glob_setfilename(0, gensym("_float_array"), gensym("."));
+ pd_eval_text2(
+ "#N canvas 0 0 458 153 10;\n"
+ "#X obj 39 26 struct float float y;\n");
+ garray_arraytemplatecanvas = s__X.thing;
+ vmess(s__X.thing, gensym("pop"), "i", 0);
+ glob_setfilename(0, &s_, &s_);
+ binbuf_free(b);
+ hack = 1; /* enable canvas visibility for upcoming canvases */
+}
+
+/* create a new scalar attached to a symbol. Used to make floating-point
+arrays (the scalar will be of type "_float_array"). Currently this is
+always called by graph_array() below; but when we make a more general way
+to save and create arrays this might get called more directly. */
+
+static t_garray *graph_scalar(t_canvas *gl, t_symbol *s, t_symbol *templatesym, int saveit) {
+ if (!template_findbyname(templatesym)) return 0;
+ t_garray *x = (t_garray *)pd_new(garray_class);
+ x->scalar = scalar_new(gl, templatesym);
+ x->realname = s;
+ x->realname = canvas_realizedollar(gl, s);
+ pd_bind(x,x->realname);
+ x->usedindsp = 0;
+ x->saveit = saveit;
+ x->listviewing = 0;
+ canvas_add(gl,x);
+ x->canvas = gl;
+ return x;
+}
+
+#define TEMPLATE_CHECK(tsym,ret) if (!t) {\
+ error("couldn't find template %s", tsym->name); return ret;}
+
+#define TEMPLATE_FLOATY(a,ret) if (!a) {\
+ error("%s: needs floating-point 'y' field", x->realname); return ret;}
+
+ /* get a garray's "array" structure. */
+t_array *garray_getarray(t_garray *x) {
+ int zonset, ztype;
+ t_symbol *zarraytype;
+ t_scalar *sc = x->scalar;
+ t_template *t = template_findbyname(sc->t);
+ TEMPLATE_CHECK(sc->t,0)
+ if (!template_find_field(t, gensym("z"), &zonset, &ztype, &zarraytype)) {
+ error("template %s has no 'z' field", sc->t->name);
+ return 0;
+ }
+ if (ztype != DT_ARRAY) {
+ error("template %s, 'z' field is not an array", sc->t->name);
+ return 0;
+ }
+ return sc->v[zonset].w_array;
+}
+
+ /* get the "array" structure and furthermore check it's float */
+static t_array *garray_getarray_floatonly(t_garray *x, int *yonsetp, int *elemsizep) {
+ t_array *a = garray_getarray(x);
+ int yonset, type;
+ t_symbol *arraytype;
+ t_template *t = template_findbyname(a->templatesym);
+ if (!template_find_field(t,&s_y,&yonset,&type,&arraytype) || type != DT_FLOAT)
+ return 0;
+ *yonsetp = yonset;
+ *elemsizep = a->elemsize;
+ return a;
+}
+
+/* get the array's name. Return nonzero if it should be hidden */
+int garray_getname(t_garray *x, t_symbol **namep) {
+// *namep = x->name;
+ *namep = x->realname;
+ return x->hidename;
+}
+
+
+/* if there is one garray in a graph, reset the graph's coordinates
+ to fit a new size and style for the garray */
+static void garray_fittograph(t_garray *x, int n, int style) {
+ t_array *array = garray_getarray(x);
+ t_canvas *gl = x->canvas;
+ if (gl->boxes->first() == x && !x->next()) {
+ vmess(gl,gensym("bounds"),"ffff",0.,gl->y1, double(style == PLOTSTYLE_POINTS || n == 1 ? n : n-1), gl->y2);
+ /* close any dialogs that might have the wrong info now... */
+ }
+ array_resize_and_redraw(array, n);
+}
+
+/* handle "array" message to canvases; call graph_scalar above with
+an appropriate template; then set size and flags. This is called
+from the menu and in the file format for patches. LATER replace this
+by a more coherent (and general) invocation. */
+
+t_garray *graph_array(t_canvas *gl, t_symbol *s, t_symbol *templateargsym, t_floatarg fsize, t_floatarg fflags) {
+ int n = (int)fsize, zonset, ztype, saveit;
+ t_symbol *zarraytype;
+ t_symbol *templatesym = gensym("pd-_float_array");
+ int flags = (int)fflags;
+ int filestyle = (flags & 6)>>1;
+ int style = filestyle == 0 ? PLOTSTYLE_POLY : filestyle == 1 ? PLOTSTYLE_POINTS : filestyle;
+ if (templateargsym != &s_float) {error("%s: only 'float' type understood", templateargsym->name); return 0;}
+ t_template *t = template_findbyname(templatesym);
+ TEMPLATE_CHECK(templatesym,0)
+ if (!template_find_field(t, gensym("z"), &zonset, &ztype, &zarraytype)) {
+ error("template %s has no 'z' field", templatesym->name);
+ return 0;
+ }
+ if (ztype != DT_ARRAY) {error("template %s, 'z' field is not an array", templatesym->name); return 0;}
+ t_template *ztemplate = template_findbyname(zarraytype);
+ if (!ztemplate) {error("no template of type %s", zarraytype->name); return 0;}
+ saveit = (flags & 1) != 0;
+ t_garray *x = graph_scalar(gl, s, templatesym, saveit);
+ x->hidename = (flags>>3)&1;
+ if (n <= 0) n = 100;
+ array_resize(x->scalar->v[zonset].w_array, n);
+ template_setfloat(t, gensym("style"), x->scalar->v, style, 1);
+ template_setfloat(t, gensym("linewidth"), x->scalar->v, style==PLOTSTYLE_POINTS?2:1, 1);
+ t_pd *x2 = pd_findbyclass(gensym("#A"), garray_class);
+ if (x2) pd_unbind(x2,gensym("#A"));
+ pd_bind(x,gensym("#A"));
+ garray_redraw(x);
+ return x;
+}
+
+/* find the graph most recently added to this canvas; if none exists, return 0. */
+static t_canvas *canvas_findgraph(t_canvas *x) {
+ t_gobj *y = 0;
+ canvas_each(z,x) if (z->_class==canvas_class && ((t_canvas *)z)->gop) y = z;
+ return (t_canvas *)y;
+}
+
+/* this is called back from the dialog window to create a garray.
+ The otherflag requests that we find an existing graph to put it in. */
+static void canvas_arraydialog(t_canvas *parent, t_symbol *name, t_floatarg size, t_floatarg fflags, t_floatarg otherflag) {
+ t_canvas *gl;
+ int flags = (int)fflags;
+ if (size < 1) size = 1;
+ if (otherflag == 0 || !(gl = canvas_findgraph(parent)))
+ gl = canvas_addcanvas(parent, &s_, 0, 1, (size>1 ? size-1 : size), -1, 0, 0, 0, 0);
+ graph_array(gl, sharptodollar(name), &s_float, size, flags);
+}
+
+void garray_arrayviewlist_close(t_garray *x) {
+ x->listviewing = 0;
+ sys_vgui("pdtk_array_listview_closeWindow %s\n", x->realname->name);
+}
+
+/* this is called from the properties dialog window for an existing array */
+void garray_arraydialog(t_garray *x, t_symbol *name, t_floatarg fsize, t_floatarg fflags, t_floatarg deleteit) {
+ int flags = (int)fflags;
+ int saveit = (flags&1)!=0;
+ int style = (flags>>1)&3;
+ float stylewas = template_getfloat(template_findbyname(x->scalar->t), gensym("style"), x->scalar->v, 1);
+ if (deleteit) {canvas_delete(x->canvas,x); return;}
+ t_symbol *argname = sharptodollar(name);
+ t_array *a = garray_getarray(x);
+ t_template *scalartemplate;
+ if (!a) {error("can't find array"); return;}
+ if (!(scalartemplate = template_findbyname(x->scalar->t))) {error("no template of type %s", x->scalar->t->name); return;}
+ if (argname != x->realname) {
+ if (x->listviewing) garray_arrayviewlist_close(x);
+ x->realname = argname; /* is this line supposed to exist? */
+ pd_unbind(x,x->realname);
+ x->realname = canvas_realizedollar(x->canvas, argname);
+ pd_bind(x,x->realname);
+ gobj_changed(x,0);
+ }
+ int size = max(1,int(fsize));
+ if (size != a->n) garray_resize(x, size);
+ else if (style != stylewas) garray_fittograph(x, size, style);
+ template_setfloat(scalartemplate, gensym("style"), x->scalar->v, (float)style, 0);
+ garray_setsaveit(x, saveit!=0);
+ garray_redraw(x);
+}
+
+void garray_arrayviewlist_new(t_garray *x) {
+ char *s = x->realname->name;
+ int yonset=0, elemsize=0;
+ char cmdbuf[200];
+ t_array *a = garray_getarray_floatonly(x, &yonset, &elemsize);
+ if (!a) {error("garray_arrayviewlist_new()"); return;}
+ x->listviewing = 1;
+ sprintf(cmdbuf, "pdtk_array_listview_new %%s %s %d\n",s,0);
+ for (int i=0; i < ARRAYPAGESIZE && i < a->n; i++) {
+ float yval = *(float *)(a->vec + elemsize*i + yonset);
+ sys_vgui(".%sArrayWindow.lb insert %d {%d) %g}\n",s,i,i,yval);
+ }
+}
+
+void garray_arrayviewlist_fillpage(t_garray *x, t_float page, t_float fTopItem) {
+ char *s = x->realname->name;
+ int yonset=0, elemsize=0, topItem=(int)fTopItem;
+ t_array *a = garray_getarray_floatonly(x, &yonset, &elemsize);
+ if (!a) {error("garray_arrayviewlist_fillpage()"); return;}
+ if (page < 0) {
+ page = 0;
+ sys_vgui("pdtk_array_listview_setpage %s %d\n",s,(int)page);
+ } else if ((page * ARRAYPAGESIZE) >= a->n) {
+ page = (int)(((int)a->n - 1)/ (int)ARRAYPAGESIZE);
+ sys_vgui("pdtk_array_listview_setpage %s %d\n",s,(int)page);
+ }
+ sys_vgui(".%sArrayWindow.lb delete 0 %d\n",s,ARRAYPAGESIZE-1);
+ for (int i = (int)page * ARRAYPAGESIZE; (i < (page+1)*ARRAYPAGESIZE && i < a->n); i++) {
+ float yval = *(float *)(a->vec + elemsize*i + yonset);
+ sys_vgui(".%sArrayWindow.lb insert %d {%d) %g}\n",s,i%ARRAYPAGESIZE,i,yval);
+ }
+ sys_vgui(".%sArrayWindow.lb yview %d\n",s,topItem);
+}
+
+static void garray_free(t_garray *x) {
+ if (x->listviewing) garray_arrayviewlist_close(x);
+ pd_unbind(x,x->realname);
+ /* LATER find a way to get #A unbound earlier (at end of load?) */
+ t_pd *x2;
+ while ((x2 = pd_findbyclass(gensym("#A"), garray_class))) pd_unbind(x2, gensym("#A"));
+}
+
+/* ------------- code used by both array and plot widget functions ---- */
+
+static void array_redraw(t_array *a, t_canvas *canvas) {
+ /* what was that for? */
+ scalar_redraw(a->gp.scalar, canvas);
+}
+
+static int canvas_xtopixels(t_canvas *x, float xval);
+static int canvas_ytopixels(t_canvas *x, float yval);
+
+ /* routine to get screen coordinates of a point in an array */
+static void array_getcoordinate(t_canvas *canvas, char *elem, int xonset, int yonset, int wonset, int indx,
+float basex, float basey, float xinc, t_slot *xslot, t_slot *yslot, t_slot *wslot,
+float *xp, float *yp, float *wp) {
+ float xval, yval, ypix, wpix;
+ if (xonset >= 0) xval = *(float *)(elem + xonset); else xval = indx * xinc;
+ if (yonset >= 0) yval = *(float *)(elem + yonset); else yval = 0;
+ ypix = canvas_ytopixels(canvas, basey + slot_cvttocoord(yslot, yval));
+ if (wonset >= 0) {
+ /* found "w" field which controls linewidth. */
+ float wval = *(float *)(elem + wonset);
+ wpix = canvas_ytopixels(canvas, basey + slot_cvttocoord(yslot,yval) + slot_cvttocoord(wslot,wval)) - ypix;
+ if (wpix < 0) wpix = -wpix;
+ } else wpix = 1;
+ *xp = canvas_xtopixels(canvas, basex + slot_cvttocoord(xslot, xval));
+ *yp = ypix;
+ *wp = wpix;
+}
+
+static struct {
+ float xcumulative, ycumulative;
+ t_slot *xfield, *yfield;
+ t_canvas *canvas;
+ t_scalar *scalar;
+ t_array *array;
+ t_word *wp;
+ t_template *t;
+ int npoints, elemsize;
+ float initx, xperpix, yperpix;
+ int lastx, fatten;
+} ammo;
+
+/* LATER protect against the template changing or the scalar disappearing
+ probably by attaching a gpointer here ... */
+#if 0
+static void array_motion(void *z, t_floatarg dx, t_floatarg dy) {
+ ammo.xcumulative += dx * ammo.xperpix;
+ ammo.ycumulative += dy * ammo.yperpix;
+ if (ammo.xfield) {// xy plot
+ for (int i=0; i<ammo.npoints; i++) {
+ t_word *thisword = (t_word *)(((char *)ammo.wp) + i*ammo.elemsize);
+ float xwas = slot_getcoord(ammo.xfield, ammo.t, thisword, 1);
+ float ywas = ammo.yfield ? slot_getcoord(ammo.yfield, ammo.t, thisword, 1) : 0;
+ slot_setcoord(ammo.xfield, ammo.t, thisword, xwas + dx, 1);
+ if (ammo.yfield) {
+ if (ammo.fatten) {
+ if (i == 0) {
+ float newy = max(0.f,ywas+dy*ammo.yperpix);
+ slot_setcoord(ammo.yfield, ammo.t, thisword, newy, 1);
+ }
+ } else slot_setcoord(ammo.yfield, ammo.t, thisword, ywas + dy*ammo.yperpix, 1);
+ }
+ }
+ } else if (ammo.yfield) {// y plot
+ int thisx = int(ammo.initx + ammo.xcumulative + 0.5), x2;
+ int increment, nchange;
+ float newy = ammo.ycumulative;
+ float oldy = slot_getcoord(ammo.yfield, ammo.t, (t_word *)(((char *)ammo.wp) + ammo.elemsize * ammo.lastx), 1);
+ float ydiff = newy-oldy;
+ CLAMP(thisx,0,1);
+ increment = thisx > ammo.lastx ? -1 : 1;
+ nchange = 1 + increment * (ammo.lastx - thisx);
+ x2 = thisx;
+ for (int i=0; i<nchange; i++, x2 += increment) {
+ slot_setcoord(ammo.yfield, ammo.t, (t_word *)(((char *)ammo.wp) + ammo.elemsize * x2), newy, 1);
+ if (nchange > 1) newy -= ydiff/(nchange-1);
+ }
+ ammo.lastx = thisx;
+ }
+ if (ammo.scalar) scalar_redraw(ammo.scalar, ammo.canvas);
+ if (ammo.array) array_redraw(ammo.array, ammo.canvas);
+}
+#endif
+
+int scalar_doclick(t_word *data, t_template *t, t_scalar *sc, t_array *ap, t_canvas *owner, float xloc, float yloc,
+int xpix, int ypix, int shift, int alt, int dbl, int doit);
+
+static int array_getfields(t_symbol *elemtemplatesym, t_canvas **elemtemplatecanvasp,
+t_template **elemtemplatep, int *elemsizep, t_slot *xslot, t_slot *yslot, t_slot *wslot,
+int *xonsetp, int *yonsetp, int *wonsetp);
+
+/* try clicking on an element of the array as a scalar (if clicking
+ on the trace of the array failed) */
+static int array_doclick_element(t_array *array, t_canvas *canvas, t_scalar *sc, t_array *ap,
+t_symbol *elemtemplatesym, float linewidth, float xloc, float xinc, float yloc,
+t_slot *xfield, t_slot *yfield, t_slot *wfield, int xpix, int ypix, int shift, int alt, int dbl, int doit) {
+ t_canvas *elemtemplatecanvas;
+ t_template *elemtemplate;
+ int elemsize, yonset, wonset, xonset, incr;
+ //float xsum=0;
+ if (elemtemplatesym == &s_float) return 0;
+ if (array_getfields(elemtemplatesym, &elemtemplatecanvas,
+ &elemtemplate, &elemsize, xfield, yfield, wfield, &xonset, &yonset, &wonset))
+ return 0;
+ /* if it has more than 2000 points, just check 300 of them. */
+ if (array->n < 2000) incr=1; else incr = array->n/300;
+ for (int i=0; i < array->n; i += incr) {
+ //float usexloc = xonset>=0 ? xloc + slot_cvttocoord(xfield, *(float *)&array->vec[elemsize*i+xonset]) : xloc + xsum;
+ //if (xonset>=0) xsum += xinc;
+ //float useyloc = yloc + (yonset>=0 ? slot_cvttocoord(yfield, *(float *)&array->vec[elemsize*i+yonset]):0);
+ int hit = 0;
+ /* hit = scalar_doclick((t_word *)&array->vec[elemsize*i],
+ elemtemplate, 0, array, canvas, usexloc, useyloc, xpix, ypix, shift, alt, dbl, doit);*/
+ if (hit) return hit;
+ }
+ return 0;
+}
+
+static float canvas_pixelstox(t_canvas *x, float xpix);
+static float canvas_pixelstoy(t_canvas *x, float xpix);
+
+/* convert an X screen distance to an X coordinate increment. */
+static float canvas_dpixtodx(t_canvas*x,float dxpix){return dxpix*(canvas_pixelstox(x,1)-canvas_pixelstox(x,0));}
+static float canvas_dpixtody(t_canvas*x,float dypix){return dypix*(canvas_pixelstoy(x,1)-canvas_pixelstoy(x,0));}
+
+/* LATER move this and others back into plot parentwidget code, so
+ they can be static (look in g_canvas.h for candidates). */
+int array_doclick(t_array *array, t_canvas *canvas, t_scalar *sc, t_array *ap,
+t_symbol *elemtemplatesym, float linewidth, float xloc, float xinc, float yloc, float scalarvis,
+t_slot *xfield, t_slot *yfield, t_slot *wfield, int xpix, int ypix, int shift, int alt, int dbl, int doit) {
+ t_canvas *elemtemplatecanvas;
+ t_template *elemtemplate;
+ int elemsize, yonset, wonset, xonset;
+ if (!array_getfields(elemtemplatesym, &elemtemplatecanvas, &elemtemplate, &elemsize,
+ xfield, yfield, wfield, &xonset, &yonset, &wonset)) {
+ float best = 100;
+ /* if it has more than 2000 points, just check 1000 of them. */
+ int incr = (array->n <= 2000 ? 1 : array->n / 1000);
+ for (int i=0; i < array->n; i += incr) {
+ float pxpix, pypix, pwpix, dx, dy;
+ array_getcoordinate(canvas, &array->vec[elemsize*i], xonset, yonset, wonset, i,
+ xloc, yloc, xinc, xfield, yfield, wfield, &pxpix, &pypix, &pwpix);
+ if (pwpix < 4) pwpix = 4;
+ dx = fabs(pxpix-xpix); if (dx>8) continue;
+ dy = fabs(pypix-ypix); if (dx+dy<best) best=dx+dy;
+ if (wonset >= 0) {
+ dy = fabs(pypix+pwpix-ypix); if (dx+dy < best) best = dx+dy;
+ dy = fabs(pypix-pwpix-ypix); if (dx+dy < best) best = dx+dy;
+ }
+ } if (best > 8) {
+ if (scalarvis != 0) return array_doclick_element(array, canvas, sc, ap, elemtemplatesym,
+ linewidth, xloc, xinc, yloc, xfield, yfield, wfield, xpix, ypix, shift, alt, dbl, doit);
+ return 0;
+ }
+ best += 0.001; /* add truncation error margin */
+ for (int i=0; i < array->n; i += incr) {
+ float pxpix, pypix, pwpix, dx, dy, dy2, dy3;
+ array_getcoordinate(canvas, &array->vec[elemsize*i], xonset, yonset, wonset, i,
+ xloc, yloc, xinc, xfield, yfield, wfield, &pxpix, &pypix, &pwpix);
+ if (pwpix < 4) pwpix = 4;
+ dx = fabs(pxpix-xpix);
+ dy = fabs(pypix-ypix);
+ if (wonset >= 0) {
+ dy2 = fabs(pypix+pwpix-ypix);
+ dy3 = fabs(pypix-pwpix-ypix);
+ if (yonset < 0) dy = 100;
+ } else dy2 = dy3 = 100;
+ if (dx + dy <= best || dx + dy2 <= best || dx + dy3 <= best) {
+ if (dy<dy2 && dy<dy3) ammo.fatten = 0;
+ else if (dy2<dy3) ammo.fatten = -1;
+ else ammo.fatten = 1;
+ if (doit) {
+ char *elem = array->vec;
+ ammo.elemsize = elemsize;
+ ammo.canvas = canvas;
+ ammo.scalar = sc;
+ ammo.array = ap;
+ ammo.t = elemtemplate;
+ ammo.xperpix = canvas_dpixtodx(canvas, 1);
+ ammo.yperpix = canvas_dpixtody(canvas, 1);
+ if (alt && xpix < pxpix) { /* delete a point */
+ if (array->n <= 1) return 0;
+ memmove(&array->vec[elemsize*i], &array->vec[elemsize*(i+1)], (array->n-1-i) * elemsize);
+ array_resize_and_redraw(array, array->n - 1);
+ return 0;
+ } else if (alt) {
+ /* add a point (after the clicked-on one) */
+ array_resize_and_redraw(array, array->n + 1);
+ elem = array->vec;
+ memmove(elem + elemsize * (i+1), elem + elemsize*i, (array->n-i-1) * elemsize);
+ i++;
+ }
+ if (xonset >= 0) {
+ ammo.xfield = xfield;
+ ammo.xcumulative = slot_getcoord(xfield,ammo.t,(t_word *)(elem+elemsize*i),1);
+ ammo.wp = (t_word *)(elem + elemsize*i);
+ if (shift) ammo.npoints = array->n - i;
+ else ammo.npoints = 1;
+ } else {
+ ammo.xfield = 0;
+ ammo.xcumulative = 0;
+ ammo.wp = (t_word *)elem;
+ ammo.npoints = array->n;
+ ammo.initx = i;
+ ammo.lastx = i;
+ ammo.xperpix *= (xinc == 0 ? 1 : 1./xinc);
+ }
+ if (ammo.fatten) {
+ ammo.yfield = wfield;
+ ammo.ycumulative = slot_getcoord(wfield,ammo.t,(t_word *)(elem+elemsize*i),1);
+ ammo.yperpix *= -ammo.fatten;
+ } else if (yonset >= 0) {
+ ammo.yfield = yfield;
+ ammo.ycumulative = slot_getcoord(yfield,ammo.t,(t_word *)(elem+elemsize*i),1);
+ } else {
+ ammo.yfield = 0;
+ ammo.ycumulative = 0;
+ }
+ /* canvas_grab(canvas, 0, array_motion, 0, xpix, ypix); */
+ }
+ return 0;
+ }
+ }
+ }
+ return 0;
+}
+
+static void garray_save(t_gobj *z, t_binbuf *b) {
+ t_garray *x = (t_garray *)z;
+ t_array *array = garray_getarray(x);
+ t_template *scalartemplate;
+ /* LATER "save" the scalar as such */
+ if (x->scalar->t != gensym("pd-_float_array")) {error("can't save arrays of type %s yet", x->scalar->t->name); return;}
+ if (!(scalartemplate = template_findbyname(x->scalar->t))) {error("no template of type %s", x->scalar->t->name); return;}
+ int style = (int)template_getfloat(scalartemplate, gensym("style"), x->scalar->v, 0);
+ int filestyle = (style == PLOTSTYLE_POINTS ? 1 : (style == PLOTSTYLE_POLY ? 0 : style));
+ binbuf_addv(b, "ttsisi;","#X","array", x->realname, array->n, &s_float, x->saveit+2*filestyle+8*x->hidename);
+ if (x->saveit) {
+ int n = array->n, n2 = 0;
+ while (n2 < n) {
+ int chunk = imin(n-n2,1000);
+ binbuf_addv(b,"ti","#A",n2);
+ for (int i=0; i<chunk; i++) binbuf_addv(b, "f", ((float *)array->vec)[n2+i]);
+ binbuf_addv(b, ";");
+ n2 += chunk;
+ }
+ }
+}
+
+/* required by d_array.c and d_soundfile */
+void garray_redraw(t_garray *x) {gobj_changed(x,0);}
+
+/* those three required by d_array.c */
+void garray_usedindsp(t_garray *x) {x->usedindsp = 1;}
+int garray_npoints(t_garray *x) {return garray_getarray(x)->n;} /* get the length */
+char *garray_vec(t_garray *x) {return (char *)garray_getarray(x)->vec;} /* get the contents */
+
+/* routine that checks if we're just an array of floats and if so returns the goods */
+int garray_getfloatarray(t_garray *x, int *size, t_float **vec) {
+ int yonset, elemsize;
+ t_array *a = garray_getarray_floatonly(x, &yonset, &elemsize);
+ TEMPLATE_FLOATY(a,0)
+ if (elemsize != sizeof(t_word)) {error("%s: has more than one field", x->realname); return 0;}
+ *size = garray_npoints(x);
+ *vec = (float *)garray_vec(x);
+ return 1;
+}
+
+/* set the "saveit" flag */
+void garray_setsaveit(t_garray *x, int saveit) {
+ if (x->saveit && !saveit) post("warning: array %s: clearing save-in-patch flag", x->realname->name);
+ x->saveit = saveit;
+}
+
+static void garray_const(t_garray *x, t_floatarg g) {
+ int yonset, elemsize;
+ t_array *array = garray_getarray_floatonly(x, &yonset, &elemsize);
+ TEMPLATE_FLOATY(array,)
+ for (int i=0; i<array->n; i++) *((float *)(array->vec + elemsize*i) + yonset) = g;
+ garray_redraw(x);
+}
+
+/* sum of Fourier components; called from functions below */
+static void garray_dofo(t_garray *x, int npoints, float dcval, int nsin, t_float *vsin, int sineflag) {
+ double phase, fj;
+ int yonset, i, j, elemsize;
+ t_array *array = garray_getarray_floatonly(x, &yonset, &elemsize);
+ TEMPLATE_FLOATY(array,)
+ if (npoints == 0) npoints = 512; /* dunno what a good default would be... */
+ if (npoints != (1 << ilog2(npoints)))
+ post("%s: rounnding to %d points", array->templatesym->name, (npoints = (1<<ilog2(npoints))));
+ garray_resize(x, npoints + 3);
+ double phaseincr = 2. * 3.14159 / npoints;
+ for (i=0, phase = -phaseincr; i < array->n; i++, phase += phaseincr) {
+ double sum = dcval;
+ if (sineflag) for (j=0, fj=phase; j<nsin; j++, fj+=phase) sum += vsin[j] * sin(fj);
+ else for (j=0, fj= 0; j<nsin; j++, fj+=phase) sum += vsin[j] * cos(fj);
+ *((float *)(array->vec + elemsize*i) + yonset) = sum;
+ }
+ garray_redraw(x);
+}
+
+static void garray_sinesum(t_garray *x, t_symbol *s, int argc, t_atom *argv) {
+ if (argc < 2) {error("%s: need number of points and partial strengths", x->realname->name); return;}
+ t_float *svec = (t_float *)getbytes(sizeof(t_float) * argc);
+ int npoints = atom_getintarg(0,argc--,argv++);
+ argv++, argc--; /* is it normal that this happens a second time? */
+ for (int i=0; i < argc; i++) svec[i] = atom_getfloatarg(i, argc, argv);
+ garray_dofo(x, npoints, 0, argc, svec, 1);
+ free(svec);
+}
+static void garray_cosinesum(t_garray *x, t_symbol *s, int argc, t_atom *argv) {
+ if (argc < 2) {error("%s: need number of points and partial strengths", x->realname->name); return;}
+ t_float *svec = (t_float *)getbytes(sizeof(t_float) * argc);
+ int npoints = atom_getintarg(0,argc--,argv++);
+ for (int i=0; i < argc; i++) svec[i] = atom_getfloatarg(i, argc, argv);
+ garray_dofo(x, npoints, 0, argc, svec, 0);
+ free(svec);
+}
+
+static void garray_normalize(t_garray *x, t_float f) {
+ double maxv=0;
+ int yonset, elemsize;
+ t_array *array = garray_getarray_floatonly(x, &yonset, &elemsize);
+ TEMPLATE_FLOATY(array,)
+ if (f <= 0) f = 1;
+ for (int i=0; i < array->n; i++) {
+ double v = *((float *)(array->vec + elemsize*i) + yonset);
+ if ( v > maxv) maxv = v;
+ if (-v > maxv) maxv = -v;
+ }
+ if (maxv > 0) {
+ double renormer = f/maxv;
+ for (int i=0; i < array->n; i++) *((float *)(array->vec + elemsize*i) + yonset) *= renormer;
+ }
+ garray_redraw(x);
+}
+
+/* list: the first value is an index; subsequent values are put in the "y" slot of the array. */
+static void garray_list(t_garray *x, t_symbol *s, int argc, t_atom *argv) {
+ int yonset, elemsize;
+ t_array *array = garray_getarray_floatonly(x, &yonset, &elemsize);
+ TEMPLATE_FLOATY(array,)
+ if (argc < 2) return;
+ else {
+ int firstindex = atom_getintarg(0,argc--,argv++);
+ if (firstindex < 0) { /* drop negative x values */
+ argc += firstindex;
+ argv -= firstindex;
+ firstindex = 0;
+ }
+ if (argc + firstindex > array->n) argc = array->n - firstindex;
+ for (int i=0; i < argc; i++)
+ *((float *)(array->vec + elemsize * (i + firstindex)) + yonset) = atom_getfloat(argv + i);
+ }
+ garray_redraw(x);
+}
+
+static void garray_bounds(t_garray *x, t_floatarg x1, t_floatarg y1, t_floatarg x2, t_floatarg y2)
+{vmess(x->canvas, gensym("bounds"), "ffff", x1, y1, x2, y2);}
+static void garray_xticks(t_garray *x, t_floatarg point, t_floatarg inc, t_floatarg f)
+{vmess(x->canvas, gensym("xticks"), "fff", point, inc, f);}
+static void garray_yticks(t_garray *x, t_floatarg point, t_floatarg inc, t_floatarg f)
+{vmess(x->canvas, gensym("yticks"), "fff", point, inc, f);}
+static void garray_xlabel(t_garray *x, t_symbol *s, int argc, t_atom *argv) {typedmess(x->canvas, s, argc, argv);}
+static void garray_ylabel(t_garray *x, t_symbol *s, int argc, t_atom *argv) {typedmess(x->canvas, s, argc, argv);}
+
+static void garray_rename(t_garray *x, t_symbol *s) {
+ if (x->listviewing) garray_arrayviewlist_close(x);
+ pd_unbind(x,x->realname);
+ x->realname = s;
+ pd_bind(x,x->realname);
+ garray_redraw(x);
+}
+
+static void garray_read(t_garray *x, t_symbol *filename) {
+ FILE *fd;
+ char *buf, *bufptr;
+ int yonset, elemsize;
+ t_array *array = garray_getarray_floatonly(x, &yonset, &elemsize);
+ TEMPLATE_FLOATY(array,)
+ int nelem = array->n;
+ int filedesc = canvas_open2(canvas_getcanvas(x->canvas), filename->name, "", &buf, &bufptr, 0);
+ if (filedesc<0) {error("%s: can't open", filename->name); free(buf); return;}
+ if (!(fd = fdopen(filedesc, "r"))) {error("%s: can't open", filename->name); free(buf); return;}
+ int i;
+ for (i=0; i < nelem; i++) {
+ if (!fscanf(fd, "%f", (float *)(array->vec + elemsize*i) + yonset)) {
+ post("%s: read %d elements into table of size %d", filename->name, i, nelem);
+ break;
+ }
+ }
+ while (i < nelem) *((float *)(array->vec + elemsize*i) + yonset) = 0, i++;
+ fclose(fd);
+ garray_redraw(x);
+ free(buf);
+}
+
+static void garray_write(t_garray *x, t_symbol *filename) {
+ int yonset, elemsize;
+ t_array *array = garray_getarray_floatonly(x, &yonset, &elemsize);
+ TEMPLATE_FLOATY(array,)
+ char *buf = canvas_makefilename(canvas_getcanvas(x->canvas),filename->name,0,0);
+ sys_bashfilename(buf, buf);
+ FILE *fd = fopen(buf, "w");
+ if (!fd) {error("can't create file '%s'", buf); free(buf); return;}
+ free(buf);
+ for (int i=0; i < array->n; i++) {
+ if (fprintf(fd, "%g\n", *(float *)(((array->vec + sizeof(t_word) * i)) + yonset)) < 1) {
+ post("%s: write error", filename->name);
+ break;
+ }
+ }
+ fclose(fd);
+}
+
+/* d_soundfile.c uses this! */
+int garray_ambigendian () {
+ unsigned short s = 1;
+ unsigned char c = *(char *)(&s);
+ return c==0;
+}
+
+/* d_soundfile.c uses this! */
+void garray_resize(t_garray *x, t_floatarg f) {
+ t_array *array = garray_getarray(x);
+ int n = f<1?1:(int)f;
+ garray_fittograph(x, n, (int)template_getfloat(template_findbyname(x->scalar->t), gensym("style"), x->scalar->v, 1));
+ array_resize_and_redraw(array, n);
+ if (x->usedindsp) canvas_update_dsp();
+}
+
+static void garray_print(t_garray *x) {
+ t_array *array = garray_getarray(x);
+ post("garray %s: template %s, length %d", x->realname->name, array->templatesym->name, array->n);
+}
+
+static void g_array_setup() {
+ t_class *c = garray_class = class_new2("array",0,garray_free,sizeof(t_garray),CLASS_GOBJ,"");
+ class_addlist(garray_class, garray_list);
+ class_addmethod2(c, garray_const, "const", "F");
+ class_addmethod2(c, garray_bounds, "bounds", "ffff");
+ class_addmethod2(c, garray_xticks, "xticks", "fff");
+ class_addmethod2(c, garray_xlabel, "xlabel", "*");
+ class_addmethod2(c, garray_yticks, "yticks", "fff");
+ class_addmethod2(c, garray_ylabel, "ylabel", "*");
+ class_addmethod2(c, garray_rename, "rename", "s");
+ class_addmethod2(c, garray_read, "read", "s");
+ class_addmethod2(c, garray_write, "write", "s");
+ class_addmethod2(c, garray_resize, "resize", "f");
+ class_addmethod2(c, garray_print, "print", "");
+ class_addmethod2(c, garray_sinesum, "sinesum", "*");
+ class_addmethod2(c, garray_cosinesum, "cosinesum", "*");
+ class_addmethod2(c, garray_normalize, "normalize", "F");
+ class_addmethod2(c, garray_arraydialog, "arraydialog", "sfff");
+ class_addmethod2(c, garray_arrayviewlist_new, "arrayviewlistnew", "");
+ class_addmethod2(c, garray_arrayviewlist_fillpage, "arrayviewlistfillpage", "fF");
+ class_addmethod2(c, garray_arrayviewlist_close, "arrayviewclose", "");
+ class_setsavefn(c, garray_save);
+ array_class = class_new2("array_really",0,array_free,sizeof(t_array),CLASS_GOBJ,"");
+}
+
+static void graph_graphrect(t_gobj *z, t_canvas *canvas, int *xp1, int *yp1, int *xp2, int *yp2);
+
+void canvas_add_debug(t_canvas *x, t_gobj *y) {
+ if (!y->_class->patchable) {
+ printf("canvas_add %p %p class=%s (non-t_text)\n",x,y,y->_class->name->name);
+ } else {
+ t_binbuf *bb = ((t_text *)y)->binbuf;
+ if (binbuf_getvec(bb)) {
+ char *buf; int bufn;
+ binbuf_gettext(bb,&buf,&bufn);
+ printf("canvas_add %p %p [%.*s]\n",x,y,bufn,buf);
+ free(buf);
+ } else {
+ printf("canvas_add %p %p class=%s (binbuf without b_vec !)\n",x,y,y->_class->name->name);
+ }
+ }
+}
+
+void canvas_add(t_canvas *x, t_gobj *y, int index) {
+ gobj_setcanvas(y,x);
+ if (index<0) y->dix->index = x->next_o_index++;
+ else y->dix->index = index;
+ x->boxes->add(y);
+ if (x->gop && !x->goprect && pd_checkobject(y)) SET(goprect,1);
+ //if (class_isdrawcommand(y->_class)) canvas_redrawallfortemplate(template_findbyname(canvas_makebindsym(canvas_getcanvas(x)->name)), 0);
+}
+
+/* delete an object from a canvas and free it */
+void canvas_delete(t_canvas *x, t_gobj *y) {
+ bool chkdsp = !!zgetfn(y,gensym("dsp"));
+ //int drawcommand = class_isdrawcommand(y->_class);
+ /* if we're a drawing command, erase all scalars now, before deleting it; we'll redraw them once it's deleted below. */
+ //if (drawcommand) canvas_redrawallfortemplate(template_findbyname(canvas_makebindsym(canvas_getcanvas(x)->name)), 2);
+ canvas_deletelinesfor(x,(t_text *)y);
+ x->boxes->remove_by_value(y);
+ /* BUG: should call gobj_onsubscribe here, to flush the zombie */
+ pd_free(y);
+ if (chkdsp) canvas_update_dsp();
+ //if (drawcommand) canvas_redrawallfortemplate(template_findbyname(canvas_makebindsym(canvas_getcanvas(x)->name)), 1);
+}
+
+static void canvas_clear(t_canvas *x) {
+ t_gobj *y;
+ int dspstate = 0, suspended = 0;
+ t_symbol *dspsym = gensym("dsp");
+ /* to avoid unnecessary DSP resorting, we suspend DSP only if we find a DSP object. */
+ canvas_each(y,x) if (!suspended && pd_checkobject(y) && zgetfn(y,dspsym)) {dspstate = canvas_suspend_dsp(); suspended=1;}
+ while ((y = x->boxes->first())) x->boxes->remove_by_value(y);
+ if (suspended) canvas_resume_dsp(dspstate);
+}
+
+
+t_canvas *canvas_getcanvas(t_canvas *x) {
+ while (x->dix->canvas && !x->havewindow && x->gop) x = x->dix->canvas;
+ return x;
+}
+
+static void scalar_getbasexy(t_scalar *x, float *basex, float *basey);
+
+static float gobj_getxforsort(t_gobj *g) {
+ if (g->_class!=scalar_class) return 0;
+ float x1, y1;
+ scalar_getbasexy((t_scalar *)g, &x1, &y1);
+ return x1;
+}
+
+static t_gobj *canvas_merge(t_canvas *x, t_gobj *g1, t_gobj *g2) {
+/*
+ t_gobj *g = 0, *g9 = 0;
+ float f1 = g1 ? gobj_getxforsort(g1) : 0;
+ float f2 = g2 ? gobj_getxforsort(g2) : 0;
+ while (1) {
+ if (g1 && !(g2 && f1>f2)) {
+ if (g9) {g9->g_next = g1; g9 = g1;} else g9 = g = g1;
+ if ((g1 = g1->next())) f1 = gobj_getxforsort(g1);
+ g9->g_next = 0;
+ continue;
+ }
+ if (g1 || g2) {
+ if (g9) {g9->g_next = g2; g9 = g2;} else g9 = g = g2;
+ if ((g2 = g2->next())) f2 = gobj_getxforsort(g2);
+ g9->g_next = 0;
+ continue;
+ }
+ break;
+ }
+ return g;
+*/
+}
+
+/*
+static t_gobj *canvas_dosort(t_canvas *x, t_gobj *g, int nitems) {
+ t_gobj *g2, *g3;
+ int n1 = nitems/2, n2 = nitems - n1, i;
+ if (nitems < 2) return g;
+ int i=n1-1;
+ for (g2 = g; i--; g2 = g2->next()) {}
+ g3 = g2->next();
+ g2->g_next = 0;
+ g = canvas_dosort(x, g, n1);
+ g3 = canvas_dosort(x, g3, n2);
+ return canvas_merge(x, g, g3);
+}
+
+void canvas_sort(t_canvas *x) {
+ int nitems = 0, foo = 0;
+ float lastx = -1e37;
+ canvas_each(g,x) {
+ float x1 = gobj_getxforsort(g);
+ if (x1 < lastx) foo = 1;
+ lastx = x1;
+ nitems++;
+ }
+ if (foo) x->list = canvas_dosort(x, x->list, nitems);
+}
+*/
+
+static t_inlet *canvas_addinlet(t_canvas *x, t_pd *who, t_symbol *s, t_symbol* h) {
+ t_inlet *ip = inlet_new(x,who,s,0); inlet_settip(ip,h);
+ if (gstack_empty()) canvas_resortinlets(x);
+ gobj_changed(x,0); return ip;
+}
+static t_outlet *canvas_addoutlet(t_canvas *x, t_pd *who, t_symbol *s) {
+ t_outlet *op = outlet_new(x,s);
+ if (gstack_empty()) canvas_resortoutlets(x);
+ gobj_changed(x,0); return op;
+}
+
+static void canvas_rminlet(t_canvas *x, t_inlet *ip) {
+ if (x->dix->canvas) canvas_deletelinesforio(x->dix->canvas,x,ip,0);
+ inlet_free(ip); /*gobj_changed(x,0);*/
+}
+static void canvas_rmoutlet(t_canvas *x, t_outlet *op) {
+ if (x->dix->canvas) canvas_deletelinesforio(x->dix->canvas,x,0,op);
+ outlet_free(op); /*gobj_changed(x,0);*/
+}
+
+extern "C" t_inlet *vinlet_getit(t_pd *x);
+extern "C" t_outlet *voutlet_getit(t_pd *x);
+
+typedef int (*t_order)(const void *, const void *);
+int gobj_order_x (t_object **a, t_object **b) {return (*a)->x - (*b)->x;}
+
+//{std::ostringstream s; s<<"disorder:"; for (int i=0; i<n; i++) s<<" "<<vec[i]->x; post("%s",s.str().data());}
+
+void obj_moveinletfirst(t_object *x, t_inlet *i);
+void obj_moveoutletfirst(t_object *x, t_outlet *o);
+
+static void canvas_resortinlets(t_canvas *x) {
+ int n=0; canvas_each(y,x) if (y->_class==vinlet_class) n++;
+ t_object **vec = new t_object *[n], **vp = vec;
+ canvas_each(y,x) if (y->_class==vinlet_class) *vp++ = (t_object *)y;
+ qsort(vec,n,sizeof(t_object *),(t_order)gobj_order_x);
+ for (int i=n; i--;) obj_moveinletfirst(x,vinlet_getit(vec[i]));
+ delete[] vec;
+}
+static void canvas_resortoutlets(t_canvas *x) {
+ int n=0; canvas_each(y,x) if (y->_class==voutlet_class) n++;
+ t_object **vec = new t_object *[n], **vp = vec;
+ canvas_each(y,x) if (y->_class==voutlet_class) *vp++ = (t_object *)y;
+ qsort(vec,n,sizeof(t_object *),(t_order)gobj_order_x);
+ for (int i=n; i--;) obj_moveoutletfirst(x,voutlet_getit(vec[i]));
+ delete[] vec;
+}
+
+static void graph_bounds(t_canvas *x, t_floatarg x1, t_floatarg y1, t_floatarg x2, t_floatarg y2) {
+ x->x1 = x1; x->y1 = y1;
+ x->x2 = x2; x->y2 = y2;
+ if (x->x2 == x->x1 || x->y2 == x->y1) {
+ error("empty bounds rectangle");
+ x->x1 = x->y1 = 0;
+ x->x2 = x->y2 = 1;
+ }
+ gobj_changed(x,0);
+}
+
+static void graph_xticks(t_canvas *x, t_floatarg point, t_floatarg inc, t_floatarg f)
+{t_tick *t = &x->xtick; t->point = point; t->inc = inc; t->lperb = (int)f; gobj_changed(x,"xticks");}
+static void graph_yticks(t_canvas *x, t_floatarg point, t_floatarg inc, t_floatarg f)
+{t_tick *t = &x->ytick; t->point = point; t->inc = inc; t->lperb = (int)f; gobj_changed(x,"yticks");}
+
+static void graph_xlabel(t_canvas *x, t_symbol *s, int argc, t_atom *argv) {
+ if (argc < 1) {error("graph_xlabel: no y value given"); return;}
+ x->xlabely = atom_getfloatarg(0,argc--,argv++);
+ x->xlabel = (t_symbol **)realloc(x->xlabel,argc*sizeof(void*));
+ x->nxlabels = argc;
+ for (int i=0; i < argc; i++) x->xlabel[i] = atom_gensym(&argv[i]);
+ gobj_changed(x,"xlabel");
+}
+static void graph_ylabel(t_canvas *x, t_symbol *s, int argc, t_atom *argv) {
+ if (argc < 1) {error("graph_ylabel: no x value given"); return;}
+ x->ylabelx = atom_getfloatarg(0,argc--,argv++);
+ x->ylabel = (t_symbol **)realloc(x->ylabel,argc*sizeof(void*));
+ x->nylabels = argc;
+ for (int i=0; i < argc; i++) x->ylabel[i] = atom_gensym(&argv[i]);
+ gobj_changed(x,"ylabel");
+}
+
+/* if we appear as a text box on parent, our range in our coordinates (x1, etc.)
+ specifies the coordinate range of a one-pixel square at top left of the window.
+ if we're a graph when shown on parent, but own our own window right now, our range
+ in our coordinates (x1, etc.) is spread over the visible window size, given by screenx1, etc.
+ otherwise, we appear in a graph within a parent canvas, so get our screen rectangle on parent and transform. */
+static float canvas_pixelstox(t_canvas *x, float xpix) {
+ int x1, y1, x2, y2; float width = x->x2-x->x1;
+ if (!x->gop) return x->x1 + width * xpix;
+ if (x->havewindow) return x->x1 + width * xpix / (x->screenx2-x->screenx1);
+ graph_graphrect(x, x->dix->canvas, &x1, &y1, &x2, &y2);
+ return x->x1 + width * (xpix-x1) / (x2-x1);
+}
+static float canvas_pixelstoy(t_canvas *x, float ypix) {
+ int x1, y1, x2, y2; float height = x->y2-x->y1;
+ if (!x->gop) return x->y1 + height * ypix;
+ if (x->havewindow) return x->y1 + height * ypix / (x->screeny2-x->screeny1);
+ graph_graphrect(x, x->dix->canvas, &x1, &y1, &x2, &y2);
+ return x->y1 + height * (ypix-y1) / (y2-y1);
+}
+
+/* convert an x coordinate value to an x pixel location in window */
+static int canvas_xtopixels(t_canvas *x, float xval) {
+ int x1, y1, x2, y2; float width = x->x2-x->x1;
+ if (!x->gop) return int((xval-x->x1)/width);
+ if (x->havewindow) return int((x->screenx2-x->screenx1) * (xval-x->x1) / width);
+ graph_graphrect(x, x->dix->canvas, &x1, &y1, &x2, &y2);
+ return int(x1 + (x2-x1) * (xval-x->x1) / width);
+}
+static int canvas_ytopixels(t_canvas *x, float yval) {
+ int x1, y1, x2, y2; float height = x->y2-x->y1;
+ if (!x->gop) return int((yval-x->y1)/height);
+ if (x->havewindow) return int((x->screeny2-x->screeny1) * (yval-x->y1) / height);
+ graph_graphrect(x, x->dix->canvas, &x1, &y1, &x2, &y2);
+ return int(y1 + (y2-y1) * (yval-x->y1) / height);
+}
+
+/* --------------------------- widget behavior ------------------- */
+/* don't remove this code yet: has to be rewritten in tcl */
+#if 1
+#define FONT "pourier"
+static void graph_vis(t_gobj *gr, int vis) {
+ t_canvas *x = (t_canvas *)gr;
+ t_canvas *c = canvas_getcanvas(x->dix->canvas);
+ char tag[50];
+ int x1=69, y1=69, x2=69, y2=69;
+ sprintf(tag, "graph%lx", (t_int)x);
+ if (vis) {
+ sys_mgui(x,"ninlets=","i",0/*obj_ninlets(x)*/);
+ sys_mgui(x,"noutlets=","i",0/*obj_noutlets(x)*/);
+ }
+ /* if we look like a graph but have been moved to a toplevel, just show the bounding rectangle */
+ if (x->havewindow) {
+ /*if (vis) sys_vgui(".x%lx.c create polygon %d %d %d %d %d %d %d %d %d %d -tags %s -fill #c0c0c0\n",
+ (long)c, x1, y1, x1, y2, x2, y2, x2, y1, x1, y1, tag);*/
+ return;
+ }
+ /* draw a rectangle around the graph */
+ sys_vgui(".x%lx.c create line %d %d %d %d %d %d %d %d %d %d -tags %s\n",
+ (long)c, x1, y1, x1, y2, x2, y2, x2, y1, x1, y1, tag);
+ /* if there's just one "garray" in the graph, write its name along the top */
+ int i = min(y1,y2)-1;
+ t_symbol *arrayname;
+ canvas_each(g,x) if (g->g_pd == garray_class && !garray_getname((t_garray *)g, &arrayname)) {
+ // i -= sys_fontheight(glist_getfont(x));
+ sys_vgui(".x%lx.c create text %d %d -text {%s} -anchor nw\
+ -font -*-courier-bold--normal--%d-* -tags %s\n",
+ (long)canvas_getcanvas(x), x1, i, arrayname->name,
+ 42/*sys_hostfontsize(canvas_getfont(x))*/, tag);
+ }
+
+ /* draw ticks on horizontal borders. If lperb field is zero, this is disabled. */
+ #define DRAWTICK(x1,y1,x2,y2) sys_vgui(".x%lx.c create line %d %d %d %d -tags %s\n", \
+ (long)c, int(x1),int(y1),int(x2),int(y2),tag)
+ float f;
+ if (x->xtick.lperb) {
+ float upix, lpix;
+ if (y2<y1) {upix = y1; lpix = y2;}
+ else {upix = y2; lpix = y1;}
+ for (i=0,f=x->xtick.point; f<0.99*x->x2+0.01*x->x1; i++, f+=x->xtick.inc) {
+ int tickpix = i%x->xtick.lperb?2:4, x0 = canvas_xtopixels(x,f);
+ DRAWTICK(x0,upix,x0,upix-tickpix);
+ DRAWTICK(x0,lpix,x0,lpix+tickpix);
+ }
+ for (i=1,f=x->xtick.point-x->xtick.inc; f>0.99*x->x1+0.01*x->x2; i++,f-=x->xtick.inc) {
+ int tickpix = i%x->xtick.lperb?2:4, x0 = canvas_xtopixels(x,f);
+ DRAWTICK(x0,upix,x0,upix-tickpix);
+ DRAWTICK(x0,lpix,x0,lpix+tickpix);
+ }
+ }
+ /* draw ticks in vertical borders*/
+ if (x->ytick.lperb) {
+ float ubound, lbound;
+ if (x->y2<x->y1) {ubound = x->y1; lbound = x->y2;}
+ else {ubound = x->y2; lbound = x->y1;}
+ for (i=0,f=x->ytick.point; f<0.99*ubound+0.01*lbound; i++, f += x->ytick.inc) {
+ int tickpix = i%x->ytick.lperb?2:4, y0 = canvas_ytopixels(x,f);
+ DRAWTICK(x1,y0,x1+tickpix,y0);
+ DRAWTICK(x2,y0,x2-tickpix,y0);
+ }
+ for (i=1,f=x->ytick.point-x->ytick.inc; f>0.99*lbound+0.01*ubound; i++,f-=x->ytick.inc) {
+ int tickpix = i%x->ytick.lperb?2:4, y0 = canvas_ytopixels(x,f);
+ DRAWTICK(x1,y0,x1+tickpix,y0);
+ DRAWTICK(x2,y0,x2-tickpix,y0);
+ }
+ }
+ /* draw labels */
+ #define DRAWLABEL(x1,y1) sys_vgui(".x%lx.c create text %d %d -text {%s} -font "FONT" -tags %s\n", (long)c, \
+ int(canvas_xtopixels(x,x1)),int(canvas_ytopixels(x,y1)),s,42,tag);
+ for (int i=0; i < x->nxlabels; i++) {char *s = x->xlabel[i]->name; DRAWLABEL(atof(s),x->xlabely);}
+ for (int i=0; i < x->nylabels; i++) {char *s = x->ylabel[i]->name; DRAWLABEL(x->ylabelx,atof(s));}
+}
+#endif
+
+static int text_xpix(t_text *x, t_canvas *canvas) {
+ float width = canvas->x2-canvas->x1;
+ if (canvas->havewindow || !canvas->gop) return x->x;
+ if (canvas->goprect) return canvas->x+x->x-canvas->xmargin;
+ return canvas_xtopixels(canvas, canvas->x1 + width * x->x / (canvas->screenx2-canvas->screenx1));
+}
+static int text_ypix(t_text *x, t_canvas *canvas) {
+ float height = canvas->y2-canvas->y1;
+ if (canvas->havewindow || !canvas->gop) return x->y;
+ if (canvas->goprect) return canvas->y+x->y-canvas->ymargin;
+ return canvas_ytopixels(canvas, canvas->y1 + height* x->y / (canvas->screeny2-canvas->screeny1));
+}
+static void graph_graphrect(t_gobj *z, t_canvas *canvas, int *xp1, int *yp1, int *xp2, int *yp2) {
+ t_canvas *x = (t_canvas *)z;
+ *xp1 = text_xpix(x,canvas); *xp2 = *xp1+x->pixwidth;
+ *yp1 = text_ypix(x,canvas); *yp2 = *yp1+x->pixheight;
+}
+
+#if 1
+static float graph_lastxpix, graph_lastypix;
+static void graph_motion(void *z, t_floatarg dx, t_floatarg dy) {
+ t_canvas *x = (t_canvas *)z;
+ float newxpix = graph_lastxpix + dx, newypix = graph_lastypix + dy;
+ t_garray *a = (t_garray *)x->boxes->first();
+ int oldx = int(0.5 + canvas_pixelstox(x, graph_lastxpix));
+ int newx = int(0.5 + canvas_pixelstox(x, newxpix));
+ float oldy = canvas_pixelstoy(x, graph_lastypix);
+ float newy = canvas_pixelstoy(x, newypix);
+ graph_lastxpix = newxpix;
+ graph_lastypix = newypix;
+ // verify that the array is OK
+ if (!a || a->_class != garray_class) return;
+ int nelem;
+ t_float *vec;
+ if (!garray_getfloatarray(a, &nelem, &vec)) return;
+ if (oldx < 0) oldx = 0; else if (oldx >= nelem) oldx = nelem - 1;
+ if (newx < 0) newx = 0; else if (newx >= nelem) newx = nelem - 1;
+ if (oldx < newx - 1) {for (int i=oldx+1; i<=newx; i++) vec[i] = newy + (oldy-newy) * float(newx-i)/float(newx - oldx);}
+ else if (oldx > newx + 1) {for (int i=oldx-1; i>=newx; i--) vec[i] = newy + (oldy-newy) * float(newx-i)/float(newx - oldx);}
+ else vec[newx] = newy;
+ garray_redraw(a);
+}
+#endif
+
+/* functions to read and write canvases to files: canvas_savetofile() writes a root canvas to a "pd" file.
+ (Reading "pd" files is done simply by passing the contents to the pd message interpreter.)
+ Alternatively, the glist_read() and glist_write() functions read and write "data" from and to files
+ (reading reads into an existing canvas), using a file format as in the dialog window for data. */
+static t_class *declare_class;
+void canvas_savedeclarationsto(t_canvas *x, t_binbuf *b);
+
+/* the following functions read "scalars" from a file into a canvas. */
+static int canvas_scanbinbuf(int natoms, t_atom *vec, int *p_indexout, int *p_next) {
+ int i;
+ int indexwas = *p_next;
+ *p_indexout = indexwas;
+ if (indexwas >= natoms) return 0;
+ for (i = indexwas; i < natoms && vec[i].a_type != A_SEMI; i++) {}
+ if (i >= natoms) *p_next = i; else *p_next = i+1;
+ return i-indexwas;
+}
+static int canvas_readscalar(t_canvas *x, int natoms, t_atom *vec, int *p_nextmsg, int selectit);
+static void canvas_readerror(int natoms, t_atom *vec, int message, int nline, char *s) {
+ error(s);
+ startpost("line was:");
+ postatom(nline, vec + message);
+ endpost();
+}
+
+/* fill in the contents of the scalar into the vector w. */
+static void canvas_readatoms(t_canvas *x, int natoms, t_atom *vec,
+int *p_nextmsg, t_symbol *templatesym, t_word *w, int argc, t_atom *argv) {
+ t_template *t = template_findbyname(templatesym);
+ if (!t) {
+ error("%s: no such template", templatesym->name);
+ *p_nextmsg = natoms;
+ return;
+ }
+ word_restore(w, t, argc, argv);
+ int n = t->n;
+ for (int i=0; i<n; i++) {
+ if (t->vec[i].type == DT_ARRAY) {
+ t_array *a = w[i].w_array;
+ int elemsize = a->elemsize, nitems = 0;
+ t_symbol *arraytemplatesym = t->vec[i].arraytemplate;
+ t_template *arraytemplate = template_findbyname(arraytemplatesym);
+ if (!arraytemplate) error("%s: no such template", arraytemplatesym->name);
+ else while (1) {
+ int message;
+ t_word *element;
+ int nline = canvas_scanbinbuf(natoms, vec, &message, p_nextmsg);
+ /* empty line terminates array */
+ if (!nline) break;
+ array_resize(a, nitems + 1);
+ element = (t_word *)&a->vec[nitems*elemsize];
+ canvas_readatoms(x, natoms, vec, p_nextmsg, arraytemplatesym, element, nline, vec + message);
+ nitems++;
+ }
+ } else if (t->vec[i].type == DT_CANVAS) {
+ while (1) {
+ if (!canvas_readscalar(w->w_canvas, natoms, vec, p_nextmsg, 0)) break;
+ }
+ }
+ }
+}
+
+static int canvas_readscalar(t_canvas *x, int natoms, t_atom *vec, int *p_nextmsg, int selectit) {
+ int nextmsg = *p_nextmsg;
+ //int wasvis = canvas_isvisible(x);
+ if (nextmsg >= natoms || vec[nextmsg].a_type != A_SYMBOL) {
+ if (nextmsg < natoms) post("stopping early: type %d", vec[nextmsg].a_type);
+ *p_nextmsg = natoms; return 0;
+ }
+ t_symbol *ts = canvas_makebindsym(vec[nextmsg].a_symbol);
+ *p_nextmsg = nextmsg + 1;
+ t_template *t = template_findbyname(ts);
+ if (!t) {error("%s: no such template", ts->name); *p_nextmsg = natoms; return 0;}
+ t_scalar *sc = scalar_new(x, ts);
+ if (!sc) {error("couldn't create scalar \"%s\"", ts->name); *p_nextmsg = natoms; return 0;}
+ //if (wasvis) canvas_getcanvas(x)->mapped = 0;
+ canvas_add(x,sc);
+ int message;
+ int nline = canvas_scanbinbuf(natoms, vec, &message, p_nextmsg);
+ canvas_readatoms(x, natoms, vec, p_nextmsg, ts, sc->v, nline, vec + message);
+ //if (wasvis) canvas_getcanvas(x)->mapped = 1;
+ gobj_changed(sc,0);//is this necessary?
+ return 1;
+}
+
+static void canvas_readfrombinbuf(t_canvas *x, t_binbuf *b, char *filename, int selectem) {
+ int message, nextmsg = 0;
+ int natoms = binbuf_getnatom(b);
+ t_atom *vec = binbuf_getvec(b);
+ /* check for file type */
+ int nline = canvas_scanbinbuf(natoms, vec, &message, &nextmsg);
+ if (nline!=1 && vec[message].a_type != A_SYMBOL && strcmp(vec[message].a_symbol->name, "data")) {
+ error("%s: file apparently of wrong type", filename);
+ binbuf_free(b);
+ return;
+ }
+ /* read in templates and check for consistency */
+ while (1) {
+ t_template *newtemplate, *existtemplate;
+ t_atom *templateargs = (t_atom *)getbytes(0);
+ int ntemplateargs = 0;
+ nline = canvas_scanbinbuf(natoms, vec, &message, &nextmsg);
+ if (nline < 2) break;
+ else if (nline > 2) canvas_readerror(natoms, vec, message, nline, "extra items ignored");
+ else if (vec[message].a_type != A_SYMBOL || strcmp(vec[message].a_symbol->name, "template") ||
+ vec[message+1].a_type != A_SYMBOL) {
+ canvas_readerror(natoms, vec, message, nline, "bad template header");
+ continue;
+ }
+ t_symbol *templatesym = canvas_makebindsym(vec[message + 1].a_symbol);
+ while (1) {
+ nline = canvas_scanbinbuf(natoms, vec, &message, &nextmsg);
+ if (nline != 2 && nline != 3) break;
+ int newnargs = ntemplateargs + nline;
+ templateargs = (t_atom *)realloc(templateargs, sizeof(*templateargs) * newnargs);
+ templateargs[ntemplateargs] = vec[message];
+ templateargs[ntemplateargs + 1] = vec[message + 1];
+ if (nline == 3) templateargs[ntemplateargs + 2] = vec[message + 2];
+ ntemplateargs = newnargs;
+ }
+ newtemplate = template_new(templatesym, ntemplateargs, templateargs);
+ free(templateargs);
+ if (!(existtemplate = template_findbyname(templatesym))) {
+ error("%s: template not found in current patch", templatesym->name);
+ template_free(newtemplate);
+ return;
+ }
+ if (!template_match(existtemplate, newtemplate)) {
+ error("%s: template doesn't match current one", templatesym->name);
+ template_free(newtemplate);
+ return;
+ }
+ template_free(newtemplate);
+ }
+ while (nextmsg < natoms) canvas_readscalar(x, natoms, vec, &nextmsg, selectem);
+}
+
+static void canvas_doread(t_canvas *x, t_symbol *filename, t_symbol *format, int clearme) {
+ t_binbuf *b = binbuf_new();
+ t_canvas *canvas = canvas_getcanvas(x);
+ int wasvis = canvas_isvisible(canvas);
+ int cr = strcmp(format->name, "cr")==0;
+ if (!cr && *format->name) error("unknown flag: %s", format->name);
+ /* flag 2 means eval continuously. this is required to autodetect the syntax */
+ if (binbuf_read_via_path(b, filename->name, canvas_getdir(canvas)->name, cr|2)) {
+ error("read failed");
+ binbuf_free(b);
+ return;
+ }
+ if (wasvis) canvas_vis(canvas, 0);
+ if (clearme) canvas_clear(x);
+ /* canvas_readfrombinbuf(x, b, filename->name, 0); */ /* what's this for? */
+ if (wasvis) canvas_vis(canvas, 1);
+ binbuf_free(b);
+}
+
+static void canvas_read( t_canvas *x, t_symbol *filename, t_symbol *format) {canvas_doread(x,filename,format,1);}
+static void canvas_mergefile(t_canvas *x, t_symbol *filename, t_symbol *format) {canvas_doread(x,filename,format,0);}
+
+/* read text from a "properties" window, in answer to scalar_properties().
+ We try to restore the object; if successful
+ we delete the scalar and put the new thing in its place on the list. */
+void canvas_dataproperties(t_canvas *x, t_scalar *sc, t_binbuf *b) {
+// t_gobj *oldone = 0;
+// t_gobj *newone = 0;
+ x->boxes->remove_by_value(sc);
+// if (!newone) {error("couldn't update properties (perhaps a format problem?)"); return;}
+// if (!oldone) {bug("data_properties: couldn't find old element"); return;}
+ canvas_readfrombinbuf(x, b, "properties dialog", 0);
+}
+
+static void canvas_doaddtemplate(t_symbol *templatesym, int *p_ntemplates, t_symbol ***p_templatevec) {
+ int n = *p_ntemplates;
+ t_symbol **templatevec = *p_templatevec;
+ for (int i=0; i < n; i++) if (templatevec[i] == templatesym) return;
+ templatevec = (t_symbol **)realloc(templatevec, (n+1)*sizeof(*templatevec));
+ templatevec[n] = templatesym;
+ *p_templatevec = templatevec;
+ *p_ntemplates = n+1;
+}
+
+static void canvas_writelist(t_gobj *y, t_binbuf *b);
+
+static void canvas_writescalar(t_symbol *templatesym, t_word *w, t_binbuf *b, int amarrayelement) {
+ t_template *t = template_findbyname(templatesym);
+ t_atom *a = (t_atom *)getbytes(0);
+ int n = t->n, natom = 0;
+ if (!amarrayelement) {
+ t_atom templatename;
+ SETSYMBOL(&templatename, gensym(templatesym->name + 3));
+ binbuf_add(b, 1, &templatename);
+ }
+ if (!t) bug("canvas_writescalar");
+ /* write the atoms (floats and symbols) */
+ for (int i=0; i<n; i++) {
+ int ty = t->vec[i].type;
+ if (ty==DT_FLOAT || ty==DT_SYMBOL) {
+ a = (t_atom *)realloc(a, (natom+1)*sizeof(*a));
+ if (t->vec[i].type == DT_FLOAT) SETFLOAT( a + natom, w[i].w_float);
+ else SETSYMBOL(a + natom, w[i].w_symbol);
+ natom++;
+ }
+ }
+ /* array elements have to have at least something */
+ if (natom == 0 && amarrayelement)
+ SETSYMBOL(a + natom, &s_bang), natom++;
+ binbuf_add(b, natom, a);
+ binbuf_addsemi(b);
+ free(a);
+ for (int i=0; i<n; i++) {
+ if (t->vec[i].type == DT_ARRAY) {
+ t_array *a = w[i].w_array;
+ int elemsize = a->elemsize, nitems = a->n;
+ t_symbol *arraytemplatesym = t->vec[i].arraytemplate;
+ for (int j = 0; j < nitems; j++)
+ canvas_writescalar(arraytemplatesym, (t_word *)&a->vec[elemsize*j], b, 1);
+ binbuf_addsemi(b);
+ } else if (t->vec[i].type == DT_CANVAS) {
+ canvas_writelist(w->w_canvas->boxes->first(), b);
+ binbuf_addsemi(b);
+ }
+ }
+}
+
+static void canvas_writelist(t_gobj *y, t_binbuf *b) {
+ for (; y; y = y->next()) if (y->_class==scalar_class) {
+ t_scalar *z = (t_scalar *)y;
+ canvas_writescalar(z->t, z->v, b, 0);
+ }
+}
+
+static void canvas_addtemplatesforlist(t_gobj *y, int *p_ntemplates, t_symbol ***p_templatevec);
+
+static void canvas_addtemplatesforscalar(t_symbol *templatesym, t_word *w, int *p_ntemplates, t_symbol ***p_templatevec) {
+ t_template *t = template_findbyname(templatesym);
+ canvas_doaddtemplate(templatesym, p_ntemplates, p_templatevec);
+ if (!t) {bug("canvas_addtemplatesforscalar"); return;}
+ t_dataslot *ds = t->vec;
+ for (int i=t->n; i--; ds++, w++) {
+ if (ds->type == DT_ARRAY) {
+ t_array *a = w->w_array;
+ int elemsize = a->elemsize, nitems = a->n;
+ t_symbol *arraytemplatesym = ds->arraytemplate;
+ canvas_doaddtemplate(arraytemplatesym, p_ntemplates, p_templatevec);
+ for (int j=0; j<nitems; j++)
+ canvas_addtemplatesforscalar(arraytemplatesym, (t_word *)&a->vec[elemsize*j], p_ntemplates, p_templatevec);
+ } else if (ds->type == DT_CANVAS)
+ canvas_addtemplatesforlist(w->w_canvas->boxes->first(), p_ntemplates, p_templatevec);
+ }
+}
+
+static void canvas_addtemplatesforlist(t_gobj *y, int *p_ntemplates, t_symbol ***p_templatevec) {
+ for (; y; y = y->next()) if (y->_class == scalar_class) {
+ t_scalar *z = (t_scalar *)y;
+ canvas_addtemplatesforscalar(z->t, z->v, p_ntemplates, p_templatevec);
+ }
+}
+
+static t_binbuf *canvas_writetobinbuf(t_canvas *x) {
+ t_symbol **templatevec = (t_symbol **)getbytes(0);
+ int ntemplates = 0;
+ t_binbuf *b = binbuf_new();
+ canvas_each(y,x) if (y->_class==scalar_class) {
+ t_scalar *s = (t_scalar *)y;
+ canvas_addtemplatesforscalar(s->t, s->v, &ntemplates, &templatevec);
+ }
+ binbuf_addv(b,"t;","data");
+ for (int i=0; i<ntemplates; i++) {
+ t_template *t = template_findbyname(templatevec[i]);
+ int m = t->n;
+ /* drop "pd-" prefix from template symbol to print it: */
+ binbuf_addv(b,"tt;","template",templatevec[i]->name + 3);
+ for (int j=0; j<m; j++) {
+ t_symbol *type;
+ switch (t->vec[j].type) {
+ case DT_FLOAT: type = &s_float; break;
+ case DT_SYMBOL: type = &s_symbol; break;
+ case DT_ARRAY: type = gensym("array"); break;
+ case DT_CANVAS: type = &s_list; break;
+ default: type = &s_float; bug("canvas_write");
+ }
+ if (t->vec[j].type == DT_ARRAY)
+ binbuf_addv(b,"sst;", type, t->vec[j].name, t->vec[j].arraytemplate->name + 3);
+ else binbuf_addv(b,"ss;", type, t->vec[j].name);
+ }
+ binbuf_addsemi(b);
+ }
+ binbuf_addsemi(b);
+ /* now write out the objects themselves */
+ canvas_each(y,x) if (y->_class==scalar_class) {
+ t_scalar *z = (t_scalar *)y;
+ canvas_writescalar(z->t, z->v, b, 0);
+ }
+ return b;
+}
+
+static void canvas_write(t_canvas *x, t_symbol *filename, t_symbol *format) {
+ t_canvas *canvas = canvas_getcanvas(x);
+ char *buf = canvas_makefilename(canvas,filename->name,0,0);
+ int cr = strcmp(format->name, "cr")==0;
+ if (!cr && *format->name) error("canvas_write: unknown flag: %s", format->name);
+ t_binbuf *b = canvas_writetobinbuf(x);
+ if (b) {
+ if (binbuf_write(b, buf, "", cr)) error("%s: write failed", filename->name);
+ binbuf_free(b);
+ }
+ free(buf);
+}
+
+/* ------ functions to save and restore canvases (patches) recursively. ----*/
+
+/* save to a binbuf, called recursively; cf. canvas_savetofile() which saves the document, and is only called on root canvases. */
+void canvas_savecontainerto(t_canvas *x, t_binbuf *b) {
+ /* have to go to original binbuf to find out how we were named. */
+ t_binbuf *bz = binbuf_new();
+ t_symbol *patchsym = &s_;
+ if (x->binbuf) {
+ binbuf_addbinbuf(bz, x->binbuf);
+ patchsym = atom_getsymbolarg(1, binbuf_getnatom(bz), binbuf_getvec(bz));
+ binbuf_free(bz);
+ }
+ int x1=x->screenx1, xs=x->screenx2-x1;
+ int y1=x->screeny1, ys=x->screeny2-y1;
+ binbuf_addv(b,"ttiiii","#N","canvas",x1,y1,xs,ys);
+ if (x->dix->canvas && !x->env) { /* subpatch */
+ binbuf_addv(b, "si;", (patchsym != &s_ ? patchsym: gensym("(subpatch)")), x->havewindow);
+ } else { /* root or abstraction */
+ binbuf_addv(b, "i;", (int)x->font);
+ canvas_savedeclarationsto(x, b);
+ }
+}
+
+static void canvas_savecoordsto(t_canvas *x, t_binbuf *b) {
+ /* if everything is the default, skip saving this line */
+ if (!x->gop && x->x1==0 && x->y1==0 && x->x2==1 && x->y2==1 && x->pixwidth==0 && x->pixheight==0) return;
+ /* if we have a graph-on-parent rectangle, we're new style. The format is arranged so
+ that old versions of Pd can at least do something with it.
+ otherwise write in 0.38-compatible form. */
+ binbuf_addv(b,"ttffffffi","#X","coords", x->x1,x->y1,x->x2,x->y2, (float)x->pixwidth,(float)x->pixheight, x->gop?x->hidetext?2:1:0);
+ if (x->goprect) binbuf_addv(b, "ff", (float)x->xmargin, (float)x->ymargin);
+ binbuf_addv(b,";");
+}
+
+/* get the index of a gobj in a canvas. If y is zero, return the total number of objects. */
+int canvas_oldindex(t_canvas *x, t_gobj *y) {
+ int i=0;
+ canvas_each(y2,x) {if (y2==y) break; else i++;}
+ return i;
+}
+
+static void canvas_saveto(t_canvas *x, t_binbuf *b) {
+ canvas_savecontainerto(x,b);
+ canvas_each(y,x) gobj_save(y, b);
+ canvas_wires_each(oc,t,x) {
+ int from = canvas_oldindex(x,t.from);
+ int to = canvas_oldindex(x,t.to);
+ binbuf_addv(b, "ttiiii;","#X","connect", from, t.outlet, to, t.inlet);
+ appendix_save(oc,b);
+ }
+ canvas_savecoordsto(x,b);
+}
+
+/* call this recursively to collect all the template names for a canvas or for the selection. */
+static void canvas_collecttemplatesfor(t_canvas *x, int *ntemplatesp, t_symbol ***templatevecp) {
+ canvas_each(y,x) {
+ if (y->_class==scalar_class) {
+ t_scalar *z = (t_scalar *)y;
+ canvas_addtemplatesforscalar(z->t, z->v, ntemplatesp, templatevecp);
+ } else if (y->_class==canvas_class) {
+ canvas_collecttemplatesfor((t_canvas *)y, ntemplatesp, templatevecp);
+ }
+ }
+}
+
+/* save the templates needed by a canvas to a binbuf. */
+static void canvas_savetemplatesto(t_canvas *x, t_binbuf *b) {
+ t_symbol **templatevec = (t_symbol **)getbytes(0);
+ int ntemplates = 0;
+ canvas_collecttemplatesfor(x, &ntemplates, &templatevec);
+ for (int i=0; i < ntemplates; i++) {
+ t_template *t = template_findbyname(templatevec[i]);
+ if (!t) {
+ bug("canvas_savetemplatesto");
+ continue;
+ }
+ /* drop "pd-" prefix from template symbol to print */
+ binbuf_addv(b,"ttt","#N","struct",templatevec[i]->name+3);
+ for (int j=0; j<t->n; j++) {
+ t_symbol *type;
+ switch (t->vec[j].type) {
+ case DT_FLOAT: type = &s_float; break;
+ case DT_SYMBOL: type = &s_symbol; break;
+ case DT_ARRAY: type = gensym("array"); break;
+ case DT_CANVAS: type = &s_list; break;
+ default: type = &s_float; bug("canvas_write");
+ }
+ binbuf_addv(b,"ss",type,t->vec[j].name);
+ if (t->vec[j].type == DT_ARRAY) binbuf_addv(b, "t", t->vec[j].arraytemplate->name + 3);
+ }
+ binbuf_addsemi(b);
+ }
+}
+
+/* save a "root" canvas to a file; cf. canvas_saveto() which saves the body (and which is called recursively.) */
+static void canvas_savetofile(t_canvas *x, t_symbol *filename, t_symbol *dir) {
+ t_binbuf *b = binbuf_new();
+ int dsp_status = canvas_suspend_dsp();
+ canvas_savetemplatesto(x, b);
+ canvas_saveto(x, b);
+ if (!binbuf_write(b, filename->name, dir->name, 0)) {
+ /* if not an abstraction, reset title bar and directory */
+ if (!x->dix->canvas) canvas_rename(x, filename, dir);
+ post("saved to: %s/%s", dir->name, filename->name);
+ canvas_reload(filename,dir,x);
+ }
+ binbuf_free(b);
+ canvas_resume_dsp(dsp_status);
+}
+
+///////////////////////////////////////////////////////////////////////////
+// from g_io.c
+
+/* graphical inlets and outlets, both for control and signals. */
+/* iohannes added multiple samplerates support in vinlet/voutlet */
+
+extern "C" void signal_setborrowed(t_signal *sig, t_signal *sig2);
+extern "C" void signal_makereusable(t_signal *sig);
+extern "C" void inlet_sethelp(t_inlet* i,t_symbol* s);
+
+/* ------------------------- vinlet -------------------------- */
+t_class *vinlet_class;
+
+struct t_vinlet : t_object {
+ t_canvas *canvas;
+ t_inlet *inlet;
+ int bufsize;
+ t_float *buf; /* signal buffer; zero if not a signal */
+ t_float *endbuf;
+ t_float *fill;
+ t_float *read;
+ int hop;
+ /* if not reblocking, the next slot communicates the parent's inlet signal from the prolog to the DSP routine: */
+ t_signal *directsignal;
+ t_resample updown; /* IOhannes */
+};
+
+static void *vinlet_new(t_symbol *s) {
+ t_vinlet *x = (t_vinlet *)pd_new(vinlet_class);
+ x->canvas = canvas_getcurrent();
+ x->inlet = canvas_addinlet(x->canvas,x,0,s);
+ x->bufsize = 0;
+ x->buf = 0;
+ outlet_new(x, 0);
+ return x;
+}
+
+static void vinlet_bang(t_vinlet *x) {outlet_bang(x->outlet);}
+static void vinlet_pointer(t_vinlet *x, t_gpointer *gp) {outlet_pointer(x->outlet, gp);}
+static void vinlet_float(t_vinlet *x, t_float f) {outlet_float(x->outlet, f);}
+static void vinlet_symbol(t_vinlet *x, t_symbol *s) {outlet_symbol(x->outlet, s);}
+static void vinlet_list(t_vinlet *x, t_symbol *s, int argc, t_atom *argv) {outlet_list(x->outlet, s, argc, argv);}
+static void vinlet_anything(t_vinlet *x, t_symbol *s, int argc, t_atom *argv) {outlet_anything(x->outlet, s, argc, argv);}
+
+static void vinlet_free(t_vinlet *x) {
+ canvas_rminlet(x->canvas, x->inlet);
+ resample_free(&x->updown);
+}
+
+t_inlet *vinlet_getit(t_pd *x) {
+ if (pd_class(x) != vinlet_class) bug("vinlet_getit");
+ return ((t_vinlet *)x)->inlet;
+}
+
+/* ------------------------- signal inlet -------------------------- */
+int vinlet_issignal(t_vinlet *x) {return x->buf!=0;}
+
+t_int *vinlet_perform(t_int *w) {
+ t_vinlet *x = (t_vinlet *)w[1];
+ t_float *out = (t_float *)w[2];
+ int n = int(w[3]);
+ t_float *in = x->read;
+ while (n--) *out++ = *in++;
+ if (in == x->endbuf) in = x->buf;
+ x->read = in;
+ return w+4;
+}
+
+/* tb: vectorized */
+t_int *vinlet_perf8(t_int *w) {
+ t_vinlet *x = (t_vinlet *)w[1];
+ t_float *out = (t_float *)w[2];
+ int n = int(w[3]);
+ t_float *in = x->read;
+ for (; n; n -= 8, in += 8, out += 8) {
+ out[0] = in[0]; out[1] = in[1]; out[2] = in[2]; out[3] = in[3];
+ out[4] = in[4]; out[5] = in[5]; out[6] = in[6]; out[7] = in[7];
+ }
+ if (in == x->endbuf) in = x->buf;
+ x->read = in;
+ return w+4;
+}
+
+/* T.Grill: SIMD version */
+t_int *vinlet_perfsimd(t_int *w) {
+ t_vinlet *x = (t_vinlet *)(w[1]);
+ t_float *in = x->read;
+ copyvec_simd((t_float *)w[2],in,w[3]);
+ if (in == x->endbuf) in = x->buf;
+ x->read = in;
+ return w+4;
+}
+
+static void vinlet_dsp(t_vinlet *x, t_signal **sp) {
+ if (!x->buf) return; /* no buffer means we're not a signal inlet */
+ t_signal *outsig = sp[0];
+ if (x->directsignal) signal_setborrowed(sp[0], x->directsignal);
+ else {
+ const int vecsize = outsig->vecsize;
+ /* if the outsig->v is aligned the x->read will also be... */
+ if(vecsize&7) dsp_add(vinlet_perform, 3, x, outsig->v,vecsize);
+ else if(SIMD_CHECK1(outsig->n,outsig->v))
+ dsp_add(vinlet_perfsimd, 3, x, outsig->v,vecsize);
+ else dsp_add(vinlet_perf8, 3, x, outsig->v,vecsize);
+ x->read = x->buf;
+ }
+}
+
+/* prolog code: loads buffer from parent patch */
+t_int *vinlet_doprolog(t_int *w) {
+ t_vinlet *x = (t_vinlet *)w[1];
+ t_float *in = (t_float *)w[2];
+ int n = int(w[3]);
+ t_float *out = x->fill;
+ if (out == x->endbuf) {
+ t_float *f1 = x->buf, *f2 = x->buf + x->hop;
+ int nshift = x->bufsize - x->hop;
+ out -= x->hop;
+ while (nshift--) *f1++ = *f2++;
+ }
+ while (n--) *out++ = *in++;
+ x->fill = out;
+ return w+4;
+}
+
+extern "C" int inlet_getsignalindex(t_inlet *x);
+
+/* set up prolog DSP code */
+extern "C" void vinlet_dspprolog(t_vinlet *x, t_signal **parentsigs, int myvecsize, int calcsize, int phase, int period,
+int frequency, int downsample, int upsample, int reblock, int switched) {
+ t_signal *insig;
+ x->updown.downsample = downsample;
+ x->updown.upsample = upsample;
+ /* if the "reblock" flag is set, arrange to copy data in from the parent. */
+ if (reblock) {
+ int parentvecsize, bufsize, oldbufsize, prologphase;
+ int re_parentvecsize; /* resampled parentvectorsize: IOhannes */
+ /* this should never happen: */
+ if (!x->buf) return;
+ /* the prolog code counts from 0 to period-1; the
+ phase is backed up by one so that AFTER the prolog code
+ runs, the "fill" phase is in sync with the "read" phase. */
+ prologphase = (phase - 1) & (period - 1);
+ if (parentsigs) {
+ insig = parentsigs[inlet_getsignalindex(x->inlet)];
+ parentvecsize = insig->vecsize;
+ re_parentvecsize = parentvecsize * upsample / downsample;
+ } else {
+ insig = 0;
+ parentvecsize = 1;
+ re_parentvecsize = 1;
+ }
+ bufsize = max(re_parentvecsize,myvecsize);
+ oldbufsize = x->bufsize;
+ if (bufsize != oldbufsize) {
+ t_float *buf = x->buf;
+ buf = (t_float *)resizealignedbytes(buf,oldbufsize * sizeof(*buf), bufsize * sizeof(*buf));
+ memset((char *)buf, 0, bufsize * sizeof(*buf));
+ x->bufsize = bufsize;
+ x->endbuf = buf + bufsize;
+ x->buf = buf;
+ }
+ if (parentsigs) {
+ /* IOhannes { */
+ x->hop = period * re_parentvecsize;
+ x->fill = x->endbuf - (x->hop - prologphase * re_parentvecsize);
+ if (upsample * downsample == 1)
+ dsp_add(vinlet_doprolog, 3, x, insig->v, re_parentvecsize);
+ else {
+ resamplefrom_dsp(&x->updown, insig->v, parentvecsize, re_parentvecsize, x->updown.method);
+ dsp_add(vinlet_doprolog, 3, x, x->updown.v, re_parentvecsize);
+ }
+ /* } IOhannes */
+ /* if the input signal's reference count is zero, we have to free it here because we didn't in ugen_doit(). */
+ if (!insig->refcount) signal_makereusable(insig);
+ } else memset((char *)x->buf, 0, bufsize * sizeof(*x->buf));
+ x->directsignal = 0;
+ } else {
+ /* no reblocking; in this case our output signal is "borrowed" and merely needs to be pointed to the real one. */
+ x->directsignal = parentsigs[inlet_getsignalindex(x->inlet)];
+ }
+}
+
+static void *vinlet_newsig(t_symbol *s) {
+ t_vinlet *x = (t_vinlet *)pd_new(vinlet_class);
+ x->canvas = canvas_getcurrent();
+ x->inlet = canvas_addinlet(x->canvas,x,&s_signal,s);
+ x->endbuf = x->buf = (t_float *)getalignedbytes(0);
+ x->bufsize = 0;
+ x->directsignal = 0;
+ outlet_new(x, &s_signal);
+ resample_init(&x->updown);
+ /* this should be thought over: it might prove hard to provide consistency between labeled up- & downsampling methods
+ maybe indices would be better...
+ up till now we provide several upsampling methods and 1 single downsampling method (no filtering !) */
+ if (s) {
+ char c=*s->name;
+ switch(c) {
+ case'h':case'H':x->updown.method=RESAMPLE_HOLD; break; /* up: sample and hold */
+ case'l':case'L':x->updown.method=RESAMPLE_LINEAR; break; /* up: linear interpolation */
+ case'b':case'B':x->updown.method=RESAMPLE_BLOCK; break; /* down: ignore the 2nd half of the block */
+ default: x->updown.method=RESAMPLE_ZERO; /* up: zero-padding */
+ }
+ }
+ return x;
+}
+
+static void vinlet_setup() {
+ t_class *c = vinlet_class = class_new2("inlet",vinlet_new,vinlet_free,sizeof(t_vinlet),CLASS_NOINLET,"S");
+ class_addcreator2("inlet~",vinlet_newsig,"S");
+ class_addbang( c, vinlet_bang);
+ class_addpointer( c, vinlet_pointer);
+ class_addfloat( c, vinlet_float);
+ class_addsymbol( c, vinlet_symbol);
+ class_addlist( c, vinlet_list);
+ class_addanything(c, vinlet_anything);
+ class_addmethod2( c, vinlet_dsp,"dsp","");
+ class_sethelpsymbol(c, gensym("pd"));
+}
+
+/* ------------------------- voutlet -------------------------- */
+
+t_class *voutlet_class;
+
+struct t_voutlet : t_object {
+ t_canvas *canvas;
+ t_outlet *parentoutlet;
+ int bufsize;
+ t_float *buf; /* signal buffer; zero if not a signal */
+ t_float *endbuf;
+ t_float *empty; /* next to read out of buffer in epilog code */
+ t_float *write; /* next to write in to buffer */
+ int hop; /* hopsize */
+ /* vice versa from the inlet, if we don't block, this holds the
+ parent's outlet signal, valid between the prolog and the dsp setup functions. */
+ t_signal *directsignal;
+ /* and here's a flag indicating that we aren't blocked but have to do a copy (because we're switched). */
+ char justcopyout;
+ t_resample updown; /* IOhannes */
+};
+
+static void *voutlet_new(t_symbol *s) {
+ t_voutlet *x = (t_voutlet *)pd_new(voutlet_class);
+ x->canvas = canvas_getcurrent();
+ x->parentoutlet = canvas_addoutlet(x->canvas,x,0);
+ inlet_new(x,x,0,0);
+ x->bufsize = 0;
+ x->buf = 0;
+ return x;
+}
+
+static void voutlet_bang(t_voutlet *x)
+{outlet_bang(x->parentoutlet);}
+static void voutlet_pointer(t_voutlet *x, t_gpointer *gp)
+{outlet_pointer(x->parentoutlet, gp);}
+static void voutlet_float(t_voutlet *x, t_float f)
+{outlet_float(x->parentoutlet, f);}
+static void voutlet_symbol(t_voutlet *x, t_symbol *s)
+{outlet_symbol(x->parentoutlet, s);}
+static void voutlet_list(t_voutlet *x, t_symbol *s, int argc, t_atom *argv)
+{outlet_list(x->parentoutlet, s, argc, argv);}
+static void voutlet_anything(t_voutlet *x, t_symbol *s, int argc, t_atom *argv)
+{outlet_anything(x->parentoutlet, s, argc, argv);}
+
+static void voutlet_free(t_voutlet *x) {
+ canvas_rmoutlet(x->canvas, x->parentoutlet);
+ resample_free(&x->updown);
+}
+
+t_outlet *voutlet_getit(t_pd *x) {
+ if (pd_class(x) != voutlet_class) bug("voutlet_getit");
+ return ((t_voutlet *)x)->parentoutlet;
+}
+
+/* ------------------------- signal outlet -------------------------- */
+
+int voutlet_issignal(t_voutlet *x) {return x->buf!=0;}
+
+/* LATER optimize for non-overlapped case where the "+=" isn't needed */
+t_int *voutlet_perform(t_int *w) {
+ t_voutlet *x = (t_voutlet *)w[1];
+ t_float *in = (t_float *)w[2];
+ int n = int(w[3]);
+ t_float *out = x->write, *outwas = out, *end = x->endbuf;
+ while (n--) {
+ *out++ += *in++;
+ if (out == end) out = x->buf;
+ }
+ outwas += x->hop;
+ if (outwas >= end) outwas = x->buf;
+ x->write = outwas;
+ return w+4;
+}
+
+/* epilog code for blocking: write buffer to parent patch */
+static t_int *voutlet_doepilog(t_int *w) {
+ t_voutlet *x = (t_voutlet *)w[1];
+ t_float *out = (t_float *)w[2]; /* IOhannes */
+ t_float *in = x->empty;
+ if (x->updown.downsample != x->updown.upsample) out = x->updown.v; /* IOhannes */
+ for (int n = (int)(w[3]); n--; in++) *out++ = *in, *in = 0;
+ if (in == x->endbuf) in = x->buf;
+ x->empty = in;
+ return w+4;
+}
+
+/* IOhannes { */
+static t_int *voutlet_doepilog_resampling(t_int *w) {
+ t_voutlet *x = (t_voutlet *)w[1];
+ t_float *in = x->empty;
+ t_float *out = x->updown.v; /* IOhannes */
+ for (int n = (int)(w[2]); n--; in++) *out++ = *in, *in = 0;
+ if (in == x->endbuf) in = x->buf;
+ x->empty = in;
+ return w+3;
+}
+/* } IOhannes */
+extern "C" int outlet_getsignalindex(t_outlet *x);
+
+/* prolog for outlets -- store pointer to the outlet on the parent, which, if "reblock" is false, will want to refer
+ back to whatever we see on our input during the "dsp" method called later. */
+extern "C" void voutlet_dspprolog(t_voutlet *x, t_signal **parentsigs, int myvecsize, int calcsize, int phase, int period,
+int frequency, int downsample, int upsample, int reblock, int switched) {
+ x->updown.downsample=downsample; x->updown.upsample=upsample; /* IOhannes */
+ x->justcopyout = (switched && !reblock);
+ if (reblock) {
+ x->directsignal = 0;
+ } else {
+ if (!parentsigs) bug("voutlet_dspprolog");
+ x->directsignal = parentsigs[outlet_getsignalindex(x->parentoutlet)];
+ }
+}
+
+static void voutlet_dsp(t_voutlet *x, t_signal **sp) {
+ if (!x->buf) return;
+ t_signal *insig = sp[0];
+ if (x->justcopyout) dsp_add_copy(insig->v, x->directsignal->v, insig->n);
+ else if (x->directsignal) {
+ /* if we're just going to make the signal available on the parent patch, hand it off to the parent signal. */
+ /* this is done elsewhere--> sp[0]->refcount++; */
+ signal_setborrowed(x->directsignal, sp[0]);
+ } else dsp_add(voutlet_perform, 3, x, insig->v, insig->n);
+}
+
+/* set up epilog DSP code. If we're reblocking, this is the
+ time to copy the samples out to the containing object's outlets.
+ If we aren't reblocking, there's nothing to do here. */
+extern "C" void voutlet_dspepilog(t_voutlet *x, t_signal **parentsigs,
+int myvecsize, int calcsize, int phase, int period, int frequency, int downsample, int upsample, int reblock, int switched) {
+ if (!x->buf) return; /* this shouldn't be necesssary... */
+ x->updown.downsample=downsample;
+ x->updown.upsample=upsample; /* IOhannes */
+ if (reblock) {
+ t_signal *outsig;
+ int parentvecsize, bufsize, oldbufsize;
+ int re_parentvecsize; /* IOhannes */
+ int bigperiod, epilogphase, blockphase;
+ if (parentsigs) {
+ outsig = parentsigs[outlet_getsignalindex(x->parentoutlet)];
+ parentvecsize = outsig->vecsize;
+ re_parentvecsize = parentvecsize * upsample / downsample;
+ } else {
+ outsig = 0;
+ parentvecsize = 1;
+ re_parentvecsize = 1;
+ }
+ bigperiod = myvecsize/re_parentvecsize; /* IOhannes */
+ if (!bigperiod) bigperiod = 1;
+ epilogphase = phase & (bigperiod - 1);
+ blockphase = (phase + period - 1) & (bigperiod - 1) & (- period);
+ bufsize = re_parentvecsize; /* IOhannes */
+ if (bufsize < myvecsize) bufsize = myvecsize;
+ if (bufsize != (oldbufsize = x->bufsize)) {
+ t_float *buf = x->buf;
+ buf = (t_float *)resizealignedbytes(buf,oldbufsize * sizeof(*buf),bufsize * sizeof(*buf));
+ memset((char *)buf, 0, bufsize * sizeof(*buf));
+ x->bufsize = bufsize;
+ x->endbuf = buf + bufsize;
+ x->buf = buf;
+ }
+ /* IOhannes: { */
+ if (re_parentvecsize * period > bufsize) bug("voutlet_dspepilog");
+ x->write = x->buf + re_parentvecsize * blockphase;
+ if (x->write == x->endbuf) x->write = x->buf;
+ if (period == 1 && frequency > 1) x->hop = re_parentvecsize / frequency;
+ else x->hop = period * re_parentvecsize;
+ /* } IOhannes */
+ if (parentsigs) {
+ /* set epilog pointer and schedule it */
+ /* IOhannes { */
+ x->empty = x->buf + re_parentvecsize * epilogphase;
+ if (upsample*downsample==1)
+ dsp_add(voutlet_doepilog, 3, x, outsig->v, re_parentvecsize);
+ else {
+ dsp_add(voutlet_doepilog_resampling, 2, x, re_parentvecsize);
+ resampleto_dsp(&x->updown, outsig->v, re_parentvecsize, parentvecsize, x->updown.method);
+ }
+ /* } IOhannes */
+ }
+ }
+ /* if we aren't blocked but we are switched, the epilog code just
+ copies zeros to the output. In this case the blocking code actually jumps over the epilog if the block is running. */
+ else if (switched) {
+ if (parentsigs) {
+ t_signal *outsig = parentsigs[outlet_getsignalindex(x->parentoutlet)];
+ dsp_add_zero(outsig->v, outsig->n);
+ }
+ }
+}
+
+static void *voutlet_newsig(t_symbol *s) {
+ t_voutlet *x = (t_voutlet *)pd_new(voutlet_class);
+ x->canvas = canvas_getcurrent();
+ x->parentoutlet = canvas_addoutlet(x->canvas,x,&s_signal);
+ inlet_new(x,x,&s_signal,&s_signal);
+ x->endbuf = x->buf = (t_float *)getalignedbytes(0);
+ x->bufsize = 0;
+ resample_init(&x->updown);
+ /* this should be though over:
+ * it might prove hard to provide consistency between labeled up- & downsampling methods
+ * maybe indeces would be better...
+ * up till now we provide several upsampling methods and 1 single downsampling method (no filtering !) */
+ if (s) {
+ char c=*s->name;
+ switch(c) {
+ case 'h': case 'H': x->updown.method=RESAMPLE_HOLD; break; /* up: sample and hold */
+ case 'l': case 'L': x->updown.method=RESAMPLE_LINEAR; break; /* up: linear interpolation */
+ case 'b': case 'B': x->updown.method=RESAMPLE_BLOCK; break; /* down: ignore the 2nd half of the block */
+ default: x->updown.method=RESAMPLE_ZERO; /* up: zero-padding */
+ }
+ }
+ return x;
+}
+
+static void voutlet_setup() {
+ t_class *c = voutlet_class = class_new2("outlet",voutlet_new,voutlet_free,sizeof(t_voutlet),CLASS_NOINLET,"S");
+ class_addcreator2("outlet~",voutlet_newsig,"S");
+ class_addbang( c, voutlet_bang);
+ class_addpointer( c, voutlet_pointer);
+ class_addfloat( c, (t_method)voutlet_float);
+ class_addsymbol( c, voutlet_symbol);
+ class_addlist( c, voutlet_list);
+ class_addanything(c, voutlet_anything);
+ class_addmethod2( c, voutlet_dsp, "dsp", "");
+ class_sethelpsymbol(c, gensym("pd"));
+}
+
+/* This file defines the "scalar" object, which is not a text object, just a
+ "gobj". Scalars have templates which describe their structures, which can contain numbers, sublists, and arrays.
+ IOhannes changed the canvas_restore, so that it might accept $args as well (like "pd $0_test")
+ so you can make multiple & distinguishable templates; added Krzysztof Czajas fix to avoid crashing... */
+t_class *scalar_class;
+
+void word_init(t_word *wp, t_template *t, t_gpointer *gp) {
+ t_dataslot *datatypes = t->vec;
+ for (int i=0; i < t->n; i++, datatypes++, wp++) {
+ int type = datatypes->type;
+ if (type == DT_FLOAT) wp->w_float = 0;
+ else if (type == DT_SYMBOL) wp->w_symbol = &s_symbol;
+ else if (type == DT_ARRAY) wp->w_array = array_new(datatypes->arraytemplate, gp);
+ else if (type == DT_CANVAS) {
+ /* LATER test this and get it to work */
+ wp->w_canvas = canvas_new(0,0,0,0);
+ }
+ }
+}
+
+void word_restore(t_word *wp, t_template *t, int argc, t_atom *argv) {
+ t_dataslot *datatypes = t->vec;
+ for (int i=0; i<t->n; i++, datatypes++, wp++) {
+ int type = datatypes->type;
+ if (type == DT_FLOAT) {
+ float f=0;
+ if (argc) {f = atom_getfloat(argv); argv++; argc--;}
+ wp->w_float = f;
+ } else if (type == DT_SYMBOL) {
+ t_symbol *s=&s_;
+ if (argc) {s = atom_getsymbol(argv); argv++; argc--;}
+ wp->w_symbol = s;
+ }
+ }
+ if (argc) post("warning: word_restore: extra arguments");
+}
+
+void word_free(t_word *wp, t_template *t) {
+ t_dataslot *dt = t->vec;
+ for (int i=0; i<t->n; i++, dt++) {
+ if (dt->type == DT_ARRAY) pd_free(wp[i].w_array);
+ else if (dt->type == DT_CANVAS) pd_free(wp[i].w_canvas);
+ }
+}
+
+static void gpointer_setcanvas(t_gpointer *gp, t_canvas *canvas, t_scalar *x);
+static void gpointer_setarray(t_gpointer *gp, t_array *array, t_word *w);
+static t_word *gpointer_word(t_gpointer *gp) {return gp->o->_class == array_class ? gp->w : gp->scalar->v;}
+static t_canvas *gpointer_getcanvas(t_gpointer *gp) {
+ if (gp->o->_class != array_class) return gp->canvas;
+ return 0; /* FIXME */
+}
+static t_scalar *gpointer_getscalar(t_gpointer *gp) {
+ if (gp->o->_class != array_class) return gp->scalar;
+ return 0;
+}
+
+/* make a new scalar and add to the canvas. We create a "gp" here which will be used for array items to point back here.
+ This gp doesn't do reference counting or "validation" updates though; the parent won't go away without the contained
+ arrays going away too. The "gp" is copied out by value in the word_init() routine so we can throw our copy away. */
+t_scalar *scalar_new(t_canvas *owner, t_symbol *templatesym) {
+ t_gpointer gp;
+ gpointer_init(&gp);
+ t_template *t = template_findbyname(templatesym);
+ TEMPLATE_CHECK(templatesym,0)
+ t_scalar *x = (t_scalar *)getbytes(sizeof(t_scalar) + (t->n - 1) * sizeof(*x->v));
+ x->_class = scalar_class;
+ x->t = templatesym;
+ gpointer_setcanvas(&gp, owner, x);
+ word_init(x->v, t, &gp);
+ return x;
+}
+
+/* Pd method to create a new scalar, add it to a canvas, and initialize it from the message arguments. */
+int canvas_readscalar(t_canvas *x, int natoms, t_atom *vec, int *p_nextmsg, int selectit);
+static void canvas_scalar(t_canvas *canvas, t_symbol *classname, t_int argc, t_atom *argv) {
+ t_symbol *templatesym = canvas_makebindsym(atom_getsymbolarg(0, argc, argv));
+ if (!template_findbyname(templatesym)) {error("%s: no such template", atom_getsymbolarg(0, argc, argv)->name); return;}
+ int nextmsg;
+ t_binbuf *b = binbuf_new();
+ binbuf_restore(b, argc, argv);
+ canvas_readscalar(canvas, binbuf_getnatom(b), binbuf_getvec(b), &nextmsg, 0);
+ binbuf_free(b);
+}
+
+static void scalar_getbasexy(t_scalar *x, float *basex, float *basey) {
+ t_template *t = template_findbyname(x->t);
+ *basex = template_getfloat(t,&s_x,x->v,0);
+ *basey = template_getfloat(t,&s_y,x->v,0);
+}
+
+/*
+static void scalar_displace(t_gobj *z, t_canvas *canvas, int dx, int dy) {
+ t_scalar *x = (t_scalar *)z;
+ t_symbol *templatesym = x->t;
+ t_template *t = template_findbyname(templatesym);
+ t_symbol *zz;
+ int xonset, yonset, xtype, ytype, gotx, goty;
+ TEMPLATE_CHECK(templatesym,)
+ gotx = template_find_field(t,&s_x,&xonset,&xtype,&zz);
+ if (gotx && (xtype != DT_FLOAT)) gotx = 0;
+ goty = template_find_field(t,&s_y,&yonset,&ytype,&zz);
+ if (goty && (ytype != DT_FLOAT)) goty = 0;
+ if (gotx) *(t_float *)(((char *)(x->v)) + xonset) += dx * (canvas_pixelstox(canvas, 1) - canvas_pixelstox(canvas, 0));
+ if (goty) *(t_float *)(((char *)(x->v)) + yonset) += dy * (canvas_pixelstoy(canvas, 1) - canvas_pixelstoy(canvas, 0));
+ scalar_redraw(x, canvas);
+}*/
+
+static void scalar_vis(t_gobj *z, t_canvas *owner, int vis) {
+ t_scalar *x = (t_scalar *)z;
+ t_template *t = template_findbyname(x->t);
+ t_canvas *templatecanvas = template_findcanvas(t);
+ float basex, basey;
+ scalar_getbasexy(x, &basex, &basey);
+ /* if we don't know how to draw it, make a small rectangle */
+ if (!templatecanvas) {
+ if (vis) {
+ int x1 = canvas_xtopixels(owner, basex);
+ int y1 = canvas_ytopixels(owner, basey);
+ sys_vgui(".x%lx.c create rectangle %d %d %d %d -tags scalar%lx\n",
+ (long)canvas_getcanvas(owner), x1-1, y1-1, x1+1, y1+1, (long)x);
+ } else sys_vgui(".x%lx.c delete scalar%lx\n", (long)canvas_getcanvas(owner), (long)x);
+ return;
+ }
+ //canvas_each(y,templatecanvas) pd_getparentwidget(y)->w_parentvisfn(y,owner,x->v,t,basex,basey,vis);
+ //sys_unqueuegui(x);
+}
+
+static void scalar_doredraw(t_gobj *client, t_canvas *canvas) {
+ scalar_vis(client, canvas, 0);
+ scalar_vis(client, canvas, 1);
+}
+
+void scalar_redraw(t_scalar *x, t_canvas *canvas) {
+ //if (canvas_isvisible(canvas)) sys_queuegui(x, canvas, scalar_doredraw);
+}
+
+#if 0
+int scalar_doclick(t_word *data, t_template *t, t_scalar *sc, t_array *ap, t_canvas *owner,
+float xloc, float yloc, int xpix, int ypix, int shift, int alt, int dbl, int doit) {
+ t_canvas *templatecanvas = template_findcanvas(t);
+ float basex = template_getfloat(t,&s_x,data,0);
+ float basey = template_getfloat(t,&s_y,data,0);
+ canvas_each(y,templatecanvas) {
+ int hit = pd_getparentwidget(y)->w_parentclickfn(y, owner, data, t, sc, ap, basex+xloc, basey+yloc,
+ xpix, ypix, shift, alt, dbl, doit);
+ if (hit) return hit;
+ }*/
+ return 0;
+}
+#endif
+
+static int scalar_click(t_gobj *z, t_canvas *owner, int xpix, int ypix, int shift, int alt, int dbl, int doit) {
+ t_scalar *x = (t_scalar *)z;
+ t_template *t = template_findbyname(x->t);
+ return scalar_doclick(x->v, t, x, 0, owner, 0, 0, xpix, ypix, shift, alt, dbl, doit);
+}
+
+void canvas_writescalar(t_symbol *templatesym, t_word *w, t_binbuf *b, int amarrayelement);
+
+static void scalar_save(t_gobj *z, t_binbuf *b) {
+ t_scalar *x = (t_scalar *)z;
+ t_binbuf *b2 = binbuf_new();
+ canvas_writescalar(x->t, x->v, b2, 0);
+ binbuf_addv(b,"tt","#X","scalar");
+ binbuf_addbinbuf(b, b2);
+ binbuf_addsemi(b);
+ binbuf_free(b2);
+}
+
+/*
+static void scalar_properties(t_gobj *z, t_canvas *owner) {
+ t_scalar *x = (t_scalar *)z;
+ char *buf, buf2[80];
+ int bufsize;
+ t_binbuf *b;
+ b = canvas_writetobinbuf(owner, 0);
+ binbuf_gettext(b, &buf, &bufsize);
+ binbuf_free(b);
+ buf = (char *)realloc(buf, bufsize+1);
+ buf[bufsize] = 0;
+ sprintf(buf2, "pdtk_data_dialog %%s {");
+ sys_gui(buf);
+ sys_gui("}\n");
+ free(buf);
+}
+*/
+
+static void scalar_free(t_scalar *x) {
+ t_template *t = template_findbyname(x->t);
+ TEMPLATE_CHECK(x->t,)
+ word_free(x->v, t);
+ /* the "size" field in the class is zero, so Pd doesn't try to free us automatically (see pd_free()) */
+ free(x);
+}
+
+static void g_scalar_setup() {
+ scalar_class = class_new2("scalar",0,scalar_free,0,CLASS_GOBJ,"");
+ class_setsavefn(scalar_class, scalar_save);
+}
+
+void array_redraw(t_array *a, t_canvas *canvas);
+
+/*
+This file contains text objects you would put in a canvas to define a
+template. Templates describe objects of type "array" (g_array.c) and "scalar" (g_scalar.c). */
+/* the structure of a "struct" object (also the obsolete "gtemplate" you get when using the name "template" in a box.) */
+struct t_gtemplate : t_object {
+ t_template *t;
+ t_canvas *owner;
+ t_symbol *sym;
+ t_gtemplate *next;
+ int argc;
+ t_atom *argv;
+};
+
+static void template_conformarray(t_template *tfrom, t_template *tto, int *conformaction, t_array *a);
+static void template_conformcanvas(t_template *tfrom, t_template *tto, int *conformaction, t_canvas *canvas);
+static t_class *gtemplate_class;
+static t_class *template_class;
+
+/* there's a pre-defined "float" template. LATER should we bind this to a symbol such as "pd-float"??? */
+
+/* return true if two dataslot definitions match */
+static int dataslot_matches(t_dataslot *ds1, t_dataslot *ds2, int nametoo) {
+ return (!nametoo || ds1->name == ds2->name) && ds1->type == ds2->type &&
+ (ds1->type != DT_ARRAY || ds1->arraytemplate == ds2->arraytemplate);
+}
+
+/* -- templates, the active ingredient in gtemplates defined below. ------- */
+
+static t_template *template_new(t_symbol *templatesym, int argc, t_atom *argv) {
+ t_template *x = (t_template *)pd_new(template_class);
+ x->n = 0;
+ x->vec = (t_dataslot *)getbytes(0);
+ while (argc > 0) {
+ int newtype, oldn, newn;
+ t_symbol *newname, *newarraytemplate = &s_, *newtypesym;
+ if (argc < 2 || argv[0].a_type != A_SYMBOL || argv[1].a_type != A_SYMBOL) goto bad;
+ newtypesym = argv[0].a_symbol;
+ newname = argv[1].a_symbol;
+ if (newtypesym == &s_float) newtype = DT_FLOAT;
+ else if (newtypesym == &s_symbol) newtype = DT_SYMBOL;
+ else if (newtypesym == &s_list) newtype = DT_CANVAS;
+ else if (newtypesym == gensym("array")) {
+ if (argc < 3 || argv[2].a_type != A_SYMBOL) {error("array lacks element template or name"); goto bad;}
+ newarraytemplate = canvas_makebindsym(argv[2].a_symbol);
+ newtype = DT_ARRAY;
+ argc--;
+ argv++;
+ } else {error("%s: no such type", newtypesym->name); goto bad;}
+ newn = (oldn = x->n) + 1;
+ x->vec = (t_dataslot *)realloc(x->vec, newn*sizeof(*x->vec));
+ x->n = newn;
+ x->vec[oldn].type = newtype;
+ x->vec[oldn].name = newname;
+ x->vec[oldn].arraytemplate = newarraytemplate;
+ bad:
+ argc -= 2; argv += 2;
+ }
+ x->sym = templatesym;
+ if (templatesym->name) pd_bind(x,x->sym);
+ return x;
+}
+
+int template_size(t_template *x) {return x->n * sizeof(t_word);}
+
+int template_find_field(t_template *x, t_symbol *name, int *p_onset, int *p_type, t_symbol **p_arraytype) {
+ if (!x) {bug("template_find_field"); return 0;}
+ for (int i = 0; i<x->n; i++) if (x->vec[i].name == name) {
+ *p_onset = i*sizeof(t_word);
+ *p_type = x->vec[i].type;
+ *p_arraytype = x->vec[i].arraytemplate;
+ return 1;
+ }
+ return 0;
+}
+
+#define ERR(msg,ret) do {\
+ if (loud) error("%s.%s: "msg, x->sym->name, fieldname->name);\
+ return ret;} while(0);
+static t_float template_getfloat(t_template *x, t_symbol *fieldname, t_word *wp, int loud) {
+ int onset, type; t_symbol *arraytype;
+ if (!template_find_field(x, fieldname, &onset, &type, &arraytype)) ERR("no such field",0);
+ if (type != DT_FLOAT) ERR("not a number",0);
+ return *(t_float *)(((char *)wp) + onset);
+}
+static t_symbol *template_getsymbol(t_template *x, t_symbol *fieldname, t_word *wp, int loud) {
+ int onset, type; t_symbol *arraytype;
+ if (!template_find_field(x, fieldname, &onset, &type, &arraytype)) ERR("no such field",&s_);
+ if (type != DT_SYMBOL) ERR("not a symbol",&s_);
+ return *(t_symbol **)(((char *)wp) + onset);
+}
+static void template_setfloat(t_template *x, t_symbol *fieldname, t_word *wp, t_float f, int loud) {
+ int onset, type; t_symbol *arraytype;
+ if (!template_find_field(x, fieldname, &onset, &type, &arraytype)) ERR("no such field",);
+ if (type != DT_FLOAT) ERR("not a number",);
+ *(t_float *)(((char *)wp) + onset) = f;
+}
+static void template_setsymbol(t_template *x, t_symbol *fieldname, t_word *wp, t_symbol *s, int loud) {
+ int onset, type; t_symbol *arraytype;
+ if (!template_find_field(x, fieldname, &onset, &type, &arraytype)) ERR("no such field",);
+ if (type != DT_SYMBOL) ERR("not a symbol",);
+ *(t_symbol **)(((char *)wp) + onset) = s;
+}
+#undef ERR
+
+/* stringent check to see if a "saved" template, x2, matches the current
+one (x1). It's OK if x1 has additional scalar elements but not (yet)
+arrays or lists. This is used for reading in "data files". */
+static int template_match(t_template *x1, t_template *x2) {
+ if (x1->n < x2->n) return 0;
+ for (int i=x2->n; i < x1->n; i++)
+ if (x1->vec[i].type == DT_ARRAY || x1->vec[i].type == DT_CANVAS) return 0;
+ if (x2->n > x1->n) post("add elements...");
+ for (int i=0; i < x2->n; i++) if (!dataslot_matches(&x1->vec[i], &x2->vec[i], 1)) return 0;
+ return 1;
+}
+
+/* --------------- CONFORMING TO CHANGES IN A TEMPLATE ------------ */
+
+/* the following functions handle updating scalars to agree with changes
+in their template. The old template is assumed to be the "installed" one
+so we can delete old items; but making new ones we have to avoid scalar_new
+which would make an old one whereas we will want a new one (but whose array
+elements might still be old ones.)
+ LATER deal with graphics updates too... */
+
+/* conform the word vector of a scalar to the new template */
+static void template_conformwords(t_template *tfrom, t_template *tto, int *conformaction, t_word *wfrom, t_word *wto) {
+ for (int i=0; i<tto->n; i++) {
+ if (conformaction[i] >= 0) {
+ /* we swap the two, in case it's an array or list, so that when "wfrom" is deleted the old one gets cleaned up. */
+ t_word wwas = wto[i];
+ wto[i] = wfrom[conformaction[i]];
+ wfrom[conformaction[i]] = wwas;
+ }
+ }
+}
+
+/* conform a scalar, recursively conforming sublists and arrays */
+static t_scalar *template_conformscalar(t_template *tfrom, t_template *tto, int *conformaction, t_canvas *canvas, t_scalar *scfrom) {
+ t_scalar *x;
+ t_template *scalartemplate;
+ /* possibly replace the scalar */
+ if (scfrom->t == tfrom->sym) {
+ t_gpointer gp;
+ /* see scalar_new() for comment about the gpointer. */
+ gpointer_init(&gp);
+ x = (t_scalar *)getbytes(sizeof(t_scalar) + (tto->n - 1) * sizeof(*x->v));
+ x->_class = scalar_class;
+ x->t = tfrom->sym;
+ gpointer_setcanvas(&gp, canvas, x);
+ /* Here we initialize to the new template, but array and list elements will still belong to old template. */
+ word_init(x->v, tto, &gp);
+ template_conformwords(tfrom, tto, conformaction, scfrom->v, x->v);
+ /* replace the old one with the new one in the list */
+ canvas->boxes->remove_by_value(scfrom);
+ canvas->boxes->add(x);
+ pd_free(scfrom);
+ scalartemplate = tto;
+ } else {
+ x = scfrom;
+ scalartemplate = template_findbyname(x->t);
+ }
+ /* convert all array elements and sublists */
+ for (int i=0; i < scalartemplate->n; i++) {
+ t_dataslot *ds = scalartemplate->vec + i;
+ if (ds->type == DT_CANVAS) template_conformcanvas(tfrom, tto, conformaction, x->v[i].w_canvas);
+ if (ds->type == DT_ARRAY) template_conformarray( tfrom, tto, conformaction, x->v[i].w_array);
+ }
+ return x;
+}
+
+/* conform an array, recursively conforming sublists and arrays */
+static void template_conformarray(t_template *tfrom, t_template *tto, int *conformaction, t_array *a) {
+ t_template *scalartemplate = 0;
+ if (a->templatesym == tfrom->sym) {
+ /* the array elements must all be conformed */
+ int oldelemsize = sizeof(t_word) * tfrom->n;
+ int newelemsize = sizeof(t_word) * tto->n;
+ char *newarray = (char *)getbytes(newelemsize * a->n);
+ char *oldarray = a->vec;
+ if (a->elemsize != oldelemsize) bug("template_conformarray");
+ for (int i=0; i<a->n; i++) {
+ t_word *wp = (t_word *)(newarray + newelemsize*i);
+ word_init(wp, tto, &a->gp);
+ template_conformwords(tfrom, tto, conformaction, (t_word *)(oldarray + oldelemsize*i), wp);
+ word_free((t_word *)(oldarray + oldelemsize*i), tfrom);
+ }
+ scalartemplate = tto;
+ a->vec = newarray;
+ free(oldarray);
+ } else scalartemplate = template_findbyname(a->templatesym);
+ /* convert all arrays and sublist fields in each element of the array */
+ for (int i=0; i<a->n; i++) {
+ t_word *wp = (t_word *)(a->vec + sizeof(t_word) * a->n * i);
+ for (int j=0; j < scalartemplate->n; j++) {
+ t_dataslot *ds = scalartemplate->vec + j;
+ if (ds->type == DT_CANVAS) template_conformcanvas(tfrom, tto, conformaction, wp[j].w_canvas);
+ if (ds->type == DT_ARRAY) template_conformarray( tfrom, tto, conformaction, wp[j].w_array);
+ }
+ }
+}
+
+/* this routine searches for every scalar in the canvas that belongs
+ to the "from" template and makes it belong to the "to" template. Descend canvases recursively.
+ We don't handle redrawing here; this is to be filled in LATER... */
+t_array *garray_getarray(t_garray *x);
+static void template_conformcanvas(t_template *tfrom, t_template *tto, int *conformaction, t_canvas *canvas) {
+ canvas_each(g,canvas) {
+ t_class *c = g->_class;
+ /* what's the purpose of the assignment here?... consult original code */
+ if (c==scalar_class) g = template_conformscalar(tfrom, tto, conformaction, canvas, (t_scalar *)g);
+ else if (c==canvas_class) template_conformcanvas(tfrom, tto, conformaction, (t_canvas *)g);
+ else if (c==garray_class) template_conformarray(tfrom, tto, conformaction, garray_getarray((t_garray *)g));
+ }
+}
+
+/* globally conform all scalars from one template to another */
+void template_conform(t_template *tfrom, t_template *tto) {
+ int nto = tto->n, nfrom = tfrom->n, doit = 0;
+ int *conformaction = (int *)getbytes(sizeof(int) * nto);
+ int *conformedfrom = (int *)getbytes(sizeof(int) * nfrom);
+ for (int i=0; i< nto; i++) conformaction[i] = -1;
+ for (int i=0; i<nfrom; i++) conformedfrom[i] = 0;
+ for (int i=0; i < nto; i++) {
+ t_dataslot *dataslot = &tto->vec[i];
+ for (int j=0; j<nfrom; j++) {
+ t_dataslot *dataslot2 = &tfrom->vec[j];
+ if (dataslot_matches(dataslot, dataslot2, 1)) {
+ conformaction[i] = j;
+ conformedfrom[j] = 1;
+ }
+ }
+ }
+ for (int i=0; i<nto; i++) if (conformaction[i] < 0) {
+ t_dataslot *dataslot = &tto->vec[i];
+ for (int j=0; j<nfrom; j++)
+ if (!conformedfrom[j] && dataslot_matches(dataslot, &tfrom->vec[j], 0)) {
+ conformaction[i] = j;
+ conformedfrom[j] = 1;
+ }
+ }
+ if (nto != nfrom) doit = 1;
+ else for (int i=0; i<nto; i++) if (conformaction[i] != i) doit = 1;
+ if (doit) {
+ post("conforming template '%s' to new structure", tfrom->sym->name);
+ for (int i=0; i<nto; i++) post("... %d", conformaction[i]);
+ foreach(gl,windowed_canvases) template_conformcanvas(tfrom, tto, conformaction, gl->first);
+ }
+ free(conformaction);
+ free(conformedfrom);
+}
+
+t_template *template_findbyname(t_symbol *s) {return (t_template *)pd_findbyclass(s, template_class);}
+
+t_canvas *template_findcanvas(t_template *t) {
+ if (!t) bug("template_findcanvas");
+ t_gtemplate *gt = t->list;
+ if (!gt) return 0;
+ return gt->owner;
+ /* return ((t_canvas *)pd_findbyclass(t->sym, canvas_class)); */
+}
+
+void template_notify(t_template *t, t_symbol *s, int argc, t_atom *argv) {
+ if (t->list) outlet_anything(t->list->outlet, s, argc, argv);
+}
+
+/* bash the first of (argv) with a pointer to a scalar, and send on
+ to template as a notification message */
+static void template_notifyforscalar(t_template *t, t_canvas *owner, t_scalar *sc, t_symbol *s, int argc, t_atom *argv) {
+ t_gpointer gp;
+ gpointer_init(&gp);
+ gpointer_setcanvas(&gp, owner, sc);
+ SETPOINTER(argv, &gp);
+ template_notify(t, s, argc, argv);
+ gpointer_unset(&gp);
+}
+
+/* call this when reading a patch from a file to declare what templates
+ we'll need. If there's already a template, check if it matches.
+ If it doesn't it's still OK as long as there are no "struct" (gtemplate)
+ objects hanging from it; we just conform everyone to the new template.
+ If there are still struct objects belonging to the other template, we're
+ in trouble. LATER we'll figure out how to conform the new patch's objects
+ to the pre-existing struct. */
+static void *template_usetemplate(void *dummy, t_symbol *s, int argc, t_atom *argv) {
+ t_symbol *templatesym = canvas_makebindsym(atom_getsymbolarg(0, argc, argv));
+ t_template *x = (t_template *)pd_findbyclass(templatesym, template_class);
+ if (!argc) return 0;
+ argc--; argv++;
+ if (x) {
+ t_template *y = template_new(&s_, argc, argv);
+ /* If the new template is the same as the old one, there's nothing to do. */
+ if (!template_match(x, y)) { /* Are there "struct" objects upholding this template? */
+ if (x->list) {
+ error("%s: template mismatch", templatesym->name);
+ } else {
+ template_conform(x, y);
+ pd_free(x);
+ t_template *y2 = template_new(templatesym, argc, argv);
+ y2->list = 0;
+ }
+ }
+ pd_free(y);
+ } else template_new(templatesym, argc, argv);
+ return 0;
+}
+
+/* here we assume someone has already cleaned up all instances of this. */
+void template_free(t_template *x) {
+ if (*x->sym->name) pd_unbind(x,x->sym);
+ free(x->vec);
+}
+
+/* ---------------- gtemplates. One per canvas. ----------- */
+
+/* "Struct": an object that searches for, and if necessary creates,
+a template (above). Other objects in the canvas then can give drawing
+instructions for the template. The template doesn't go away when the
+"struct" is deleted, so that you can replace it with another one to add new fields, for example. */
+static void *gtemplate_donew(t_symbol *sym, int argc, t_atom *argv) {
+ t_gtemplate *x = (t_gtemplate *)pd_new(gtemplate_class);
+ t_template *t = template_findbyname(sym);
+ x->owner = canvas_getcurrent();
+ x->next = 0;
+ x->sym = sym;
+ x->argc = argc;
+ x->argv = (t_atom *)getbytes(argc * sizeof(t_atom));
+ for (int i=0; i<argc; i++) x->argv[i] = argv[i];
+ /* already have a template by this name? */
+ if (t) {
+ x->t = t;
+ /* if it's already got a "struct" object we
+ just tack this one to the end of the list and leave it there. */
+ if (t->list) {
+ t_gtemplate *x2, *x3;
+ for (x2 = x->t->list; (x3 = x2->next); x2 = x3) {}
+ x2->next = x;
+ post("template %s: warning: already exists.", sym->name);
+ } else {
+ /* if there's none, we just replace the template with our own and conform it. */
+ t_template *y = template_new(&s_, argc, argv);
+ //canvas_redrawallfortemplate(t, 2);
+ /* Unless the new template is different from the old one, there's nothing to do. */
+ if (!template_match(t, y)) {
+ /* conform everyone to the new template */
+ template_conform(t, y);
+ pd_free(t);
+ t = template_new(sym, argc, argv);
+ }
+ pd_free(y);
+ t->list = x;
+ //canvas_redrawallfortemplate(t, 1);
+ }
+ } else {
+ /* otherwise make a new one and we're the only struct on it. */
+ x->t = t = template_new(sym, argc, argv);
+ t->list = x;
+ }
+ outlet_new(x,0);
+ return x;
+}
+
+static void *gtemplate_new(t_symbol *s, int argc, t_atom *argv) {
+ t_symbol *sym = atom_getsymbolarg(0, argc, argv);
+ if (argc >= 1) {argc--; argv++;}
+ return (gtemplate_donew(canvas_makebindsym(sym), argc, argv));
+}
+
+/* old version (0.34) -- delete 2003 or so */
+static void *gtemplate_new_old(t_symbol *s, int argc, t_atom *argv) {
+ t_symbol *sym = canvas_makebindsym(canvas_getcurrent()->name);
+ static int warned;
+ if (!warned) {
+ post("warning -- 'template' (%s) is obsolete; replace with 'struct'", sym->name);
+ warned = 1;
+ }
+ return gtemplate_donew(sym, argc, argv);
+}
+
+t_template *gtemplate_get(t_gtemplate *x) {return x->t;}
+
+static void gtemplate_free(t_gtemplate *x) {
+ /* get off the template's list */
+ t_template *t = x->t;
+ if (x == t->list) {
+ //canvas_redrawallfortemplate(t, 2);
+ if (x->next) {
+ /* if we were first on the list, and there are others on the list, make a new template corresponding
+ to the new first-on-list and replace the existing template with it. */
+ t_template *z = template_new(&s_, x->next->argc, x->next->argv);
+ template_conform(t, z);
+ pd_free(t);
+ pd_free(z);
+ z = template_new(x->sym, x->next->argc, x->next->argv);
+ z->list = x->next;
+ for (t_gtemplate *y=z->list; y ; y=y->next) y->t=z;
+ } else t->list = 0;
+ //canvas_redrawallfortemplate(t, 1);
+ } else {
+ t_gtemplate *x2, *x3;
+ for (x2=t->list; (x3=x2->next); x2=x3) if (x==x3) {x2->next=x3->next; break;}
+ }
+ free(x->argv);
+}
+
+/* --------------- FIELD DESCRIPTORS (NOW CALLED SLOT) ---------------------- */
+/* a field descriptor can hold a constant or a variable's name; in the latter case,
+ it's the name of a field in the template we belong to. LATER, we might want to cache the offset
+ of the field so we don't have to search for it every single time we draw the object.
+*/
+/* note: there is also t_dataslot which plays a similar role. could they be merged someday? */
+
+struct _slot {
+ char type; /* LATER consider removing this? */
+ char var;
+ union {
+ t_float f; /* the field is a constant float */
+ t_symbol *s; /* the field is a constant symbol */
+ t_symbol *varsym; /* the field is variable and this is the name */
+ };
+ float min,max;
+ float scrmin,scrmax; /* min and max screen values */
+ float quantum; /* quantization in value */
+};
+
+static void slot_setfloat_const( t_slot *fd, float f) {
+ fd->type = A_FLOAT; fd->var = 0; fd->f = f; fd->min = fd->max = fd->scrmin = fd->scrmax = fd->quantum = 0;}
+static void slot_setsymbol_const(t_slot *fd, t_symbol *s) {
+ fd->type = A_SYMBOL; fd->var = 0; fd->s = s; fd->min = fd->max = fd->scrmin = fd->scrmax = fd->quantum = 0;}
+
+static void slot_setfloat_var(t_slot *fd, t_symbol *s) {
+ char *s1, *s2, *s3;
+ fd->type = A_FLOAT;
+ fd->var = 1;
+ if (!(s1 = strchr(s->name, '(')) || !(s2 = strchr(s->name, ')')) || s1>s2) {
+ fd->varsym = s;
+ fd->min = fd->max = fd->scrmin = fd->scrmax = fd->quantum = 0;
+ } else {
+ fd->varsym = symprintf("%.*s",s1-s->name,s->name);
+ t_int got = sscanf(s1, "(%f:%f)(%f:%f)(%f)", &fd->min, &fd->max, &fd->scrmin, &fd->scrmax, &fd->quantum);
+ if (got < 2) goto fail;
+ if (got == 3 || (got < 4 && strchr(s2, '('))) goto fail;
+ if (got < 5 && (s3 = strchr(s2, '(')) && strchr(s3+1, '(')) goto fail;
+ if (got == 4) fd->quantum = 0;
+ else if (got == 2) {
+ fd->quantum = 0;
+ fd->scrmin = fd->min;
+ fd->scrmax = fd->max;
+ }
+ return;
+ fail:
+ error("parse error: %s", s->name);
+ fd->min = fd->scrmin = fd->max = fd->scrmax = fd->quantum = 0;
+ }
+}
+
+#define CLOSED 1
+#define BEZ 2
+#define NOMOUSE 4
+#define A_ARRAY 55 /* LATER decide whether to enshrine this in m_pd.h */
+
+static void slot_setfloatarg(t_slot *fd, int argc, t_atom *argv) {
+ if (argc <= 0) slot_setfloat_const(fd, 0);
+ else if (argv->a_type == A_SYMBOL) slot_setfloat_var( fd, argv->a_symbol);
+ else slot_setfloat_const(fd, argv->a_float);
+}
+static void slot_setsymbolarg(t_slot *fd, int argc, t_atom *argv) {
+ if (argc <= 0) slot_setsymbol_const(fd, &s_);
+ else if (argv->a_type == A_SYMBOL) {
+ fd->type = A_SYMBOL;
+ fd->var = 1;
+ fd->varsym = argv->a_symbol;
+ fd->min = fd->max = fd->scrmin = fd->scrmax = fd->quantum = 0;
+ } else slot_setsymbol_const(fd, &s_);
+}
+static void slot_setarrayarg(t_slot *fd, int argc, t_atom *argv) {
+ if (argc <= 0) slot_setfloat_const(fd, 0);
+ else if (argv->a_type == A_SYMBOL) {
+ fd->type = A_ARRAY;
+ fd->var = 1;
+ fd->varsym = argv->a_symbol;
+ } else slot_setfloat_const(fd, argv->a_float);
+}
+
+/* getting and setting values via slots -- note confusing names; the above are setting up the slot itself. */
+
+/* convert a variable's value to a screen coordinate via its slot */
+static t_float slot_cvttocoord(t_slot *f, float val) {
+ float coord, extreme, div;
+ if (f->max == f->min) return val;
+ div = (f->scrmax - f->scrmin)/(f->max - f->min);
+ coord = f->scrmin + (val - f->min) * div;
+ extreme = f->scrmin<f->scrmax ? f->scrmin : f->scrmax; if (coord<extreme) coord = extreme;
+ extreme = f->scrmin>f->scrmax ? f->scrmin : f->scrmax; if (coord>extreme) coord = extreme;
+ return coord;
+}
+
+/* read a variable via slot and convert to screen coordinate */
+static t_float slot_getcoord(t_slot *f, t_template *t, t_word *wp, int loud) {
+ if (f->type!=A_FLOAT) {if (loud) error("symbolic data field used as number"); return 0;}
+ if (f->var) return slot_cvttocoord(f, template_getfloat(t, f->varsym, wp, loud));
+ return f->f;
+}
+static t_float slot_getfloat(t_slot *f, t_template *t, t_word *wp, int loud) {
+ if (f->type!=A_FLOAT) {if (loud) error("symbolic data field used as number"); return 0;}
+ if (f->var) return template_getfloat(t, f->varsym, wp, loud);
+ return f->f;
+}
+static t_symbol *slot_getsymbol(t_slot *f, t_template *t, t_word *wp, int loud) {
+ if (f->type!=A_SYMBOL) {if (loud) error("numeric data field used as symbol"); return &s_;}
+ if (f->var) return template_getsymbol(t, f->varsym, wp, loud);
+ return f->s;
+}
+
+/* convert from a screen coordinate to a variable value */
+static float slot_cvtfromcoord(t_slot *f, float coord) {
+ if (f->scrmax == f->scrmin) return coord;
+ else {
+ float div = (f->max - f->min)/(f->scrmax - f->scrmin);
+ float extreme;
+ float val = f->min + (coord - f->scrmin) * div;
+ if (f->quantum != 0) val = ((int)((val/f->quantum) + 0.5)) * f->quantum;
+ extreme = f->min<f->max ? f->min : f->max; if (val<extreme) val=extreme;
+ extreme = f->min>f->max ? f->min : f->max; if (val>extreme) val=extreme;
+ return val;
+ }
+ }
+
+static void slot_setcoord(t_slot *f, t_template *t, t_word *wp, float coord, int loud) {
+ if (f->type == A_FLOAT && f->var) {
+ float val = slot_cvtfromcoord(f, coord);
+ template_setfloat(t, f->varsym, wp, val, loud);
+ } else {
+ if (loud) error("attempt to set constant or symbolic data field to a number");
+ }
+}
+
+#define FIELDSET(T,F,D) if (argc) slot_set##T##arg(&x->F,argc--,argv++); \
+ else slot_setfloat_const(&x->F,D);
+
+/* curves belong to templates and describe how the data in the template are to be drawn.
+ The coordinates of the curve (and other display features) can be attached to fields in the template. */
+
+t_class *curve_class;
+
+/* includes polygons too */
+struct t_curve : t_object {
+ int flags; /* CLOSED and/or BEZ and/or NOMOUSE */
+ t_slot fillcolor, outlinecolor, width, vis;
+ int npoints;
+ t_slot *vec;
+ t_canvas *canvas;
+};
+
+static void *curve_new(t_symbol *classsym, t_int argc, t_atom *argv) {
+ t_curve *x = (t_curve *)pd_new(curve_class);
+ char *classname = classsym->name;
+ int flags = 0;
+ x->canvas = canvas_getcurrent();
+ if (classname[0] == 'f') {classname += 6; flags |= CLOSED;} else classname += 4;
+ slot_setfloat_const(&x->vis, 1);
+ if (classname[0] == 'c') flags |= BEZ;
+ while (1) {
+ t_symbol *firstarg = atom_getsymbolarg(0, argc, argv);
+ if (!strcmp(firstarg->name,"-v") && argc > 1) {
+ slot_setfloatarg(&x->vis, 1, argv+1);
+ argc -= 2; argv += 2;
+ } else
+ if (!strcmp(firstarg->name,"-x")) {
+ flags |= NOMOUSE;
+ argc -= 1; argv += 1;
+ } else break;
+ }
+ x->flags = flags;
+ if (flags&CLOSED&&argc) slot_setfloatarg( &x->fillcolor, argc--,argv++);
+ else slot_setfloat_const(&x->fillcolor, 0);
+ FIELDSET(float,outlinecolor,0);
+ FIELDSET(float,width,1);
+ if (argc < 0) argc = 0;
+ int nxy = argc + (argc&1);
+ x->npoints = nxy>>1;
+ x->vec = (t_slot *)getbytes(nxy * sizeof(t_slot));
+ t_slot *fd = x->vec;
+ for (int i=0; i<argc; i++, fd++, argv++) slot_setfloatarg(fd, 1, argv);
+ if (argc & 1) slot_setfloat_const(fd, 0);
+ return x;
+}
+
+static void curve_float(t_curve *x, t_floatarg f) {
+ if (x->vis.type != A_FLOAT || x->vis.var) {
+ error("global vis/invis for a template with variable visibility");
+ return;
+ }
+ int viswas = x->vis.f!=0;
+ if ((f!=0 && viswas) || (f==0 && !viswas)) return;
+ canvas_redrawallfortemplatecanvas(x->canvas, 2);
+ slot_setfloat_const(&x->vis, f!=0);
+ canvas_redrawallfortemplatecanvas(x->canvas, 1);
+}
+
+static int rangecolor(int n) {return n*9/255;}
+
+static void numbertocolor(int n, char *s) {
+ n = (int)max(n,0);
+ sprintf(s, "#%2.2x%2.2x%2.2x", rangecolor(n/100), rangecolor((n/10)%10), rangecolor(n%10));
+}
+
+static void curve_vis(t_gobj *z, t_canvas *canvas, t_word *data, t_template *t, float basex, float basey, int vis) {
+ t_curve *x = (t_curve *)z;
+ int n = x->npoints;
+ t_slot *f = x->vec;
+ if (!slot_getfloat(&x->vis, t, data, 0)) return;
+ if (vis) {
+ if (n > 1) {
+ int flags = x->flags;
+ char outline[20], fill[20];
+ int pix[200];
+ if (n > 100) n = 100;
+ /* calculate the pixel values before we start printing out the TK message so that
+ "error" printout won't be interspersed with it. Only show up to 100 points so we don't
+ have to allocate memory here. */
+ for (int i=0; i<n; i++, f += 2) {
+ pix[2*i ] = canvas_xtopixels(canvas, basex + slot_getcoord(f+0, t, data, 1));
+ pix[2*i+1] = canvas_ytopixels(canvas, basey + slot_getcoord(f+1, t, data, 1));
+ }
+ numbertocolor((int)slot_getfloat(&x->outlinecolor, t, data, 1), outline);
+ if (flags & CLOSED) {
+ numbertocolor((int)slot_getfloat(&x->fillcolor, t, data, 1), fill);
+ //sys_vgui(".x%lx.c create polygon\\\n", (long)canvas_getcanvas(canvas));
+ } else sys_vgui(".x%lx.c create line\\\n", (long)canvas_getcanvas(canvas));
+ for (int i=0; i<n; i++) sys_vgui("%d %d\\\n", pix[2*i], pix[2*i+1]);
+ sys_vgui("-width %f\\\n", max(slot_getfloat(&x->width, t, data, 1),1.0f));
+ if (flags & CLOSED) sys_vgui("-fill %s -outline %s\\\n", fill, outline);
+ else sys_vgui("-fill %s\\\n", outline);
+ if (flags & BEZ) sys_vgui("-smooth 1\\\n");
+ sys_vgui("-tags curve%lx\n", (long)data);
+ } else post("warning: curves need at least two points to be graphed");
+ } else {
+ if (n > 1) sys_vgui(".x%lx.c delete curve%lx\n", (long)canvas_getcanvas(canvas), (long)data);
+ }
+}
+
+static struct {
+ int field;
+ float xcumulative, xbase, xper;
+ float ycumulative, ybase, yper;
+ t_canvas *canvas;
+ t_scalar *scalar;
+ t_array *array;
+ t_word *wp;
+ t_template *t;
+ t_gpointer gpointer;
+} cm;
+
+/* LATER protect against the template changing or the scalar disappearing probably by attaching a gpointer here ... */
+#if 0
+static void curve_motion(void *z, t_floatarg dx, t_floatarg dy) {
+ t_curve *x = (t_curve *)z;
+ t_slot *f = x->vec + cm.field;
+ t_atom at;
+ if (!gpointer_check(&curve_motion_gpointer, 0)) {post("curve_motion: scalar disappeared"); return;}
+ cm.xcumulative += dx;
+ cm.ycumulative += dy;
+ if (f[0].var && dx!=0) slot_setcoord(f, cm.t, cm.wp, cm.xbase + cm.xcumulative*cm.xper, 1);
+ if (f[1].var && dy!=0) slot_setcoord(f+1, cm.t, cm.wp, cm.ybase + cm.ycumulative*cm.yper, 1);
+ /* LATER figure out what to do to notify for an array? */
+ if (cm.scalar) template_notifyforscalar(cm.t, cm.canvas, cm.scalar, gensym("change"), 1, &at);
+ if (cm.scalar) gobj_changed(cm.scalar,0); else gobj_changed(cm.array,0);
+}
+#endif
+
+int iabs(int a) {return a<0?-a:a;}
+
+static int curve_click(t_gobj *z, t_canvas *canvas, t_word *data, t_template *t, t_scalar *sc,
+t_array *ap, float basex, float basey, int xpix, int ypix, int shift, int alt, int dbl, int doit) {
+ t_curve *x = (t_curve *)z;
+ int bestn = -1;
+ int besterror = 0x7fffffff;
+ t_slot *f = x->vec;
+ if (!slot_getfloat(&x->vis, t, data, 0)) return 0;
+ for (int i=0; i<x->npoints; i++, f += 2) {
+ int xval = (int)slot_getcoord(f , t, data, 0), xloc = canvas_xtopixels(canvas, basex + xval);
+ int yval = (int)slot_getcoord(f+1, t, data, 0), yloc = canvas_ytopixels(canvas, basey + yval);
+ int xerr = iabs(xloc-xpix);
+ int yerr = iabs(yloc-ypix);
+ if (!f->var && !(f+1)->var) continue;
+ if (yerr > xerr) xerr = yerr;
+ if (xerr < besterror) {
+ cm.xbase = xval;
+ cm.ybase = yval;
+ besterror = xerr;
+ bestn = i;
+ }
+ }
+ if (besterror > 10) return 0;
+ if (doit) {
+ cm.xper = canvas_pixelstox(canvas, 1) - canvas_pixelstox(canvas, 0);
+ cm.yper = canvas_pixelstoy(canvas, 1) - canvas_pixelstoy(canvas, 0);
+ cm.xcumulative = cm.ycumulative = 0;
+ cm.canvas = canvas;
+ cm.scalar = sc;
+ cm.array = ap;
+ cm.wp = data;
+ cm.field = 2*bestn;
+ cm.t = t;
+ if (cm.scalar) gpointer_setcanvas(&cm.gpointer, cm.canvas, cm.scalar);
+ else gpointer_setarray(&cm.gpointer, cm.array, cm.wp);
+ /* canvas_grab(canvas, z, curve_motion, 0, xpix, ypix); */
+ }
+ return 1;
+}
+
+t_class *plot_class;
+
+struct t_plot : t_object {
+ t_canvas *canvas;
+ t_slot outlinecolor, width, xloc, yloc, xinc, style;
+ t_slot data, xpoints, ypoints, wpoints;
+ t_slot vis;
+ t_slot scalarvis; /* true if drawing the scalar at each point */
+};
+
+static void *plot_new(t_symbol *classsym, t_int argc, t_atom *argv) {
+ t_plot *x = (t_plot *)pd_new(plot_class);
+ int defstyle = PLOTSTYLE_POLY;
+ x->canvas = canvas_getcurrent();
+ slot_setfloat_var(&x->xpoints,&s_x);
+ slot_setfloat_var(&x->ypoints,&s_y);
+ slot_setfloat_var(&x->wpoints, gensym("w"));
+ slot_setfloat_const(&x->vis, 1);
+ slot_setfloat_const(&x->scalarvis, 1);
+ while (1) {
+ const char *f = atom_getsymbolarg(0, argc, argv)->name;
+ argc--; argv++;
+ if (!strcmp(f, "curve") || !strcmp(f, "-c")) defstyle = PLOTSTYLE_BEZ;
+ else if (!strcmp(f,"-v") &&argc>0) {slot_setfloatarg(&x->vis, 1,argv+1);argc--;argv++;}
+ else if (!strcmp(f,"-vs")&&argc>0) {slot_setfloatarg(&x->scalarvis,1,argv+1);argc--;argv++;}
+ else if (!strcmp(f,"-x") &&argc>0) {slot_setfloatarg(&x->xpoints, 1,argv+1);argc--;argv++;}
+ else if (!strcmp(f,"-y") &&argc>0) {slot_setfloatarg(&x->ypoints, 1,argv+1);argc--;argv++;}
+ else if (!strcmp(f,"-w") &&argc>0) {slot_setfloatarg(&x->wpoints, 1,argv+1);argc--;argv++;}
+ else break;
+ }
+ FIELDSET(array,data,1);
+ FIELDSET(float,outlinecolor,0);
+ FIELDSET(float,width,1);
+ FIELDSET(float,xloc,1);
+ FIELDSET(float,yloc,1);
+ FIELDSET(float,xinc,1);
+ FIELDSET(float,style,defstyle);
+ return x;
+}
+
+void plot_float(t_plot *x, t_floatarg f) {
+ int viswas;
+ if (x->vis.type != A_FLOAT || x->vis.var) {error("global vis/invis for a template with variable visibility"); return;}
+ viswas = x->vis.f!=0;
+ if ((f!=0 && viswas) || (f==0 && !viswas)) return;
+ canvas_redrawallfortemplatecanvas(x->canvas, 2);
+ slot_setfloat_const(&x->vis, f!=0);
+ canvas_redrawallfortemplatecanvas(x->canvas, 1);
+}
+
+/* get everything we'll need from the owner template of the array being
+ plotted. Not used for garrays, but see below */
+static int plot_readownertemplate(t_plot *x, t_word *data, t_template *ownertemplate,
+t_symbol **elemtemplatesymp, t_array **arrayp, float *linewidthp, float *xlocp, float *xincp, float *ylocp,
+float *stylep, float *visp, float *scalarvisp) {
+ int arrayonset, type;
+ t_symbol *elemtemplatesym;
+ t_array *array;
+ if (x->data.type != A_ARRAY || !x->data.var) {error("needs an array field"); return -1;}
+ if (!template_find_field(ownertemplate, x->data.varsym, &arrayonset, &type, &elemtemplatesym)) {
+ error("%s: no such field", x->data.varsym->name);
+ return -1;
+ }
+ if (type != DT_ARRAY) {error("%s: not an array", x->data.varsym->name); return -1;}
+ array = *(t_array **)(((char *)data) + arrayonset);
+ *linewidthp = slot_getfloat(&x->width, ownertemplate, data, 1);
+ *xlocp = slot_getfloat(&x->xloc, ownertemplate, data, 1);
+ *xincp = slot_getfloat(&x->xinc, ownertemplate, data, 1);
+ *ylocp = slot_getfloat(&x->yloc, ownertemplate, data, 1);
+ *stylep = slot_getfloat(&x->style, ownertemplate, data, 1);
+ *visp = slot_getfloat(&x->vis, ownertemplate, data, 1);
+ *scalarvisp = slot_getfloat(&x->scalarvis, ownertemplate, data, 1);
+ *elemtemplatesymp = elemtemplatesym;
+ *arrayp = array;
+ return 0;
+}
+
+/* get everything else you could possibly need about a plot,
+ either for plot's own purposes or for plotting a "garray" */
+static int array_getfields(t_symbol *elemtemplatesym, t_canvas **elemtemplatecanvasp,
+t_template **elemtemplatep, int *elemsizep, t_slot *xslot, t_slot *yslot, t_slot *wslot,
+int *xonsetp, int *yonsetp, int *wonsetp) {
+ int type;
+ t_symbol *dummy, *varname;
+ t_canvas *elemtemplatecanvas = 0;
+ /* the "float" template is special in not having to have a canvas;
+ template_findbyname is hardwired to return a predefined template. */
+ t_template *elemtemplate = template_findbyname(elemtemplatesym);
+ if (!elemtemplate) {error("%s: no such template", elemtemplatesym->name); return -1;}
+ if (!(elemtemplatesym==&s_float || (elemtemplatecanvas = template_findcanvas(elemtemplate)))) {
+ error("%s: no canvas for this template", elemtemplatesym->name);
+ return -1;
+ }
+ *elemtemplatecanvasp = elemtemplatecanvas;
+ *elemtemplatep = elemtemplate;
+ *elemsizep = elemtemplate->n * sizeof(t_word);
+#define FOO(f,name,onset) \
+ varname = f && f->var ? f->varsym : gensym(name); \
+ if (!template_find_field(elemtemplate,varname,&onset,&type,&dummy) || type!=DT_FLOAT) onset=-1;
+ FOO(yslot,"y",*yonsetp)
+ FOO(xslot,"x",*xonsetp)
+ FOO(wslot,"w",*wonsetp)
+#undef FOO
+ return 0;
+}
+
+static void plot_vis(t_gobj *z, t_canvas *canvas, t_word *data, t_template *t, float basex, float basey, int tovis) {
+ t_plot *x = (t_plot *)z;
+ int elemsize, yonset, wonset, xonset;
+ t_canvas *elemtemplatecanvas;
+ t_template *elemtemplate;
+ t_symbol *elemtemplatesym;
+ float linewidth, xloc, xinc, yloc, style, xsum, yval, vis, scalarvis;
+ t_array *array;
+ if (plot_readownertemplate(x, data, t, &elemtemplatesym, &array, &linewidth, &xloc, &xinc, &yloc, &style, &vis, &scalarvis)) return;
+ t_slot *xslot = &x->xpoints, *yslot = &x->ypoints, *wslot = &x->wpoints;
+ if (!vis) return;
+ if (array_getfields(elemtemplatesym, &elemtemplatecanvas, &elemtemplate, &elemsize,
+ xslot, yslot, wslot, &xonset, &yonset, &wonset)) return;
+ int nelem = array->n;
+ char *elem = (char *)array->vec;
+ if (tovis) {
+ if (style == PLOTSTYLE_POINTS) {
+ float minyval = 1e20, maxyval = -1e20;
+ int ndrawn = 0;
+ xsum = basex + xloc;
+ for (int i=0; i<nelem; i++) {
+ float yval;
+ int ixpix, inextx;
+ if (xonset >= 0) {
+ float usexloc = basex + xloc + *(float *)((elem + elemsize*i) + xonset);
+ ixpix = canvas_xtopixels(canvas, slot_cvttocoord(xslot, usexloc));
+ inextx = ixpix + 2;
+ } else {
+ ixpix = canvas_xtopixels(canvas, slot_cvttocoord(xslot, xsum)); xsum += xinc;
+ inextx = canvas_xtopixels(canvas, slot_cvttocoord(xslot, xsum));
+ }
+ yval = yonset>=0 ? yloc + *(float *)((elem + elemsize*i) + yonset) : 0;
+ if (yval > maxyval) maxyval = yval;
+ if (yval < minyval) minyval = yval;
+ if (i == nelem-1 || inextx != ixpix) {
+ sys_vgui(".x%lx.c create rectangle %d %d %d %d -fill black -width 0 -tags plot%lx\n",
+ (long)canvas_getcanvas(canvas), ixpix,
+ (int) canvas_ytopixels(canvas, basey + slot_cvttocoord(yslot, minyval)), inextx,
+ (int)(canvas_ytopixels(canvas, basey + slot_cvttocoord(yslot, maxyval))+linewidth),
+ (long)data);
+ ndrawn++;
+ minyval = 1e20;
+ maxyval = -1e20;
+ }
+ if (ndrawn > 2000 || ixpix >= 3000) break;
+ }
+ } else {
+ char outline[20];
+ int lastpixel = -1, ndrawn = 0;
+ float yval = 0, wval = 0;
+ int ixpix = 0;
+ /* draw the trace */
+ numbertocolor((int)slot_getfloat(&x->outlinecolor, t, data, 1), outline);
+ if (wonset >= 0) {
+ /* found "w" field which controls linewidth. The trace is a filled polygon with 2n points. */
+ //sys_vgui(".x%lx.c create polygon \\\n", (long)canvas_getcanvas(canvas));
+ xsum = xloc;
+ for (int i=0; i<nelem; i++) {
+ float usexloc = xonset>=0 ? xloc+*(float *)(elem+elemsize*i+xonset) : (xsum+=xinc);
+ float yval = yonset>=0 ? *(float *)(elem+elemsize*i+yonset) : 0;
+ wval = *(float *)(elem+elemsize*i+wonset);
+ float xpix = canvas_xtopixels(canvas, basex + slot_cvttocoord(xslot, usexloc));
+ ixpix = (int)roundf(xpix);
+ if (xonset >= 0 || ixpix != lastpixel) {
+ sys_vgui("%d %f \\\n", ixpix, canvas_ytopixels(canvas,
+ basey + slot_cvttocoord(yslot,yval+yloc)
+ - slot_cvttocoord(wslot,wval)));
+ ndrawn++;
+ }
+ lastpixel = ixpix;
+ if (ndrawn >= 1000) goto ouch;
+ }
+ lastpixel = -1;
+ for (int i=nelem-1; i>=0; i--) {
+ float usexloc = xonset>=0 ? xloc+*(float *)(elem+elemsize*i+xonset) : (xsum-=xinc);
+ float yval = yonset>=0 ? *(float *)(elem+elemsize*i+yonset) : 0;
+ wval = *(float *)((elem + elemsize*i) + wonset);
+ float xpix = canvas_xtopixels(canvas, basex + slot_cvttocoord(xslot, usexloc));
+ ixpix = (int)roundf(xpix);
+ if (xonset >= 0 || ixpix != lastpixel) {
+ sys_vgui("%d %f \\\n", ixpix, canvas_ytopixels(canvas,
+ basey + yloc + slot_cvttocoord(yslot, yval) + slot_cvttocoord(wslot, wval)));
+ ndrawn++;
+ }
+ lastpixel = ixpix;
+ if (ndrawn >= 1000) goto ouch;
+ }
+ /* TK will complain if there aren't at least 3 points. There should be at least two already. */
+ if (ndrawn < 4) {
+ int y = int(slot_cvttocoord(yslot, yval));
+ int w = int(slot_cvttocoord(wslot, wval));
+ sys_vgui("%d %f %d %f\\\n",
+ ixpix + 10, canvas_ytopixels(canvas, basey + yloc + y + w),
+ ixpix + 10, canvas_ytopixels(canvas, basey + yloc + y - w));
+ }
+ ouch:
+ sys_vgui(" -width 1 -fill %s -outline %s\\\n", outline, outline);
+ if (style == PLOTSTYLE_BEZ) sys_vgui("-smooth 1\\\n");
+ sys_vgui("-tags plot%lx\n", (long)data);
+ } else if (linewidth > 0) {
+ /* no "w" field. If the linewidth is positive, draw a segmented line with the
+ requested width; otherwise don't draw the trace at all. */
+ sys_vgui(".x%lx.c create line \\\n", (long)canvas_getcanvas(canvas));
+ xsum = xloc;
+ for (int i=0; i<nelem; i++) {
+ float usexloc = xonset>=0 ? xloc+*(float *)(elem+elemsize*i+xonset) : xsum; if (xonset>=0) xsum+=(int)xinc;
+ float yval = yonset>=0 ? *(float *)(elem+elemsize*i+yonset) : 0;
+ float xpix = canvas_xtopixels(canvas, basex + slot_cvttocoord(xslot, usexloc));
+ ixpix = (int)roundf(xpix);
+ if (xonset >= 0 || ixpix != lastpixel) {
+ sys_vgui("%d %f \\\n", ixpix, canvas_ytopixels(canvas, basey + yloc + slot_cvttocoord(yslot, yval)));
+ ndrawn++;
+ }
+ lastpixel = ixpix;
+ if (ndrawn >= 1000) break;
+ }
+ /* TK will complain if there aren't at least 2 points... */
+ if (ndrawn == 0) sys_vgui("0 0 0 0 \\\n");
+ else if (ndrawn == 1) sys_vgui("%d %f \\\n", ixpix + 10,
+ canvas_ytopixels(canvas, basey + yloc + slot_cvttocoord(yslot, yval)));
+ sys_vgui("-width %f -fill %s -smooth %d -tags plot%lx",linewidth,outline,style==PLOTSTYLE_BEZ,(long)data);
+ }
+ }
+ /* We're done with the outline; now draw all the points. This code is inefficient since
+ the template has to be searched for drawing instructions for every last point. */
+ if (scalarvis != 0) {
+ int xsum = (int)xloc;
+ for (int i=0; i<nelem; i++) {
+ //float usexloc = xonset>=0 ? basex + xloc + *(float *)(elem+elemsize*i+xonset) : basex+xsum;
+ if (xonset>=0) xsum+=int(xinc);
+ yval = yonset>=0 ? *(float *)(elem+elemsize*i+yonset) : 0;
+ //float useyloc = basey + yloc + slot_cvttocoord(yslot, yval);
+ /*canvas_each(y,elemtemplatecanvas) pd_getparentwidget(y)->w_parentvisfn(y, canvas,
+ (t_word *)(elem+elemsize*i), elemtemplate, usexloc, useyloc, tovis);*/
+ }
+ }
+ } else {
+ /* un-draw the individual points */
+ /* if (scalarvis != 0)
+ for (int i=0; i<nelem; i++)
+ canvas_each(y,elemtemplatecanvas)
+ pd_getparentwidget(y)->w_parentvisfn(y, canvas, (t_word *)(elem+elemsize*i), elemtemplate,0,0,0);*/
+ /* and then the trace */
+ sys_vgui(".x%lx.c delete plot%lx\n", (long)canvas_getcanvas(canvas), (long)data);
+ }
+}
+
+static int plot_click(t_gobj *z, t_canvas *canvas, t_word *data, t_template *t, t_scalar *sc,
+t_array *ap, float basex, float basey, int xpix, int ypix, int shift, int alt, int dbl, int doit) {
+ t_plot *x = (t_plot *)z;
+ t_symbol *elemtemplatesym;
+ float linewidth, xloc, xinc, yloc, style, vis, scalarvis;
+ t_array *array;
+ if (plot_readownertemplate(x, data, t, &elemtemplatesym, &array, &linewidth, &xloc, &xinc,
+ &yloc, &style, &vis, &scalarvis)) return 0;
+ if (!vis) return 0;
+ return array_doclick(array, canvas, sc, ap, elemtemplatesym, linewidth, basex + xloc, xinc,
+ basey + yloc, scalarvis, &x->xpoints, &x->ypoints, &x->wpoints, xpix, ypix, shift, alt, dbl, doit);
+}
+
+/* ---------------- drawnumber: draw a number (or symbol) ---------------- */
+/* drawnumbers draw numeric fields at controllable locations, with controllable color and label.
+ invocation: (drawnumber|drawsymbol) [-v <visible>] variable x y color label */
+
+t_class *drawnumber_class;
+
+#define DRAW_SYMBOL 1
+
+struct t_drawnumber : t_object {
+ t_slot value, xloc, yloc, color, vis;
+ t_symbol *label;
+ int flags;
+ t_canvas *canvas;
+};
+
+static void *drawnumber_new(t_symbol *classsym, t_int argc, t_atom *argv) {
+ t_drawnumber *x = (t_drawnumber *)pd_new(drawnumber_class);
+ char *classname = classsym->name;
+ int flags = 0;
+ if (classname[4] == 's') flags |= DRAW_SYMBOL;
+ x->flags = flags;
+ slot_setfloat_const(&x->vis, 1);
+ x->canvas = canvas_getcurrent();
+ while (1) {
+ t_symbol *firstarg = atom_getsymbolarg(0, argc, argv);
+ if (!strcmp(firstarg->name,"-v") && argc > 1) {
+ slot_setfloatarg(&x->vis, 1, argv+1);
+ argc -= 2; argv += 2;
+ } else break;
+ }
+ if (flags & DRAW_SYMBOL) {
+ if (argc) slot_setsymbolarg( &x->value,argc--,argv++);
+ else slot_setsymbol_const(&x->value,&s_);
+ } else FIELDSET(float,value, 0);
+ FIELDSET(float,xloc,0);
+ FIELDSET(float,yloc,0);
+ FIELDSET(float,color,1);
+ if (argc) x->label = atom_getsymbolarg(0, argc, argv); else x->label = &s_;
+ return x;
+}
+
+void drawnumber_float(t_drawnumber *x, t_floatarg f) {
+ if (x->vis.type != A_FLOAT || x->vis.var) {error("global vis/invis for a template with variable visibility"); return;}
+ int viswas = x->vis.f!=0;
+ if ((f != 0 && viswas) || (f == 0 && !viswas)) return;
+ canvas_redrawallfortemplatecanvas(x->canvas, 2);
+ slot_setfloat_const(&x->vis, f!=0);
+ canvas_redrawallfortemplatecanvas(x->canvas, 1);
+}
+
+static void drawnumber_vis(t_gobj *z, t_canvas *canvas, t_word *data, t_template *t, float basex, float basey, int vis) {
+ t_drawnumber *x = (t_drawnumber *)z;
+ if (!slot_getfloat(&x->vis, t, data, 0)) return;
+ if (vis) {
+ t_atom at;
+ int xloc = canvas_xtopixels(canvas, basex + slot_getcoord(&x->xloc, t, data, 0));
+ int yloc = canvas_ytopixels(canvas, basey + slot_getcoord(&x->yloc, t, data, 0));
+ char colorstring[20];
+ numbertocolor((int)slot_getfloat(&x->color, t, data, 1), colorstring);
+ if (x->flags & DRAW_SYMBOL) SETSYMBOL(&at, slot_getsymbol(&x->value, t, data, 0));
+ else SETFLOAT( &at, slot_getfloat( &x->value, t, data, 0));
+ std::ostringstream buf;
+ buf << x->label->name;
+ atom_ostream(&at,buf);
+ sys_vgui(".x%lx.c create text %d %d -anchor nw -fill %s -text {%s}",
+ (long)canvas_getcanvas(canvas), xloc, yloc, colorstring, buf.str().data());
+ sys_vgui(" -font {Courier 42} -tags drawnumber%lx\n", (long)data); /*sys_hostfontsize(canvas_getfont(canvas))*/
+ } else sys_vgui(".x%lx.c delete drawnumber%lx\n", (long)canvas_getcanvas(canvas), (long)data);
+}
+
+static struct {
+ float ycumulative;
+ t_canvas *canvas;
+ t_scalar *scalar;
+ t_array *array;
+ t_word *wp;
+ t_template *t;
+ t_gpointer gpointer;
+ int symbol;
+ int firstkey;
+} dn;
+
+/* LATER protect against the template changing or the scalar disappearing probably by attaching a gpointer here ... */
+#if 0
+static void drawnumber_motion(void *z, t_floatarg dx, t_floatarg dy) {
+ t_drawnumber *x = (t_drawnumber *)z;
+ t_slot *f = &x->value;
+ t_atom at;
+ if (!gpointer_check(&dn.gpointer, 0)) {post("drawnumber_motion: scalar disappeared"); return;}
+ if (dn.symbol) {post("drawnumber_motion: symbol"); return;}
+ dn.ycumulative -= dy;
+ template_setfloat(dn.t, f->varsym, dn.wp, dn.ycumulative, 1);
+ if (dn.scalar) gobj_changed(dn.scalar); else gobj_changed(dn.array);
+}
+#endif
+
+static void drawnumber_key(void *z, t_floatarg fkey) {
+ //t_drawnumber *x = (t_drawnumber *)z;
+ int key = (int)fkey;
+ if (!gpointer_check(&dn.gpointer, 0)) {
+ post("drawnumber_motion: scalar disappeared");
+ return;
+ }
+ if (key == 0) return;
+ if (dn.symbol) {
+ /* key entry for a symbol field... has to be rewritten in Tcl similarly to TextBox for edition of [drawsymbol] */
+ // template_getsymbol(dn.t, f->varsym, dn.wp, 1)->name;
+ } else {
+ /* key entry for a numeric field... same here... [drawnumber] */
+ //t_slot *f = &x->value;
+ //float newf;
+ //if (sscanf(sbuf, "%g", &newf) < 1) newf = 0;
+ //template_setfloat(dn.t, f->varsym, dn.wp, newf, 1);
+ //t_atom at;
+ //if (dn.scalar) template_notifyforscalar(dn.t, dn.canvas, dn.scalar, gensym("change"), 1, &at);
+ //if (dn.scalar) gobj_changed(dn.scalar,0); else gobj_changed(dn.array,0);
+ }
+}
+
+#if 0
+static int drawnumber_click(t_gobj *z, t_canvas *canvas, t_word *data, t_template *t, t_scalar *sc, t_array *ap, float basex, float basey, int xpix, int ypix, int shift, int alt, int dbl, int doit) {
+ t_drawnumber *x = (t_drawnumber *)z;
+ int x1, y1, x2, y2;
+ drawnumber_getrect(z, canvas, data, t, basex, basey, &x1, &y1, &x2, &y2);
+ if (xpix >= x1 && xpix <= x2 && ypix >= y1 && ypix <= y2
+ && x->value.var && slot_getfloat(&x->vis, t, data, 0)) {
+ if (doit) {
+ dn.canvas = canvas;
+ dn.wp = data;
+ dn.t = t;
+ dn.scalar = sc;
+ dn.array = ap;
+ dn.firstkey = 1;
+ dn.ycumulative = slot_getfloat(&x->value, t, data, 0);
+ dn.symbol = (x->flags & DRAW_SYMBOL)!=0;
+ if (dn.scalar)
+ gpointer_setcanvas(&dn.gpointer, dn.canvas, dn.scalar);
+ else gpointer_setarray(&dn.gpointer, dn.array, dn.wp);
+ /* canvas_grab(glist, z, drawnumber_motion, drawnumber_key, xpix, ypix); */
+ }
+ return 1;
+ } else return 0;
+}
+#endif
+
+static void drawnumber_free(t_drawnumber *x) {}
+
+static void g_template_setup() {
+ template_class = class_new2("template",0,template_free,sizeof(t_template),CLASS_PD,"");
+ class_addmethod2(pd_canvasmaker._class, template_usetemplate, "struct", "*");
+ gtemplate_class = class_new2("struct",gtemplate_new,gtemplate_free,sizeof(t_gtemplate),CLASS_NOINLET,"*");
+ class_addcreator2("template",gtemplate_new_old,"*");
+
+ curve_class = class_new2("drawpolygon",curve_new,0,sizeof(t_curve),0,"*");
+ class_setdrawcommand(curve_class);
+ class_addcreator2("drawcurve", curve_new,"*");
+ class_addcreator2("filledpolygon",curve_new,"*");
+ class_addcreator2("filledcurve", curve_new,"*");
+ class_addfloat(curve_class, curve_float);
+ plot_class = class_new2("plot",plot_new,0,sizeof(t_plot),0,"*");
+ class_setdrawcommand(plot_class);
+ class_addfloat(plot_class, plot_float);
+ drawnumber_class = class_new2("drawnumber",drawnumber_new,drawnumber_free,sizeof(t_drawnumber),0,"*");
+ class_setdrawcommand(drawnumber_class);
+ class_addfloat(drawnumber_class, drawnumber_float);
+ class_addcreator2("drawsymbol",drawnumber_new,"*");
+}
+
+/* ------------- gpointers - safe pointing --------------- */
+
+/* call this to verify that a pointer is fresh, i.e., that it either points to real data or to the head of a list,
+ and that in either case the object hasn't disappeared since this pointer was generated. Unless "headok" is set,
+ the routine also fails for the head of a list. */
+int gpointer_check(const t_gpointer *gp, int headok) {
+ if (!gp->o) return 0;
+ if (gp->o->_class == array_class) return 1;
+ return headok || gp->scalar;
+}
+
+/* get the template for the object pointer to. Assumes we've already checked freshness. Returns 0 if head of list. */
+static t_symbol *gpointer_gettemplatesym(const t_gpointer *gp) {
+ if (gp->o->_class == array_class) return gp->array->templatesym;
+ t_scalar *sc = gp->scalar;
+ return sc ? sc->t : 0;
+}
+
+/* copy a pointer to another, assuming the second one hasn't yet been initialized. New gpointers should be initialized
+ either by this routine or by gpointer_init below. */
+void gpointer_copy(const t_gpointer *gpfrom, t_gpointer *gpto) {
+ *gpto = *gpfrom;
+ if (gpto && gpto->o) gpto->o->refcount++; else bug("gpointer_copy");
+}
+
+void gpointer_unset(t_gpointer *gp) {
+ if (gp->scalar) {
+ if (!--gp->o->refcount) pd_free(gp->o);
+ gp->o=0;
+ gp->scalar=0;
+ }
+}
+
+static void gpointer_setcanvas(t_gpointer *gp, t_canvas *o, t_scalar *x) {
+ gpointer_unset(gp);
+ gp->o=o; gp->scalar = x; gp->o->refcount++;
+}
+static void gpointer_setarray(t_gpointer *gp, t_array *o, t_word *w) {
+ gpointer_unset(gp);
+ gp->o=o; gp->w = w; gp->o->refcount++;
+}
+
+void gpointer_init(t_gpointer *gp) {
+ gp->o = 0;
+ gp->scalar = 0;
+}
+
+/* ---------------------- pointers ----------------------------- */
+
+static t_class *ptrobj_class;
+
+struct t_typedout {
+ t_symbol *type;
+ t_outlet *outlet;
+};
+
+struct t_ptrobj : t_object {
+ t_gpointer gp;
+ t_typedout *typedout;
+ int ntypedout;
+ t_outlet *otherout;
+ t_outlet *bangout;
+};
+
+static void *ptrobj_new(t_symbol *classname, int argc, t_atom *argv) {
+ t_ptrobj *x = (t_ptrobj *)pd_new(ptrobj_class);
+ t_typedout *to;
+ gpointer_init(&x->gp);
+ x->typedout = to = (t_typedout *)getbytes(argc * sizeof (*to));
+ x->ntypedout = argc;
+ for (int n=argc; n--; to++) {
+ to->outlet = outlet_new(x,&s_pointer);
+ to->type = canvas_makebindsym(atom_getsymbol(argv++));
+ }
+ x->otherout = outlet_new(x,&s_pointer);
+ x->bangout = outlet_new(x,&s_bang);
+ pointerinlet_new(x,&x->gp);
+ return x;
+}
+
+static void ptrobj_traverse(t_ptrobj *x, t_symbol *s) {
+ t_canvas *canvas = (t_canvas *)pd_findbyclass(s, canvas_class);
+ if (canvas) gpointer_setcanvas(&x->gp, canvas, 0);
+ else error("list '%s' not found", s->name);
+}
+
+static void ptrobj_vnext(t_ptrobj *x, float f) {
+ t_gpointer *gp = &x->gp;
+ int wantselected = f!=0;
+ if (!gp->o) {error("next: no current pointer"); return;}
+ if (gp->o->_class == array_class) {error("next: lists only, not arrays"); return;}
+ t_canvas *canvas = gp->canvas;
+ if (wantselected) {error("next: next-selected unsupported in desiredata"); return;}
+ /* if (wantselected && !canvas_isvisible(canvas)) {error("next: next-selected only works for a visible window"); return;} */
+ t_gobj *gobj = gp->scalar;
+ if (!gobj) gobj = canvas->boxes->first();
+ else gobj = gobj->next();
+ while (gobj && (gobj->_class != scalar_class || wantselected)) gobj = gobj->next();
+ if (gobj) {
+ t_typedout *to = x->typedout;
+ t_scalar *sc = (t_scalar *)gobj;
+ gp->scalar = sc;
+ for (int n = x->ntypedout; n--; to++)
+ if (to->type == sc->t) {outlet_pointer(to->outlet, &x->gp); return;}
+ outlet_pointer(x->otherout, &x->gp);
+ } else {
+ gpointer_unset(gp);
+ outlet_bang(x->bangout);
+ }
+}
+
+static void ptrobj_next(t_ptrobj *x) {ptrobj_vnext(x, 0);}
+
+static void ptrobj_sendwindow(t_ptrobj *x, t_symbol *s, int argc, t_atom *argv) {
+ if (!gpointer_check(&x->gp, 1)) {error("bang: empty pointer"); return;}
+ t_canvas *canvas = gpointer_getcanvas(&x->gp);
+ if (argc && argv->a_type == A_SYMBOL) pd_typedmess(canvas_getcanvas(canvas), argv->a_symbol, argc-1, argv+1);
+ else error("send-window: no message?");
+}
+
+static void ptrobj_bang(t_ptrobj *x) {
+ t_typedout *to = x->typedout;
+ if (!gpointer_check(&x->gp, 1)) {error("bang: empty pointer"); return;}
+ t_symbol *templatesym = gpointer_gettemplatesym(&x->gp);
+ for (int n=x->ntypedout; n--; to++)
+ if (to->type == templatesym) {outlet_pointer(to->outlet, &x->gp); return;}
+ outlet_pointer(x->otherout, &x->gp);
+}
+
+static void ptrobj_pointer(t_ptrobj *x, t_gpointer *gp) {
+ gpointer_unset(&x->gp);
+ gpointer_copy(gp, &x->gp);
+ ptrobj_bang(x);
+}
+
+static void ptrobj_rewind(t_ptrobj *x) {
+ if (!gpointer_check(&x->gp, 1)) {error("rewind: empty pointer"); return;}
+ if (x->gp.o->_class == array_class) {error("rewind: sorry, unavailable for arrays"); return;}
+ gpointer_setcanvas(&x->gp, x->gp.canvas, 0);
+ ptrobj_bang(x);
+}
+
+static void ptrobj_free(t_ptrobj *x) {
+ free(x->typedout);
+ gpointer_unset(&x->gp);
+}
+
+/* ---------------------- get ----------------------------- */
+
+static t_class *get_class;
+struct t_getvariable {
+ t_symbol *sym;
+ t_outlet *outlet;
+};
+struct t_get : t_object {
+ t_symbol *templatesym;
+ int nout;
+ t_getvariable *variables;
+};
+static void *get_new(t_symbol *why, int argc, t_atom *argv) {
+ t_get *x = (t_get *)pd_new(get_class);
+ x->templatesym = canvas_makebindsym(atom_getsymbolarg(0, argc, argv));
+ if (argc) argc--, argv++;
+ t_getvariable *sp = x->variables = (t_getvariable *)getbytes(argc * sizeof (*x->variables));
+ x->nout = argc;
+ for (int i=0; i < argc; i++, sp++) {
+ sp->sym = atom_getsymbolarg(i, argc, argv);
+ sp->outlet = outlet_new(x,0);
+ /* LATER connect with the template and set the outlet's type
+ correctly. We can't yet guarantee that the template is there
+ before we hit this routine. */
+ }
+ return x;
+}
+
+static void get_pointer(t_get *x, t_gpointer *gp) {
+ int nitems = x->nout;
+ t_template *t = template_findbyname(x->templatesym);
+ t_getvariable *vp;
+ TEMPLATE_CHECK(x->templatesym,)
+ if (!gpointer_check(gp, 0)) {error("stale or empty pointer"); return;}
+ t_word *vec = gpointer_word(gp);
+ vp = x->variables + nitems-1;
+ for (int i=nitems-1; i>=0; i--, vp--) {
+ int onset, type;
+ t_symbol *arraytype;
+ if (template_find_field(t, vp->sym, &onset, &type, &arraytype)) {
+ if (type == DT_FLOAT) outlet_float(vp->outlet, *(t_float *)(((char *)vec) + onset));
+ else if (type == DT_SYMBOL) outlet_symbol(vp->outlet, *(t_symbol **)(((char *)vec) + onset));
+ else error("%s.%s is not a number or symbol", t->sym->name, vp->sym->name);
+ } else error("%s.%s: no such field", t->sym->name, vp->sym->name);
+ }
+}
+
+static void get_free(t_get *x) {free(x->variables);}
+
+/* ---------------------- set ----------------------------- */
+
+static t_class *set_class;
+
+struct t_setvariable {
+ t_symbol *sym;
+ union word w;
+};
+
+struct t_set : t_object {
+ t_gpointer gp;
+ t_symbol *templatesym;
+ int nin;
+ int issymbol;
+ t_setvariable *variables;
+};
+
+static void *set_new(t_symbol *why, int argc, t_atom *argv) {
+ t_set *x = (t_set *)pd_new(set_class);
+ if (argc && (argv[0].a_type == A_SYMBOL) && !strcmp(argv[0].a_symbol->name,"-symbol")) {
+ x->issymbol = 1;
+ argc--;
+ argv++;
+ }
+ else x->issymbol = 0;
+ x->templatesym = canvas_makebindsym(atom_getsymbolarg(0, argc, argv));
+ if (argc) argc--, argv++;
+ t_setvariable *sp = x->variables = (t_setvariable *)getbytes(argc * sizeof (*x->variables));
+ x->nin = argc;
+ if (argc) {
+ for (int i=0; i<argc; i++, sp++) {
+ sp->sym = atom_getsymbolarg(i, argc, argv);
+ if (x->issymbol) sp->w.w_symbol = &s_;
+ else sp->w.w_float = 0;
+ if (i) {
+ if (x->issymbol) symbolinlet_new(x,&sp->w.w_symbol);
+ else floatinlet_new(x, &sp->w.w_float);
+ }
+ }
+ }
+ pointerinlet_new(x,&x->gp);
+ gpointer_init(&x->gp);
+ return x;
+}
+
+static void set_bang(t_set *x) {
+ int nitems = x->nin;
+ t_template *t = template_findbyname(x->templatesym);
+ t_gpointer *gp = &x->gp;
+ TEMPLATE_CHECK(x->templatesym,)
+ if (!gpointer_check(gp, 0)) {error("empty pointer"); return;}
+ if (gpointer_gettemplatesym(gp) != x->templatesym) {
+ error("%s: got wrong template (%s)",x->templatesym->name,gpointer_gettemplatesym(gp)->name);
+ return;
+ }
+ if (!nitems) return;
+ t_word *vec = gpointer_word(gp);
+ t_setvariable *vp=x->variables;
+ if (x->issymbol) for (int i=0; i<nitems; i++,vp++) template_setsymbol(t, vp->sym, vec, vp->w.w_symbol, 1);
+ else for (int i=0; i<nitems; i++,vp++) template_setfloat(t, vp->sym, vec, vp->w.w_float, 1);
+ scalar_redraw(gp->scalar, gpointer_getcanvas(gp)); /* but ought to use owner_array->gp.scalar */
+}
+
+static void set_float(t_set *x, t_float f) {
+ if (x->nin && !x->issymbol) {x->variables[0].w.w_float = f; set_bang(x);}
+ else error("type mismatch or no field specified");
+}
+static void set_symbol(t_set *x, t_symbol *s) {
+ if (x->nin && x->issymbol) {x->variables[0].w.w_symbol = s; set_bang(x);}
+ else error("type mismatch or no field specified");
+}
+
+static void set_free(t_set *x) {
+ free(x->variables);
+ gpointer_unset(&x->gp);
+}
+
+/* ---------------------- elem ----------------------------- */
+
+static t_class *elem_class;
+
+struct t_elem : t_object {
+ t_symbol *templatesym;
+ t_symbol *fieldsym;
+ t_gpointer gp;
+ t_gpointer gparent;
+};
+
+static void *elem_new(t_symbol *templatesym, t_symbol *fieldsym) {
+ t_elem *x = (t_elem *)pd_new(elem_class);
+ x->templatesym = canvas_makebindsym(templatesym);
+ x->fieldsym = fieldsym;
+ gpointer_init(&x->gp);
+ gpointer_init(&x->gparent);
+ pointerinlet_new(x,&x->gparent);
+ outlet_new(x,&s_pointer);
+ return x;
+}
+
+static void elem_float(t_elem *x, t_float f) {
+ int indx = (int)f, nitems, onset;
+ t_symbol *fieldsym = x->fieldsym, *elemtemplatesym;
+ t_template *t = template_findbyname(x->templatesym);
+ t_template *elemtemplate;
+ t_gpointer *gparent = &x->gparent;
+ t_array *array;
+ int elemsize, type;
+ if (!gpointer_check(gparent, 0)) {error("empty pointer"); return;}
+ if (gpointer_gettemplatesym(gparent) != x->templatesym) {
+ error("%s: got wrong template (%s)", x->templatesym->name, gpointer_gettemplatesym(gparent)->name);
+ return;
+ }
+ t_word *w = gpointer_word(gparent);
+ TEMPLATE_CHECK(x->templatesym,)
+ if (!template_find_field(t, fieldsym, &onset, &type, &elemtemplatesym)) {
+ error("couldn't find array field %s", fieldsym->name);
+ return;
+ }
+ if (type != DT_ARRAY) {error("element: field %s not of type array", fieldsym->name); return;}
+ if (!(elemtemplate = template_findbyname(elemtemplatesym))) {
+ error("couldn't find field template %s", elemtemplatesym->name);
+ return;
+ }
+ elemsize = elemtemplate->n * sizeof(t_word);
+ array = *(t_array **)(((char *)w) + onset);
+ nitems = array->n;
+ if (indx < 0) indx = 0;
+ if (indx >= nitems) indx = nitems-1;
+ gpointer_setarray(&x->gp, array, (t_word *)&array->vec[indx*elemsize]);
+ outlet_pointer(x->outlet, &x->gp);
+}
+
+static void elem_free(t_elem *x, t_gpointer *gp) {
+ gpointer_unset(&x->gp);
+ gpointer_unset(&x->gparent);
+}
+
+/* ---------------------- getsize ----------------------------- */
+
+static t_class *getsize_class;
+
+struct t_getsize : t_object {
+ t_symbol *templatesym;
+ t_symbol *fieldsym;
+};
+
+static void *getsize_new(t_symbol *templatesym, t_symbol *fieldsym) {
+ t_getsize *x = (t_getsize *)pd_new(getsize_class);
+ x->templatesym = canvas_makebindsym(templatesym);
+ x->fieldsym = fieldsym;
+ outlet_new(x,&s_float);
+ return x;
+}
+
+static void getsize_pointer(t_getsize *x, t_gpointer *gp) {
+ int onset, type;
+ t_symbol *fieldsym = x->fieldsym, *elemtemplatesym;
+ t_template *t = template_findbyname(x->templatesym);
+ TEMPLATE_CHECK(x->templatesym,)
+ if (!template_find_field(t, fieldsym, &onset, &type, &elemtemplatesym)) {
+ error("couldn't find array field %s", fieldsym->name);
+ return;
+ }
+ if (type != DT_ARRAY) {error("field %s not of type array", fieldsym->name); return;}
+ if (!gpointer_check(gp, 0)) {error("stale or empty pointer"); return;}
+ if (gpointer_gettemplatesym(gp) != x->templatesym) {
+ error("%s: got wrong template (%s)", x->templatesym->name, gpointer_gettemplatesym(gp)->name);
+ return;
+ }
+ t_word *w = gpointer_word(gp);
+ t_array *array = *(t_array **)(((char *)w) + onset);
+ outlet_float(x->outlet, (float)(array->n));
+}
+
+/* ---------------------- setsize ----------------------------- */
+
+static t_class *setsize_class;
+
+struct t_setsize : t_object {
+ t_symbol *templatesym;
+ t_symbol *fieldsym;
+ t_gpointer gp;
+};
+
+static void *setsize_new(t_symbol *templatesym, t_symbol *fieldsym, t_floatarg newsize) {
+ t_setsize *x = (t_setsize *)pd_new(setsize_class);
+ x->templatesym = canvas_makebindsym(templatesym);
+ x->fieldsym = fieldsym;
+ gpointer_init(&x->gp);
+ pointerinlet_new(x,&x->gp);
+ return x;
+}
+
+static void setsize_float(t_setsize *x, t_float f) {
+ int onset, type;
+ t_template *t = template_findbyname(x->templatesym);
+ int newsize = (int)f;
+ t_gpointer *gp = &x->gp;
+ if (!gpointer_check(&x->gp, 0)) {error("empty pointer"); return;}
+ if (gpointer_gettemplatesym(&x->gp) != x->templatesym) {
+ error("%s: got wrong template (%s)", x->templatesym->name, gpointer_gettemplatesym(&x->gp)->name);
+ return;
+ }
+ t_word *w = gpointer_word(gp);
+ TEMPLATE_CHECK(x->templatesym,)
+ t_symbol *elemtemplatesym;
+ if (!template_find_field(t, x->fieldsym, &onset, &type, &elemtemplatesym)) {
+ error("couldn't find array field %s", x->fieldsym->name);
+ return;
+ }
+ if (type != DT_ARRAY) {error("field %s not of type array", x->fieldsym->name); return;}
+ t_template *elemtemplate = template_findbyname(elemtemplatesym);
+ if (!elemtemplate) {
+ error("couldn't find field template %s", elemtemplatesym->name);
+ return;
+ }
+ int elemsize = elemtemplate->n * sizeof(t_word);
+ t_array *array = *(t_array **)(((char *)w) + onset);
+ if (elemsize != array->elemsize) bug("setsize_gpointer");
+ int nitems = array->n;
+ if (newsize < 1) newsize = 1;
+ if (newsize == nitems) return;
+
+ /* here there was something to erase the array before resizing it */
+
+ /* now do the resizing and, if growing, initialize new scalars */
+ array->vec = (char *)resizealignedbytes(array->vec, elemsize * nitems, elemsize * newsize);
+ array->n = newsize;
+ if (newsize > nitems) {
+ char *newelem = &array->vec[nitems*elemsize];
+ int nnew = newsize - nitems;
+ while (nnew--) {
+ word_init((t_word *)newelem, elemtemplate, gp);
+ newelem += elemsize;
+ }
+ }
+ gobj_changed(gpointer_getscalar(gp),0);
+}
+
+static void setsize_free(t_setsize *x) {gpointer_unset(&x->gp);}
+
+/* ---------------------- append ----------------------------- */
+
+static t_class *append_class;
+
+struct t_appendvariable {
+ t_symbol *sym;
+ t_float f;
+};
+
+struct t_append : t_object {
+ t_gpointer gp;
+ t_symbol *templatesym;
+ int nin;
+ t_appendvariable *variables;
+};
+
+static void *append_new(t_symbol *why, int argc, t_atom *argv) {
+ t_append *x = (t_append *)pd_new(append_class);
+ x->templatesym = canvas_makebindsym(atom_getsymbolarg(0, argc, argv));
+ if (argc) argc--, argv++;
+ x->variables = (t_appendvariable *)getbytes(argc * sizeof (*x->variables));
+ x->nin = argc;
+ if (argc) {
+ t_appendvariable *sp = x->variables;
+ for (int i=0; i<argc; i++, sp++) {
+ sp->sym = atom_getsymbolarg(i, argc, argv);
+ sp->f = 0;
+ if (i) floatinlet_new(x,&sp->f);
+ }
+ }
+ pointerinlet_new(x,&x->gp);
+ outlet_new(x,&s_pointer);
+ gpointer_init(&x->gp);
+ return x;
+}
+
+static void append_float(t_append *x, t_float f) {
+ int nitems = x->nin;
+ t_template *t = template_findbyname(x->templatesym);
+ t_gpointer *gp = &x->gp;
+ TEMPLATE_CHECK(x->templatesym,)
+ if (!gp->o) {error("no current pointer"); return;}
+ if (gp->o->_class == array_class) {error("lists only, not arrays"); return;}
+ t_canvas *canvas = gp->canvas;
+ if (!nitems) return;
+ x->variables[0].f = f;
+ t_scalar *sc = scalar_new(canvas,x->templatesym);
+ if (!sc) {error("%s: couldn't create scalar", x->templatesym->name); return;}
+ canvas->boxes->add(sc);
+ gobj_changed(sc,0);
+ gp->scalar = sc;
+ t_word *vec = sc->v;
+ t_appendvariable *vp=x->variables;
+ for (int i=0; i<nitems; i++,vp++) template_setfloat(t, vp->sym, vec, vp->f, 1);
+ scalar_redraw(sc, canvas);
+ outlet_pointer(x->outlet, gp);
+}
+
+static void append_free(t_append *x) {
+ free(x->variables);
+ gpointer_unset(&x->gp);
+}
+
+/* ---------------------- sublist ----------------------------- */
+
+static t_class *sublist_class;
+
+struct t_sublist : t_object {
+ t_symbol *templatesym;
+ t_symbol *fieldsym;
+ t_gpointer gp;
+};
+
+static void *sublist_new(t_symbol *templatesym, t_symbol *fieldsym) {
+ t_sublist *x = (t_sublist *)pd_new(sublist_class);
+ x->templatesym = canvas_makebindsym(templatesym);
+ x->fieldsym = fieldsym;
+ gpointer_init(&x->gp);
+ outlet_new(x,&s_pointer);
+ return x;
+}
+
+static void sublist_pointer(t_sublist *x, t_gpointer *gp) {
+ t_symbol *dummy;
+ t_template *t = template_findbyname(x->templatesym);
+ int onset, type;
+ TEMPLATE_CHECK(x->templatesym,)
+ if (!gpointer_check(gp, 0)) {error("stale or empty pointer"); return;}
+ if (!template_find_field(t, x->fieldsym, &onset, &type, &dummy)) {
+ error("couldn't find field %s", x->fieldsym->name);
+ return;
+ }
+ if (type != DT_CANVAS) {error("field %s not of type list", x->fieldsym->name); return;}
+ t_word *w = gpointer_word(gp);
+ gpointer_setcanvas(&x->gp, *(t_canvas **)(((char *)w) + onset), 0);
+ outlet_pointer(x->outlet, &x->gp);
+}
+
+static void sublist_free(t_sublist *x, t_gpointer *gp) {gpointer_unset(&x->gp);}
+
+static void g_traversal_setup() {
+ t_class *c = ptrobj_class = class_new2("pointer",ptrobj_new,ptrobj_free,sizeof(t_ptrobj),0,"*");
+ class_addmethod2(c, ptrobj_traverse,"traverse", "s");
+ class_addmethod2(c, ptrobj_next,"next","");
+ class_addmethod2(c, ptrobj_vnext,"vnext","F");
+ class_addmethod2(c, ptrobj_sendwindow,"send-window","*");
+ class_addmethod2(c, ptrobj_rewind, "rewind","");
+ class_addpointer(c, ptrobj_pointer);
+ class_addbang(c, ptrobj_bang);
+ get_class = class_new2("get",get_new,get_free,sizeof(t_get),0,"*");
+ class_addpointer(get_class, get_pointer);
+ set_class = class_new2("set",set_new,set_free,sizeof(t_set),0,"*");
+ class_addfloat(set_class, set_float);
+ class_addsymbol(set_class, set_symbol);
+ class_addbang(set_class, set_bang);
+ elem_class = class_new2("element",elem_new,elem_free,sizeof(t_elem),0,"SS");
+ class_addfloat(elem_class, elem_float);
+ getsize_class = class_new2("getsize",getsize_new,0,sizeof(t_getsize),0,"SS");
+ class_addpointer(getsize_class, getsize_pointer);
+ setsize_class = class_new2("setsize",setsize_new,setsize_free,sizeof(t_setsize),0,"SSFF");
+ class_addfloat(setsize_class, setsize_float);
+ append_class = class_new2("append",append_new,append_free,sizeof(t_append),0,"*");
+ class_addfloat(append_class, append_float);
+ sublist_class = class_new2("sublist",sublist_new,sublist_free,sizeof(t_sublist),0,"SS");
+ class_addpointer(sublist_class, sublist_pointer);
+}
+
+/*EXTERN*/ void canvas_savecontainerto(t_canvas *x, t_binbuf *b);
+
+struct t_iemgui : t_object {
+ t_canvas *canvas;
+ int h,w;
+ int ldx,ldy;
+ int isa; /* bit 0: loadinit; bit 20: scale */
+ int font_style, fontsize;
+ int fcol,bcol,lcol; /* foreground, background, label colors */
+ t_symbol *snd,*rcv,*lab; /* send, receive, label symbols */
+};
+
+struct t_bng : t_iemgui {
+ int count;
+ int ftbreak; /* flash time break (ms) */
+ int fthold; /* flash time hold (ms) */
+};
+
+struct t_slider : t_iemgui {
+ t_float val;
+ t_float min,max;
+ int steady;
+ int is_log;
+ int orient;
+};
+
+struct t_radio : t_iemgui {
+ int on, on_old;
+ int change;
+ int number;
+ t_atom at[2];
+ int orient;
+ int oldstyle;
+};
+
+struct t_toggle : t_iemgui {
+ float on;
+ float nonzero;
+};
+
+struct t_cnv : t_iemgui {
+ t_atom at[3];
+ int vis_w, vis_h;
+};
+
+struct t_dropper : t_iemgui {
+ t_symbol *s;
+ t_symbol *ds;
+};
+
+struct t_vu : t_iemgui {
+ int led_size;
+ int peak,rms;
+ float fp,fr;
+ int scale;
+};
+
+struct t_nbx : t_iemgui {
+ double val;
+ double min,max;
+ double k;
+ char buf[32];
+ int log_height;
+ int change;
+ int is_log;
+};
+
+struct t_foo { int argc; t_atom *argv; t_binbuf *b; };
+static int pd_pickle(t_foo *foo, char *fmt, ...);
+static int pd_savehead(t_binbuf *b, t_iemgui *x, char *name);
+
+static t_class *radio_class, *slider_class;
+static t_symbol *sym_hdl, *sym_hradio, *sym_vdl, *sym_vradio, *sym_vsl, *sym_vslider;
+
+t_class *dummy_class;
+/*static*/ t_class *text_class;
+static t_class *mresp_class;
+static t_class *message_class;
+static t_class *gatom_class;
+
+void canvas_text(t_canvas *gl, t_symbol *s, int argc, t_atom *argv) {
+ t_text *x = (t_text *)pd_new(text_class);
+ x->binbuf = binbuf_new();
+ x->x = atom_getintarg(0, argc, argv);
+ x->y = atom_getintarg(1, argc, argv);
+ if (argc > 2) binbuf_restore(x->binbuf, argc-2, argv+2);
+ canvas_add(gl,x);
+ pd_set_newest(x);
+}
+
+void canvas_getargs(int *argcp, t_atom **argvp) {
+ t_canvasenvironment *e = canvas_getenv(canvas_getcurrent());
+ *argcp = e->argc;
+ *argvp = e->argv;
+}
+
+static void canvas_objtext(t_canvas *gl, int xpix, int ypix, t_binbuf *b, int index=-1) {
+ t_text *x=0;
+ int argc, n;
+ t_atom *argv;
+ char *s;
+ newest = 0;
+ binbuf_gettext(b,&s,&n);
+ pd_pushsym(gl);
+ canvas_getargs(&argc, &argv);
+ binbuf_eval(b, &pd_objectmaker, argc, argv);
+ if (binbuf_getnatom(b)) {
+ if (!newest) {
+ char *s = binbuf_gettext2(b);
+ error("couldn't create %s",s);
+ free(s);
+ } else if (!(x = pd_checkobject(newest))) {
+ char *s = binbuf_gettext2(b);
+ error("didn't return a patchable object: %s",s);
+ free(s);
+ }
+ }
+ /* make a "broken object", that is, one that should appear with a dashed contour. */
+ if (!x) {
+ x = (t_text *)pd_new(dummy_class);
+ pd_set_newest(x);
+ }
+ x->binbuf = b;
+ x->x = xpix;
+ x->y = ypix;
+ canvas_add(gl,x,index);
+ if (x->_class== vinlet_class) canvas_resortinlets(canvas_getcanvas(gl));
+ if (x->_class==voutlet_class) canvas_resortoutlets(canvas_getcanvas(gl));
+ pd_popsym(gl);
+}
+
+void canvas_obj(t_canvas *gl, t_symbol *s, int argc, t_atom *argv) {
+ t_binbuf *b = binbuf_new();
+ if (argc >= 2) {
+ binbuf_restore(b, argc-2, argv+2);
+ canvas_objtext(gl, atom_getintarg(0, argc, argv), atom_getintarg(1, argc, argv), b);
+ } else canvas_objtext(gl,0,0,b);
+}
+
+void canvas_objfor(t_canvas *gl, t_text *x, int argc, t_atom *argv) {
+ x->binbuf = binbuf_new();
+ x->x = atom_getintarg(0, argc, argv);
+ x->y = atom_getintarg(1, argc, argv);
+ if (argc > 2) binbuf_restore(x->binbuf, argc-2, argv+2);
+ canvas_add(gl,x);
+}
+
+struct t_mresp : t_pd {
+ t_outlet *outlet;
+};
+struct t_message : t_text {
+ t_mresp mresp;
+ t_canvas *canvas;
+};
+
+static void mresp_bang(t_mresp *x) {outlet_bang(x->outlet);}
+static void mresp_float(t_mresp *x, t_float f) {outlet_float(x->outlet, f);}
+static void mresp_symbol(t_mresp *x, t_symbol *s) {outlet_symbol(x->outlet, s);}
+static void mresp_list(t_mresp *x, t_symbol *s, int argc, t_atom *argv)
+ {outlet_list(x->outlet, s, argc, argv);}
+static void mresp_anything(t_mresp *x, t_symbol *s, int argc, t_atom *argv)
+ {outlet_anything(x->outlet, s, argc, argv);}
+
+static void message_bang(t_message *x)
+{binbuf_eval(x->binbuf,&x->mresp, 0, 0);}
+static void message_float(t_message *x, t_float f)
+{t_atom at; SETFLOAT(&at, f); binbuf_eval(x->binbuf, &x->mresp, 1, &at);}
+static void message_symbol(t_message *x, t_symbol *s)
+{t_atom at; SETSYMBOL(&at, s); binbuf_eval(x->binbuf, &x->mresp, 1, &at);}
+static void message_list(t_message *x, t_symbol *s, int argc, t_atom *argv)
+{binbuf_eval(x->binbuf, &x->mresp, argc, argv);}
+static void message_add2(t_message *x, t_symbol *s, int argc, t_atom *argv)
+{binbuf_add(x->binbuf, argc, argv); gobj_changed(x,"binbuf");}
+static void message_set(t_message *x, t_symbol *s, int argc, t_atom *argv)
+{binbuf_clear(x->binbuf); message_add2(x,s,argc,argv);}
+static void message_add(t_message *x, t_symbol *s, int argc, t_atom *argv)
+{binbuf_add(x->binbuf, argc, argv); binbuf_addsemi(x->binbuf); gobj_changed(x,"binbuf");}
+static void message_addcomma(t_message *x)
+{t_atom a; SETCOMMA(&a); binbuf_add(x->binbuf, 1, &a); gobj_changed(x,"binbuf");}
+static void message_adddollar(t_message *x, t_floatarg f)
+{t_atom a; SETDOLLAR(&a, f<0?0:(int)f); binbuf_add(x->binbuf, 1, &a); gobj_changed(x,"binbuf");}
+//static void message_adddollsym(t_message *x, t_symbol *s)
+//{t_atom a; SETDOLLSYM(&a, s); binbuf_add(x->binbuf, 1, &a); gobj_changed(x,"binbuf");}
+
+static void message_adddollsym(t_message *x, t_symbol *s) {
+ t_atom a;
+ SETDOLLSYM(&a, symprintf("$%s",s->name));
+ binbuf_add(x->binbuf, 1, &a);
+ gobj_changed(x,"binbuf");
+}
+
+static void message_addsemi(t_message *x) {message_add(x,0,0,0);}
+
+void canvas_msg(t_canvas *gl, t_symbol *s, int argc, t_atom *argv) {
+ t_message *x = (t_message *)pd_new(message_class);
+ x->mresp._class = mresp_class;
+ x->mresp.outlet = outlet_new(x,&s_float);
+ x->binbuf = binbuf_new();
+ x->canvas = gl;
+ pd_set_newest(x);
+ if (argc > 1) {
+ x->x = atom_getintarg(0, argc, argv);
+ x->y = atom_getintarg(1, argc, argv);
+ if (argc > 2) binbuf_restore(x->binbuf, argc-2, argv+2);
+ } else {
+ x->x = 0;
+ x->y = 0;
+ }
+ canvas_add(gl,x);
+}
+
+struct t_gatom : t_text {
+ t_atom atom; /* this holds the value and the type */
+ t_canvas *canvas; /* owning canvas */
+ t_float max,min;
+ t_symbol *label; /* symbol to show as label next to box */
+ t_symbol *rcv;
+ t_symbol *snd;
+ char wherelabel; /* 0-3 for left, right, up, down */
+ t_symbol *expanded_to; /* snd after $0, $1, ... expansion */
+ short width;
+};
+
+/* prepend "-" as necessary to avoid empty strings, so we can use them in Pd messages.
+ A more complete solution would be to introduce some quoting mechanism;
+ but then we'd be much more complicated. */
+static t_symbol *gatom_escapit(t_symbol *s) {
+ if (!s || !*s->name) return gensym("-");
+ if (*s->name == '-') {
+ char shmo[1000];
+ snprintf(shmo,1000,"-%s",s->name);
+ shmo[999] = 0;
+ return gensym(shmo);
+ }
+ else return s;
+}
+
+/* undo previous operation: strip leading "-" if found. */
+static t_symbol *gatom_unescapit(t_symbol *s) {
+ if (*s->name == '-') return gensym(s->name+1);
+ return s;
+}
+
+static void gatom_set(t_gatom *x, t_symbol *s, int argc, t_atom *argv) {
+ t_atom oldatom = x->atom;
+ if (!argc) return;
+ if (x->atom.a_type == A_FLOAT) {
+ SETFLOAT( &x->atom,atom_getfloat(argv)); if (x->atom.a_float !=oldatom.a_float ) gobj_changed(x,"atom");
+ } else if (x->atom.a_type == A_SYMBOL) {
+ SETSYMBOL(&x->atom,atom_getsymbol(argv)); if (x->atom.a_symbol!=oldatom.a_symbol) gobj_changed(x,"atom");
+ }
+}
+
+static void gatom_bang(t_gatom *x) {
+ t_symbol *s = x->expanded_to;
+ t_outlet *o = x->outlet;
+ if (x->atom.a_type == A_FLOAT) {
+ if (o) outlet_float(o, x->atom.a_float);
+ if (*s->name && s->thing) {
+ if (x->snd == x->rcv) goto err;
+ pd_float(s->thing, x->atom.a_float);
+ }
+ } else if (x->atom.a_type == A_SYMBOL) {
+ if (o) outlet_symbol(o, x->atom.a_symbol);
+ if (*s->name && s->thing) {
+ if (x->snd == x->rcv) goto err;
+ pd_symbol(s->thing, x->atom.a_symbol);
+ }
+ }
+ return;
+err:
+ error("%s: atom with same send/receive name (infinite loop)", x->snd->name);
+}
+
+static void gatom_float(t_gatom *x, t_float f)
+{t_atom at; SETFLOAT(&at, f); gatom_set(x, 0, 1, &at); gatom_bang(x);}
+static void gatom_symbol(t_gatom *x, t_symbol *s)
+{t_atom at; SETSYMBOL(&at, s); gatom_set(x, 0, 1, &at); gatom_bang(x);}
+
+static void gatom_reload(t_gatom *x, t_symbol *sel, int argc, t_atom *argv) {
+ int width; t_float wherelabel;
+ t_symbol *rcv,*snd;
+ if (!pd_scanargs(argc,argv,"ifffaaa",&width,&x->min,&x->max,&wherelabel,&x->label,&rcv,&snd)) return;
+ gobj_changed(x,0);
+ SET(label,gatom_unescapit(x->label));
+ if (x->min>=x->max) {SET(min,0); SET(max,0);}
+ CLAMP(width,1,80);
+ SET(width,width);
+ SET(wherelabel,(int)wherelabel&3);
+ if (x->rcv) pd_unbind(x, canvas_realizedollar(x->canvas, x->rcv));
+ SET(rcv,gatom_unescapit(rcv));
+ if (x->rcv) pd_bind( x, canvas_realizedollar(x->canvas, x->rcv));
+ SET(snd,gatom_unescapit(snd));
+ SET(expanded_to,canvas_realizedollar(x->canvas, x->snd));
+}
+
+/* We need a list method because, since there's both an "inlet" and a
+ "nofirstin" flag, the standard list behavior gets confused. */
+static void gatom_list(t_gatom *x, t_symbol *s, int argc, t_atom *argv) {
+ if (!argc) gatom_bang(x);
+ else if (argv->a_type == A_FLOAT) gatom_float(x, argv->a_w.w_float);
+ else if (argv->a_type == A_SYMBOL) gatom_symbol(x, argv->a_w.w_symbol);
+ else error("gatom_list: need float or symbol");
+}
+
+void canvas_atom(t_canvas *gl, t_atomtype type, int argc, t_atom *argv) {
+ t_gatom *x = (t_gatom *)pd_new(gatom_class);
+ if (type == A_FLOAT) {SET(width, 5); SETFLOAT(&x->atom, 0);}
+ else {SET(width,10); SETSYMBOL(&x->atom, &s_symbol);}
+ x->canvas = gl;
+ SET(min,0);
+ SET(max,0);
+ SET(wherelabel,0);
+ SET(label,0);
+ SET(rcv,0);
+ SET(snd,0);
+ x->expanded_to = &s_; //???
+ x->binbuf = binbuf_new();
+ binbuf_add(x->binbuf, 1, &x->atom);
+ SET(x,atom_getintarg(0, argc, argv));
+ SET(y,atom_getintarg(1, argc, argv));
+ inlet_new(x,x,0,0);
+ outlet_new(x, type == A_FLOAT ? &s_float: &s_symbol);
+ if (argc>2) gatom_reload(x,&s_,argc-2,argv+2);
+ canvas_add(gl,x);
+ pd_set_newest(x);
+}
+
+void canvas_floatatom( t_canvas *gl, t_symbol *s, int argc, t_atom *argv) {canvas_atom(gl, A_FLOAT, argc, argv);}
+void canvas_symbolatom(t_canvas *gl, t_symbol *s, int argc, t_atom *argv) {canvas_atom(gl, A_SYMBOL, argc, argv);}
+static void gatom_free(t_gatom *x) {if (x->rcv) pd_unbind(x, canvas_realizedollar(x->canvas, x->rcv));}
+
+extern "C" void text_save(t_gobj *z, t_binbuf *b) {
+ t_text *x = (t_text *)z;
+ t_canvas *c = (t_canvas *)z; /* in case it is */
+ if (x->_class == message_class) {
+ binbuf_addv(b,"ttii","#X","msg", (t_int)x->x, (t_int)x->y);
+ binbuf_addbinbuf(b, x->binbuf);
+ } else if (x->_class == gatom_class) {
+ t_gatom *g = (t_gatom *)x;
+ t_symbol *sel = g->atom.a_type==A_SYMBOL? gensym("symbolatom") : gensym("floatatom");
+ binbuf_addv(b,"tsii","#X", sel, (t_int)x->x, (t_int)x->y);
+ binbuf_addv(b,"iffi", (t_int)g->width, g->min, g->max, (t_int)g->wherelabel);
+ binbuf_addv(b,"sss", gatom_escapit(g->label), gatom_escapit(g->rcv), gatom_escapit(g->snd));
+ } else if (x->_class == text_class) {
+ binbuf_addv(b, "ttii","#X","text", (t_int)x->x, (t_int)x->y);
+ binbuf_addbinbuf(b, x->binbuf);
+ } else {
+ if (zgetfn(x,gensym("saveto")) &&
+ !(x->_class==canvas_class && (canvas_isabstraction(c) || canvas_istable(c)))) {
+ mess1(x,gensym("saveto"),b);
+ binbuf_addv(b,"ttii","#X","restore", (t_int)x->x, (t_int)x->y);
+ } else {
+ binbuf_addv(b,"ttii","#X","obj", (t_int)x->x, (t_int)x->y);
+ }
+ if (x->binbuf) {
+ binbuf_addbinbuf(b, x->binbuf);
+ } else {
+ /*bug("binbuf missing at #X restore !!!");*/
+ }
+ }
+ binbuf_addv(b, ";");
+}
+
+static t_binbuf *canvas_cut_wires(t_canvas *x, t_gobj *o) {
+ t_binbuf *buf = binbuf_new();
+ canvas_wires_each(oc,t,x) {
+ if ((o==t.from) != (o==t.to))
+ binbuf_addv(buf,"ttiiii;","#X","connect", t.from->dix->index, t.outlet, t.to->dix->index, t.inlet);
+ }
+ return buf;
+}
+static void canvas_paste_wires(t_canvas *x, t_binbuf *buf) {
+ pd_bind(x,gensym("#X"));
+ binbuf_eval(buf,0,0,0);
+ pd_unbind(x,gensym("#X"));
+}
+
+static void text_setto(t_text *x, t_canvas *canvas, char *buf, int bufsize) {
+ if (x->_class == message_class || x->_class == gatom_class || x->_class == text_class) {
+ binbuf_text(x->binbuf, buf, bufsize);
+ gobj_changed(x,"binbuf");
+ pd_set_newest(x);
+ return;
+ }
+ t_binbuf *b = binbuf_new();
+ binbuf_text(b, buf, bufsize);
+ int natom1 = binbuf_getnatom(x->binbuf); t_atom *vec1 = binbuf_getvec(x->binbuf);
+ int natom2 = binbuf_getnatom(b); t_atom *vec2 = binbuf_getvec(b);
+ /* special case: if pd args change just pass the message on. */
+ if (natom1 >= 1 && natom2 >= 1 &&
+ vec1[0].a_type == A_SYMBOL && vec1[0].a_symbol == s_pd &&
+ vec2[0].a_type == A_SYMBOL && vec2[0].a_symbol == s_pd) {
+ typedmess(x,gensym("rename"),natom2-1,vec2+1);
+ binbuf_free(x->binbuf);
+ x->binbuf = b;
+ pd_set_newest(x); /* fake object creation, for simplicity of client */
+ } else {
+ int xwas=x->x, ywas=x->y;
+ int backupi = x->dix->index;
+ t_binbuf *buf = canvas_cut_wires(canvas_getcanvas(canvas),x);
+ canvas_delete(canvas,x);
+ canvas_objtext(canvas,xwas,ywas,b,backupi);
+ t_pd *backup = newest;
+ post("backupi=%d newest->index=%d",backupi,((t_object *)newest)->dix->index);
+ if (newest && pd_class(newest) == canvas_class) canvas_loadbang((t_canvas *)newest);
+ canvas_paste_wires(canvas_getcanvas(canvas), buf);
+ newest = backup;
+ }
+}
+
+t_object *symbol2opointer(t_symbol *s) {
+ t_text *o;
+ if (sscanf(s->name,"x%lx",(long*)&o)<1) {error("expected object-id"); return 0;}
+ if (!object_table->exists(o)) {error("%s target is not a currently valid pointer",s->name); return 0;}
+ if ((object_table->get(o)&1)==0) {
+ error("%s target is zombie? object_table says '%ld'",s->name,object_table->get(o));
+ return 0;
+ }
+ if (!o->_class->patchable) {error("%s target not a patchable object"); return 0;}
+ return o;
+}
+
+t_object *atom2opointer(t_atom *a) {return symbol2opointer(atom_getsymbol(a));}
+
+static void canvas_text_setto(t_canvas *x, t_symbol *s, int argc, t_atom *argv) {
+ t_text *o = atom2opointer(&argv[0]); if (!o) return;
+ char str[4096];
+ for (int i=0; i<argc-1; i++) str[i] = atom_getint(argv+i+1);
+ str[argc-1]=0;
+ text_setto(o,x,str,argc-1);
+}
+
+static void canvas_object_moveto(t_canvas *x, t_symbol *name, t_floatarg px, t_floatarg py) {
+ t_text *o = symbol2opointer(name); if (!o) return;
+ o->x=(int)px; gobj_changed(o,"x");
+ o->y=(int)py; gobj_changed(o,"y");
+}
+static void canvas_object_delete(t_canvas *x, t_symbol *name) {
+ t_text *o = symbol2opointer(name); if (!o) return;
+ fprintf(stderr,"canvas_object_delete %p\n",o);
+ canvas_delete(x,o);
+}
+
+static void canvas_object_get_tips(t_canvas *x, t_symbol *name) {
+ t_text *o = symbol2opointer(name); if (!o) return;
+ char foo[666];
+ if (o->_class->firstin) strcpy(foo,o->_class->firsttip->name); else strcpy(foo,"");
+ int n = obj_ninlets(x);
+ //char *foop = foo;
+ for (int i=!!o->_class->firstin; i<n; i++) {
+ strcat(foo," ");
+ strcat(foo,inlet_tip(o->inlet,i));
+ }
+ sys_mgui(o,"tips=","S",foo);
+}
+
+extern "C" void open_via_helppath(const char *name, const char *dir);
+static void canvas_object_help(t_canvas *x, t_symbol *name) {
+ t_text *o = symbol2opointer(name); if (!o) return;
+ const char *hn = class_gethelpname(o->_class);
+ bool suffixed = strcmp(hn+strlen(hn)-3, ".pd")==0;
+ char *buf;
+ asprintf(&buf,"%s%s",hn,suffixed?"":".pd");
+ open_via_helppath(buf, o->_class->externdir->name);
+ free(buf);
+}
+
+static long canvas_children_count(t_canvas *x) {
+ long n=0;
+ canvas_each(y,x) n++;
+ return n;
+}
+
+static void canvas_reorder_last(t_canvas *x, int dest) {
+ int n = canvas_children_count(x);
+ t_gobj *foo = canvas_remove_nth(x,n-1);
+ fprintf(stderr,"canvas_reorder_last(x=%p,dest=%d) n=%d\n",x,dest,n);
+ fprintf(stderr,"foo=%p\n",foo);
+ if (!foo) {bug("canvas_remove_nth returned NULL"); return;}
+ canvas_insert_nth(x,dest,foo);
+}
+
+/* this supposes that $2=#X */
+#if 0
+static void canvas_object_insert(t_canvas *x, t_symbol *s, int argc, t_atom *argv) {
+ //t_text *o;
+ //t_binbuf *b;
+ if (argc<1) {error("not enough args"); return;}
+ if (argv[0].a_type != A_FLOAT) {error("$1 must be float"); return;}
+ int i = atom_getint(argv);
+ if (argv[2].a_type != A_SYMBOL) {error("$2 must be symbol"); return;}
+ s = argv[2].a_symbol;
+ x->next_add = i;
+ if (s == gensym("obj")) {
+ /* b = binbuf_new(); binbuf_restore(b, argc-5, argv+5);
+ canvas_objtext(x,atom_getintarg(3,argc,argv),atom_getintarg(4,argc,argv),0,b); */
+ canvas_obj(x,s,argc-3,argv+3);
+ } else if (s == gensym("restore")) { canvas_restore(x,s,argc-3,argv+3);
+ } else if (s == gensym("floatatom")) { canvas_floatatom(x,s,argc-3,argv+3);
+ } else if (s == gensym("symbolatom")) { canvas_floatatom(x,s,argc-3,argv+3);
+ } else if (s == gensym("text")) { canvas_text(x,gensym("text"),argc-3,argv+3);
+ } else post("UNSUPPORTED object_insert: %s",s->name);
+ /* canvas_reorder_last(x,i); */
+ x->next_add = -1;
+/*err: pd_popsym(x);*/
+}
+#endif
+
+static void g_text_setup() {
+ t_class *c;
+ text_class = class_new2("text", 0,0,sizeof(t_text),CLASS_NOINLET|CLASS_PATCHABLE,0);
+ dummy_class = class_new2("dummy",0,0,sizeof(t_text),CLASS_NOINLET|CLASS_PATCHABLE,0);
+
+ c = mresp_class = class_new2("messresponder",0,0,sizeof(t_text),CLASS_PD,"");
+ class_addbang( c, mresp_bang);
+ class_addfloat( c, (t_method) mresp_float);
+ class_addsymbol( c, mresp_symbol);
+ class_addlist( c, mresp_list);
+ class_addanything(c, mresp_anything);
+
+ c = message_class = class_new2("message",0,0,sizeof(t_message),CLASS_PATCHABLE,"");
+ class_addbang(c, message_bang);
+ class_addfloat(c, message_float);
+ class_addsymbol(c, message_symbol);
+ class_addlist(c, message_list);
+ class_addanything(c, message_list);
+ class_addmethod2(c, message_set, "set","*");
+ class_addmethod2(c, message_add, "add","*");
+ class_addmethod2(c, message_add2,"add2","*");
+ class_addmethod2(c, message_addcomma, "addcomma", "");
+ class_addmethod2(c, message_addsemi, "addsemi", "");
+ class_addmethod2(c, message_adddollar, "adddollar", "f");
+ class_addmethod2(c, message_adddollsym, "adddollsym","s");
+
+ c = gatom_class = class_new2("gatom",0,gatom_free,sizeof(t_gatom),CLASS_NOINLET|CLASS_PATCHABLE,"");
+ class_addbang(c, gatom_bang);
+ class_addfloat(c, gatom_float);
+ class_addsymbol(c, gatom_symbol);
+ class_addlist(c, gatom_list);
+ class_addmethod2(c, gatom_set, "set","*");
+ class_addmethod2(c, gatom_reload, "reload","*");
+}
+
+static int iemgui_color_hex[]= {
+ 0xfcfcfc, 0xa0a0a0, 0x404040, 0xfce0e0, 0xfce0c0,
+ 0xfcfcc8, 0xd8fcd8, 0xd8fcfc, 0xdce4fc, 0xf8d8fc,
+ 0xe0e0e0, 0x7c7c7c, 0x202020, 0xfc2828, 0xfcac44,
+ 0xe8e828, 0x14e814, 0x28f4f4, 0x3c50fc, 0xf430f0,
+ 0xbcbcbc, 0x606060, 0x000000, 0x8c0808, 0x583000,
+ 0x782814, 0x285014, 0x004450, 0x001488, 0x580050
+};
+
+static int iemgui_clip_size(int size) {return max(8,size);}
+
+int convert_color2(int x) {
+ return ~ (((0xfc0000&x)>>6) | ((0xfc00&x)>>4) | ((0xfc&x)>>2));
+}
+
+static int convert_color(int x) {
+ if (x>=0) return iemgui_color_hex[x%30];
+ x=~x;
+ return ((x&0x3f000)<<6) | ((x&0xfc0)<<4) | ((x&0x3f)<<2);
+}
+
+static void iemgui_send(t_iemgui *x, t_symbol *s) {
+ SET(snd,canvas_realizedollar(x->canvas, s));
+ if (x->snd==s_empty) SET(snd,0);
+}
+
+static void iemgui_receive(t_iemgui *x, t_symbol *s) {
+ t_symbol *rcv = canvas_realizedollar(x->canvas, s);
+ if (rcv==s_empty) rcv=0;
+ if (rcv==x->rcv) return;
+ if(x->rcv) pd_unbind(x,x->rcv);
+ SET(rcv,rcv);
+ if(x->rcv) pd_bind(x,x->rcv);
+}
+
+static void iemgui_label(t_iemgui *x, t_symbol *s) {
+ SET(lab,s==s_empty?0:s);
+}
+static void iemgui_label_pos(t_iemgui *x, t_float ldx, t_float ldy) {
+ SET(ldx,(int)ldx);
+ SET(ldy,(int)ldy);
+}
+static void iemgui_label_font(t_iemgui *x, t_symbol *s, int ac, t_atom *av) {
+ SET(fontsize,max(4,(int)atom_getintarg(1, ac, av)));
+ SET(font_style,atom_getintarg(0, ac, av));
+}
+static void iemgui_delta(t_iemgui *x, t_symbol *s, int ac, t_atom *av) {
+ SET(x,x->x+(int)atom_getintarg(0, ac, av));
+ SET(y,x->y+(int)atom_getintarg(1, ac, av));
+}
+static void iemgui_pos(t_iemgui *x, t_symbol *s, int ac, t_atom *av) {
+ SET(x,x->x+(int)atom_getintarg(0, ac, av));
+ SET(y,x->y+(int)atom_getintarg(1, ac, av));
+}
+
+static int iemgui_compatible_col(int i) {return i>=0 ? iemgui_color_hex[i%30] : (~i)&0xffffff;}
+
+static void iemgui_color(t_iemgui *x, t_symbol *s, int ac, t_atom *av) {
+ int i=0;
+ SET(bcol,iemgui_compatible_col(atom_getintarg(i++, ac, av)));
+ if(ac > 2) SET(fcol,iemgui_compatible_col(atom_getintarg(i++, ac, av)));
+ SET(lcol,iemgui_compatible_col(atom_getintarg(i++, ac, av)));
+}
+
+#define NEXT p=va_arg(val,void*); /*printf("p=%p\n",p);*/
+int pd_vscanargs(int argc, t_atom *argv, char *fmt, va_list val) {
+ int optional=0;
+ int i,j=0;
+ for (i=0; fmt[i]; i++) {
+ switch (fmt[i]) {
+ case 0: error("too many args"); return 0;
+ case '*': goto break1; /* rest is any type */
+ case 'F': case 'f': case 'd': case 'i': case 'c': case 'b':
+ if (!IS_A_FLOAT(argv,j)) {error("expected float in $%d",i+1); return 0;}
+ j++; break;
+ case 'S': case 's':
+ if (!IS_A_SYMBOL(argv,j)) {error("expected symbol in $%d",i+1); return 0;}
+ j++; break;
+ case '?': break;
+ case 'a':
+ if (!IS_A_FLOAT(argv,j) && !IS_A_SYMBOL(argv,j)) {error("expected float or symbol in $%d",i+1); return 0;}
+ j++; break;
+ case ';': optional=1; break;
+ default: error("bad format string"); return 0;
+ }
+ }
+ if (j<argc && !optional) {error("not enough args"); return 0;}
+break1:
+ i=0;
+ for (int j=0; fmt[j] || i<argc; j++) {
+ void *p;
+ switch (fmt[j]) {
+ case ';': continue; /*ignore*/
+ case '*': goto break2;
+ case '?': case 'F': case 'S': break; /* skip */ /* what are those for, again? */
+ case 'd': NEXT; *(double*)p = atom_getfloatarg(i,argc,argv); break;
+ case 'f': NEXT; *(float*)p = atom_getfloatarg(i,argc,argv); break;
+ case 'i': NEXT; *(int*)p = atom_getintarg(i,argc,argv); break;
+ case 'b': NEXT; *(int*)p = !!atom_getintarg(i,argc,argv); break; /* 0 or 1 */
+ case 'c': NEXT; *(int*)p = convert_color(atom_getintarg(i,argc,argv)); break; /* IEM-style 8:8:8 colour */
+ case 's': NEXT; *(t_symbol**)p=atom_getsymbolarg(i,argc,argv); break;
+ case 'a': NEXT; /* send-symbol, receive-symbol, or IEM-style label */
+ if (IS_A_SYMBOL(argv,i))
+ *(t_symbol**)p = atom_getsymbolarg(i,argc,argv);
+ if (*(t_symbol**)p == s_empty) *(t_symbol**)p = 0;
+ else if (IS_A_FLOAT(argv,i)) {
+ char str[80];
+ sprintf(str, "%d", (int)atom_getintarg(i,argc,argv));
+ *(t_symbol**)p = gensym(str);
+ }
+ break;
+ default: post("WARNING: bug using pd_scanargs()"); return 0; /* hmm? */
+ }
+ i++;
+ }
+break2:
+ return 1;
+}
+
+/* exceptionally we're using pointers for each of the args even though
+ we are saving. this is so we can copy+paste pd_scanargs lines almost
+ directly. in the future, this could be merged with pd_scanargs and
+ made declarative, by storing a list of &(0->blah) relative offsets
+ into each struct...
+*/
+int pd_vsaveargs(t_binbuf *b, char *fmt, va_list val) {
+ t_atom a;
+ int i;
+ for (i=0; ; i++) {
+ switch (fmt[i]) {
+ case 0: goto break2;
+ case ';': continue; /* skip */
+ case '?': case 'F': case 'S': break; /* skip */
+ case 'd': SETFLOAT(&a,*(va_arg(val,double*))); break;
+ case 'f': SETFLOAT(&a,*(va_arg(val,float *))); break;
+ case 'i': SETFLOAT(&a,*(va_arg(val, int *))); break;
+ case 'b': SETFLOAT(&a,!!*(va_arg(val,int *))); break;
+ case 'c': /* colour, from IEM format to RGB 8:8:8 format */
+ SETFLOAT(&a,convert_color2(*(va_arg(val, int *)))); break;
+ case 'a':
+ case 's': { t_symbol *s = *(va_arg(val,t_symbol**));
+ SETSYMBOL(&a,s?s:s_empty); } break;
+ default: post("WARNING: bug using pd_saveargs()"); goto err; /* WHAT? */
+ }
+ binbuf_add(b,1,&a);
+ }
+break2:
+ binbuf_addv(b, ";");
+ return 1;
+err:
+ post("WARNING: pd_saveargs failed; fmt=%s, i=%d",fmt,i);
+ return 0;
+}
+
+int pd_scanargs(int argc, t_atom *argv, char *fmt, ...) {
+ int i;
+ va_list val;
+ va_start(val,fmt);
+ i=pd_vscanargs(argc,argv,fmt,val);
+ va_end(val);
+ return i;
+}
+
+int pd_saveargs(t_binbuf *b, char *fmt, ...) {
+ int i;
+ va_list val;
+ va_start(val,fmt);
+ i=pd_vsaveargs(b,fmt,val);
+ va_end(val);
+ return i;
+}
+
+int pd_pickle(t_foo *foo, char *fmt, ...) {
+ va_list val;
+ va_start(val,fmt);
+ int r = foo->b ?
+ pd_vsaveargs(foo->b,fmt,val) :
+ pd_vscanargs(foo->argc,foo->argv,fmt,val);
+ va_end(val);
+ return r;
+}
+
+static int pd_savehead(t_binbuf *b, t_iemgui *x, char *name) {
+ binbuf_addv(b, "ttiit","#X","obj", (t_int)x->x, (t_int)x->y, name);
+ return 1;
+}
+
+void pd_upload(t_gobj *self) {
+ long alive = (long)object_table->get(self) & 1;
+ if (!alive) {
+ sys_mgui(self,"delete","");
+ pd_free_zombie(self);
+ return;
+ }
+ t_binbuf *b = binbuf_new();
+ t_class *c = self->_class;
+ t_text *x = (t_text *)self;
+ if (c==canvas_class) {
+ /* just the "#N canvas" line, not the contents */
+ canvas_savecontainerto((t_canvas *)self,b);
+ canvas_savecoordsto((t_canvas *)self,b); /* this may be too early */
+ binbuf_addv(b, "ttii", "#X","restore", (t_int)x->x, (t_int)x->y);
+ if (x->binbuf) {
+ //pd_print(x,"pd_upload");
+ binbuf_addbinbuf(b, x->binbuf);
+ } else {
+ /*bug("binbuf missing at #X restore !!!");*/
+ }
+ binbuf_addv(b, ";");
+ } else { /* this was outside of the "else" for a while. why? I don't remember */
+ c->savefn(self,b);
+ }
+ int n;
+ char *s;
+ appendix_save(self,b);
+ binbuf_gettext(b,&s,&n);
+ if (s[n-1]=='\n') n--;
+ if (c->patchable) {
+ sys_vgui("change x%lx x%lx %d {%.*s} %d %d %d\n",(long)self,(long)self->dix->canvas,self->dix->index,n,s,
+ obj_ninlets((t_text *)self), obj_noutlets((t_text *)self), x->_class!=dummy_class);
+ } else {
+ sys_vgui("change x%lx x%lx %d {%.*s}\n",(long)self,(long)self->dix->canvas,self->dix->index,n,s);
+ }
+ binbuf_free(b);
+ free(s);
+ if (c==canvas_class) {
+ t_canvas *can = (t_canvas *)self;
+ sys_mgui(self,"name=","s",can->name);
+ sys_mgui(self,"folder=","s",canvas_getenv(can)->dir);
+ sys_mgui(self,"havewindow=","i",can->havewindow);
+ }
+ if (c==gatom_class) {
+ t_gatom *g = (t_gatom *)x;
+ if (g->atom.a_type==A_SYMBOL) sys_mgui(g,"set","s",g->atom.a_symbol);
+ else sys_mgui(g,"set","f",g->atom.a_float);
+ }
+ if (object_table->exists(self)) {
+ object_table->set(self,object_table->get(self)|2); /* has been uploaded */
+ } else post("object_table is broken");
+}
+
+void sys_mgui(void *self_, const char *sel, const char *fmt, ...) {
+ t_gobj *self = (t_gobj *)self_;
+ char buf[4096];
+ int i=0, n=sizeof(buf);
+ va_list val;
+ va_start(val,fmt);
+ i+=snprintf(buf+i,n-i,"x%lx %s", (long)self, sel);
+ if (i>=n) goto over;
+ while (*fmt) {
+ switch (*fmt) {
+ case 'f': case 'd': i+=snprintf(buf+i,n-i," %f",va_arg(val,double)); break;
+ case 'i': i+=snprintf(buf+i,n-i," %d",va_arg(val,int)); break;
+ case 'p': i+=snprintf(buf+i,n-i," x%lx",(long)va_arg(val,void*)); break;
+ /*
+ case 's': i+=snprintf(buf+i,n-i," \"%s\"",va_arg(val,t_symbol *)->name); break;
+ case 'S': i+=snprintf(buf+i,n-i," \"%s\"",va_arg(val,const char *)); break;
+ */
+ case 's': i+=snprintf(buf+i,n-i," {%s}",va_arg(val,t_symbol *)->name); break;
+ case 'S': i+=snprintf(buf+i,n-i," {%s}",va_arg(val,const char *)); break;
+ }
+ if (i>=n) goto over;
+ fmt++;
+ }
+ va_end(val);
+ i+=snprintf(buf+i,n-i,"\n");
+ if (i>=n) goto over;
+ sys_gui(buf);
+ return;
+over:
+ post("sys_mgui: can't send: buffer overflow");
+ abort();
+}
+
+static void iemgui_subclass (t_class *c) {
+ class_addmethod2(c, iemgui_delta, "delta","*");
+ class_addmethod2(c, iemgui_pos, "pos","*");
+ class_addmethod2(c, iemgui_color, "color","*");
+ class_addmethod2(c, iemgui_send, "send","S");
+ class_addmethod2(c, iemgui_receive, "receive","S");
+ class_addmethod2(c, iemgui_label, "label","S");
+ class_addmethod2(c, iemgui_label_pos, "label_pos","ff");
+ class_addmethod2(c, iemgui_label_font, "label_font","*");
+}
+
+t_symbol *pd_makebindsym(t_pd *x) {return symprintf(".x%lx",(long)x);}
+
+t_iemgui *iemgui_new(t_class *qlass) {
+ t_iemgui *x = (t_iemgui *)pd_new(qlass);
+ x->canvas = canvas_getcurrent();
+ x->w = x->h = 15;
+ x->ldx=0;
+ x->ldy=-6;
+ x->isa=0;
+ x->font_style = 0;
+ x->fontsize = 8;
+ x->snd = 0;
+ x->rcv = 0;
+ x->lab = s_empty;
+ x->bcol = 0xffffff;
+ x->fcol = 0x000000;
+ x->lcol = 0x000000;
+ pd_bind(x,pd_makebindsym(x));
+ return x;
+}
+
+static void iemgui_constrain(t_iemgui *x) {
+ SET(fontsize,max(x->fontsize,4));
+ SET(h,iemgui_clip_size(x->h));
+ SET(w,iemgui_clip_size(x->w));
+}
+
+void iemgui_init(t_iemgui *x, t_floatarg f) {SET(isa,(x->isa&~1)|!!f);}
+
+void binbuf_update(t_iemgui *x, t_symbol *qlass, int argc, t_atom *argv) {
+ t_binbuf *buf = x->binbuf;
+ if (!buf) return;
+ binbuf_clear(buf);
+ t_atom foo;
+ SETSYMBOL(&foo,qlass);
+ binbuf_add(buf,1,&foo);
+ binbuf_add(buf,argc,argv);
+}
+
+static /*bool*/ int iemgui_loadbang (t_iemgui *self) {
+ return !sys_noloadbang && self->isa&1;
+}
+
+static /*bool*/ int iemgui_forward (t_iemgui *self) {
+ return !self->snd || !self->rcv || self->snd != self->rcv;
+}
+
+static t_class *bng_class;
+
+static void bng_check_minmax(t_bng *x) {
+ if(x->ftbreak > x->fthold) {
+ int h = x->ftbreak;
+ SET(ftbreak,x->fthold);
+ SET(fthold,h);
+ }
+ SET(ftbreak,max(x->ftbreak,10));
+ SET(fthold ,max(x->fthold, 50));
+}
+
+static void bng_set(t_bng *x) {
+ SET(count,x->count+1);
+ sys_mgui(x,"bang","i",x->count);
+}
+
+static void bng_bout2(t_bng *x) {
+ outlet_bang(x->outlet);
+ if(x->snd && x->snd->thing) pd_bang(x->snd->thing);
+}
+
+static void bng_bang(t_bng *x) {
+ bng_set(x);
+ outlet_bang(x->outlet);
+ if(x->snd && x->snd->thing && iemgui_forward(x)) pd_bang(x->snd->thing);
+}
+static void bng_bang2 (t_bng *x) { {bng_set(x); bng_bout2(x);}}
+static void bng_loadbang(t_bng *x) {if(iemgui_loadbang(x)) {bng_set(x); bng_bout2(x);}}
+
+static void bng_size(t_bng *x, t_symbol *s, int ac, t_atom *av) {
+ SET(w,iemgui_clip_size((int)atom_getintarg(0, ac, av)));
+ SET(h,x->w);
+}
+
+static void bng_flashtime(t_bng *x, t_symbol *s, int ac, t_atom *av) {
+ SET(ftbreak,atom_getintarg(0, ac, av));
+ SET(fthold ,atom_getintarg(1, ac, av));
+ bng_check_minmax(x);
+}
+
+static int bng_pickle(t_bng *x, t_foo *foo) {
+ return pd_pickle(foo,"iiiiaaaiiiiccc",&x->w,&x->fthold,&x->ftbreak,&x->isa,&x->snd,&x->rcv,&x->lab,
+ &x->ldx,&x->ldy,&x->font_style,&x->fontsize,&x->bcol,&x->fcol,&x->lcol);
+}
+
+static void bng_savefn(t_bng *x, t_binbuf *b) {
+ t_foo foo = {0,0,b}; if (!b) return;
+ pd_savehead(b,x,"bng"); bng_pickle(x,&foo);
+}
+
+static void bng_reload(t_bng *x, t_symbol *s, int argc, t_atom *argv) {
+ t_foo foo = { argc, argv, 0 };
+ binbuf_update(x,gensym("bng"),argc,argv);
+ if (!bng_pickle(x,&foo)) return;
+ SET(h,x->w);
+ bng_check_minmax(x);
+ iemgui_constrain(x);
+ if (x->rcv) pd_bind(x,x->rcv);
+}
+
+static void *bng_new(t_symbol *s, int argc, t_atom *argv) {
+ t_bng *x = (t_bng *)iemgui_new(bng_class);
+ SET(ftbreak,250);
+ SET(fthold,50);
+ SET(count,0);
+ bng_check_minmax(x);
+ outlet_new(x, &s_bang);
+ if (argc) bng_reload(x,0,argc,argv);
+ return x;
+}
+
+static void iemgui_free(t_iemgui *x) {
+ if(x->rcv) pd_unbind(x,x->rcv);
+}
+
+static t_class *toggle_class;
+
+static void toggle_action(t_toggle *x) {
+ outlet_float(x->outlet, x->on);
+ if(x->snd && x->snd->thing) pd_float(x->snd->thing, x->on);
+}
+
+static void toggle_bang(t_toggle *x) {SET(on,x->on?0.0:x->nonzero); toggle_action(x);}
+static void toggle_set(t_toggle *x, t_floatarg f) {SET(on,f); if(f) SET(nonzero,f);}
+static void toggle_float(t_toggle *x, t_floatarg f) {toggle_set(x,f);if(iemgui_forward(x)) toggle_action(x);}
+static void toggle_fout (t_toggle *x, t_floatarg f) {toggle_set(x,f); toggle_action(x);}
+static void toggle_loadbang(t_toggle *x) {if(iemgui_loadbang(x)) toggle_fout(x, (float)x->on);}
+static void toggle_nonzero(t_toggle *x, t_floatarg f) {if (f) SET(nonzero,f);}
+
+static void toggle_size(t_toggle *x, t_symbol *s, int ac, t_atom *av) {
+ SET(w,iemgui_clip_size((int)atom_getintarg(0, ac, av)));
+ SET(h,x->w);
+}
+
+static int toggle_pickle(t_toggle *x, t_foo *foo) {
+ return pd_pickle(foo,"iiaaaiiiicccf;f",&x->w,&x->isa,&x->snd,&x->rcv,&x->lab,
+ &x->ldx,&x->ldy,&x->font_style,&x->fontsize,&x->bcol,&x->fcol,&x->lcol,&x->on,&x->nonzero);
+}
+
+static void toggle_savefn(t_toggle *x, t_binbuf *b) {
+ t_foo foo = {0,0,b}; if (!b) return;
+ pd_savehead(b,x,"tgl"); toggle_pickle(x,&foo);
+}
+
+static void toggle_reload(t_toggle *x, t_symbol *s, int argc, t_atom *argv) {
+ t_foo foo = { argc, argv, 0 };
+ binbuf_update(x,gensym("tgl"),argc,argv);
+ if (!toggle_pickle(x,&foo)) return;
+ SET(h,x->w);
+ SET(on,x->isa&1 && x->on ? x->nonzero : 0.0);
+ SET(nonzero,argc==14 && IS_A_FLOAT(argv,13) ? atom_getfloatarg(13, argc, argv) : 1.0);
+ if (!x->nonzero) SET(nonzero,1.0);
+ iemgui_constrain(x);
+ if (x->rcv) pd_bind(x,x->rcv);
+}
+
+static void *toggle_new(t_symbol *s, int argc, t_atom *argv) {
+ t_toggle *x = (t_toggle *)iemgui_new(toggle_class);
+ SET(on,0.0);
+ SET(nonzero,1.0);
+ outlet_new(x, &s_float);
+ if (argc) toggle_reload(x,0,argc,argv);
+ return x;
+}
+
+static void radio_set(t_radio *x, t_floatarg f) {
+ int i=(int)f;
+ int old=x->on_old;
+ CLAMP(i,0,x->number-1);
+ if(x->on!=old) SET(on_old,x->on);
+ SET(on,i);
+ if(x->on!=old) SET(on_old,old);
+}
+
+static void radio_send2(t_radio *x, float a, float b) {
+ SETFLOAT(x->at,a);
+ SETFLOAT(x->at+1,b);
+ outlet_list(x->outlet, &s_list, 2, x->at);
+ if(x->snd && x->snd->thing) pd_list(x->snd->thing, &s_list, 2, x->at);
+}
+
+static void radio_send(t_radio *x, float a) {
+ outlet_float(x->outlet,a);
+ if(x->snd && x->snd->thing) pd_float(x->snd->thing,a);
+}
+
+static void radio_bang(t_radio *x) {
+ if (x->oldstyle) {
+ if(x->change && x->on!=x->on_old) radio_send2(x,x->on_old,0.0);
+ SET(on_old,x->on);
+ radio_send2(x,x->on,1.0);
+ } else {
+ radio_send(x,x->on);
+ }
+}
+
+static void radio_fout2(t_radio *x, t_floatarg f, int forwardonly) {
+ int i=(int)f;
+ CLAMP(i,0,x->number-1);
+ if (x->oldstyle) {
+ /* compatibility with earlier "hdial" behavior */
+ if(x->change && i!=x->on_old && (!forwardonly || iemgui_forward(x))) radio_send2(x,x->on_old,0.0);
+ SET(on_old,x->on);
+ SET(on,i);
+ SET(on_old,x->on);
+ radio_send2(x,x->on,1.0);
+ if (!forwardonly || iemgui_forward(x)) radio_send2(x,x->on,1.0);
+ } else {
+ SET(on,i);
+ if (!forwardonly || iemgui_forward(x)) radio_send(x,x->on);
+ SET(on_old,x->on);
+ }
+}
+
+static void radio_fout (t_radio *x, t_floatarg f) {radio_fout2(x,f,0);}
+static void radio_float(t_radio *x, t_floatarg f) {radio_fout2(x,f,1);}
+static void radio_loadbang(t_radio *x) {if(iemgui_loadbang(x)) radio_bang(x);}
+static void radio_orient(t_radio *x,t_floatarg v) {SET(orient,!!v);
+post("v=%f, !!v=%d, orient=%d",v,!!v,x->orient);}
+
+static void radio_number(t_radio *x, t_floatarg num) {
+ int n=(int)num;
+ CLAMP(n,1,128);
+ if (n != x->number) {
+ SET(number,n);
+ CLAMP(x->on,0,x->number-1); gobj_changed(x,"on");
+ SET(on_old,x->on);
+ }
+}
+
+static void radio_size(t_radio *x, t_float size) {
+ SET(w,iemgui_clip_size((int)size));
+ SET(h,x->w);
+}
+
+static void radio_double_change(t_radio *x) {SET(change,1);}
+static void radio_single_change(t_radio *x) {SET(change,0);}
+
+static int radio_pickle(t_radio *x, t_foo *foo) {
+ return pd_pickle(foo, "ibiiaaaiiiiccci",&x->w,&x->change,&x->isa,&x->number,&x->snd,&x->rcv,&x->lab,
+ &x->ldx,&x->ldy,&x->font_style,&x->fontsize,&x->bcol,&x->fcol,&x->lcol,&x->on);
+}
+
+static t_symbol *radio_flavor(t_radio *x) {
+ return x->orient?x->oldstyle?sym_vdl:sym_vradio:x->oldstyle?sym_hdl:sym_hradio;
+}
+
+static void radio_savefn(t_radio *x, t_binbuf *b) {
+ t_foo foo = {0,0,b}; if (!b) return;
+ pd_savehead(b,x,radio_flavor(x)->name);
+ radio_pickle(x,&foo);
+}
+
+static void radio_reload(t_radio *x, t_symbol *s, int argc, t_atom *argv) {
+ t_foo foo = { argc, argv, 0 };
+ binbuf_update(x,radio_flavor(x),argc,argv);
+ if (!radio_pickle(x,&foo)) return;
+ iemgui_constrain(x);
+ if (x->rcv) pd_bind(x,x->rcv);
+ gobj_changed(x,0);
+}
+
+static void *radio_new(t_symbol *s, int argc, t_atom *argv) {
+ t_radio *x = (t_radio *)iemgui_new(radio_class);
+ SET(on_old,0);
+ SET(on,0);
+ SET(number,8);
+ SET(change,1);
+ if (s==sym_hdl) {SET(orient,0); SET(oldstyle,1);} else
+ if (s==sym_vdl) {SET(orient,1); SET(oldstyle,1);} else
+ if (s==sym_hradio) {SET(orient,0); SET(oldstyle,0);} else
+ if (s==sym_vradio) {SET(orient,1); SET(oldstyle,0);}
+ SET(on,x->isa&1 ? x->on : 0);
+ SET(on_old,x->on);
+ outlet_new(x, &s_list);
+ if (argc) radio_reload(x,0,argc,argv);
+ return x;
+}
+
+#define IEM_SL_DEFAULTSIZE 128
+#define IEM_SL_MINSIZE 2
+
+static void slider_check_width(t_slider *x, int w) {
+ double l = (double)(x->orient ? x->h : x->w)-1;
+ int m = (int)(l*100);
+ if(w < IEM_SL_MINSIZE) w = IEM_SL_MINSIZE;
+ if (x->orient) SET(h,w); else SET(w,w);
+ if(x->val > m) SET(val,m);
+}
+
+static void slider_check_minmax(t_slider *x) {
+ double min=x->min, max=x->max;
+ if(x->is_log) {
+ if(min == 0.0 && max == 0.0) max = 1.0;
+ if(max > 0.0) { if (min<=0.0) min = 0.01*max; }
+ else { if (min >0.0) max = 0.01*min; }
+ }
+ SET(min,min);
+ SET(max,max);
+}
+
+// the value/centipixel ratio
+static double slider_ratio (t_slider *x) {
+ double diff = x->is_log ? log(x->max/x->min) : (x->max-x->min);
+ return diff / (double)(x->orient ? (x->h-1) : (x->w-1));
+}
+
+static void slider_set(t_slider *x, t_floatarg f) {
+ if(x->min > x->max) CLAMP(f,x->max,x->min);
+ else CLAMP(f,x->min,x->max);
+ SET(val,floor(100.0 * (x->is_log ? log(f/x->min) : (f-x->min)) / slider_ratio(x) + 0.5));
+}
+
+static void slider_bang(t_slider *x) {
+ double t = (double)x->val * slider_ratio(x) * 0.01;
+ double out = x->is_log ? x->min*exp(t) : x->min+t;
+ if (fabs(out) < 1.0e-10) out = 0.0;
+ outlet_float(x->outlet, out);
+ if(x->snd && x->snd->thing) pd_float(x->snd->thing, out);
+}
+
+static void slider_size(t_slider *x, t_symbol *s, int ac, t_atom *av) {
+ int a = atom_getintarg(0,ac,av);
+ int b = ac>1 ? atom_getintarg(1,ac,av) : 0;
+ if (x->orient) {
+ SET(w,iemgui_clip_size(a));
+ if(ac>1) slider_check_width(x,b);
+ } else {
+ slider_check_width(x,a);
+ if(ac>1) SET(h,iemgui_clip_size(b));
+ }
+}
+
+static void slider_range(t_slider *x, t_float min, t_float max)
+{SET(min,min); SET(max,max); slider_check_minmax(x);}
+static void slider_lin(t_slider *x) {SET(is_log,0); slider_check_minmax(x);}
+static void slider_log(t_slider *x) {SET(is_log,1); slider_check_minmax(x);}
+static void slider_steady(t_slider *x, t_floatarg f) {SET(steady,!!f);}
+static void slider_float(t_slider *x, t_floatarg f) {slider_set(x,f);if(iemgui_forward(x))slider_bang(x);}
+static void slider_loadbang(t_slider *x) {if(iemgui_loadbang(x)) slider_bang(x);}
+static void slider_orient(t_slider *x,t_floatarg v) {SET(orient,!!v);}
+
+static int slider_pickle(t_slider *x, t_foo *foo) {
+ return pd_pickle(foo, "iiffbiaaaiiiicccf;b",
+ &x->w,&x->h,&x->min,&x->max,&x->is_log,&x->isa,&x->snd,&x->rcv,&x->lab,
+ &x->ldx,&x->ldy,&x->font_style,&x->fontsize,&x->bcol,&x->fcol,&x->lcol,&x->val,&x->steady);
+}
+
+static void slider_savefn(t_slider *x, t_binbuf *b) {
+ t_foo foo = {0,0,b}; if (!b) return;
+ pd_savehead(b,x,(char *)(x->orient?"vsl":"hsl")); slider_pickle(x,&foo);
+}
+
+static void slider_reload(t_slider *x, t_symbol *s, int argc, t_atom *argv) {
+ t_foo foo = { argc, argv, 0 };
+ binbuf_update(x,gensym((char *)(x->orient?"vsl":"hsl")),argc,argv);
+ if (!slider_pickle(x,&foo)) return;
+//this is wrong because it should happen when loading a file but not when loading from properties:
+ SET(val,x->isa&1 ? x->val : 0);
+//end wrong.
+ iemgui_constrain(x);
+ slider_check_minmax(x);
+ slider_check_width(x, x->orient ? x->h : x->w);
+ if(x->rcv) pd_bind(x,x->rcv);
+ gobj_changed(x,0);
+}
+
+static void *slider_new(t_symbol *s, int argc, t_atom *argv) {
+ t_slider *x = (t_slider *)iemgui_new(slider_class);
+ SET(orient,s==sym_vslider||s==sym_vsl);
+ SET(is_log,0);
+ SET(min,0.0);
+ SET(steady,1);
+ SET(max,(double)(IEM_SL_DEFAULTSIZE-1));
+ if (x->orient) SET(h,IEM_SL_DEFAULTSIZE); else SET(w,IEM_SL_DEFAULTSIZE);
+ outlet_new(x, &s_float);
+ if (argc) slider_reload(x,0,argc,argv);
+ return x;
+}
+
+static t_class *nbx_class;
+
+static void nbx_clip(t_nbx *x) {CLAMP(x->val,x->min,x->max);}
+
+static int nbx_check_minmax(t_nbx *x) {
+ double min=x->min, max=x->max;
+ int val=(int)x->val;
+ if(x->is_log) {
+ if(min==0.0 && max==0.0) max = 1.0;
+ if(max>0.0 && min<=0.0) min = 0.01*max;
+ if(max<=0.0 && min>0.0) max = 0.01*min;
+ } else {
+ if(min>max) swap(min,max);
+ }
+ SET(min,min);
+ SET(max,max);
+ CLAMP(x->val,x->min,x->max);
+ SET(k,x->is_log ? exp(log(x->max/x->min)/(double)(x->log_height)) : 1.0);
+ return x->val!=val;
+}
+
+static void nbx_bang(t_nbx *x) {
+ outlet_float(x->outlet, x->val);
+ if(x->snd && x->snd->thing) pd_float(x->snd->thing, x->val);
+}
+
+static void nbx_set(t_nbx *x, t_floatarg f) {SET(val,f); nbx_clip(x);}
+static void nbx_float(t_nbx *x, t_floatarg f) {nbx_set(x, f); if(iemgui_forward(x)) nbx_bang(x);}
+
+static void nbx_log_height(t_nbx *x, t_floatarg lh) {
+ SET(log_height,max(10,(int)lh));
+ SET(k,x->is_log ? exp(log(x->max/x->min)/(double)(x->log_height)) : 1.0);
+}
+
+static void nbx_size(t_nbx *x, t_symbol *s, int ac, t_atom *av) {
+ SET(w,max(1,(int)atom_getintarg(0, ac, av)));
+ if(ac > 1) SET(h,max(8,(int)atom_getintarg(1, ac, av)));
+}
+
+static void nbx_range(t_nbx *x, t_float min, t_float max)
+{SET(min,min); SET(max,max); nbx_check_minmax(x);}
+
+static void nbx_lin(t_nbx *x) {SET(is_log,0); }
+static void nbx_log(t_nbx *x) {SET(is_log,1); nbx_check_minmax(x);}
+static void nbx_loadbang(t_nbx *x) {if(iemgui_loadbang(x)) nbx_bang(x);}
+
+static void nbx_list(t_nbx *x, t_symbol *s, int ac, t_atom *av) {
+ if (!IS_A_FLOAT(av,0)) return;
+ nbx_set(x, atom_getfloatarg(0, ac, av));
+ nbx_bang(x);
+}
+
+static int nbx_pickle(t_nbx *x, t_foo *foo) {
+ return pd_pickle(foo,"iiddbiaaaiiiicccd;i",
+ &x->w,&x->h,&x->min,&x->max,&x->is_log,&x->isa,&x->snd,&x->rcv,&x->lab,
+ &x->ldx,&x->ldy,&x->font_style,&x->fontsize,&x->bcol,&x->fcol,&x->lcol,&x->val,&x->log_height);
+}
+
+static void nbx_savefn(t_nbx *x, t_binbuf *b) {
+ t_foo foo = {0,0,b};
+ if (!b) return;
+ pd_savehead(b,x,"nbx");
+ nbx_pickle(x,&foo);
+}
+
+static void nbx_reload(t_nbx *x, t_symbol *s, int argc, t_atom *argv) {
+ t_foo foo = { argc, argv, 0 };
+ binbuf_update(x,gensym("nbx"),argc,argv);
+ if (!nbx_pickle(x,&foo)) return;
+ if (!x->isa&1) SET(val,0.0);
+ iemgui_constrain(x);
+ SET(w,max(x->w,1));
+ nbx_check_minmax(x);
+ SET(w,max(x->w,1));
+ if (x->rcv) pd_bind(x,x->rcv);
+ gobj_changed(x,0);
+}
+
+static void *nbx_new(t_symbol *s, int argc, t_atom *argv) {
+ t_nbx *x = (t_nbx *)iemgui_new(nbx_class);
+ SET(log_height,256);
+ SET(is_log,0);
+ SET(w,5);
+ SET(h,14);
+ SET(min,-1.0e+37);
+ SET(max,1.0e+37);
+ x->buf[0]=0;
+ SET(change,0);
+ outlet_new(x, &s_float);
+ if (argc) nbx_reload(x,0,argc,argv);
+ return x;
+}
+
+#define IEM_VU_STEPS 40
+
+static char vu_db2i[]= {
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 9, 9, 9, 9, 9,10,10,10,10,10,11,11,11,11,11,12,12,12,12,12,
+ 13,13,13,13,14,14,14,14,15,15,15,15,16,16,16,16,17,17,17,18,
+ 18,18,19,19,19,20,20,20,21,21,22,22,23,23,24,24,25,26,27,28,
+ 29,30,31,32,33,33,34,34,35,35,36,36,37,37,37,38,38,38,39,39,
+ 39,39,39,39,40,40
+};
+
+static void vu_check_height(t_vu *x, int h) {
+ int n=max(h/IEM_VU_STEPS,2);
+ SET(led_size,n-1);
+ SET(h,IEM_VU_STEPS * n);
+}
+
+static void vu_scale(t_vu *x, t_floatarg fscale) {SET(scale,!!fscale);}
+
+static void vu_size(t_vu *x, t_symbol *s, int ac, t_atom *av) {
+ SET(w, iemgui_clip_size((int)atom_getintarg(0, ac, av)));
+ if(ac>1) vu_check_height(x, (int)atom_getintarg(1, ac, av));
+}
+
+static int vuify(t_vu *x, float v) {
+ return v<=-99.9 ? 0 :
+ v>=12.0 ? IEM_VU_STEPS :
+ vu_db2i[(int)(2.0*(v+100.0))];
+}
+
+static float vu_round(float v) {return 0.01*(int)(100.0*v+0.5);}
+
+static void vu_float0(t_vu *x, t_floatarg v) {
+ SET(rms, vuify(x,v)); SET(fr,vu_round(v)); outlet_float(x->out(0), x->fr);
+ sys_mgui(x,"rms=","i",x->rms);}
+static void vu_float1(t_vu *x, t_floatarg v) {
+ SET(peak,vuify(x,v)); SET(fp,vu_round(v)); outlet_float(x->out(1),x->fp);
+ sys_mgui(x,"peak=","i",x->peak);}
+
+static void vu_bang(t_vu *x) {
+ outlet_float(x->out(1), x->fp);
+ outlet_float(x->out(0), x->fr);
+}
+
+static int vu_pickle(t_vu *x, t_foo *foo) {
+ return pd_pickle(foo,"iiaaiiiiccb;i",&x->w,&x->h,&x->rcv,&x->lab,&x->ldx,&x->ldy,&x->font_style,
+ &x->fontsize,&x->bcol,&x->lcol,&x->scale,&x->isa);
+}
+
+static void vu_savefn(t_vu *x, t_binbuf *b) {
+ t_foo foo = {0,0,b}; if (!b) return;
+ pd_savehead(b,x,"vu"); vu_pickle(x,&foo);
+}
+
+static void vu_reload(t_vu *x, t_symbol *s, int argc, t_atom *argv) {
+ t_foo foo = { argc, argv, 0 };
+ binbuf_update(x,gensym("vu"),argc,argv);
+ if (!vu_pickle(x,&foo)) return;
+ iemgui_constrain(x);
+ if(x->rcv) pd_bind(x,x->rcv);
+ gobj_changed(x,0);
+}
+
+static t_class *vu_class;
+
+static void *vu_new(t_symbol *s, int argc, t_atom *argv) {
+ t_vu *x = (t_vu *)iemgui_new(vu_class);
+ outlet_new(x, &s_float);
+ outlet_new(x, &s_float);
+ SET(bcol,0x000000);
+ SET(h,IEM_VU_STEPS*3);
+ SET(scale,1);
+ SET(rms,0); /* ??? */
+ SET(peak,0);
+ SET(fp,-101.0);
+ SET(fr,-101.0);
+ vu_check_height(x,x->h);
+ inlet_new(x,x,&s_float,gensym("ft1"));
+ if (argc) vu_reload(x,0,argc,argv);
+ return x;
+}
+
+static t_class *cnv_class;
+
+static void cnv_get_pos(t_cnv *x) {
+ error("unimplemented (TODO)");
+// if(x->snd && x->snd->thing) {x->at[0].a_float = x; x->at[1].a_float = y; pd_list(x->snd->thing, &s_list, 2, x->at);}
+}
+
+static void cnv_size(t_cnv *x, t_symbol *s, int ac, t_atom *av) {
+ SET(h,max(1,(int)atom_getintarg(0, ac, av)));
+ SET(w,x->h);
+}
+
+static void cnv_vis_size(t_cnv *x, t_symbol *s, int ac, t_atom *av) {
+ SET(vis_w,max(1,(int)atom_getintarg(0, ac, av)));
+ SET(vis_h,x->w);
+ if(ac > 1) SET(vis_h,max(1,(int)atom_getintarg(1, ac, av)));
+ gobj_changed(x,0);
+}
+
+static int cnv_pickle(t_cnv *x, t_foo *foo) {
+ return pd_pickle(foo,"iiiaaaiiiicc;i",&x->w,&x->vis_w,&x->vis_h,
+ &x->snd,&x->rcv,&x->lab,&x->ldx,&x->ldy,&x->font_style,&x->fontsize,&x->bcol,&x->lcol,&x->isa);
+}
+
+static void cnv_savefn(t_cnv *x, t_binbuf *b) {
+ t_foo foo = {0,0,b}; if (!b) return;
+ pd_savehead(b,x,"cnv"); cnv_pickle(x,&foo);
+}
+
+static void cnv_reload(t_cnv *x, t_symbol *s, int argc, t_atom *argv) {
+ t_foo foo = { argc, argv, 0 };
+ binbuf_update(x,gensym("cnv"),argc,argv);
+ if (!cnv_pickle(x,&foo)) return;
+ SET(w,max(x->w,1));
+ SET(h,x->w);
+ SET(vis_w,max(x->vis_w,1));
+ SET(vis_h,max(x->vis_h,1));
+ x->at[0].a_type = x->at[1].a_type = A_FLOAT; //???
+ iemgui_constrain(x);
+ if (x->rcv) pd_bind(x,x->rcv);
+ gobj_changed(x,0);
+}
+#undef FOO
+
+static void *cnv_new(t_symbol *s, int argc, t_atom *argv) {
+ t_cnv *x = (t_cnv *) iemgui_new(cnv_class);
+ SET(bcol,0xe0e0e0);
+ SET(fcol,0x000000);
+ SET(lcol,0x404040);
+ SET(w,15);
+ SET(vis_w,100);
+ SET(vis_h,60);
+ if (argc) cnv_reload(x,0,argc,argv);
+ return x;
+}
+
+void canvas_notice(t_gobj *x, t_gobj *origin, int argc, t_atom *argv) {
+ t_canvas *self = (t_canvas *)x;
+ gobj_changed3(self,origin,argc,argv);
+}
+
+void gobj_onsubscribe(t_gobj *x, t_gobj *observer) {gobj_changed(x,0);}
+
+void canvas_onsubscribe(t_gobj *x, t_gobj *observer) {
+ t_canvas *self = (t_canvas *)x;
+ gobj_onsubscribe(x,observer);
+ canvas_each( y,self) y->_class->onsubscribe( y,observer);
+ canvas_wires_each(oc,t,self) oc->_class->onsubscribe(oc,observer);
+}
+
+/* [declare] and canvas_open come from 0.40 */
+/* ------------------------------- declare ------------------------ */
+
+/* put "declare" objects in a patch to tell it about the environment in
+which objects should be created in this canvas. This includes directories to
+search ("-path", "-stdpath") and object libraries to load
+("-lib" and "-stdlib"). These must be set before the patch containing
+the "declare" object is filled in with its contents; so when the patch is
+saved, we throw early messages to the canvas to set the environment
+before any objects are created in it. */
+
+struct t_declare : t_object {
+ int useme;
+};
+
+static void *declare_new(t_symbol *s, int argc, t_atom *argv) {
+ t_declare *x = (t_declare *)pd_new(declare_class);
+ x->useme = 1;
+ /* LATER update environment and/or load libraries */
+ return x;
+}
+
+static void declare_free(t_declare *x) {
+ x->useme = 0;
+ /* LATER update environment */
+}
+
+void canvas_savedeclarationsto(t_canvas *x, t_binbuf *b) {
+ canvas_each(y,x) {
+ if (pd_class(y) == declare_class) {
+ binbuf_addv(b,"t","#X");
+ binbuf_addbinbuf(b, ((t_declare *)y)->binbuf);
+ binbuf_addv(b, ";");
+ } else if (pd_class(y) == canvas_class) canvas_savedeclarationsto((t_canvas *)y, b);
+ }
+}
+
+static void canvas_declare(t_canvas *x, t_symbol *s, int argc, t_atom *argv) {
+ t_canvasenvironment *e = canvas_getenv(x);
+#if 0
+ startpost("declare:: %s", s->name);
+ postatom(argc, argv);
+ endpost();
+#endif
+ for (int i=0; i<argc; i++) {
+ char *buf;
+ char *flag = atom_getsymbolarg(i, argc, argv)->name;
+ if ((argc > i+1) && !strcmp(flag, "-path")) {
+ e->path = namelist_append(e->path, atom_getsymbolarg(i+1, argc, argv)->name, 0);
+ i++;
+ } else if (argc>i+1 && !strcmp(flag, "-stdpath")) {
+ asprintf(&buf, "%s/%s", sys_libdir->name, atom_getsymbolarg(i+1, argc, argv)->name);
+ e->path = namelist_append(e->path,buf,0);
+ i++;
+ } else if (argc>i+1 && !strcmp(flag, "-lib")) {
+ sys_load_lib(x, atom_getsymbolarg(i+1, argc, argv)->name);
+ i++;
+ } else if (argc>i+1 && !strcmp(flag, "-stdlib")) {
+ asprintf(&buf, "%s/%s", sys_libdir->name, atom_getsymbolarg(i+1, argc, argv)->name);
+ sys_load_lib(0,buf);
+ i++;
+ } else post("declare: %s: unknown declaration", flag);
+ }
+}
+
+/* utility function to read a file, looking first down the canvas's search path (set with "declare"
+ objects in the patch and recursively in calling patches), then down the system one. The filename
+ is the concatenation of "name" and "ext". "Name" may be absolute, or may be relative with slashes.
+ If anything can be opened, the true directory is put in the buffer dirresult (provided by caller),
+ which should be "size" bytes. The "nameresult" pointer will be set somewhere in the interior of
+ "dirresult" and will give the file basename (with slashes trimmed). If "bin" is set a 'binary'
+ open is attempted, otherwise ASCII (this only matters on Microsoft.) If "x" is zero, the file is
+ sought in the directory "." or in the global path.*/
+int canvas_open2(t_canvas *x, const char *name, const char *ext, char **dirresult, char **nameresult, int bin) {
+ int fd = -1;
+ /* first check if "name" is absolute (and if so, try to open) */
+ if (sys_open_absolute(name, ext, dirresult, nameresult, bin, &fd)) return fd;
+ /* otherwise "name" is relative; start trying in directories named in this and parent environments */
+ for (t_canvas *y=x; y; y = y->dix->canvas) if (y->env) {
+ t_canvas *x2 = x;
+ while (x2 && x2->dix->canvas) x2 = x2->dix->canvas;
+ const char *dir = x2 ? canvas_getdir(x2)->name : ".";
+ for (t_namelist *nl = y->env->path; nl; nl = nl->nl_next) {
+ char *realname;
+ asprintf(&realname, "%s/%s", dir, nl->nl_string);
+ if ((fd = sys_trytoopenone(realname, name, ext, dirresult, nameresult, bin)) >= 0) return fd;
+ }
+ }
+ return open_via_path2((x ? canvas_getdir(x)->name : "."), name, ext, dirresult, nameresult, bin);
+}
+/* end miller 0.40 */
+
+int canvas_open(t_canvas *x, const char *name, const char *ext, char *dirresult, char **nameresult, unsigned int size, int bin) {
+ char *dirr;
+ int r = canvas_open2(x,name,ext,&dirr,nameresult,bin);
+ if (dirr) {strncpy(dirresult,dirr,size); dirresult[size-1]=0; free(dirr);}
+ return r;
+}
+
+static void canvas_with_reply (t_pd *x, t_symbol *s, int argc, t_atom *argv) {
+ if (!( argc>=2 && IS_A_FLOAT(argv,0) && IS_A_SYMBOL(argv,1) )) return;
+ pd_typedmess(x,atom_getsymbol(&argv[1]),argc-2,argv+2);
+ queue_put(manager->q,reply_new((short)atom_getfloat(&argv[0]),newest));
+}
+
+static void canvas_get_elapsed (t_canvas *x) {
+ canvas_each(y,x) {
+ sys_mgui(y,"elapsed","f",y->dix->elapsed / 800000000.0);
+ }
+}
+
+static void g_canvas_setup() {
+ reply_class = class_new2("reply",0,reply_free,sizeof(t_reply),CLASS_GOBJ,"!");
+// class_setsavefn(reply_class, (t_savefn)reply_savefn);
+ declare_class = class_new2("declare",declare_new,declare_free,sizeof(t_declare),CLASS_NOINLET,"*");
+ t_class *c = canvas_class = class_new2("canvas",0,canvas_free,sizeof(t_canvas),CLASS_NOINLET,"");
+ /* here is the real creator function, invoked in patch files
+ by sending the "canvas" message to #N, which is bound to pd_canvasmaker. */
+ class_addmethod2(pd_canvasmaker._class,canvas_new,"canvas","*");
+ class_addmethod2(c,canvas_restore,"restore","*");
+ class_addmethod2(c,canvas_coords,"coords","*");
+ class_addmethod2(c,canvas_setbounds,"bounds","ffff");
+ class_addmethod2(c,canvas_obj,"obj","*");
+ class_addmethod2(c,canvas_msg,"msg","*");
+ class_addmethod2(c,canvas_floatatom,"floatatom","*");
+ class_addmethod2(c,canvas_symbolatom,"symbolatom","*");
+ class_addmethod2(c,canvas_text,"text","*");
+ class_addmethod2(c,canvas_canvas,"graph","*");
+ class_addmethod2(c,canvas_scalar,"scalar","*");
+ class_addmethod2(c,canvas_declare,"declare","*");
+ class_addmethod2(c,canvas_push,"push","");
+ class_addmethod2(c,canvas_pop,"pop","F");
+ class_addmethod2(c,canvas_loadbang,"loadbang","");
+ class_addmethod2(c,canvas_relocate,"relocate","ss");
+ class_addmethod2(c,canvas_vis,"vis","f");
+ class_addmethod2(c,canvas_menu_open,"menu-open","");
+ class_addmethod2(c,canvas_clear,"clear","");
+ class_addcreator2("pd",subcanvas_new,"S");
+ class_addcreator2("page",subcanvas_new,"S");
+ class_addmethod2(c,canvas_dsp,"dsp","");
+ class_addmethod2(c,canvas_rename_method,"rename","*");
+ class_addcreator2("table",table_new,"SF");
+ class_addmethod2(c,canvas_close,"close","F");
+ class_addmethod2(c,canvas_redraw,"redraw","");
+ class_addmethod2(c,canvas_find_parent,"findparent","");
+ class_addmethod2(c,canvas_arraydialog,"arraydialog","sfff");
+ class_addmethod2(c,canvas_connect,"connect","ffff");
+ class_addmethod2(c,canvas_disconnect,"disconnect","ffff");
+ class_addmethod2(c,canvas_write,"write","sS");
+ class_addmethod2(c,canvas_read, "read","sS");
+ class_addmethod2(c,canvas_mergefile, "mergefile","sS");
+ class_addmethod2(c,canvas_savetofile,"savetofile","ss");
+ class_addmethod2(c,canvas_saveto, "saveto","!");
+ class_addmethod2(c,graph_bounds,"bounds","ffff");
+ class_addmethod2(c,graph_xticks,"xticks","fff");
+ class_addmethod2(c,graph_xlabel,"xlabel","*");
+ class_addmethod2(c,graph_yticks,"yticks","fff");
+ class_addmethod2(c,graph_ylabel,"ylabel","*");
+ class_addmethod2(c,graph_array,"array","sfsF");
+ //class_addmethod2(c,canvas_sort,"sort","");
+// dd-specific
+ class_addmethod2(c,canvas_object_moveto,"object_moveto","sff");
+ class_addmethod2(c,canvas_object_delete,"object_delete","s");
+ //class_addmethod2(c,canvas_object_insert,"object_insert","*");
+ class_addmethod2(c,canvas_object_get_tips,"object_get_tips","s");
+ class_addmethod2(c,canvas_object_help,"object_help","s");
+ class_addmethod2(c,canvas_text_setto,"text_setto","*");
+ class_addmethod2(c,canvas_with_reply,"with_reply","*");
+ class_addmethod2(pd_canvasmaker._class,canvas_with_reply,"with_reply","*");
+ class_addmethod2(c,canvas_get_elapsed,"get_elapsed","");
+ class_setnotice(c, canvas_notice);
+ class_setonsubscribe(c, canvas_onsubscribe);
+}
+
+t_class *visualloader_class;
+
+static t_pd *visualloader_new(t_symbol *s, int argc, t_atom *argv) {return pd_new(visualloader_class);}
+static void visualloader_free(t_pd *self) {free(self);}
+static void copy_atoms(int argc, t_atom *argvdest, t_atom *argvsrc) {memcpy(argvdest,argvsrc,argc*sizeof(t_atom));}
+static void visualloader_anything(t_gobj *self, t_symbol *s, int argc, t_atom *argv) {
+ int i=0,j=0;
+ //printf("visualloader_anything start newest=%p\n",newest);
+ while (j<argc) {
+ i=j;
+ while (j<argc && atom_getsymbolarg(j,argc,argv)!=gensym(",")) j++;
+ if (i==j) {j++; continue;}
+ t_arglist *al = (t_arglist *) malloc(sizeof(t_arglist) + (j-i)*sizeof(t_atom));
+ al->c=j-i;
+ copy_atoms(al->c,al->v,&argv[i]);
+ //printf("#V reading '%s':\n",s->name);
+ if (!newest) {error("#V: there is no newest object\n"); return;}
+ t_visual *h = ((t_gobj *)newest)->dix->visual;
+ if (h->exists(s)) {
+ //printf("'%s' exists, deleting\n",s->name);
+ free(h->get(s));
+ }
+ h->set(s,al);
+ //fprintf(stderr,"visualloader... %p %d\n",newest,hash_size(h));
+ j++;
+ if (j<argc) {s=atom_getsymbolarg(j,argc,argv);j++;}
+ }
+ //printf("visualloader_anything end\n");
+ gobj_changed(self,0);
+}
+
+extern "C" void glob_update_path ();
+
+void glob_help(t_pd *bogus, t_symbol *s) {
+ t_class *c = class_find(s);
+ if (!c) {
+ //post("help: no such class '%s'",s->name); return;
+ t_binbuf *b = binbuf_new();
+ binbuf_addv(b,"s",s);
+ newest = 0;
+ binbuf_eval(b,&pd_objectmaker,0,0);
+ if (!newest) {post("help: no such class '%s'",s->name); return;}
+ c = newest->_class;
+ pd_free(newest);
+ }
+ const char *hn = class_gethelpname(c);
+ char *buf;
+ bool suffixed = strcmp(hn+strlen(hn)-3, ".pd")==0;
+ asprintf(&buf,"%s%s",hn,suffixed?"":".pd");
+ open_via_helppath(buf, c->externdir->name);
+ free(buf);
+}
+
+extern "C" void glob_update_class_list (t_pd *self, t_symbol *cb_recv, t_symbol *cb_sel) {
+ t_symbol *k; t_class *v;
+ sys_gui("global class_list; set class_list {");
+ hash_foreach(k,v,class_table) sys_vgui("%s ", ((t_symbol *)k)->name);
+ sys_gui("}\n");
+ sys_vgui("%s %s\n",cb_recv->name, cb_sel->name);
+}
+
+EXTERN t_class *glob_pdobject;
+
+t_pd *pd_new2(int argc, t_atom *argv) {
+ if (argv[0].a_type != A_SYMBOL) {error("pd_new2: start with symbol please"); return 0;}
+ pd_typedmess(&pd_objectmaker,argv[0].a_symbol,argc-1,argv+1);
+ return newest;
+}
+t_pd *pd_new3(const char *s) {
+ t_binbuf *b = binbuf_new();
+ binbuf_text(b,(char *)s,strlen(s));
+ t_pd *self = pd_new2(binbuf_getnatom(b),binbuf_getvec(b));
+ binbuf_free(b);
+ return self;
+}
+
+extern "C" void boxes_init() {
+ t_class *c;
+ c = boxes_class = class_new2("__boxes" ,0/*boxes_new*/ , boxes_free,sizeof(t_boxes),CLASS_GOBJ,"");
+ class_setnotice(c,t_notice(boxes_notice));
+ c = gop_filtre_class = class_new2("__gop_filtre",0/*gop_filtre_new*/,gop_filtre_free,sizeof(t_boxes),CLASS_GOBJ,"");
+ class_setnotice(c,t_notice(gop_filtre_notice));
+}
+
+static void desire_setup() {
+ t_class *c;
+ s_empty = gensym("empty");
+ s_Pd = gensym("Pd");
+ s_pd = gensym("pd");
+ manager_class = class_new2("__manager",manager_new,manager_free,sizeof(t_manager),0,"*");
+ class_addanything(manager_class,manager_anything);
+ class_setnotice(manager_class,manager_notice);
+ manager = manager_new(0,0,0);
+#define S(x) x##_setup();
+ S(vinlet) S(voutlet) S(g_array) S(g_canvas) S(g_scalar) S(g_template) S(g_traversal) S(g_text)
+#undef S
+
+ c = bng_class = class_new2("bng",bng_new,iemgui_free,sizeof(t_bng),0,"*");
+ iemgui_subclass(c);
+ class_addbang (c, bng_bang);
+ class_addfloat (c, bng_bang2);
+ class_addsymbol (c, bng_bang2);
+ class_addpointer (c, bng_bang2);
+ class_addlist (c, bng_bang2);
+ class_addanything(c, bng_bang2);
+ class_addmethod2(c,bng_reload,"reload","*");
+ class_addmethod2(c,bng_loadbang,"loadbang","");
+ class_addmethod2(c,bng_size,"size","*");
+ class_addmethod2(c,bng_flashtime,"flashtime","*");
+ class_addmethod2(c,iemgui_init,"init","f");
+ class_setsavefn(c, (t_savefn)bng_savefn);
+ class_sethelpsymbol(c, gensym("bng"));
+ class_setfieldnames(c, "foo bar x1 y1 class w hold break isa snd rcv lab ldx ldy fstyle fs bcol fcol lcol");
+
+ c = toggle_class = class_new2("tgl",toggle_new,iemgui_free,sizeof(t_toggle),0,"*");
+ class_addcreator2("toggle",toggle_new,"*");
+ iemgui_subclass(c);
+ class_addbang(c, toggle_bang);
+ class_addfloat(c, toggle_float);
+ class_addmethod2(c,toggle_reload,"reload","*");
+ class_addmethod2(c,toggle_loadbang,"loadbang","");
+ class_addmethod2(c,toggle_set,"set","f");
+ class_addmethod2(c,toggle_size,"size","*");
+ class_addmethod2(c,iemgui_init,"init","f");
+ class_addmethod2(c,toggle_nonzero,"nonzero","f");
+ class_setsavefn(c, (t_savefn)toggle_savefn);
+ class_sethelpsymbol(c, gensym("toggle"));
+
+ c = radio_class = class_new2("radio",radio_new,iemgui_free,sizeof(t_radio),0,"*");
+ iemgui_subclass(c);
+ class_addbang(c, radio_bang);
+ class_addfloat(c, radio_float);
+ class_addmethod2(c,radio_reload, "reload","*");
+ class_addmethod2(c,radio_loadbang, "loadbang","");
+ class_addmethod2(c,radio_set, "set","f");
+ class_addmethod2(c,radio_size, "size","f");
+ class_addmethod2(c,iemgui_init, "init","f");
+ class_addmethod2(c,radio_fout, "fout","f");
+ class_addmethod2(c,radio_number, "number","f");
+ class_addmethod2(c,radio_orient,"orient","f");
+ class_addmethod2(c,radio_single_change, "single_change","");
+ class_addmethod2(c,radio_double_change, "double_change","");
+ sym_hdl = gensym("hdl"); sym_hradio = gensym("hradio");
+ sym_vdl = gensym("vdl"); sym_vradio = gensym("vradio");
+ class_setsavefn(c,(t_savefn)radio_savefn);
+ class_sethelpsymbol(c, gensym("hradio"));
+ class_addcreator2("hradio",radio_new,"*");
+ class_addcreator2("vradio",radio_new,"*");
+ class_addcreator2("hdl",radio_new,"*");
+ class_addcreator2("vdl",radio_new,"*");
+ class_addcreator2("rdb",radio_new,"*");
+ class_addcreator2("radiobut",radio_new,"*");
+ class_addcreator2("radiobutton",radio_new,"*");
+
+ c = slider_class = class_new2("slider",slider_new,iemgui_free,sizeof(t_slider),0,"*");
+ class_addcreator2("hslider",slider_new,"*");
+ class_addcreator2("vslider",slider_new,"*");
+ class_addcreator2("hsl" ,slider_new,"*");
+ class_addcreator2("vsl" ,slider_new,"*");
+
+ iemgui_subclass(c);
+ class_addbang(c,slider_bang);
+ class_addfloat(c,slider_float);
+ class_addmethod2(c,slider_reload,"reload","*");
+ class_addmethod2(c,slider_loadbang,"loadbang","");
+ class_addmethod2(c,slider_set,"set","f");
+ class_addmethod2(c,slider_size,"size","*");
+ class_addmethod2(c,slider_range,"range","ff");
+ class_addmethod2(c,slider_log,"log","");
+ class_addmethod2(c,slider_lin,"lin","");
+ class_addmethod2(c,iemgui_init,"init","f");
+ class_addmethod2(c,slider_steady,"steady","f");
+ class_addmethod2(c,slider_orient,"orient","f");
+ sym_vsl = gensym("vsl");
+ sym_vslider = gensym("vslider");
+ class_setsavefn(c,(t_savefn)slider_savefn);
+ class_sethelpsymbol(c, gensym("hslider"));
+
+ c = nbx_class = class_new2("nbx",nbx_new,iemgui_free,sizeof(t_nbx),0,"*");
+ iemgui_subclass(c);
+ class_addbang(c,nbx_bang);
+ class_addfloat(c,nbx_float);
+ class_addlist(c, nbx_list);
+ class_addmethod2(c,nbx_reload,"reload","*");
+ class_addmethod2(c,nbx_loadbang,"loadbang","");
+ class_addmethod2(c,nbx_set,"set","f");
+ class_addmethod2(c,nbx_size,"size","*");
+ class_addmethod2(c,nbx_range,"range","*");
+ class_addmethod2(c,nbx_log,"log","");
+ class_addmethod2(c,nbx_lin,"lin","");
+ class_addmethod2(c,iemgui_init,"init","f");
+ class_addmethod2(c,nbx_log_height,"log_height","f");
+ class_setsavefn(c,(t_savefn)nbx_savefn);
+ class_sethelpsymbol(c, gensym("numbox2"));
+
+ c = cnv_class = class_new2("cnv",cnv_new,iemgui_free,sizeof(t_cnv),CLASS_NOINLET,"*");
+ class_addmethod2(c,cnv_reload,"reload","*");
+ class_addmethod2(c,cnv_size,"size","*");
+ class_addmethod2(c,cnv_vis_size,"vis_size","*");
+ class_addmethod2(c,cnv_get_pos,"get_pos","");
+ iemgui_subclass(c);
+ class_setsavefn(c,(t_savefn)cnv_savefn);
+ class_sethelpsymbol(c, gensym("my_canvas"));
+
+ c = vu_class = class_new2("vu",vu_new,iemgui_free,sizeof(t_vu),0,"*");
+ iemgui_subclass(c);
+ class_addbang(c,vu_bang);
+ class_addfloat(c,vu_float0);
+ class_addmethod2(c,vu_float1,"ft1","f");
+ class_addmethod2(c,vu_reload,"reload","*");
+ class_addmethod2(c,vu_size,"size","*");
+ class_addmethod2(c,vu_scale,"scale","F");
+ class_setsavefn(c,(t_savefn)vu_savefn);
+ class_sethelpsymbol(c, gensym("vu"));
+
+ visualloader_class = class_new2("#V",visualloader_new,visualloader_free,sizeof(t_object),CLASS_GOBJ,"*");
+ class_addanything(visualloader_class,visualloader_anything);
+ pd_bind(pd_new(visualloader_class),gensym("#V"));
+}
+
+/* ---------------------------------------------------------------- */
+/* formerly m_glob.c */
+
+t_class *glob_pdobject;
+static t_class *maxclass;
+
+#define IGN(sym) if (s==gensym(sym)) return;
+void max_default(t_pd *x, t_symbol *s, int argc, t_atom *argv) {
+ IGN("audioindev");
+ IGN("audiooutdev");
+ IGN("audioininfo");
+ IGN("audiooutinfo");
+ IGN("testaudiosettingresult");
+ IGN("audiodevice");
+ IGN("xrun");
+ IGN("audio_started");
+ IGN("sys_lock_timeout");
+ IGN("midiindev");
+ IGN("midioutdev");
+ IGN("midicurrentindev");
+ IGN("midicurrentoutdev");
+ IGN("audiocurrentininfo");
+ IGN("audiocurrentoutinfo");
+ IGN("asiolatency");
+ startpost("%s: unknown message %s ", class_getname(pd_class(x)), s->name);
+ std::ostringstream buf;
+ for (int i = 0; i < argc; i++) {buf << " "; atom_ostream(argv+i,buf);}
+ post("%s",buf.str().data());
+ endpost();
+}
+
+static void openit(const char *dirname, const char *filename) {
+ char *dirbuf;
+ char *nameptr;
+ int fd = open_via_path2(dirname,filename,"",&dirbuf,&nameptr,0);
+ if (!fd) {error("%s: can't open", filename); return;}
+ close(fd);
+ glob_evalfile(0, gensym(nameptr), gensym(dirbuf));
+ free(dirbuf);
+}
+
+extern "C" t_socketreceiver *netreceive_newest_receiver(t_text *x);
+
+/* this should be rethought for multi-client */
+void glob_initfromgui(void *dummy, t_symbol *s) {
+ char buf[256], buf2[256];
+ char cwd[666];
+ getcwd(cwd,665);
+ sys_socketreceiver=netreceive_newest_receiver(sys_netreceive);
+ sys_vgui("%s",lost_posts.str().data());
+ /* load dynamic libraries specified with "-lib" args */
+ for (t_namelist *nl=sys_externlist; nl; nl = nl->nl_next)
+ if (!sys_load_lib(0, nl->nl_string))
+ post("%s: can't load library", nl->nl_string);
+ /* open patches specified with "-open" args */
+ for (t_namelist *nl=sys_openlist; nl; nl = nl->nl_next) openit(cwd, nl->nl_string);
+ namelist_free(sys_openlist);
+ sys_openlist = 0;
+ /* send messages specified with "-send" args */
+ for (t_namelist *nl=sys_messagelist; nl; nl = nl->nl_next) {
+ t_binbuf *b = binbuf_new();
+ binbuf_text(b, nl->nl_string, strlen(nl->nl_string));
+ binbuf_eval(b, 0, 0, 0);
+ binbuf_free(b);
+ }
+ namelist_free(sys_messagelist);
+ sys_messagelist = 0;
+ sys_get_audio_apis(buf);
+ sys_get_midi_apis(buf2);
+ sys_vgui("pd_startup {%s} %s %s\n", pd_version, buf, buf2);
+/*
+ fprintf(stdout,"This line was printed on stdout\n");
+ fprintf(stderr,"This line was printed on stderr\n");
+*/
+}
+
+void glob_meters(void *dummy, t_floatarg f);
+void glob_audiostatus(void *dummy);
+void glob_audio_properties(t_pd *dummy, t_floatarg flongform);
+void glob_audio_dialog(t_pd *dummy, t_symbol *s, int argc, t_atom *argv);
+void glob_audio_setapi(t_pd *dummy, t_floatarg f);
+void glob_midi_properties(t_pd *dummy, t_floatarg flongform);
+void glob_midi_dialog(t_pd *dummy, t_symbol *s, int argc, t_atom *argv);
+void glob_midi_setapi(t_pd *dummy, t_floatarg f);
+void glob_start_path_dialog(t_pd *dummy, t_floatarg flongform);
+void glob_path_dialog(t_pd *dummy, t_symbol *s, int argc, t_atom *argv);
+void glob_start_startup_dialog(t_pd *dummy, t_floatarg flongform);
+void glob_startup_dialog(t_pd *dummy, t_symbol *s, int argc, t_atom *argv);
+void glob_ping(t_pd *dummy);
+extern "C" {
+void glob_finderror(t_pd *dummy);
+};
+/* tb: message-based audio configuration { */
+void glob_audio_testaudiosetting(t_pd * dummy, t_symbol *s, int ac, t_atom *av);
+void glob_audio_getaudioindevices(t_pd * dummy, t_symbol *s, int ac, t_atom *av);
+void glob_audio_getaudiooutdevices(t_pd * dummy, t_symbol *s, int ac, t_atom *av);
+void glob_audio_getaudioininfo(t_pd * dummy, t_float f);
+void glob_audio_getaudiooutinfo(t_pd * dummy, t_float f);
+//void glob_audio_samplerate(t_pd * dummy, t_float f);
+//void glob_audio_delay(t_pd * dummy, t_float f);
+//void glob_audio_dacblocksize(t_pd * dummy, t_float f);
+//void glob_audio_scheduler(t_pd * dummy, t_float f);
+void glob_audio_device(t_pd * dummy, t_symbol *s, int argc, t_atom *argv);
+//void glob_audio_device_in(t_pd * dummy, t_symbol *s, int argc, t_atom *argv);
+//void glob_audio_device_out(t_pd * dummy, t_symbol *s, int argc, t_atom *argv);
+void glob_audio_getcurrent_devices ();
+void glob_audio_asio_latencies(t_pd * dummy, t_float f);
+void glob_midi_getindevs( t_pd *dummy, t_symbol *s, int ac, t_atom *av);
+void glob_midi_getoutdevs(t_pd *dummy, t_symbol *s, int ac, t_atom *av);
+void glob_midi_getcurrentindevs(t_pd *dummy);
+void glob_midi_getcurrentoutdevs(t_pd *dummy);
+/* tb } */
+
+static void glob_object_table() {
+ t_symbol *s_inlet = gensym("inlet");
+ t_symbol *s___list = gensym("__list");
+ size_t inlets=0, lists=0, zombies=0;
+ t_pd *k; long v;
+ post("object_table = {");
+ hash_foreach(k,v,object_table) {
+ t_pd *x = (t_pd *)k;
+ if (!(long)v&1) {zombies++; continue;} /* skip zombies */
+ //post(" %p %ld %s",k,(long)v,x->_class->name->name);
+ if (x->_class->name == s_inlet) {inlets++; continue;}
+ if (x->_class->name == s___list) {lists++; continue;}
+ int nobs = x->_class->gobj ? ((t_gobj *)x)->dix->nobs : 0;
+ // this has been duplicated as the ostream operator of t_pd * (see above).
+ t_binbuf *b;
+ if (x->_class->patchable && (b = ((t_text *)x)->binbuf)) {
+ char *buf; int bufn;
+ binbuf_gettext(b,&buf,&bufn);
+ post(" %p %ld (%dobs) %s [%.*s]",k,(long)v,nobs,x->_class->name->name,bufn,buf);
+ } else post(" %p %ld (%dobs) %s",k,(long)v,nobs,x->_class->name->name);
+ }
+ post("} (%ld non-omitted objects, plus %ld [inlet], plus %ld [__list], plus %ld zombies)",
+ object_table->size()-inlets-lists-zombies,inlets,lists,zombies);
+}
+
+extern t_class *glob_pdobject;
+extern "C" void glob_init () {
+ /* can this one really be called "max"? isn't that a name conflict? */
+ maxclass = class_new2("max",0,0,sizeof(t_pd),CLASS_DEFAULT,"");
+ class_addanything(maxclass, max_default);
+ pd_bind((t_pd *)&maxclass, gensym("max"));
+
+ /* this smells bad... a conflict with [pd] subpatches */
+ t_class *c = glob_pdobject = class_new2("pd",0,0,sizeof(t_pd),CLASS_DEFAULT,"");
+ class_addmethod2(c,glob_initfromgui, "init", "*");
+ class_addmethod2(c,glob_setfilename, "filename", "ss");
+ class_addmethod2(c,glob_evalfile, "open", "ss");
+ class_addmethod2(c,glob_quit, "quit", "");
+ class_addmethod2(c,glob_dsp, "dsp", "*");
+ class_addmethod2(c,glob_meters, "meters", "f");
+ class_addmethod2(c,glob_audiostatus, "audiostatus", "");
+ class_addmethod2(c,glob_finderror, "finderror", "");
+ class_addmethod2(c,glob_audio_properties, "audio-properties", "F");
+ class_addmethod2(c,glob_audio_dialog, "audio-dialog", "*");
+ class_addmethod2(c,glob_audio_setapi, "audio-setapi", "f");
+ class_addmethod2(c,glob_midi_setapi, "midi-setapi", "f");
+ class_addmethod2(c,glob_midi_properties, "midi-properties", "F");
+ class_addmethod2(c,glob_midi_dialog, "midi-dialog", "*");
+ class_addmethod2(c,glob_ping, "ping","");
+ /* tb: message-based audio configuration { */
+// class_addmethod2(c,glob_audio_samplerate, "audio-samplerate", "F");
+// class_addmethod2(c,glob_audio_delay, "audio-delay", "F");
+// class_addmethod2(c,glob_audio_dacblocksize,"audio-dacblocksize", "F");
+// class_addmethod2(c,glob_audio_scheduler, "audio-scheduler", "F");
+ class_addmethod2(c,glob_audio_device, "audio-device", "*");
+// class_addmethod2(c,glob_audio_device_in, "audio-device-in", "*");
+// class_addmethod2(c,glob_audio_device_out, "audio-device-out", "*");
+ class_addmethod2(c,glob_audio_getaudioindevices, "getaudioindev", "*");
+ class_addmethod2(c,glob_audio_getaudiooutdevices,"getaudiooutdev", "*");
+ class_addmethod2(c,glob_audio_getaudioininfo, "getaudioininfo", "f");
+ class_addmethod2(c,glob_audio_getaudiooutinfo, "getaudiooutinfo", "f");
+ class_addmethod2(c,glob_audio_testaudiosetting, "testaudiosetting", "*");
+ class_addmethod2(c,glob_audio_getcurrent_devices,"getaudiodevice", "");
+ class_addmethod2(c,glob_audio_asio_latencies, "getasiolatencies", "F");
+ class_addmethod2(c,glob_midi_getoutdevs,"getmidioutdev", "*");
+ class_addmethod2(c,glob_midi_getindevs, "getmidiindev", "*");
+ class_addmethod2(c,glob_midi_getcurrentoutdevs, "getmidicurrentoutdev", "");
+ class_addmethod2(c,glob_midi_getcurrentindevs, "getmidicurrentindev", "");
+ /* tb } */
+#ifdef UNIX
+ class_addmethod2(c,glob_watchdog, "watchdog", "");
+#endif
+ class_addmethod2(c,glob_update_class_list, "update-class-list", "ss");
+ class_addmethod2(c,glob_update_class_info, "update-class-info", "sss");
+ class_addmethod2(c,glob_update_path, "update-path", "");
+ class_addmethod2(c,glob_help, "help", "s");
+ class_addmethod2(c,glob_object_table,"object_table","");
+ class_addanything(c, max_default);
+ pd_bind((t_pd *)&glob_pdobject, gensym("pd"));
+}
+
+/* ---------------------------------------------------------------- */
+/* formerly s_print.c */
+
+t_printhook sys_printhook;
+int sys_printtostderr;
+
+static void dopost(const char *s) {
+ if (sys_printhook) sys_printhook(s);
+ else if (sys_printtostderr) fprintf(stderr, "%s", s);
+ else {
+ std::ostringstream t;
+ for(int i=0; s[i]; i++) {
+ if (strchr("\\\"[]$\n",s[i])) t << '\\';
+ t << char(s[i]=='\n' ? 'n' : s[i]);
+ }
+ sys_vgui("pdtk_post \"%s\"\n",t.str().data());
+ }
+}
+
+void post(const char *fmt, ...) {
+ char *buf; va_list ap; va_start(ap, fmt);
+ size_t n = vasprintf(&buf, fmt, ap); va_end(ap);
+ buf=(char*)realloc(buf,n+2); strcpy(buf+n,"\n");
+ dopost(buf); free(buf);
+}
+void startpost(const char *fmt, ...) {
+ char *buf; va_list ap; va_start(ap, fmt);
+ vasprintf(&buf, fmt, ap); va_end(ap);
+ dopost(buf); free(buf);
+}
+
+void poststring(const char *s) {dopost(" "); dopost(s);}
+
+void postatom(int argc, t_atom *argv) {
+ std::ostringstream buf;
+ for (int i=0; i<argc; i++) {buf << " "; atom_ostream(argv+i,buf);}
+ dopost(buf.str().data());
+}
+
+/* what's the point? */
+void postfloat(float f) {t_atom a; SETFLOAT(&a, f); postatom(1, &a);}
+void endpost () {dopost("\n");}
+
+static t_pd *error_object;
+static char *error_string;
+void canvas_finderror(void *object);
+
+void verror(const char *fmt, va_list ap) {
+ if (error_string) free(error_string);
+ dopost("error: ");
+ vasprintf(&error_string,fmt,ap);
+ dopost(error_string);
+ dopost("\n");
+ //post("at stack level %ld\n",pd_stackn);
+ error_object = pd_stackn>=0 ? pd_stack[pd_stackn-1].self : 0;
+}
+void error( const char *fmt, ...) {va_list ap; va_start(ap,fmt); verror(fmt,ap); va_end(ap);}
+void pd_error(void *moot, const char *fmt, ...) {va_list ap; va_start(ap,fmt); verror(fmt,ap); va_end(ap);}
+
+void verbose(int level, const char *fmt, ...) {
+ char *buf;
+ va_list ap;
+ if (level>sys_verbose) return;
+ dopost("verbose(");
+ postfloat((float)level);
+ dopost("):");
+ va_start(ap, fmt);
+ vasprintf(&buf,fmt,ap);
+ va_end(ap);
+ dopost(buf);
+ dopost("\n");
+}
+
+extern "C" void glob_finderror(t_pd *dummy) {
+ if (!error_object) {post("no findable error yet."); return;}
+ post("last trackable error was for object x%lx: %s", error_object, error_string);
+ sys_mgui(error_object,"show_error","S",error_string);
+ canvas_finderror(error_object);
+}
+
+void bug(const char *fmt, ...) {
+ char *buf;
+ va_list ap;
+ dopost("bug: ");
+ va_start(ap, fmt);
+ vasprintf(&buf,fmt,ap);
+ va_end(ap);
+ dopost(buf);
+ free(buf);
+ dopost("\n");
+}
+
+static const char *errobject;
+static const char *errstring;
+
+void sys_logerror (const char *object, const char *s){errobject=object; errstring = s;}
+void sys_unixerror(const char *object) {errobject=object; errstring = strerror(errno);}
+
+void sys_ouch () {
+ if (*errobject) error("%s: %s", errobject, errstring); else error("%s", errstring);
+}
+
+/* properly close all open root canvases */
+extern "C" void glob_closeall(void *dummy, t_floatarg fforce) {
+ foreach(x,windowed_canvases) canvas_close(x->first);
+}
+
+/* ---------------------------------------------------------------- */
+/* formerly m_conf.c */
+
+void builtins_setup ();
+void builtins_dsp_setup ();
+void desire_setup ();
+void d_soundfile_setup ();
+void d_ugen_setup ();
+
+extern "C" void conf_init () {
+ builtins_setup();
+ builtins_dsp_setup();
+ desire_setup();
+ d_soundfile_setup();
+ d_ugen_setup();
+}
+
+// and just to make some externs happy:
+#define BYE error("%s unimplemented in desiredata!", __PRETTY_FUNCTION__);
+extern "C" {
+ void glist_grab () {BYE}
+ void glist_xtopixels () {BYE}
+ void glist_ytopixels () {BYE}
+ void *glist_findrtext () {BYE return 0;}
+ void canvas_fixlinesfor () {BYE}
+ void class_setpropertiesfn () {BYE}
+ void glist_eraseiofor () {BYE}
+ void glist_getcanvas () {BYE}
+ void rtext_gettag () {BYE}
+ void class_setwidget () {BYE}
+ void glist_isvisible () {BYE}
+ void gobj_vis () {BYE}
+ void gfxstub_deleteforkey () {BYE}
+ void gfxstub_new () {BYE}
+
+ //redundantwards-compatibility
+ void canvas_setcurrent (t_canvas *x) {pd_pushsym(x);}
+ void canvas_unsetcurrent(t_canvas *x) {pd_popsym(x);}
+};
diff --git a/desiredata/src/desire.h b/desiredata/src/desire.h
new file mode 100644
index 00000000..f3cefe02
--- /dev/null
+++ b/desiredata/src/desire.h
@@ -0,0 +1,353 @@
+/*
+ This file is part of PureData
+ Copyright 2004-2006 by Mathieu Bouchard
+ Copyright 2000-2001 IEM KUG Graz Austria (Thomas Musil)
+ Copyright (c) 1997-1999 Miller Puckette.
+ For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ WARRANTIES, see the file, "LICENSE.txt", in this distribution.
+
+ this file declares the C interface for the second half of DesireData.
+ this is where most of the differences between DesireData and PureData lie.
+
+ SYNONYMS:
+ 1. glist = graph = canvas = patcher; those were not always synonymous.
+ however, graph sometimes means a canvas that is displaying an array.
+ 2. outconnect = connection = patchcord = wire
+
+ canvases have a few flags that determine their appearance:
+ gl_havewindow: should open its own window (only if mapped? or...)
+ gl_isgraph: the GOP flag: show as graph-on-parent, vs TextBox.
+ gl_owner==0: it's a root canvas, should be in canvas_list.
+ In this case "gl_havewindow" is always set.
+
+ canvas_list is a list of root windows only, which can be traversed using canvases_each.
+
+ If a canvas has a window it may still not be "mapped." Miniaturized
+ windows aren't mapped, for example, but a window is also not mapped
+ immediately upon creation. In either case gl_havewindow is true but
+ gl_mapped is false.
+
+ Closing a non-root window makes it invisible; closing a root destroys it.
+ A canvas that's just a text object on its parent is always "toplevel." An
+ embedded canvas can switch back and forth to appear as a toplevel by double-
+ clicking on it. Single-clicking a text box makes the toplevel become visible
+ and raises the window it's in.
+
+ If a canvas shows up as a graph on its parent, the graph is blanked while the
+ canvas has its own window, even if miniaturized.
+*/
+
+#ifndef DESIRE
+#define DESIRE
+#endif
+#ifndef __DESIRE_H
+#define __DESIRE_H
+
+#include "m_pd.h"
+#include "s_stuff.h"
+
+#if defined(_LANGUAGE_C_PLUS_PLUS) || defined(__cplusplus)
+//#include <map>
+extern "C" {
+#endif
+
+/* ----------------------- m_imp.h ---------------------------------------------------*/
+
+typedef struct _methodentry {
+ t_symbol *me_name;
+ t_gotfn me_fun;
+ t_atomtype me_arg[MAXPDARG+1];
+} t_methodentry;
+
+typedef void (*t_bangmethod) (t_pd *x);
+typedef void (*t_pointermethod)(t_pd *x, t_gpointer *gp);
+typedef void (*t_floatmethod) (t_pd *x, t_float f);
+typedef void (*t_symbolmethod) (t_pd *x, t_symbol *s);
+typedef void (*t_stringmethod) (t_pd *x, const char *s);
+typedef void (*t_listmethod) (t_pd *x, t_symbol *s, int argc, t_atom *argv);
+typedef void (*t_anymethod) (t_pd *x, t_symbol *s, int argc, t_atom *argv);
+
+t_pd *pd_new2(int argc, t_atom *argv);
+t_pd *pd_new3(const char *s);
+
+struct _class {
+ t_symbol *name; /* name (mostly for error reporting) */
+ t_symbol *helpname; /* name of help file */
+ t_symbol *externdir; /* directory extern was loaded from */
+ size_t size; /* size of an instance */
+ t_methodentry *methods; /* methods other than bang, etc below */
+ int nmethod; /* number of methods */
+ t_method freemethod; /* function to call before freeing */
+ t_bangmethod bangmethod; /* common methods */
+ t_pointermethod pointermethod;
+ t_floatmethod floatmethod;
+ t_symbolmethod symbolmethod; /* or t_stringmethod, but only C++ has anonymous unions, so... */
+ t_listmethod listmethod;
+ t_anymethod anymethod;
+ t_savefn savefn; /* function to call when saving */
+ int floatsignalin; /* onset to float for signal input */
+ unsigned gobj:1; /* true if is a gobj */
+ unsigned patchable:1; /* true if we have a t_object header */
+ unsigned firstin:1; /* if patchable, true if draw first inlet */
+ unsigned drawcommand:1; /* a drawing command for a template */
+ unsigned newatoms:1; /* can handle refcounting of atoms (future use) */
+ unsigned use_stringmethod:1; /* the symbolmethod slot holds a stringmethod instead */
+ t_symbol *firsttip;
+ t_symbol **fields; /* names of fields aka attributes, and I don't mean the #V attributes. */
+ int nfields; /* ... and how many of them */
+ t_notice notice; /* observer method */
+ t_onsubscribe onsubscribe; /* observable method */
+};
+
+//#define c_methods methods /* for Cyclone */
+//#define c_nmethod nmethod /* for Cyclone */
+//#define c_externdir externdir /* for PDDP */
+//#define c_name name /* for Cyclone,Creb,Pidip */
+//#define c_size size /* for Cyclone,Flext */
+//#define me_name name /* for Cyclone */
+//#define me_fun fun /* for Cyclone */
+//#define me_arg arg /* for Cyclone */
+
+/* m_obj.c */
+EXTERN int obj_noutlets(t_object *x);
+EXTERN int obj_ninlets(t_object *x);
+EXTERN t_outconnect *obj_starttraverseoutlet(t_object *x, t_outlet **op, int nout);
+EXTERN t_outconnect *obj_nexttraverseoutlet(t_outconnect *lastconnect, t_object **destp, t_inlet **inletp, int *whichp);
+EXTERN t_outconnect *obj_connect(t_object *source, int outno, t_object *sink, int inno);
+EXTERN void obj_disconnect(t_object *source, int outno, t_object *sink, int inno);
+EXTERN void outlet_setstacklim(void);
+EXTERN int obj_issignalinlet(t_object *x, int m);
+EXTERN int obj_issignaloutlet(t_object *x, int m);
+EXTERN int obj_nsiginlets(t_object *x);
+EXTERN int obj_nsigoutlets(t_object *x);
+EXTERN int obj_siginletindex(t_object *x, int m);
+EXTERN int obj_sigoutletindex(t_object *x, int m);
+
+/* misc */
+EXTERN void glob_evalfile(t_pd *ignore, t_symbol *name, t_symbol *dir);
+EXTERN void glob_initfromgui(void *dummy, t_symbol *s);
+EXTERN void glob_quit(void *dummy);
+
+/* ----------------------- g_canvas.h ------------------------------------------------*/
+
+/* i don't know whether this is currently used at all in DesireData. -- matju 2006.09 */
+#ifdef GARRAY_THREAD_LOCK
+#include <pthread.h> /* TB: for t_garray */
+#endif
+
+typedef struct t_gtemplate t_gtemplate;
+typedef struct _canvasenvironment t_canvasenvironment;
+typedef struct _slot t_slot;
+
+/* the t_tick structure describes where to draw x and y "ticks" for a canvas */
+typedef struct _tick { /* where to put ticks on x or y axes */
+ float point; /* one point to draw a big tick at */
+ float inc; /* x or y increment per little tick */
+ int lperb; /* little ticks per big; 0 if no ticks to draw */
+} t_tick;
+
+typedef struct t_boxes t_boxes;
+
+/* the t_canvas structure, which describes a list of elements that live on an area of a window.*/
+#ifdef PD_PLUSPLUS_FACE
+struct _glist : t_object {
+#else
+struct _glist {
+ t_object gl_obj; /* header in case we're a [pd] or abstraction */
+#endif
+ int pixwidth, pixheight; /* width in pixels (on parent, if a graph) */
+ float x1,y1,x2,y2; /* bounding rectangle in our own coordinates */
+ int screenx1, screeny1, screenx2, screeny2; /* screen coordinates when toplevel */
+ int xmargin, ymargin; /* origin for GOP rectangle */
+ /* ticks and tick labels */
+ t_tick xtick; int nxlabels; t_symbol **xlabel; float xlabely;
+ t_tick ytick; int nylabels; t_symbol **ylabel; float ylabelx;
+ t_symbol *name; /* symbol bound here */
+ int font; /* nominal font size in points, e.g., 10 */
+ t_canvasenvironment *env; /* one of these per $0; env=0 for subpatches */
+ unsigned int havewindow:1; /* this indicates whether we publish to the manager */
+ unsigned int gop:1;
+ unsigned int goprect:1; /* gop version >= 0.39 */
+ unsigned int hidetext:1; /* hide object-name + args when doing graph on parent */
+ long next_o_index; /* next object index. to be incremented on each use */
+ long next_w_index; /* next wire index. to be incremented on each use */
+ t_boxes *boxes;
+};
+
+/* LATER consider adding font size to this struct (see canvas_getfont()) */
+struct _canvasenvironment {
+ t_symbol *dir; /* directory patch lives in */
+ int argc; /* number of "$" arguments */
+ t_atom *argv; /* array of "$" arguments */
+ long dollarzero; /* value of "$0" */
+ t_namelist *path;/* search path (0.40) */
+};
+
+/* a data structure to describe a field in a pure datum */
+#define DT_FLOAT 0
+#define DT_SYMBOL 1
+#define DT_CANVAS 2
+#define DT_ARRAY 3
+
+typedef struct t_dataslot {
+ int type;
+ t_symbol *name;
+ t_symbol *arraytemplate; /* filled in for arrays only */
+} t_dataslot;
+
+#ifdef PD_PLUSPLUS_FACE
+typedef struct t_template : t_pd {
+#else
+typedef struct t_template {
+ t_pd t_pdobj; /* header */
+#endif
+ t_gtemplate *list; /* list of "struct"/gtemplate objects */
+ t_symbol *sym; /* name */
+ int n; /* number of dataslots (fields) */
+ t_dataslot *vec; /* array of dataslots */
+} t_template;
+
+/* this is not really a t_object, but it needs to be observable and have a refcount, so... */
+#ifdef PD_PLUSPLUS_FACE
+struct _array : t_object {
+#else
+struct _array {
+ t_gobj gl_obj;
+#endif
+ int n; /* number of elements */
+ int elemsize; /* size in bytes; LATER get this from template */
+ char *vec; /* array of elements */
+ t_symbol *templatesym; /* template for elements */
+ t_gpointer gp; /* pointer to scalar or array element we're in */
+};
+
+#ifdef PD_PLUSPLUS_FACE
+struct _garray : t_gobj {
+#else
+struct _garray {
+ t_gobj x_gobj;
+#endif
+ t_scalar *scalar; /* scalar "containing" the array */
+ t_canvas *canvas; /* containing canvas */
+ t_symbol *name; /* unexpanded name (possibly with leading '$') */
+ t_symbol *realname; /* expanded name (symbol we're bound to) */
+ unsigned int usedindsp:1; /* true if some DSP routine is using this */
+ unsigned int saveit:1; /* true if we should save this with parent */
+ unsigned int listviewing:1; /* true if list view window is open */
+ unsigned int hidename:1; /* don't print name above graph */
+};
+
+t_array *garray_getarray(t_garray *x);
+
+/* structure for traversing all the connections in a canvas */
+typedef struct t_linetraverser {
+ t_canvas *canvas;
+ t_object *from; int nout; int outlet; t_outlet *outletp;
+ t_object *to; int nin; int inlet; t_inlet *inletp;
+ t_outconnect *next;
+ int nextoutno;
+#ifdef __cplusplus
+ t_linetraverser() {}
+ t_linetraverser(t_canvas *canvas);
+#endif
+} t_linetraverser;
+
+extern t_canvas *canvas_list; /* list of all root canvases */
+extern t_class *vinlet_class, *voutlet_class, *canvas_class;
+extern int canvas_valid; /* incremented when pointers might be stale */
+EXTERN int sys_noloadbang;
+EXTERN t_symbol *s_empty;
+
+#define PLOTSTYLE_POINTS 0 /* plotting styles for arrays */
+#define PLOTSTYLE_POLY 1
+#define PLOTSTYLE_BEZ 2
+
+/* from kernel.c */
+EXTERN void gobj_save(t_gobj *x, t_binbuf *b);
+EXTERN void pd_eval_text(char *t, size_t size);
+EXTERN int sys_syntax;
+
+/* from desire.c */
+EXTERN int pd_scanargs(int argc, t_atom *argv, char *fmt, ...);
+EXTERN int pd_saveargs(t_binbuf *b, char *fmt, ...);
+EXTERN void pd_upload(t_gobj *self);
+EXTERN void sys_mgui(void *self, const char *sel, const char *fmt, ...);
+EXTERN void canvas_add(t_canvas *x, t_gobj *g, int index=-1);
+EXTERN void canvas_delete(t_canvas *x, t_gobj *y);
+EXTERN void canvas_deletelinesfor(t_canvas *x, t_text *text);
+EXTERN void canvas_deletelinesforio(t_canvas *x, t_text *text, t_inlet *inp, t_outlet *outp);
+EXTERN int canvas_isvisible(t_canvas *x);
+EXTERN int canvas_istoplevel(t_canvas *x);
+EXTERN int canvas_istable(t_canvas *x);
+EXTERN int canvas_isabstraction(t_canvas *x);
+EXTERN t_canvas *canvas_getcanvas(t_canvas *x);
+EXTERN t_canvas *canvas_getrootfor(t_canvas *x);
+EXTERN t_canvas *canvas_getcurrent(void);
+EXTERN t_canvasenvironment *canvas_getenv(t_canvas *x);
+EXTERN int canvas_getdollarzero(void);
+EXTERN t_symbol *canvas_realizedollar(t_canvas *x, t_symbol *s);
+EXTERN t_symbol *canvas_makebindsym(t_symbol *s);
+
+EXTERN void linetraverser_start(t_linetraverser *t, t_canvas *x);
+EXTERN t_outconnect *linetraverser_next(t_linetraverser *t);
+
+/* -------------------- TO BE SORTED OUT --------------------- */
+EXTERN void canvas_redrawallfortemplatecanvas(t_canvas *x, int action);
+EXTERN void array_resize(t_array *x, int n);
+EXTERN void word_init(t_word *wp, t_template *tmpl, t_gpointer *gp);
+EXTERN void word_restore(t_word *wp, t_template *tmpl, int argc, t_atom *argv);
+EXTERN t_scalar *scalar_new(t_canvas *owner, t_symbol *templatesym);
+EXTERN void word_free(t_word *wp, t_template *tmpl);
+EXTERN void scalar_redraw(t_scalar *x, t_canvas *canvas);
+//EXTERN int pd_pickle(t_foo *foo, char *fmt, ...);
+EXTERN void pd_set_newest (t_pd *x);
+char* inlet_tip(t_inlet* i,int num);
+
+extern t_hash<t_pd *,long> *object_table;
+extern t_hash<t_symbol *,t_class *> *class_table;
+
+/* some kernel.c stuff that wasn't in any header, when shifting to C++. */
+void obj_moveinletfirst(t_object *x, t_inlet *i);
+void obj_moveoutletfirst(t_object *x, t_outlet *o);
+int inlet_getsignalindex(t_inlet *x);
+int outlet_getsignalindex(t_outlet *x);
+void text_save(t_gobj *z, t_binbuf *b);
+t_sample *obj_findsignalscalar(t_object *x, int m);
+void class_set_extern_dir(t_symbol *s);
+void glob_update_class_info (t_pd *bogus, t_symbol *s, t_symbol *cb_recv, t_symbol *cb_sel);
+void pd_free_zombie(t_pd *x);
+
+/* some other stuff that wasn't in any header */
+void glob_watchdog(t_pd *dummy);
+
+#if defined(_LANGUAGE_C_PLUS_PLUS) || defined(__cplusplus)
+}
+#endif
+
+#ifdef __cplusplus
+#include<iostream>
+template <class T> static T min(T a, T b) {return a<b?a:b;}
+template <class T> static T max(T a, T b) {return a>b?a:b;}
+template <class T> T clip(T a, T b, T c) {return min(max(a,b),c);}
+void oprintf(std::ostream &buf, const char *s, ...);
+void voprintf(std::ostream &buf, const char *s, va_list args);
+EXTERN std::ostringstream lost_posts;
+#endif
+
+#define L post("%s:%d in %s",__FILE__,__LINE__,__PRETTY_FUNCTION__);
+#define LS(self) post("%s:%d in %s (self=%lx class=%s)",__FILE__,__LINE__,__PRETTY_FUNCTION__,(long)self, \
+ ((t_gobj *)self)->_class->name->name);
+
+#define STACKSIZE 1024
+struct t_call {
+ t_pd *self; /* receiver */
+ t_symbol *s; /* selector */
+ /* insert temporary profiling variables here */
+};
+
+EXTERN t_call pd_stack[STACKSIZE];
+EXTERN int pd_stackn;
+
+EXTERN int gstack_empty(); /* that's a completely different stack: see pd_pushsym,pd_popsym */
+
+#endif /* __DESIRE_H */
diff --git a/desiredata/src/desire.tk b/desiredata/src/desire.tk
new file mode 100644
index 00000000..70f3d052
--- /dev/null
+++ b/desiredata/src/desire.tk
@@ -0,0 +1,9019 @@
+#!/usr/bin/env wish
+set cvsid {$Id: desire.tk,v 1.1.2.600.2.419 2007-10-27 00:22:27 matju Exp $}
+#-----------------------------------------------------------------------------------#
+#
+# DesireData
+# Copyright (c) 2004 by Mathieu Bouchard
+# Copyright (c) 2005,2006,2007 by Mathieu Bouchard and Chun Lee
+#
+# 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.desire-client.txt 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.
+#
+# Note that this is not under the same license as the rest of PureData.
+# Even the DesireData server-side modifications stay on the same license
+# as the rest of PureData.
+#
+#-----------------------------------------------------------------------------------#
+
+# this command rebuilds the package index: echo pkg_mkIndex . | tclsh
+
+set debug 0 ;# DON'T TOUCH THIS, make yourself a debug.tcl instead!
+
+if {[catch {winfo children .}]} {set tk 0} {set tk 1}
+
+set argh0 [file normalize [file join [pwd] $argv0]]
+set auto_path [concat . \
+ [list [file join [file dirname [file dirname $argh0]] lib/pd/bin]] \
+ /usr/lib/tcllib1.7 \
+ /usr/lib/tclx8.4 \
+ $auto_path]
+
+package require poe
+if {$tk} {package require bgerror}
+
+catch {package require Tclx}
+#if {[catch {source /home/matju/src/pd-desiredata/pd/src/profile_dd.tcl}]} {error_dump}
+if {[file exists debug.tcl]} {source debug.tcl}
+
+proc which {file} {
+ global env
+ foreach dir [split $::env(PATH) ":"] {
+ if {[file exists $dir/$file]} {return $dir/$file}
+ }
+ return ""
+}
+
+#-----------------------------------------------------------------------------------#
+# some list processing functions and some math too
+# these could become another library like objective.tcl
+# if they become substantial enough
+
+# min finds the smallest of two values
+# max finds the biggest of two values
+# [clip $v $min $max] does [max $min [min $max $v]]
+proc min {x y} {expr {$x<$y?$x:$y}}
+proc max {x y} {expr {$x>$y?$x:$y}}
+proc clip {x min max} {
+ if {$x<$min} {return $min}
+ if {$x>$max} {return $max}
+ return $x
+}
+
+# set several variables from elements of a list
+# WARNING: for @-variables, use [list @a @b @c] instead of {@a @b @c}
+proc mset {vars list} {
+ uplevel 1 "foreach {$vars} {$list} {break}"
+}
+
+# add or subtract two lists
+proc l+ { al bl} {set r {}; foreach a $al b $bl {lappend r [expr {$a+$b}]}; return $r}
+proc l- { al bl} {set r {}; foreach a $al b $bl {lappend r [expr {$a-$b}]}; return $r}
+# halve a list
+proc l/2 { al } {set r {}; foreach a $al {lappend r [expr {$a/2 }]}; return $r}
+
+# like l+ or l- but for any infix supported by expr
+proc lzip {op al bl} {
+ set r {}
+ set e "\$a $op \$b"
+ foreach a $al b $bl {lappend r [expr $e]}
+ return $r
+}
+
+# do an operation between all elements of a list and a second argument
+proc lmap {op al b } {
+ set r {}
+ set e "\$a $op \$b"
+ foreach a $al {lappend r [expr $e]}
+ return $r
+}
+
+# sum and product of a list, like math's capital Sigma and capital Pi.
+proc lsum {al} {set r 0; foreach a $al {set r [expr {$r+$a}]}; return $r}
+proc lprod {al} {set r 1; foreach a $al {set r [expr {$r*$a}]}; return $r}
+
+# all elements from end to beginning
+proc lreverse {list} {
+ set r {}
+ for {set i [expr {[llength $list]-1}]} {$i>=0} {incr i -1} {lappend r [lindex $list $i]}
+ return $r
+}
+
+# list substraction is like set substraction but order-preserving
+# this is the same algorithm as Ruby's - operation on Arrays
+proc lwithout {a b} {
+ set r {}
+ foreach x $b {set c($x) {}}
+ foreach x $a {if {![info exists c($x)]} {lappend r $x}}
+ return $r
+}
+
+proc lintersection {a b} {
+ set r {}
+ foreach x $b {set c($x) {}}
+ foreach x $a {if {[info exists c($x)]} {lappend r $x}}
+ return $r
+}
+
+# removes duplicates from a list, but it must be already sorted.
+proc luniq {a} {
+ set last [lindex $a 0]
+ set r [list $last]
+ set i 0
+ foreach x $a {
+ if {$i && [string compare $last $x]} {lappend r $x}
+ incr i; set last $x
+ }
+ return $r
+}
+
+# one-dimensional intervals (left-closed, right-open); not much in use at the moment, not that they wouldn't deserve to!
+proc inside {x x0 x1} {return [expr $x>=$x0 && $x<$x1]}
+proc overlap {y0 y1 x0 x1} {return [expr [inside $y0 $x0 $x1] || [inside $y1 $x0 $x1]]}
+
+proc distance {point1 point2} {
+ set off [l- $point1 $point2]
+ return [expr {sqrt([lsum [lzip * $off $off]])}]
+}
+
+proc rect_centre {rect} {
+ mset {x1 y1 x2 y2} $rect
+ return [list [expr {($x1+$x2)/2}] [expr {($y1+$y2)/2}]]
+}
+
+proc lmake {start end} {for {set i $start} {$i<=$end} {incr i} {lappend l $i}; return $l}
+#-----------------------------------------------------------------------------------#
+set callback_list {}
+
+proc append_callback {mode when def} {
+ global callback_list
+ dict set callback_list $mode $when $def
+}
+
+proc remove_callback {mode} {
+ global callback_list
+ set callback_list [dict remove $callback_list $mode]
+}
+
+proc modes_callback {self def {args}} {
+ global callback_list
+ set i 0
+ dict for {mode callbacks} $callback_list {
+ foreach {when call} $callbacks {
+ if {$def == $when} {eval $self $call $args; incr i}
+ }
+ }
+ if {!$i} {return 0} else {return 1}
+}
+
+#-----------------------------------------------------------------------------------#
+# Observer pattern
+# there's no class for "observer".
+# it's anything that has def $myclass notice {args} {...} in which args indicate
+# attributes that have changed, or is an empty list if an unspecified number of
+# attributes (maybe all) have changed.
+
+class_new Observable {}
+def Observable init {args} {
+ eval [concat [list super] $args]
+ set @subscribers {}
+}
+def Observable subscribe {observer} {
+ set i [lsearch $@subscribers $observer]
+ if {$i<0} {lappend @subscribers $observer}
+}
+def Observable unsubscribe {observer} {
+ set i [lsearch $@subscribers $observer]
+ if {$i>=0} {set @subscribers [lreplace $@subscribers $i $i]}
+}
+
+if {$have_expand} {
+ #def Observable changed {args} {
+ # puts "Observable changed $self called from [info level [expr [info level]-2]]"
+ # foreach x $@subscribers {$x notice $self {expand}$args]}
+ #}
+ def Observable changed {args} {foreach x $@subscribers {$x notice $self {expand}$args}}
+ def Observable child_changed {origin args} {foreach x $@subscribers {$x notice $origin {expand}$args}}
+} else {
+ def Observable changed {args} {foreach x $@subscribers {eval [concat [list $x notice $self] $args]}}
+ def Observable child_changed {origin args} {foreach x $@subscribers {eval [concat [list $x notice $origin] $args]}}
+}
+def Observable subscribers {} {return $@subscribers}
+
+#-----------------------------------------------------------------------------------#
+set poolset(foo) bar
+array unset poolset foo
+
+class_new Manager {Thing}
+
+def Manager init {} {
+ set @q {}
+ $self call
+}
+
+def Manager call {} {
+ global poolset
+ #if {[llength $@q]} {post "client queue %d" [llength $@q]}
+
+ for {set i 0} {$i < [llength $@q]} {incr i} {
+ set o [lindex $@q $i]
+ unset poolset($o)
+ if {[info exists _($o:_class)]} {
+ if {[catch {$o draw_maybe}]} {puts [error_dump]}
+ } else {
+ puts " tries to draw ZOMBIE $o"
+ }
+ if {$i == [expr [llength $@q] - 1]} {set @q {}}
+ }
+ after 50 "$self call"
+}
+
+def Manager notice {origin args} {
+ global poolset
+ if {[info exists poolset($origin)]} {
+ # post %s "def Manager notice: double dirty"
+ # nothing for now
+ } {
+ set poolset($origin) {-1}
+ lappend @q $origin
+ }
+ #post "Manager notice: queue length is now %d" [llength $@q]
+}
+
+set serial 0
+proc serial {n obj} {
+ if {$n >= $::serial} {error "object creation serial number is in the future"}
+ eval [concat $::replyset($n) [list $obj]]
+ array unset ::replyset $n
+}
+
+proc philtre {atoms} {
+ set r {}
+ foreach atom $atoms {lappend r [regsub -all {([;,\\ ])} $atom {\\\1}]}
+ return [join $r]
+}
+
+# you pass the 2nd argument if and only if the message creates an object (or pretends to).
+# this happens with #N canvas, and those methods of #X:
+# obj, msg, floatatom, symbolatom, text, connect, text_setto, array.
+# this does NOT happen with #X coords/restore/pop.
+proc netsend {message {callback ""}} {
+ #if {$message == ""} {error "empty message... surely a mistake"}
+ if {$::sock == ""} {error "connection to server needed for doing this"}
+ if {$callback != ""} {
+ set ::replyset($::serial) $callback
+ set message [concat [lrange $message 0 0] [list with_reply $::serial] [lrange $message 1 end]]
+ incr ::serial
+ }
+ set text "[philtre $message];"
+ if {$::debug} {puts "[VTcyan]<- $text[VTgrey]"}
+ puts $::sock $text
+}
+
+#-----------------------------------------------------------------------------------#
+# This is not a real Hash, just the same interface as a Ruby/Python/Perl Hash... or quite like Tcl arrays themselves
+class_new Hash {Thing}
+
+def Hash init {args} { super; foreach {k v} $args {$self set $k $v}}
+def Hash reinit {args} {$self clear; foreach {k v} $args {$self set $k $v}}
+def Hash set {k v} {set ::hash($self:$k) $v}
+def Hash exists {k} {info exists ::hash($self:$k)}
+def Hash get {k} {set ::hash($self:$k)}
+def Hash size {} {llength [$self keys]}
+def Hash unset {k} {unset ::hash($self:$k)}
+def Hash list {} {set r {}; foreach k [$self keys] {lappend r $k [$self get $k]}; return $r}
+def Hash keys {} {
+ set r {}
+ set n [string length $self:]
+ foreach k [array names ::hash $self:*] {lappend r [string range $k $n end]}
+ return $r
+}
+def Hash values {} {
+ set r {}
+ foreach k [array names ::hash $self:*] {lappend r $::hash($k)}
+ return $r
+}
+def Hash clear {} {foreach k [$self keys] {$self unset $k}}
+def Hash delete {} {$self clear; super}
+
+def Hash search {v} {
+ foreach k [$self keys] {if {[$self get $k] == $v} {return $k}}
+ return -1 ;# this is not correct as -1 could be a Hash key, though not in its current context of use...
+}
+
+if 0 {
+ set h [Hash new foo bar 1 2 3 4]
+ $h set hello world
+ puts keys=[$h keys]
+ puts values=[$h values]
+ puts list=[$h list]
+ $h unset foo
+ puts list=[$h list]
+ $h clear
+ puts list=[$h list]
+ foreach i {1 2 3 4} {puts "exists $i : [$h exists $i]"}
+}
+
+class_new Selection {Hash}
+def Selection set {k v} {super $k $v; $v selected?= 1}
+def Selection unset {k} {
+ #set v [$self get $k]; puts "$v ::: [$v class]"
+ if {[$self exists $k]} {[$self get $k] selected?= 0}
+ super $k
+}
+#-----------------------------------------------------------------------------------#
+# abstract class: subclass must def {value value= <<}
+class_new Clipboard {Observable Thing}
+def Clipboard init {{value ""}} {super; $self value= $value; set @copy_count 0}
+
+# uses system clipboard
+class_new Clipboard1 {Clipboard}
+def Clipboard1 value= {value} {clipboard clear; clipboard append $value; $self changed}
+def Clipboard1 << {value} { clipboard append $value; $self changed}
+def Clipboard1 value {} {clipboard get}
+
+# uses string buffer (not system clipboard)
+class_new Clipboard2 {Clipboard}
+def Clipboard2 value= {value} {set @value $value; $self changed}
+def Clipboard2 << {value} {append @value $value; $self changed}
+def Clipboard2 value {} {return $@value}
+
+if {$tk} {
+ set clipboard [Clipboard1 new]
+} else {
+ set clipboard [Clipboard2 new]
+}
+
+#-----------------------------------------------------------------------------------#
+class_new EventHistory {Observable Thing}
+
+def EventHistory init {} {super; set @list {}}
+def EventHistory add {e} {lappend @list $e; $self changed add $e}
+def EventHistory list {{formatted 1}} {
+ if {!$formatted} {return $@list}
+ set r {}
+ foreach event $@list {
+ mset {type W x y mod K k} $event
+ lappend r [format "%-13s %9s %4d %4d %4d %4d %s" $type $K $k $x $y $mod $W]
+ }
+ return $r
+}
+set ::event_history [EventHistory new]
+
+#-----------------------------------------------------------------------------------#
+class_new CommandHistory {Observable Thing}
+
+def CommandHistory init {} {
+ super
+ set @undo_stack {}
+ set @redo_stack {}
+}
+
+def CommandHistory can_undo? {} {return [expr [llength @undo_stack] > 0]}
+def CommandHistory can_redo? {} {return [expr [llength @redo_stack] > 0]}
+def CommandHistory next_undo_name {} {return stuff}
+def CommandHistory next_redo_name {} {return stuff}
+def CommandHistory undo_stack {} {return $@undo_stack}
+def CommandHistory redo_stack {} {return $@redo_stack}
+
+# overload this if you want to control how many levels
+# of undo may be kept.
+# keep in mind that undo information is kept hierarchically.
+def CommandHistory add {message} {
+ lappend @undo_stack [list do $message [lrange [info level -3] 1 end]]
+ set @redo_stack {}
+ $self changed
+}
+
+def CommandHistory can't {} {
+ lappend @undo_stack [list can't {} [lrange [info level -3] 1 end]]
+ set @redo_stack {}
+ $self changed
+}
+
+# runs the restore procedure for the last item in the root undo queue.
+def CommandHistory undo {} {
+ global errorInfo
+ if {![$self can_perform? [lindex $@undo_stack end]]} {error "Can't undo this!"}
+ set backup $@undo_stack
+ set @undo_stack $@redo_stack
+ set @redo_stack {}
+ #set err [catch {$self perform [lindex $backup end]}]; if {$err} {set err $errorInfo}
+ $self perform [lindex $backup end]
+ set @redo_stack $@undo_stack
+ set @undo_stack [lrange $backup 0 end-1]
+ $self changed
+ #if {$err} {post %s $err; error "undo: $err"}
+}
+
+def CommandHistory redo {} {
+ global errorInfo
+ if {![$self can_perform? [lindex $@undo_stack end]]} {error "Can't redo this!"}
+ set backup $@redo_stack
+ set @redo_stack {}
+ set err [catch {$self perform [lindex $backup end]}]; if {$err} {set err $errorInfo}
+ $self perform [lindex $backup end]
+ set @redo_stack [lrange $backup 0 end-1]
+ $self changed
+ #if {$err} {post %s $err; error "redo: $err"}
+}
+
+def CommandHistory can_perform? {action} {
+ switch -- [lindex $action 0] {
+ do {return 1}
+ can't {return 0}
+ default {
+ foreach x [lrange $action 1 end] {
+ if {![$self can_perform? $x]} {return 0}
+ }
+ return 1
+ }
+ }
+}
+
+def CommandHistory perform {action} {
+ switch -- [lindex $action 0] {
+ do {eval [lindex $action 1]}
+ can't {error "can't undo this!"}
+ default {foreach x [lindex $action 1] {$self perform $x}}
+ }
+}
+
+def CommandHistory atomically {what code} {
+ global errorInfo
+ set ubackup @undo_stack; set @undo_stack {}
+ set rbackup @redo_stack; set @redo_stack {}
+ uplevel 2 $code
+ set atom $@undo_stack
+ set @undo_stack $ubackup
+ set @redo_stack $rbackup
+ lappend @undo_stack [list $what $atom [lrange [info level -3] 1 end]]
+ $self changed
+}
+
+def CommandHistory list {} {
+ set r {}
+ set hist [concat [$self undo_stack] [list "You Are Here"] [lreverse [$self redo_stack]]]
+ set i 0
+ foreach e $hist {lappend r "$i: $e"; incr i}
+ return $r
+}
+
+set command_history [CommandHistory new]
+
+#-----------------------------------------------------------------------------------#
+class_new History {Thing}
+
+def History init {size} {
+ set @size $size
+ set @hist {{}}
+ set @histi -1
+}
+
+def History histi= {val} {set @histi $val}
+def History histi {} {return $@histi}
+
+def History set_hist {idx stuff} {set @hist [lreplace $@hist $idx $idx $stuff]}
+
+def History prepend {stuff} {
+ set @hist [linsert $@hist 1 $stuff]
+ if {[llength $@hist] >= $@size} {set @hist [lrange $@hist 0 [expr $@size-1]]}
+}
+
+def History traverse {incr} {
+ set @histi [expr $@histi + $incr]
+ set mod [expr ([llength $@hist]<[expr $@size+1]) ?[llength $@hist]:[expr $@size+1]]
+ if {$@histi >=$mod} {set @histi [expr $@histi%$mod]}
+ if {$@histi < 0} {set @histi [expr ($@histi+$mod)%$mod]}
+ return [lindex $@hist $@histi]
+}
+
+History new_as obj_hist 5
+#-----------------------------------------------------------------------------------#
+# this is the beginning of the more application-dependent part.
+
+switch $tcl_platform(os) {
+ Darwin {set OS osx}
+ default {set OS $tcl_platform(platform)}
+}
+
+if {$tk} {
+ option add *foreground #000000
+ option add *font {Helvetica -12}
+ foreach tkclass {Menu Button Checkbutton Radiobutton Entry Text Spinbox Scrollbar Canvas} {
+ option add *$tkclass*borderWidth 1
+ option add *$tkclass*activeBorderWidth 1
+ }
+ foreach tkclass {CheckButton RadioButton} {
+ option add *$tkclass*selectColor #dd3000
+ }
+ foreach tkclass {Entry Text} {
+ option add *$tkclass*background #b0c4d8
+ option add *$tkclass*selectBackground #6088b0
+ }
+ option add *__tk__messagebox*Canvas*borderWidth 0
+ foreach tkclass {Listbox} {
+ option add *$tkclass*background #c4d8b0
+ option add *$tkclass*selectBackground #88b060
+ }
+ foreach tkclass {Label} {
+ #option add *$tkclass*background #909090
+ }
+ # very small icons:
+ foreach {name w h values} {
+ icon_empty 7 7 "0,0,0,0,0,0,0"
+ icon_plus 7 7 "8,8,8,127,8,8,8"
+ icon_minus 7 7 "0,0,0,127,0,0,0"
+ icon_close 7 7 "99,119,62,28,62,119,99"
+ icon_wedge_up 7 5 "8,28,62,127,0"
+ icon_wedge_down 7 5 "0,127,62,28,8"
+ icon_up 7 7 "8,28,62,127,28,28,28"
+ icon_down 7 7 "28,28,28,127,62,28,8"
+ icon_right 7 7 "8,24,63,127,63,24,8"
+ icon_left 7 7 "8,12,126,127,126,12,8"
+ } {
+ image create bitmap $name -data "#define z_width $w\n#define z_height $h
+ static unsigned char z_bits[] = { $values };"
+ }
+ # it's unfortunate but we seem to have to turn off global bindings
+ # for Text objects to get control-s and control-t to do what we want for
+ # "text" dialogs below. Also we have to get rid of tab's changing the focus.
+ bind all <Key-Tab> ""
+ #bind all <Key-Shift-Tab> ""
+ bind all <<PrevWindow>> ""
+ bind Text <Control-t> {}
+ bind Text <Control-s> {}
+ set mods {{} 0 Shift- 1 Control- 4 Shift-Control- 5 Alt- 8 Shift-Alt- 9 Control-Alt- 12 Shift-Control-Alt- 13}
+ foreach type {KeyPress KeyRelease} {
+ foreach {subtype mod} $mods {
+ bind all <$subtype$type> "$::event_history add \[list $type %W %x %y $mod %K %k\]"
+ }
+ }
+ foreach type {ButtonPress ButtonRelease} {
+ foreach {subtype mod} $mods {
+ bind all <$subtype$type> "$::event_history add \[list $type %W %x %y $mod %b %b\]"
+ }
+ }
+}
+
+proc modekey {k mode} {
+ set s ""
+ if {$mode&1} {append s Shift-}
+ if {$mode&4} {append s Control-}
+ if {$mode&8} {append s Alt-}
+ if {[regexp {[0-9]} $k]} {set k Key-$k}
+ return $s$k
+}
+
+proc modeclick {k mode event} {
+ set s ""
+ if {$mode&1} {append s Shift-}
+ if {$mode&4} {append s Control-}
+ if {$mode&8} {append s Alt-}
+ if {[regexp {[0-9]} $k]} {set k $event-$k}
+ return $s$k
+}
+
+
+# there are two palettes of 30 colours used in Pd
+# when placed in a 3*10 grid, the difference is that
+# the left corner of 3*3 (the greys) are transposed (matrixwise)
+# here is the one used in the swatch color selector:
+set preset_colors {
+ fcfcfc e0e0e0 bcbcbc fce0e0 fce0c0 fcfcc8 d8fcd8 d8fcfc dce4fc f8d8fc
+ a0a0a0 7c7c7c 606060 fc2828 fcac44 e8e828 14e814 28f4f4 3c50fc f430f0
+ 404040 202020 000000 8c0808 583000 782814 285014 004450 001488 580050
+}
+
+set preset_colors2 {
+ fcfcfc a0a0a0 404040 fce0e0 fce0c0 fcfcc8 d8fcd8 d8fcfc dce4fc f8d8fc
+ e0e0e0 7c7c7c 202020 fc2828 fcac44 e8e828 14e814 28f4f4 3c50fc f430f0
+ bcbcbc 606060 000000 8c0808 583000 782814 285014 004450 001488 580050
+}
+
+switch $::OS {
+ osx {set pd_tearoff 0}
+ default {set pd_tearoff 1}
+}
+
+proc guess_lang {} {
+ set lang C
+ if {[info exist ::env(LC_ALL)]} {set lang $::env(LC_ALL)}
+ if {[info exist ::env(LANG)]} {set lang $::env(LANG)}
+ set lang [lindex [split $lang {[_.]}] 0]
+ return $lang
+}
+
+#temporary
+set leet 0
+
+proc say {k args} {
+ global text
+ if {[llength $args]} {
+ set text($k) [lindex $args 0]
+ } else {
+ if {[info exist text($k)]} {
+ if {$::leet} {
+ return [string map -nocase {a 4 e 3 t 7 s 5 i 1 o 0 g 9} $text($k)]
+ } else {
+ return $text($k)
+ }
+ } else {return "{{$k}}"}
+ }
+}
+
+proc can_say {k args} {
+ return [info exist ::text($k)]
+}
+
+proc say_namespace {k code} {uplevel 1 $code}
+proc say_category {text} {}
+
+switch -- [lindex [file split $argh0] end] {
+ desire.tk {set cmdline(server) [file join [file dirname $argh0] pd]}
+ default {set cmdline(server) [file join [file dirname [file dirname $argh0]] bin/pd]}
+}
+
+set cmdline(rcfilename) ~/.pdrc
+set cmdline(ddrcfilename) ~/.ddrc
+set cmdline(console) 1000
+if {[file exists ../icons/mode_edit.gif]} {
+ set cmdline(icons) ../icons
+} else {
+ set cmdline(icons) [file join [file dirname [file dirname $argh0]] lib/pd/icons]
+}
+
+#-----------------------------------------------------------------------------------#
+set accels {}
+proc read_client_prefs_from {filename} {
+ global cmdline look key accels
+ set ::accels {}
+ puts "reading from $filename"
+ set fd [open $filename]
+ set contents [read $fd]
+ close $fd
+ foreach {category category_data} $contents {
+ foreach {class class_data} $category_data {
+ foreach {var val} $class_data {set ${category}($class:$var) $val}
+ }
+ }
+ foreach k [array names key] {
+ if {[llength $key($k)]} {
+ if {![dict exists $accels $key($k)]} {
+ dict set accels $key($k) $k
+ } else {
+ dict lappend accels $key($k) $k
+ }
+ }
+ }
+}
+proc read_ddrc {} { ;# load defaults then load .ddrc
+ if {[file exists "defaults.ddrc"]} {
+ read_client_prefs_from "defaults.ddrc"
+ } else {
+ read_client_prefs_from [file join [file dirname [file dirname $::argh0]] "lib/pd/bin/defaults.ddrc"]
+ }
+ if {[file exists $::cmdline(ddrcfilename)]} {
+ read_client_prefs_from $::cmdline(ddrcfilename)
+ }
+}
+read_ddrc
+
+#-----------------------------------------------------------------------------------#
+
+set cmdline(port) 0
+set cmdline(gdb) 0
+set cmdline(gdbconsole) 1
+set cmdline(valgrind) 0
+if {$look(View:language) eq "auto"} {
+ set language [guess_lang]
+} else {
+ set language $look(View:language)
+}
+
+set files_to_open {}
+
+proc cmdline_help {} {
+ puts "DesireData commandline options:
+ -serverargs (for future use)
+ -server select the executable for the pd server
+ -gdb run pd server through gdb
+ -manualgdb run gdb in the terminal
+ -valgrind run pd server through valgrind
+ -novalgrind ... or don't
+ -safemode run desiredata with all default settings
+ -dzinc use zinc emulation"
+}
+
+for {set i 0} {$i < $argc} {incr i} {
+ global cmdline files_to_open
+ set o [lindex $argv $i]
+ switch -regexp -- $o {
+ ^-port\$ {incr i; set cmdline(port) [lindex $argv $i]}
+ ^-serverargs\$ {error "not supported yet"}
+ ^-server\$ {incr i; set cmdline(server) [lindex $argv $i]}
+ ^-gdb\$ {set cmdline(gdb) 1}
+ ^-manualgdb\$ {set cmdline(gdbconsole) 0}
+ ^-valgrind\$ {set cmdline(valgrind) 1}
+ ^-novalgrind\$ {set cmdline(valgrind) 0}
+ ^-safemode\$ {set cmdline(safemode) 1}
+ ^-dzinc\$ {set cmdline(dzinc) 1}
+ ^(-h|-help|--help)\$ {cmdline_help; exit 1}
+ ^- {puts "ERROR: command line argument: unknown $o"}
+ default {lappend files_to_open [lindex $argv $i]}
+ }
+}
+
+#set cmdline(server) \"$cmdline(server)\"
+set encoding ""
+set langoptions {
+ english francais deutsch catala espanol portugues italiano bokmal
+ euskara polski dansk chinese nihongo brasiliano turkce nederlands
+ russkij
+
+}
+#lappend langoptions {chinese}
+#lappend langoptions {esperanto}
+set langfile locale/[switch -regexp -- $language {
+ ^(en|english|C)$ {list english}
+ ^(fr|francais)$ {list francais}
+ ^(de|deutsch)$ {list deutsch}
+ ^(ca|catala)$ {list catala}
+ ^(es|espanol)$ {list espanol}
+ ^(pt|portugues)$ {list portugues}
+ ^(it|italiano)$ {list italiano}
+ ^(nb|norsk|bokmal)$ {list bokmal}
+ ^(ch|chinese)$ {set encoding utf-8; list chinese}
+ ^(eu|euskara)$ {list euskara}
+ ^(eo|esperanto)$ {set encoding utf-8; list esperanto}
+ ^(pl|polski)$ {set encoding utf-8; list polski}
+ ^(dk|dansk)$ {list dansk}
+ ^(ja|japanese|nihongo)$ {list nihongo}
+ ^(br|brasiliano)$ {list brasiliano}
+ ^(tr|turkce)$ {set encoding utf-8; list turkce}
+ ^(nl|nederlands)$ {list nederlands}
+ ^(ru|russkij)$ {set encoding utf-8; list russkij}
+ default {error "huh??? unknown language (locale)"}
+}].tcl
+
+proc localedir {x} {file join [file dirname [file dirname $::argh0]] lib/pd/bin/$x}
+if {[regexp {desire\.tk$} $argh0]} {
+ source locale/index.tcl
+ if {$encoding != ""} {source -encoding $encoding $langfile} else {source $langfile}
+} else {
+ source [localedir locale/index.tcl]
+ if {$encoding != ""} {source -encoding $encoding [localedir $langfile]} else {source [localedir $langfile]}
+}
+
+if {[info exists ::cmdline(safemode)]} {read_client_prefs_from "defaults.ddrc"}
+if {[info exists ::cmdline(dzinc)]} {package require dzinc}
+
+#-----------------------------------------------------------------------------------#
+
+#!@#$ is this still valid?
+set look(Box:extrapix) [switch $::OS {
+ osx {concat 2}
+ default {concat 1}}]
+
+#font is defined as Thing for now, as the completion needs to get to these ones.
+
+#!@#$ View->???
+#set look(View:tooltip) 1
+
+#!@#$ View->TextBox ?
+#set look(View:minobjwidth) 21
+
+#!@#$ View->ObjectBox
+#set look(View:fg) #000000
+#set look(View:bg) #ffffff
+#set look(View:frame1) #99cccc
+#set look(View:frame2) #668888
+#set look(View:frame3) #000000
+
+#!@#$ this is supposed to be BlueBox!
+#set look(Slider:bg) #ccebff
+
+set zoom(canned) [list 25 33 50 75 100 125 150 200 250 300 400]
+set scale_amount 1.1
+################## set up main window #########################
+
+class_new Console {View}
+
+def Console init {c} {
+ set @c $c
+ frame $c
+ text $c.1 -width 72 -height 20 -yscrollcommand "$c.2 set" -font [$self look font]
+ scrollbar $c.2 -command "$c.1 yview"
+ pack $c.1 -side left -fill both -expand yes
+ pack $c.2 -side left -fill y -expand no
+ pack $c -fill both -expand yes
+ $c.2 set 0.0 1.0
+ switch $::OS { osx {
+ bind $c.1 <MouseWheel> {$c.1 yview scroll [expr -2-abs(%D)/%D] units}
+ }}
+ set @lines 0
+}
+
+def Console widget {} {return $@c}
+
+def Console post_string {x} {
+ set oldpos [lindex [$@c.2 get] 1]
+ $@c.1 insert end $x
+ regsub -all "\n" $x "" y
+ set n [expr [string length $x]-[string length $y]]
+ incr @lines $n
+ while {$@lines >= $::cmdline(console)} {
+ $@c.1 delete 1.0 2.0
+ incr @lines -1
+ }
+ if {$oldpos > 0.9999} {$@c.1 see end}
+}
+
+#class_new Client {Menuable View}
+class_new Client {Menuable Thing}
+
+set ctrls_audio_on 0
+set ctrls_meter_on 0
+
+def Client window {} {return .}
+
+def Client init_binds {} {
+ bind . <Control-Key> {$main ctrlkey %x %y %K %A 0}
+ bind . <Control-Shift-Key> {$main ctrlkey %x %y %K %A 1}
+ switch $::OS {
+ osx {
+ bind . <Mod1-Key> {$main ctrlkey %x %y %K %A 0}
+ bind . <Mod1-Shift-Key> {$main ctrlkey %x %y %K %A 1}
+ }
+ }
+# bind . <Motion> {.debug.1 configure -text "widget = %W"}
+}
+
+# miller uses this nowadays (matju fished it in pd-cvs for 0.40). we don't use it for now.
+# remember to fix all quoting problems, which in the end may or may not involve the following proc.
+proc pdtk_unspace {x} {
+ set y [string map {" " "_" ";" "" "," "" "{" "" "}" "" "\\" ""} $x]
+ if {$y == ""} {set y "empty"}
+ concat $y
+}
+
+proc pdtk_pd_meters {indb outdb inclip outclip} {
+ foreach {z clip db} [list in $inclip $indb out $outclip $outdb] {
+ .controls.$z.1.mtr coords m 0 0 $db 0
+ .controls.$z.1.clip configure -background [if {$clip==1} {concat red} {concat black}]
+ }
+}
+
+proc pd_startup {version apilist midiapilist args} {
+ set ::pd_version $version
+ set ::pd_apilist $apilist
+ set ::pd_midiapilist $midiapilist
+ foreach api $apilist {
+ lappend ::pd_apilist2 "-[string tolower [lindex $api 0]]"
+ }
+ set version [regsub "^DesireData " $::pd_version ""]
+ post "DesireData server version $version"
+}
+
+def Client init_controls {} {
+ menu .mbar
+ pack [frame .controls] -side top -fill x
+ foreach t {file window help} {
+ .mbar add cascade -label [say $t] -menu [menu .mbar.$t -tearoff $::pd_tearoff]
+ }
+ .mbar.window configure -postcommand "$self fix_window_menu"
+ foreach {z fill} {in #0060ff out #00ff60} {
+ set f .controls.$z
+ frame $f
+ frame $f.1 -borderwidth 2 -relief groove
+ canvas $f.1.mtr -width 100 -height 10 -bg #222222
+ $f.1.mtr create line [list 0 0 0 0] -width 24 -fill $fill -tags m
+ canvas $f.1.clip -width 5 -height 10 -bg #222222
+ pack $f.1.mtr $f.1.clip -side left
+ pack [label $f.2 -text [say $z]:] $f.1 -side left
+ pack $f -side left -pady 0 -padx 0
+ }
+ foreach {w x y z} {
+ audiobutton audio ctrls_audio_on {netsend [list pd dsp $ctrls_audio_on]}
+ meterbutton meters ctrls_meter_on {netsend [list pd meters $ctrls_meter_on]}
+ } {
+ pack [checkbutton .controls.$w -text [say $x] -variable $y -anchor w -command $z] -side left
+ }
+ button .controls.clear -text [say console_clear] -command {.log.1 delete 0.0 end} -padx 2 -pady 0
+ button .controls.dio -text [say io_errors] -command {netsend [list pd audiostatus]} -padx 2 -pady 0
+ pack .controls.clear .controls.dio -side right
+ if {$::debug} {
+ frame .debug
+ pack [label .debug.1 -anchor w -text ""] -side left
+ pack [entry .debug.3 -textvariable ::serial -width 5] -side right
+ pack [label .debug.2 -text "obj.serial: " -justify right] -side right
+ pack .debug -side bottom -fill x
+ }
+ if {$::cmdline(console)} {set ::console [Console new .log]}
+ . configure -menu .mbar
+ wm title . "DesireData"
+ catch {wm iconphoto . icon_pd}
+ regexp {\d\d\d\d/\d\d/\d\d} $::cvsid version
+ regsub -all "/" $version "." version
+ set ::pd_version_client $version
+ post "DesireData client version $version with Tcl %s and Tk %s" $::tcl_patchLevel $::tk_patchLevel
+}
+
+proc pdtk_pd_dsp {value} {
+ global ctrls_audio_on
+ set ctrls_audio_on $value
+}
+
+proc pdtk_pd_dio {red} {
+ .controls.dio configure -background red -activebackground [if {$red==1} {list red} {list lightgrey}]
+}
+
+############### set up global variables ################################
+
+set pd_opendir [pwd]
+
+############### set up socket ##########################################
+set sock {}
+set sock_lobby {}
+
+proc poll_sock {} {
+ global sock sock_lobby cmdline
+ if {[llength $sock]==0} {return}
+ while {1} {
+ set cmd [gets $sock]
+ if {[eof $sock]} {
+ if {!$cmdline(gdb)} {
+ tk_messageBox -message "connection ended by server.\n(crash? try: desire -gdb)" -type ok
+ }
+ set sock {}
+ return
+ }
+ if {[fblocked $sock]} {break}
+ if {$::debug} {if {[string first pdtk_post $cmd]!=0} {puts "[VTmagenta]-> $cmd[VTgrey]"}}
+ append sock_lobby "\n$cmd"
+ if {[catch {eval $sock_lobby}]} {
+ global errorCode errorInfo
+ switch -regexp -- $errorInfo { "^missing close-brace" {
+ #puts "waiting for the end of: [string range $sock_lobby 0 40]"
+ continue
+ }}
+ error_dump
+ }
+ set sock_lobby {}
+ }
+ flush $sock
+ after 50 poll_sock
+}
+
+set server_pid 0
+proc poll_gdb {} {
+ global gdb
+ while {1} {
+ set line [gets $gdb]
+ if {$line=="" || [fblocked $gdb]} {break} ;# which way should i check for no input?
+ if {[eof $gdb]} {return}
+ regsub {^\(gdb\) ?} $line {} line
+ if {[regexp {^\[Thread debug} $line]} {continue}
+ if {[regexp {^\[New Thread.*LWP (\d+)} $line dummy pid]} {
+ if {!$::server_pid} {
+ set ::server_pid $pid
+ post "server pid=$pid"
+ continue
+ }
+ }
+ if {[regexp {^Reading symbols from} $line]} {continue}
+ if {[regexp {^Using host libthread_db} $line]} {continue}
+ if {[regexp {^Starting program:} $line]} {continue}
+ if {[regexp {^Program received signal (\w+), (.*)\.} $line bogus sig1 sig2]} {
+ set where ""
+ # can anyone figure out why a long backtrace won't be slurped in this case?
+ set timeout [expr [clock seconds]+2]
+ #fconfigure $gdb -blocking 1 -buffering none
+ while {![eof $gdb] && [clock seconds] < $timeout} {
+ set line [gets $gdb]
+ if {$line eq ""} {continue} ;# busy-wait
+ regsub {^\(gdb\) ?} $line {} line
+ append where "$line\n"
+ #puts "where size = [string length $where]"
+ }
+ OopsDialog new $sig1 $sig2 $where
+ }
+ post "\[gdb\] %s" $line
+ }
+ after 100 poll_gdb
+}
+
+proc pd_connect {} {
+ global sock
+ if {[catch {set sock [socket 127.0.0.1 13666]}]} {
+ post "can't connect... wait a second"
+ after 1000 pd_connect
+ return
+ }
+ post "Connected to server"
+ fconfigure $sock -blocking 0 -buffering line
+ netsend [list pd init]
+ poll_sock
+ foreach f $::files_to_open {
+ set ff [file split [file normalize $f]]
+ set ffl [llength $ff]
+ set file [lindex $ff [expr $ffl-1]]
+ set dir [join [lrange $ff 0 [expr $ffl-2]] [file separator]]
+ netsend [join [list pd open $file $dir]]
+ }
+}
+
+set server_port 13666
+after 1000 pd_connect
+
+after 0 {
+ if {$cmdline(port)} {
+ set server_port $cmdline(port)
+ # and then do nothing...
+ } elseif {$cmdline(valgrind)} {
+ #exec valgrind --tool=memcheck $cmdline(server) -guiport $server_port &
+ exec valgrind --tool=memcheck --gen-suppressions=all --suppressions=valgrind3.supp $cmdline(server) -guiport $server_port &
+ } else {
+ if {$cmdline(gdb)} {
+ if {$cmdline(console) && $cmdline(gdbconsole)} {
+ set gdb [open "| gdb --quiet 2&>1" w+]
+ fconfigure $gdb -blocking 0 -buffering none
+ puts $gdb "file \"$cmdline(server)\"" ;# bad quoting, sorry
+ puts $gdb "run -guiport $server_port"
+ puts $gdb "where"
+ puts $gdb "quit"
+ flush $gdb
+ after 0 poll_gdb
+ } else {
+ exec gdb --args $cmdline(server) -guiport $server_port &
+ #exec gdb --tui --args $cmdline(server) -guiport $server_port &
+ }
+ } else {
+ exec $cmdline(server) -guiport $server_port &
+ }
+ }
+}
+
+################ utility functions #########################
+
+proc enquote {x} {
+ set foo [string map {"," "" ";" "" "\"" ""} $x]
+ return [string map {" " "\\ " "{" "" "}" ""} $foo]
+}
+
+proc pdtk_watchdog {} {netsend [list pd ping]; after 2000 {pdtk_watchdog}}
+
+proc accel_munge {acc} {
+ switch $::OS {
+ osx {
+ set tmp [string toupper [string map {Ctrl Meta} $acc] end]
+ if [string is upper [string index $acc end]] {
+ return Shift+$tmp
+ } else {
+ return $tmp
+ }
+ }
+ default {return $acc}
+ }
+}
+
+# a menuable must be a View
+# and it must have a window so that the Menuable methods work
+# it could be renamed to Windowed
+class_new Menuable {}
+def Menuable init {args} {
+ eval [concat [list super] $args]
+ set @accel {}
+ set @menubar .$self.m
+}
+
+# this doesn't have to do with menus, only with toplevel windows.
+def Menuable raise {} {
+ set w [$self window]
+ set w $w.c
+ raise $w
+ focus -force $w
+}
+
+set untitled_number 1
+set untitled_folder [pwd]
+
+# just a dummy proc
+proc none {args} {}
+
+def Client new_file {} {
+ global untitled_number untitled_folder
+ netsend [list pd filename Untitled-$untitled_number $untitled_folder]
+ netsend [list #N canvas]
+ netsend [list #X pop 1]
+ incr untitled_number
+}
+
+
+set patch_filetypes {
+ {"pd files" ".pd"}
+ {"max files" ".pat"}
+ {"all files" "*"}
+}
+
+set image_filetypes {
+ {"image files" ".gif .png"}
+ {"gif files" ".gif"}
+ {"png files" ".png"}
+ {"all files" "*"}
+}
+
+#only works with tcltk 8.5
+catch {tk_getOpenFile -load-once}
+if {$tcl_version>=8.5} {
+ set ::tk::dialog::file::showHiddenBtn 1
+ set ::tk::dialog::file::showHiddenVar 0
+}
+
+def Client open_file {} {
+ global pd_opendir patch_filetypes
+ set filename [tk_getOpenFile -defaultextension .pd -filetypes $patch_filetypes -initialdir $pd_opendir]
+ if {$filename != ""} {$self open_file_really $filename}
+}
+
+def Client open_file_really {filename} {
+ set i [string last / $filename]
+ set folder [string range $filename 0 [expr $i-1]]
+ set ::pd_opendir $folder
+ set basename [string range $filename [expr $i+1] end]
+ if {[string last .pd $filename] >= 0} {
+ netsend [list pd open [enquote $basename] [enquote $folder]]
+ }
+}
+
+def Client send_message {} {
+ toplevel .sendpanel
+ set e .sendpanel.entry
+ pack [entry $e -textvariable send_textvar] -side bottom -fill both -ipadx 100
+ $e select from 0
+ $e select adjust end
+ bind $e <KeyPress-Return> {netsend $send_textvar; after 50 {destroy .sendpanel}}
+ focus $e
+}
+
+def Client quit {} {
+ set answer [tk_messageBox -message "Do you really wish to quit?" -type yesno -icon question]
+ switch -- $answer {yes {netsend [list pd quit]; exit}}
+}
+
+def Client abort_server {} {
+ set answer [tk_messageBox -message "Do you really wish to abort?" -type yesno -icon question]
+ switch -- $answer {yes {exec kill -ABRT $::server_pid}}
+}
+
+def Client server_prefs {} {ServerPrefsDialog new_as pdrc}
+def Client client_prefs {} {ClientPrefsDialog new_as ddrc}
+
+proc menu_pop_pd {} {raise .}
+
+def Menuable populate_menu {menu list} {
+ global key
+ if {[string index $menu 0] != "."} {set menu $@menubar.$menu}
+ foreach name $list {
+ if {$name == ""} {$menu add separator; continue}
+ set k ""
+ if {[info exists key($@_class:$name)]} {
+ if {[string length $key($@_class:$name)]} {set k $key($@_class:$name)}
+ }
+ $menu add command -label [say $name] -command "$self $name" -accelerator [accel_munge $k]
+ }
+}
+
+def Client init_menus {} {
+ #removed paths after send_message
+ $self populate_menu file {
+ new_file open_file {}
+ server_prefs client_prefs send_message {}
+ audio_on audio_off {}
+ abort_server quit}
+ $self populate_menu help {
+ about documentation class_browser do_what_i_mean {}
+ test_audio_and_midi load_meter latency_meter {}
+ clipboard_view command_history_view event_history_view keyboard_view client_class_tree}
+}
+
+def Client init {} {
+ super
+ set @menubar .mbar
+ $self init_controls
+ $self init_binds
+ $self init_menus
+ # it's necessary to raise the window on OSX
+ switch $::OS { osx {raise .; wm iconify .; after 100 {wm deiconify .}}}
+ after 0 {
+ Listener new .tcl [say "tcl_console"] tcl_eval
+ Listener new .pd [say "pd_console"] pd_eval
+ }
+ #wm geometry .[$self keyboard_view] -0+0
+ #wm geometry .[$self event_history_view] -0-0
+}
+
+proc post {args} {
+ set s "[eval [linsert $args 0 format]]\n"
+ # set s "[info level -1]: $s"
+ if {$::cmdline(console)} {$::console post_string $s} else {puts stderr $s}
+}
+proc pdtk_post {s} {
+ if {$::cmdline(console)} {$::console post_string $s} else {puts stderr $s}
+}
+
+def Menuable eval% {code} {
+ regsub -all %W $code $self code
+ uplevel [info level] $code
+}
+
+def Menuable getkey {k} {
+ global accels
+ if {[dict exists $accels $k]} {
+ set vars [dict get $accels $k]
+ foreach var $vars {
+ #mset {class key} [split [dict get $accels $k] ":"]
+ mset {class key} [split $var ":"]
+ #if {$class != $@_class} {return ""} else {return $key}
+ if {$class == $@_class} {return $key}
+ }
+ }
+}
+
+def Menuable ctrlkey {x y key iso shift} {
+ set key [if {$shift} {string toupper $key} {string tolower $key}]
+ set key "Ctrl+$key"
+ set cmd [$self getkey $key]
+ if {![string length $cmd]} {
+ switch [$self class]:$key {
+ #explicitly listed here to do nothing
+ Client:Ctrl+c {}
+ Client:Ctrl+v {}
+ default {post "unknown key $key"}
+ }
+ } else {$self eval% "%W $cmd"}
+}
+
+def Menuable altkey {x y key iso shift} {
+ set key [if {$shift} {string toupper $key} {string tolower $key}]
+ set key "Alt+$key"
+ set cmd [$self getkey $key]
+ if {[string length $cmd]} {$self eval% "%W $cmd"} else {post "unknown key $key"}
+}
+
+#-----------------------------------------------------------------------------------#
+set pd_apilist "{ALSA 1}"
+set pd_apilist2 "default"
+
+#-----------------------------------------------------------------------------------#
+#fixme: actually, is it ok that View<Menuable ? --matju
+class_new View {Menuable Observable Thing}
+
+# normally ninlets/noutlets should be in class "Box", but server-side isn't smart enough
+def View pdclass= {v} {set @pdclass $v}
+def View pdclass {} {return $@pdclass}
+def View ninlets= {v} {set @ninlets $v}
+def View ninlets {} {return $@ninlets}
+def View noutlets= {v} {set @noutlets $v}
+def View noutlets {} {return $@noutlets}
+def View click {x y f target} {}
+def View unclick {x y f target} {}
+def View motion {x y f target} {}
+
+def View subpatch {} {if {[info exists @subpatch]} {return 1} else {return 0}}
+
+def View look_cache {k} {
+ global look look_cache
+ foreach super [$@_class ancestors] {
+ if {[info exists look($super:$k)]} {
+ set look_cache($@_class:$k) $super
+ return $super
+ }
+ }
+}
+def View look {k} {
+ if {![info exists ::look_cache($@_class:$k)]} {$self look_cache $k}
+ return $::look($::look_cache($@_class:$k):$k)
+}
+
+def View init {} {
+ super
+ set @selected? 0
+ set @index 0xDEADBEEF
+ set @ninlets 1 ;# should be in Box init
+ set @noutlets 0 ;# should be in Box init
+ set @canvas ""
+# set @inside_box 42 ;# temporary fix
+ set @ioselect {}
+}
+
+def View classtags {} {return {foo}}
+
+set item {
+ set canvas [$self get_canvas]
+ if {$canvas == ""} {return}
+ set c [$self cwidget]
+ set zoom [$canvas zoom]
+ set coords [lmap * $coords $zoom]
+ set find [lsearch $args "-width"]
+ if {$find >= 0} {
+ incr find
+ set w [lindex $args $find]
+ lset args $find [format %.0f [expr {$w*$zoom}]]
+ }
+ set find [lsearch $args "-font"]
+ if {$find >= 0} {
+ incr find
+ set fs [lindex [lindex $args $find] 1]
+ lset args $find 1 [format %.0f [expr {$fs*$zoom}]]
+ }
+ set tags {}
+ foreach s $suffixes {lappend tags "$self$s"}
+ set ss [lindex $tags 0]
+ lappend tags $self
+ set tags [concat $tags [$self classtags]]
+}
+if {$have_expand} {
+ append item {
+ if {![llength [$c gettags $ss]]} {
+ $c create $type $coords -tags $tags {expand}$args
+ } {
+ $c itemconfigure $ss {expand}$args
+ $c coords $ss {expand}$coords
+ }
+ }
+} else {
+ append item {
+ if {![llength [$c gettags $ss]]} {
+ eval [concat [list $c create $type $coords -tags $tags] $args]
+ } {
+ eval [concat [list $c itemconfigure $ss] $args]
+ eval [concat [list $c coords $ss] $coords]
+ }
+ }
+}
+def View item {suffixes type coords args} $item
+
+def View item_delete {{suffix all}} {
+ if {$@canvas == ""} {return}
+ set c [$@canvas widget]
+ if {![winfo exists $c]} {
+ set canvas [$@canvas get_canvas]
+ if {$canvas == ""} {return}
+ set c [[$@canvas get_canvas] widget]
+ if {![winfo exists $c]} {return}
+ }
+ switch -- $suffix {
+ all {$c delete $self}
+ default {$c delete $self$suffix}}
+}
+
+def View draw {} {}
+
+def View delete {} {$self erase; super}
+def View erase {} {$self item_delete}
+def View selected? {} {return $@selected?}
+def View selected?= {x} {set @selected? $x; $self changed} ;# this is for use by the Selection class only
+def View edit? {} {if {[info exists @edit]} {return $@edit} else {return 0}}
+def View select {state} {
+ set ostate [$self selected?]
+ set @selected? $state
+ if {$state!=$ostate} {$self changed}
+}
+
+# give topleft point of an object in the canvas it's rendered in.
+# this includes GOP and excludes zoom.
+# inheritance problem: this doesn't work for Wire, which doesn't store its positions
+def View xy {} {
+ if {$@canvas == ""} {return [list $@x1 $@y1]}
+ set type [$@canvas type]
+ if {$type == "gopabs" || $type == "gopsub"} {
+ mset {xmargin ymargin} [$@canvas margin]
+ mset {x y} [$@canvas xy]
+ set x1 [expr {($@x1-$xmargin)+$x}]
+ set y1 [expr {($@y1-$ymargin)+$y}]
+ #if $self's gop is opened
+ if {[regexp {^.x[0-9a-f]{6,8}.c} [focus] f]} {
+ if {$f == ".$@canvas.c"} {set x1 $@x1; set y1 $@y1}
+ }
+ #if {[focus] != "." && [focus] == ".$@canvas.c"} {set x1 $@x1; set y1 $@y1}
+ return [list $x1 $y1]
+ }
+ return [list $@x1 $@y1]
+}
+
+def View canvas {} {return $@canvas}
+def View canvas= {c} {
+ set @canvas $c
+ # should "subscribe" call "changed"? (or pretend to?)
+ $self subscribe $c
+ $self changed
+ $self outside_of_the_box
+}
+
+def View visible {} {if {[info exists @inside_box]} {return $@inside_box} {return -1}}
+
+# this returns the canvas actually exists/drawn
+# see also def Canvas get_canvas
+def View get_canvas {} {
+ set canvas $@canvas
+ if {$canvas == ""} {return ""}
+ #while {![$canvas havewindow]} {set canvas [$canvas canvas]}
+ while {![winfo exists [$canvas widget]]} {set canvas [$canvas canvas]}
+ return $canvas
+}
+# this will return the top level gop if gop is nested
+def View get_parent_gop {canvas} {
+ set obj $self
+ while {$canvas != [$obj canvas]} {set obj [$obj canvas]}
+ return $obj
+}
+
+def View outside_of_the_box {} {
+ if {$@canvas eq ""} {return}
+ # always hide these things
+ if {[$self class] == "Wire"} {set @inside_box 0; return}
+ if {[$self class] == "ObjectBox"} {set @inside_box 0; return}
+ if {[$self class] == "MessageBox"} {set @inside_box 0; return}
+ if {[$self class] == "Comment"} {set @inside_box 0; return}
+ if {[$self class] == "Array"} {$@canvas visibles+= $self; set @inside_box 1; return}
+ set x1 $@x1; set y1 $@y1
+ if {[$@canvas gop]} {
+ set mess [$@canvas get_mess]
+ set pixwidth [lindex $mess 4]
+ set pixheight [lindex $mess 5]
+ if {[llength $mess] == 6} {
+ set xmargin 0; set ymargin 0
+ } else {
+ set xmargin [lindex $mess 6]; set ymargin [lindex $mess 7]
+ }
+ if {$x1 < $pixwidth +$xmargin && $x1 > $xmargin && \
+ $y1 < $pixheight+$ymargin && $y1 > $ymargin} {
+ set @inside_box 1
+ $@canvas visibles+= $self
+ } else {
+ set @inside_box 0
+ $@canvas visibles-= $self
+ }
+ } else {set @inside_box 1}
+}
+
+def View draw_maybe {} {
+ if {$@canvas == "" && [winfo exists .$self.c]} {$self draw; return}
+ if {[$self class] == "Canvas" && $@canvas == ""} {return}
+ if {$@inside_box} {
+ #if {[$@canvas mapped] && ![$@canvas abs] && [$self gop_check]} {$self draw}
+ if {[$@canvas mapped] && [$self gop_check]} {$self draw}
+ } else {
+ # for drawing opened gop
+ if {[winfo exists .$@canvas.c]} {$self draw}
+ }
+}
+#this checks if $self can be seen, ie nested gop.
+def View gop_check {} {
+ set canvases $@canvas
+ while {[lindex $canvases end] != ""} {lappend canvases [[lindex $canvases end] canvas]}
+ set canvases [lreplace $canvases end-1 end]; # all canvases
+ foreach canvas $canvases {
+ # if a canvas is not a gop and its window does not exists
+ if {![$canvas gop] && ![winfo exists [$canvas widget]]} {return 0; break}
+ }
+ return 1
+}
+
+#-----------------------------------------------------------------------------------#
+
+class_new Canvas {Menuable ObjectBox}
+
+def Canvas close {} {
+ after cancel $@motion_after_id
+ if {$@subpatch} {
+ #can't wait till @mapped get updated thru proc change
+ if {$@gop} {foreach x [$@objects values] {$x outside_of_the_box}}
+ $self save_geometry
+ $self copy_times= 0
+ netsend [list .$self vis 0]
+ #netsend [list .$self close]
+ return
+ }
+ if {$@gop} {
+ foreach x [$@objects values] {$x outside_of_the_box}
+ netsend [list .$self close]
+ return
+ }
+ switch [tk_messageBox -message [say save_changes?] -icon question -type yesnocancel -default cancel] {
+ yes {$self save; netsend [list .$self close]}
+ no { netsend [list .$self close]}
+ cancel {}
+ }
+}
+
+def Canvas save_geometry {} {
+ set geometry [wm geometry .$self]
+ set cw [winfo width [$self widget]]; set ch [winfo height [$self widget]]
+ foreach {size x y} [split $geometry "+"] {mset {w h} [split $size "x"]; set x1 $x; set y1 $y}
+ set x2 [expr $x1+$cw]; set y2 [expr $y1+$ch]
+ netsend [list .$self bounds $x1 $y1 $x2 $y2]
+}
+
+def Canvas save {} {
+ if {$@subpatch} {return [$@canvas save]}
+ $self checkgeometry
+ set c [$self widget]
+ if {![regexp {^Untitled-[0-9]} $@name]} {
+ $self save_geometry
+ netsend [list .$self savetofile $@name $@folder]
+ } else {
+ $self save_as
+ }
+}
+
+def Canvas save_as {} {
+ $self checkgeometry
+ set filename [tk_getSaveFile -filetypes $::patch_filetypes]
+ if {$filename != ""} {
+ set @file [string range $filename [expr [string last / $filename]+1] end]
+ set @folder [string range $filename 0 [expr [string last / $filename]-1]]
+ $self save_geometry
+ puts "save $@file dir to $@folder"
+ netsend [list .$self savetofile $@file $@folder]
+ }
+}
+
+def Canvas print {} {
+ set filename [tk_getSaveFile -initialfile pd.ps -defaultextension .ps -filetypes { {{postscript} {.ps}} }]
+ if {$filename != ""} {[$self widget] postscript -file $filename}
+}
+def Canvas quit {} {$::main quit}
+def Canvas abort_server {} {$::main abort_server}
+
+proc wonder {} {tk_messageBox -message [say ask_cool] -type yesno -icon question}
+
+def Canvas eval% {code} {
+ mset {x y} $@curpos
+ regsub -all %X $code $x code
+ regsub -all %Y $code $y code
+ super $code
+}
+
+def Client documentation {} {
+ set filename [tk_getOpenFile -defaultextension .pd -filetypes { {{documentation} {.pd .txt .htm}} } -initialdir $::docdir]
+ if {$filename != ""} {
+ if {[string first .txt $filename] >= 0} {
+ menu_opentext $filename
+ } elseif {[string first .htm $filename] >= 0} {
+ menu_openhtml $filename
+ } else {
+ set i [string last / $filename]
+ set help_directory [string range $filename 0 [expr $i-1]]
+ set basename [string range $filename [expr $i+1] end]
+ netsend [list pd open [enquote $basename] [enquote $help_directory]]
+ }
+ }
+}
+
+def Canvas new_file {} {$::main new_file}
+def Canvas open_file {} {$::main open_file}
+def Canvas send_message {} {$::main send_message}
+def Client test_audio_and_midi {} {menu_doc_open doc/7.stuff/tools testtone.pd }
+def Client load_meter {} {menu_doc_open doc/7.stuff/tools load-meter.pd}
+def Client latency_meter {} {menu_doc_open doc/7.stuff/tools latency.pd }
+def Client about {} {AboutDialog new}
+def Client class_browser {} {Browser new_as browser browser 0 0 ""}
+def Client audio_on {} {netsend [list pd dsp 1]}
+def Client audio_off {} {netsend [list pd dsp 0]}
+def Client keyboard_view {} { KeyboardDialog new $::event_history}
+def Client clipboard_view {} { ClipboardDialog new $::clipboard}
+def Client command_history_view {} { ListDialog new $::command_history [say command_history_view]}
+def Client event_history_view {} {EventHistoryDialog new $::event_history}
+def Client do_what_i_mean {} {wonder}
+
+set pd_prefix [file dirname [file dirname [which pd]]]
+set pd_guidir ${pd_prefix}/lib/pd
+set doc_number 1
+set updir [file dirname [file dirname $argh0]]
+if {[file exists $updir/lib/pd/doc]} {
+ set docdir $updir/lib/pd/doc
+} else {
+ set docdir $updir/doc
+}
+
+proc menu_opentext {filename} {
+ set w [format ".help%d" $::doc_number]
+ toplevel $w
+ wm title $w $filename
+ frame $w.1
+ frame $w.2
+ pack [text $w.1.text -relief raised -bd 2 -yscrollcommand "$w.1.scroll set"] -side left -fill both -expand 1
+ pack [scrollbar $w.1.scroll -command "$w.1.text yview"] -side right -fill y
+ pack [button $w.2.close -text [say close] -command "destroy $w"] -side right
+ pack $w.2 -side bottom -fill x -expand 0
+ pack $w.1 -side bottom -fill both -expand 1
+ set f [open $filename]
+ while {![eof $f]} {
+ set bigstring [read $f 1000]
+ regsub -all PD_BASEDIR $bigstring $::pd_guidir bigstring
+ regsub -all PD_VERSION $bigstring $::pd_version bigstring
+ $w.1.text insert end $bigstring
+ }
+ $w.1.text configure -state disabled
+ close $f
+ incr ::doc_number
+ return $w
+}
+
+proc menu_doc_open {subdir basename} {
+ set dirname $::pd_guidir/$subdir
+ if {[string first .txt $basename] >= 0} {
+ return [menu_opentext $dirname/$basename]
+ } else {
+ netsend [list pd open $basename $dirname]
+ }
+}
+
+#-----------------------------------------------------------------------------------#
+def Canvas editmode {} {return $@editmode}
+def Canvas editmode= {mode} {
+ if {$mode == $@editmode} {return}
+ if {!$mode} {$self deselect_all}
+ $self redraw ;# why this???
+ set @editmode $mode; $self changed editmode
+# catch {.$self.bbar.edit configure -image icon_mode_$mode}
+ if {$@mapped} {
+ if {$mode} {set im icon_mode_edit} else {set im icon_mode_run}
+ [$self window].bbar.edit configure -image $im
+ if {[$self look hairstate] && !$@editmode} {$@crosshair erase}
+ if {[$self look gridstate]} {
+ if {$@editmode} {$@grid draw} else {$@grid erase}
+ }
+ }
+ # comment's look depends on the value of @editmode
+ foreach child [$@objects values] {if {[[$child class] <= Comment]} {$child changed}}
+ #!@#$ should update the checkbox in the editmenu
+}
+
+def Canvas editmodeswitch {} {$self editmode= [expr !$@editmode]}
+
+def Canvas window {} {
+ #if {$@gop && $@canvas != ""} {return [$@canvas window]}
+ return .$self
+}
+def Canvas widget {} {return .$self.c}
+def View cwidget {} {return .[$self get_canvas].c}
+
+#-----------------------------------------------------------------------------------#
+
+def Canvas atomically {proc} {$@history atomically $proc}
+def Canvas undo {} {$@history undo}
+def Canvas redo {} {$@history redo}
+
+def Canvas init {mess} {
+ set @mapped 0
+ set @gop 0
+ set @goprect ""
+ set @abs 0
+ set @name ""
+ set @folder "???"
+ set @file ""
+ super {#X obj 666 666 pd} ;# bogus
+ $self reinit $mess
+ set @zoom 1.0 ;# must be a float, not int
+ set @action none
+ set @objects [Hash new]; set @objectsel [Selection new]; set @visibles {}
+ set @wires [Hash new]; set @wiresel [Selection new]
+
+ set @focus ""
+ set @curpos {30 30}
+ set @bbox {0 0 100 100}
+ set @dehighlight {}
+# if {$@mapped} {$self init_window} ;#!@#$ @mapped can't possibly be 1 at this point
+ set @history $::command_history
+ $self subscribe $::manager
+ $self changed
+ #$self canvas= $self ;#!@#$ EEVIL
+ set @coords 0
+ set @jump 0
+ set @keynav_iocount 0 ;# the io select count
+ set @keynav_port 0 ;# which in/outlet is selected
+ set @keynav 0 ;# the list of objects that has io selected
+ set @keynav_iosel 0 ;# last object that is io selected
+ set @keynav_iosel_o {} ;# list of objects that has outlet selected
+ set @keynav_iosel_i {} ;# list of objects that has inlet selected
+ set @iosel_deselect 0 ;# if selected should be deselected by clicking at empty space
+ set @keynav_current 0
+ set @keynav_last_obj 0
+ set @keynav_last_wire 0
+ set @keynav_tab_sel "wire"
+ set @keynav_shift 0
+ set @copy_count 0
+ set @findbar ""
+ set @find_string ""
+ set @iohilite {-1 0 0 0 0}
+ set @keyprefix 0
+ set @coords {0 0 1 1} ;# default #X coords line
+ set @pixsize {0 0}
+ set @margin {0 0}
+ set @macro_q {}
+ set @macro_delay 200
+ set @blinky ""
+ set @editmode 0
+ set @show_id 0
+ set @motion_queue {}
+}
+
+def Canvas reinit {mess} {
+ switch -- [lindex $mess 0] {
+ "#N" {
+ # those four are not to be confused with other @variables of similar names.
+ set @canvas_pos [lrange $mess 2 3]
+ set @canvas_size [lrange $mess 4 5]
+ set args [lrange $mess 6 end]
+ switch [llength $args] {
+ 1 {
+ set @subpatch 0
+ mset [list @fontsize] $args
+ set @name ""
+ set @mapped 1
+ }
+ 2 {
+ set @subpatch 1
+ mset [list @name @mapped] $args
+ set @fontsize "what?"
+ }
+ default {error "wrong number of arguments (expecting 5 or 6, got [expr 4+[llength $args]])"}
+ }
+ }
+ "#X" {
+ switch -- [lindex $mess 1] {
+ obj {}
+ restore {
+ set @x1 [lindex $mess 2]
+ set @y1 [lindex $mess 3]
+ set args [lrange $mess 4 end]
+ $self text= [lrange $mess 4 end]
+ if {!$@subpatch && [llength $args] != 0} {set @abs 1}
+ if {$@mapped && !$@gop} {
+ #if {!$@subpatch && $@text != ""} {set @abs 1; return}
+ #if {![winfo exists .$self.c]} {$self init_window}
+ }
+ }
+ coords {
+ set @coords [lrange $mess 2 5]
+ set @pixsize [lrange $mess 6 7]
+ switch [llength $mess] {
+ 8 {set @gop 0}
+ 9 {set @gop [lindex $mess 8]}
+ 11 {
+ set @gop [lindex $mess 8]
+ set @margin [lrange $mess 9 10]
+ }
+ default {error "what???"}
+ }
+ if {$@gop} {set @mapped 1}
+ }
+ }
+ }
+ "" {return}
+ default {error "huh? mess=$mess"}
+ }
+}
+
+# doesn't this look like Canvas deconstruct ?
+def Canvas get_mess {} {
+ return [concat $@coords $@pixsize $@margin]
+}
+
+
+def Canvas margin {} {return $@margin}
+def Canvas gop {} {return $@gop}
+def Canvas hidtext {} {return $@hidetext}
+def Canvas abs {} {return $@abs}
+#def Canvas abs {} {if {!$@subpatch} {return 1} else {return 0}}
+def Canvas subpatch {} {return $@subpatch}
+def Canvas get_dimen {} {return $@canvas_size}
+
+def Canvas gop_rect {} {
+ mset {pxs pys} $@pixsize
+ mset {mx my} $@margin
+ set rect [list $mx $my [expr $mx+$pxs] [expr $my+$pys]]
+ if {$@goprect == ""} {
+ set @goprect [GopRect new $self $rect]
+ } elseif {!$@editmode} {$@goprect delete; set @goprect ""; return}
+ $@goprect draw
+
+}
+
+# should be called once and only from init
+def Canvas init_window {} {
+ lappend ::window_list $self
+ set win .$self
+ set c [$self widget]
+ if {$::tcl_platform(platform) == "macintosh"} {
+ toplevel $win -menu $win.m
+ } else {
+ if {[$self look menubar]} {toplevel $win -menu $win.m} else {toplevel $win -menu ""}
+
+ }
+ catch {wm iconphoto $win icon_pd}
+ set @menubar $win.m
+ $self init_menus
+ # turn buttonbar on/off
+ set @buttonbar [ButtonBar new $self]
+ if {[$self look buttonbar]} {pack [$@buttonbar widget] -side top -fill x -expand no}
+ set @statusbar [StatusBar new $self]
+ # turn statusbar on/off
+ if {[$self look statusbar]} {pack [$@statusbar widget] -side bottom -fill x}
+ set w [expr [lindex $@canvas_size 0]-4];# dd canvas is 4 pixel out with pd canvas?
+ set h [expr [lindex $@canvas_size 1]-4]
+ pack [canvas $c -width $w -height $h -background white] -side left -expand 1 -fill both
+ set @yscroll $win.yscroll; set @xscroll $win.xscroll
+ $self init_scrollbars
+ wm minsize $win 1 1
+ wm geometry $win +[lindex $@canvas_pos 0]+[lindex $@canvas_pos 1]
+ wm protocol $win WM_DELETE_WINDOW "$self close"
+ focus $c
+ $self new_binds
+ $self update_title
+ $self motion_update
+ set @runcommand [Runcommand new .$self "command" canvas_eval]
+ set @crosshair [Crosshair new $self]
+ set @active [Active new $self]
+ set @sense [Sense new $self]
+ set @grid [Grid new $self]
+}
+
+def Canvas activate_menubar= {val} {if {$val} {.$self configure -menu $@menubar} {.$self configure -menu ""}}
+
+def Canvas activate_buttonbar= {val} {
+ if {$val} {
+ pack [$@buttonbar widget] -side top -fill x -expand no -before [$self widget]
+ } else {pack forget [$@buttonbar widget]}
+}
+
+def Canvas activate_statusbar= {val} {
+ if {$val} {
+ if {[winfo exists $@yscroll]} {set w .$self.yscroll} else {set w .$self.c}
+ pack [$@statusbar widget] -side bottom -fill x -before $w
+ } else {pack forget [$@statusbar widget]}
+}
+
+def Canvas activate_scrollbars= {val} {if {!$val} {$self init_scrollbars} {$self remove_scrollbars}}
+
+def Canvas activate_grid= {val} {if {$val} {$@grid draw} {$@grid erase}}
+
+def Canvas init_scrollbars {} {
+ set win .$self
+ set c [$self widget]
+ if {[winfo exists $win.yscroll]} {return}
+ set size [$c bbox foo]
+ mset {xs ys} $@canvas_size
+ pack [scrollbar $win.yscroll -command "$c yview" ] -side right -fill y -before $c
+ pack [scrollbar $win.xscroll -command "$c xview" -orient horizontal] -side bottom -fill x -before $c
+ set xw $win.xscroll; set yw $win.yscroll
+ $c configure -yscrollcommand "$self scroll_set $yw" -xscrollcommand "$self scroll_set $xw"
+ after 0 [list $self adjust_scrollbars]
+}
+
+def Canvas remove_scrollbars {} {
+ set win .$self
+ set c [$self widget]
+ if {![winfo exists $win.yscroll]} {return}
+ #use destroy instead of pack forget so that it can be tested with winfo exists
+ destroy $win.yscroll
+ destroy $win.xscroll
+ $c configure -yscrollcommand "" -xscrollcommand "" -scrollregion ""
+}
+
+def Canvas adjust_scrollbars {} {
+ set c [$self widget]
+ set size [$c bbox foo]
+ if {[$self look scrollbar]} {$self auto_scrollbars}
+ if {$size != ""} {
+ mset {xmin ymin xmax ymax} {0 0 100 100}
+ mset {x1 y1 x2 y2} $size
+ if {$x2 > 100} {set xmax $x2}
+ if {$y2 > 100} {set ymax $y2}
+ set bbox [list $xmin $ymin $xmax $ymax]
+ set oldbbox [$c cget -scrollregion]
+ # it is very inefficient to call "configure" here
+ if {"$oldbbox" != "$bbox"} {$c configure -scrollregion $bbox}
+ set @bbox $bbox
+ }
+}
+
+def Canvas auto_scrollbars {} {
+ set c [$self widget]
+ if {[$c bbox foo] != ""} {
+ mset {cx1 cy1 cx2 cy2} [$c bbox foo]
+ } else {
+ set cx2 [lindex $@canvas_size 0]; set cy2 [lindex $@canvas_size 1]
+ }
+ set x2 [$c canvasx [winfo width $c]]
+ set y2 [$c canvasy [winfo height $c]]
+ if {$x2 == 1} {set x2 $cx2; set y2 $cy2}
+ if {$cx2 <= $x2 && $cy2 <= $y2} {$self remove_scrollbars} {$self init_scrollbars}
+}
+
+def Canvas delete_window {} {
+ set wl {}
+ foreach w $::window_list {if {$w != $self} {lappend wl $w}}
+ set ::window_list $wl
+ destroy .$self
+}
+
+def Canvas delete {} {
+ $self delete_window
+ super
+}
+
+def Canvas focus {} {return $@focus}
+def Canvas focus= {o} {set @focus $o}
+def Canvas history {} {return $@history}
+
+#-----------------------------------------------------------------------------------#
+def Canvas find {} {
+ if {[info exists ::_(findmodel:_class)]} {
+ focus .$self.find.find
+ findmodel reinit
+ } else {
+ FindModel new_as findmodel $self
+ FindView new $self
+ focus .$self.find.find
+ }
+}
+def Canvas find_again {} {
+ if {[info exists ::_(findmodel:_class)]} {findmodel remove_info;findmodel search_recursive}
+}
+
+def Canvas find_last_error {} {netsend [list pd finderror]}
+
+def Canvas bind {eventtype selector args} {
+ set c [$self widget]
+ #bind $c $eventtype [concat [list $self $selector] $args \; $self statusbar_draw %x %y]
+ #bind $c $eventtype "puts \[time {[concat [list $self $selector] $args \; $self statusbar_draw %x %y]}\]"
+ #bind $c $eventtype "puts \[time {[concat [list $self $selector] $args]}\]"
+ if {[$self look statusbar]} {
+ bind $c $eventtype [concat [list $self $selector] $args \; $self statusbar_draw %x %y]
+ } else {
+ bind $c $eventtype [concat [list $self $selector] $args]
+ }
+}
+
+def Canvas new_binds {} {
+ # mouse buttons
+ $self bind <Button> click_wrap %x %y %b 0
+ $self bind <Shift-Button> click_wrap %x %y %b 1
+ $self bind <Control-Button> click_wrap %x %y %b 2
+ $self bind <Control-Shift-Button> click_wrap %x %y %b 3
+ $self bind <Alt-Button> click_wrap %x %y %b 4
+ $self bind <Alt-Shift-Button> click_wrap %x %y %b 5
+ $self bind <Alt-Control-Button> click_wrap %x %y %b 6
+ $self bind <Alt-Control-Shift-Button> click_wrap %x %y %b 7
+ switch $::OS {
+ osx {
+ $self bind <Button-2> click_wrap %x %y %b 8
+ $self bind <Control-Button> click_wrap %x %y 3 8
+ }
+ default {
+ $self bind <Button-3> click_wrap %x %y %b 8
+ }
+ }
+ switch $::OS { unix {
+ $self bind <Button-4> scroll y -1
+ $self bind <Button-5> scroll y +1
+ $self bind <Shift-Button-4> scroll x -1
+ $self bind <Shift-Button-5> scroll x +1
+ } default {
+ $self bind <MouseWheel> scroll y \[expr -abs(%D)/%D\]
+ $self bind <Shift-MouseWheel> scroll x \[expr -abs(%D)/%D\]
+ }}
+ $self bind <ButtonRelease> unclick_wrap %x %y %b 0
+ $self bind <Shift-ButtonRelease> unclick_wrap %x %y %b 1
+
+ # keyboard
+ $self bind <Control-Key> ctrlkey %x %y %K %A 0
+ $self bind <Control-Shift-Key> ctrlkey %x %y %K %A 1
+ $self bind <Alt-Key> altkey %x %y %K %A 0
+ $self bind <Alt-Shift-Key> altkey %x %y %K %A 1
+ switch $::OS {
+ unix {
+ $self bind <Mod1-Key> altkey %x %y %K %A 0
+ $self bind <Mod1-Shift-Key> altkey %x %y %K %A 1
+ $self bind <Mod4-Key> altkey %x %y %K %A 0
+ $self bind <Mod4-Shift-Key> altkey %x %y %K %A 1
+ }
+ osx {
+ $self bind <Mod1-Key> ctrlkey %x %y %K %A 0
+ $self bind <Mod1-Shift-Key> ctrlkey %x %y %K %A 1
+ }
+ }
+ $self bind <Key> key_wrap %x %y %K %A 0
+ $self bind <Shift-Key> key_wrap %x %y %K %A 1
+ $self bind <KeyRelease> keyup_wrap %x %y %K %A 0
+ $self bind <Shift-KeyRelease> keyup_wrap %x %y %K %A 1
+ $self bind <Control-KeyRelease> keyup_wrap %x %y %K %A 0
+ $self bind <Motion> motion_wrap %x %y 0
+ $self bind <Alt-Motion> motion_wrap %x %y 4
+ $self bind <Control-Motion> motion_wrap %x %y 9
+ #$self bind <Map> map
+ #$self bind <Unmap> unmap
+ $self bind <Leave> leave
+ $self bind <Configure> configure %h %w
+}
+
+def Canvas configure {h w} {
+ if {[$self look gridstate]} {
+ $@grid update $h $w
+ if {[winfo exists .$self.yscroll]} {return}; # scrollbar will update grid already
+ $@grid draw
+ }
+}
+
+#def Canvas map {} {}
+#def Canvas unmap {} {}
+def Canvas leave {} {$@crosshair erase}
+
+def Canvas scroll {axis diff} {
+ set c [$self widget]
+ $c [list $axis]view scroll $diff units
+ if {[$self look hairstate] && $@editmode} {
+ # this should be changed so that we don't need to recompute x,y here.
+ set x [expr [$c canvasx [expr [winfo pointerx $c] - [winfo rootx $c]]]/$@zoom]
+ set y [expr [$c canvasy [expr [winfo pointery $c] - [winfo rooty $c]]]/$@zoom]
+ set target [$self identify_target $x $y 0]
+ $@crosshair data= $x $y $target
+ $@crosshair draw
+ } else {
+ $@crosshair erase
+ }
+}
+
+# this allows the grid to update when scroll
+def Canvas scroll_set {w v1 v2} {if {[$self look gridstate] && $@editmode} {$@grid draw}; $w set $v1 $v2}
+
+def Canvas reload {} {netsend [list .$self reupload]}
+def Canvas redraw {} {
+ $self changed
+ foreach x [$@objects values] {$x changed}
+ foreach x [ $@wires values] {$x changed}
+}
+
+#patch editing commandline shortcuts
+def Canvas o {x y {name ""}} {
+ set c [$self widget]
+ if {[$self snap_grid]} {set off [expr [$self look grid_size]/2]} {set off 0}
+ set @curpos [list [expr [$c canvasx $x]+$off] [expr [$c canvasy $y]+$off]]
+ $self new_object obj $name
+}
+
+def Canvas c {from outlet to inlet} {
+ set out_objs [$self parse_idx $from]
+ set in_objs [$self parse_idx $to]
+ foreach out $out_objs {
+ foreach in $in_objs {
+ $self connect [list $out $outlet $in $inlet]
+ }
+ }
+}
+
+def Canvas pc {from outlet to inlet} {
+ set out_objs [$self parse_idx $from]
+ set in_objs [$self parse_idx $to]
+ if {[llength $out_objs] != [llength $in_objs]} {return "No can do :("}
+ for {set i 0} {$i < [llength $out_objs]} {incr i} {
+ $self connect [list [lindex $out_objs $i] $outlet [lindex $in_objs $i] $inlet]
+ }
+}
+
+def Canvas s {selection} {
+ set objs [$self parse_idx $selection]
+ foreach obj $objs {$self selection+= [$@objects get $obj]}
+}
+
+def Canvas s+ {selection} {
+ set objs [$self parse_idx $selection]; set ids {}
+ foreach obj $objs {
+ set v [$@objects get $obj]; lappend ids $v
+ $self selection+= $v
+ }
+ $self selection_wire= [$self implicit_wires $ids]
+}
+
+def Canvas sw {from outlet to inlet} {
+ set out_objs [$self parse_idx $from]
+ set in_objs [$self parse_idx $to]
+ foreach out $out_objs {
+ foreach in $in_objs {
+ set id [$self wire_idx [list $out $outlet $in $inlet]]
+ if {$id>=0} {$self selection_wire+= [$@wires get $id]}
+ }
+ }
+}
+
+def Canvas parse_idx {val} {
+ set objs {}
+ foreach obj [split $val ","] {
+ if {[regexp {\d+-\d+} $obj range]} {
+ set l [split $range "-"]
+ set objs [concat $objs [lmake [lindex $l 0] [lindex $l 1]]]
+ continue
+ }
+ lappend objs $obj
+ }
+ return $objs
+}
+
+def Canvas xy_snap {x y} {
+ if {[$self look snap_grid]} {
+ set grid [$self look grid_size]
+ set x [expr floor($x/$grid)*$grid]
+ set y [expr floor($y/$grid)*$grid]
+ }
+ return [list $x $y]
+
+}
+
+def Canvas new_object {sel args} {
+ $self editmode= 1
+ $self deselect_all
+ mset {x y} $@curpos
+ if {[$self look snap_grid]} {
+ set grid [$self look grid_size]
+ set x [expr floor($x/$grid)*$grid]
+ set y [expr floor($y/$grid)*$grid]
+ }
+ switch -- $sel {
+ obj { set goto [list $self new_object_edit]}
+ msg { set goto [list $self new_object_edit]}
+ text { set goto [list $self new_object_edit]}
+ default {set goto [list $self new_object_callback]}
+ }
+ netsend [concat [list .$self $sel $x $y] $args] $goto
+}
+
+def Canvas new_wire_callback {wire} {}
+
+def Canvas new_object_callback {obj} {
+ $self add_to_obj_history $obj
+ set @keynav_last_obj $obj
+ $self selection+= $obj
+ if {$@keynav} {$self update_Active $obj}
+}
+
+def Canvas new_object_copyselect {obj} {
+ $self selection+= $obj
+ #set @action "move"
+ #$self click_on_object $obj 0
+}
+
+def Canvas new_wire_select {wire} {$self selection_wire+= $wire}
+
+def Canvas new_object_edit {obj} {
+ if {[$obj class] == "NumBox"} {return}
+ $obj edit
+}
+
+def Canvas add_to_obj_history {obj} {
+ if {![[$obj class] <= ObjectBox]} {return}
+ obj_hist prepend [$obj text]
+}
+
+
+def Canvas insertxy {} {return [list $@insert_x $@insert_y]}
+
+def Canvas insert_object {} {$self do_insert_obj "none" "none"}
+
+def Canvas get_canvas {} {
+ if {![info exists @gop]} {
+ if {[info exists @subpatch]} {if {$@subpatch} {return [$self canvas]}}
+ if {[info exists @abs]} {if {$@abs} {return [$self canvas]}}
+ if {[winfo exists .$self.c]} {return $self}
+ }
+ #if {[info exists @subpatch]} {if {$@subpatch} {return [$self canvas]}}
+ return [super]
+}
+
+def Canvas get_topcanvas {} {
+ set canvas $@canvas
+ if {$@canvas == ""} {return $self}
+ while {[$canvas canvas] != ""} {set canvas [$canvas canvas]}
+ return $canvas
+}
+
+def Canvas do_insert_obj {x y} {
+ if {$x == "none" && $y == "none"} {
+ if {[$@wiresel size] != 1} {return}
+ set wire [$@wiresel values]
+ puts "insert object for wire $wire"
+ mset {from outlet to inlet} [$wire report]
+ set c [$self widget]
+ set iowidth [$self look iowidth]
+ mset {ox1 oy1 ox2 oy2} [lmap / [$c bbox ${from}o${outlet}] [$self zoom]]
+ mset {ix1 iy1 ix2 iy2} [lmap / [$c bbox ${to}i${inlet} ] [$self zoom]]
+ set x1 [expr $ox1 + $iowidth/2]; set y1 [expr ($oy1+$oy2)/2]
+ set x2 [expr $ix1 + $iowidth/2]; set y2 [expr ($iy1+$iy2)/2]
+ set x [expr $x1 + ($x2-$x1)/2]
+ set y [expr $y1 + ($y2-$y1)/2]
+ }
+ netsend [list .$self obj $x $y] [list $self new_object_edit]
+ set @action insert
+}
+
+def Canvas new_object_insert_wire {obj} {
+ set wire [$self selection_wire]
+ $self selection_wire-= $wire
+ mset {from outlet to inlet} [$wire report]
+ $self disconnect [$wire connects]
+ set @keynav 0; $@active hide; set @keynav_tab_sel "object"
+ set from_idx [$@objects search $from]
+ set to_idx [$@objects search $to]
+ set obj3_idx [$@objects search $obj]
+ $self connect [list $from_idx $outlet $obj3_idx 0] [list $self keynav_current=]
+ $self connect [list $obj3_idx 0 $to_idx $inlet]
+ $self action= none
+}
+
+def Canvas chain_object {} {
+ if {[$@objectsel size] != 1} {return}
+ set o [$@objectsel values]
+ mset {x1 y1 x2 y2} [$o bbox]
+ set grid [$self look grid_size]
+ if {[$self look snap_grid]} {set y [expr floor(($y2+$grid)/$grid)*$grid]} {set y [expr $y2+10]}
+ netsend [list .$self obj $x1 $y] [list $self new_object_edit]
+ set @action chain_obj
+}
+def Canvas new_object_chain_wire {obj} {
+ obj_hist prepend [$obj text]
+ set from_idx [$@objects search [lindex [$self selection] 0]]
+ $self deselect_all
+ set to_idx [$@objects search $obj]
+ $self connect [list $from_idx 0 $to_idx 0]
+ $self action= none
+ $self selection= $obj
+}
+
+def Canvas objects {} {return $@objects}
+#def Canvas wires {} {return $@wires}
+def Canvas selection {} {$@objectsel values}
+def Canvas selection= {objs} {$@objectsel clear; $self selection+= $objs}
+def Canvas selection+= {objs} {foreach obj $objs {$@objectsel set [$obj index] $obj}}
+def Canvas selection-= {objs} {foreach obj $objs {set k [$obj index]; if {[$@objectsel exists $k]} {$@objectsel unset $k}}}
+def Canvas selection_wire {} {$@wiresel values}
+def Canvas selection_wire= {objs} {$@wiresel clear; $self selection_wire+= $objs}
+def Canvas selection_wire+= {objs} {foreach obj $objs {$@wiresel set [$obj index] $obj}}
+def Canvas selection_wire-= {objs} {foreach obj $objs {set k [$obj index]; if {[ $@wiresel exists $k]} { $@wiresel unset $k}}}
+
+def Canvas Object {} {$self new_object obj}
+def Canvas Message {} {$self new_object msg}
+def Canvas Number {} {$self new_object floatatom}
+def Canvas Symbol {} {$self new_object symbolatom}
+def Canvas Comment {} {$self new_object text}
+
+#!@#$ these 9 should be harmonised with the class list instead of having special names
+def Canvas bng {} {$self new_object obj bng}
+def Canvas tgl {} {$self new_object obj tgl}
+def Canvas nbx {} {$self new_object obj nbx}
+def Canvas vsl {} {$self new_object obj vsl}
+def Canvas hsl {} {$self new_object obj hsl}
+def Canvas vradio {} {$self new_object obj vradio}
+def Canvas hradio {} {$self new_object obj hradio}
+def Canvas vu {} {$self new_object obj vu}
+def Canvas dropper {} {$self new_object obj dropper}
+def Canvas cnv {} {$self new_object obj cnv}
+
+def Canvas Graph {} {$self editmode= 1; netsend [list .x$self graph ]}
+def Canvas Array {} {$self editmode= 1; netsend [list .x$self menuarray]}
+
+def Canvas init_menus {} {
+ set name .$self
+ set m $name.m
+ menu $m
+ #removed Paths after send_message
+ foreach x {file edit find view put window help} {menu $m.$x -tearoff $::pd_tearoff}
+ $self populate_menu file {new_file open_file {} send_message {} close save save_as print {} abort_server quit}
+ $self populate_menu edit {undo redo {} cut copy paste duplicate select_all subpatcherize {} tidy_up {}}
+ $self populate_menu find {find find_again find_last_error}
+ $m.view add checkbutton -label [say visual_diff] -selectcolor grey0 -command [list $self visual_diff] \
+ -accelerator [accel_munge "Ctrl+e"] -indicatoron 1
+ $self populate_menu view {get_elapsed {} reload redraw}
+ $self populate_menu put {Object Message Number Symbol Comment {} bng tgl nbx vsl hsl vradio hradio vu dropper cnv {} Graph Array}
+ $self populate_menu window {{}}
+ $m.edit add checkbutton -label [say edit_mode] -selectcolor grey0 -command [list $self editmodeswitch] \
+ -accelerator [accel_munge "Ctrl+e"] -indicatoron 1
+ $m.edit configure -postcommand "$self fix_edit_menu"
+ $m.window configure -postcommand "$self fix_window_menu"
+ foreach x {file edit view find put window help} {
+ if {$x=="help"} {
+ # help menu is in the wrong place in patch windows because it's taken from .mbar ???
+ $m add cascade -label [say $x] -menu .mbar.$x
+ } {
+ $m add cascade -label [say $x] -menu $m.$x
+ }
+ }
+}
+
+# corrects edit menu, enabling or disabling undo/redo
+# LATER also cut/copy/paste
+def Canvas fix_edit_menu {} {
+ set e .$self.m.edit
+ switch $::OS {osx {set i 0} default {set i 1}}
+ set t [say undo]
+ if {[$@history can_undo?]} {
+ $e entryconfigure $i -state normal -label "$t [$@history next_undo_name]"
+ } else {
+ $e entryconfigure $i -state disabled -label "[say cannot] $t"
+ }
+ incr i
+ set t [say redo]
+ if {[$@history can_redo?]} {
+ $e entryconfigure $i -state normal -label "$t [$@history next_redo_name]"
+ } else {
+ $e entryconfigure $i -state disabled -label "[say cannot] $t"
+ }
+}
+
+def Menuable fix_window_menu {} {
+ set menu $@menubar.window
+ $menu delete 0 end
+ foreach w $::window_list {$menu add command -label [wm title [$w window]] -command "$w raise"}
+# {"parentwindow" {menu_windowparent} ""}
+}
+
+#-----------------------------------------------------------------------------------#
+#this just tells whether an object is part of the selection, that is, what usually makes objects turn blue.
+def Canvas selection_include? {member} {expr [$@objectsel search $member]>=0}
+
+def Canvas type {} {
+ if {$@subpatch && !$@gop} {return "sub"}
+ if {$@subpatch && $@gop} {return "gopsub"}
+ if {$@abs && !$@gop} {return "abs"}
+ if {$@abs && $@gop} {return "gopabs"}
+ if {!$@subpatch && !$@abs && !$@gop} {return "toplevel"}
+}
+
+def Canvas draw {} {
+ if {$@gop} {
+ if {[$self gop_check]} {$self all_changed}
+ #if the focus is not in the opened gop
+ if {[regexp {^.x[0-9a-f]{6,8}.c} [focus] f]} {
+ if {$@canvas != ""&& $f != [$self widget]} {super;return}
+ } elseif {$@canvas != "" && [focus] != [$self widget]} {super;return}
+ } elseif {$@subpatch || $@abs} {super}
+ if {!$@mapped} {return} else {if {![winfo exists [$self widget]]} {return}}
+ $self check_findbar
+ if {$@editmode} {set bg [$self look bgedit]} else {set bg [$self look bgrun]}
+ [$self widget] configure -background $bg
+ $self adjust_scrollbars
+ if {$@gop} {$self gop_rect}
+}
+
+def Canvas popup_properties {} {CanvasPropertiesDialog new $self}
+
+def Canvas gop_target {id} {
+ while {[$id canvas] != $self} {set id [$id canvas]}; return $id
+}
+
+#-----------------------------------------------------------------------------------#
+class_new Macro_Rect {View}
+
+def Macro_Rect init {} {super; $self data= 0 0 0 0 blue}
+
+def Macro_Rect data= {x1 y1 x2 y2 col} {
+ set @x1 $x1; set @y1 $y1
+ set @x2 $x2; set @y2 $y2
+ set @col $col
+}
+
+def Macro_Rect flash {x1 y1 x2 y2 col} {
+ $self data= $x1 $y1 $x2 $y2 $col
+ $self draw
+ after 500 $self erase
+}
+
+def Macro_Rect draw {} {
+ set @canvas [string range [focus] 1 [string first . [focus] 1]-1]
+ $self item MACRO rect [list $@x1 $@y1 $@x2 $@y2] -outline $@col
+}
+
+class_new Macro {EventHistory}
+def Macro init {} {
+ $::event_history subscribe $self
+ set @idx 0
+ set @state 0
+ set @list {}
+ set @ref_list {}
+ set @delay 200
+ set @offset_x 0
+ set @offset_y 0
+ set @rect [Macro_Rect new]
+}
+def Macro state= {val} {
+ set @state $val
+ if {$val} {
+ set @ref_list {}
+ set @list {}
+ post %s "start recording macro..."
+ } else {
+ post %s "end..."
+ }
+}
+def Macro state {} {return $@state}
+def Macro dump {} {set i 0; foreach step $@list {post %s "step $i -> $step"; incr i}}
+def Macro idx= {val} {set @idx $val}
+def Macro idx {} {return $@idx}
+def Macro delay {} {return $@delay}
+def Macro append_ref {mess} {lappend @ref_list $mess}
+def Macro ref_list {} {puts "$@ref_list";return $@ref_list}
+def Canvas ref_list {} {$::macro ref_list}
+
+
+def Macro notice {args} {
+ if {$@state} {
+ set mess [lindex $args 2]
+ switch [lindex $args 1] {
+ add {$self add $mess}
+ default {}
+ }
+ }
+}
+
+def Macro add {mess} {
+ mset {event widget x y mode k kval} $mess
+ if {[regexp {^Control_} $k]} {return}
+ if {[regexp {^Alt_} $k]} {return}
+ if {[regexp {^Shift_} $k]} {return}
+ if {$event == "KeyRelease"} {return}
+ if {$event == "ButtonRelease"} {lappend @list [lreplace $mess 0 0 "Motion"]}
+ if {$event == "KeyPress"} {lappend @list [lreplace $mess 0 0 "Motion"]}
+ if {$event == "ButtonPress"} {lappend @list [lreplace $mess 0 0 "Motion"]}
+ lappend @list $mess
+}
+
+def Macro test_playable {x y} {
+ mset {macro_width macro_height} [$self calc_size]
+ set c [string range [focus] 0 [string first . [focus] 1]+1]
+ set cwidth [winfo width $c]; set cheight [winfo height $c]
+ set cx1 [$c canvasx 0]; set cy1 [$c canvasy 0]
+ set cx2 [$c canvasx $cwidth]; set cy2 [$c canvasy $cheight]
+ set new_x [expr $x+$macro_width]; set new_y [expr $y+$macro_height]
+ $@rect flash $x $y $new_x $new_y blue
+ if {$new_x > $cx2 || $new_x < $cx1 || $new_y > $cy2 || $new_y < $cy1} {
+ puts "Can't playback Macro:: outside of canvas area"
+ return
+ } else {$self idx= 0; $self offset $x $y; $self play [$self delay]}
+
+}
+
+def Macro offset {new_x new_y} {
+ mset {event widget x y mode k kval} [lindex $@list 0]
+ set @offset_x [expr $new_x-$x]
+ set @offset_y [expr $new_y-$y]
+}
+
+def Macro play {delay} {
+ if {$@idx == [llength $@list]} {return}
+ #$self test_canvas_size
+ set i 0
+ set focus [string range [focus] 1 [string first . [focus] 2]-1]
+ set step [lindex $@list $@idx]
+ #puts "\t $step"
+ mset {event widget x y mode k kval} $step
+ switch $event {
+ #KeyRelease {set name [modekey $k $mode]}
+ KeyPress {set name [modekey $k $mode]}
+ ButtonPress {set name $event-$k}
+ ButtonRelease {set name $event-$k}
+ Motion {set name $event}
+ default {puts "Error: event $event should not have been here.."}
+ }
+ if {$@idx < [llength $@list]} {
+ #after $delay [list $self run $event $name $k [expr $X+$@offset_x] [expr $Y+$@offset_y] \
+ # [expr $x+$@offset_x] [expr $y+$@offset_y]]
+ after $delay [list $self run $event $name $k $x $y]
+ }
+}
+
+#this don't make sense when multiple window, and should be re implemeneted somehow
+def Macro calc_size {} {
+ set x1 66666; set x2 0
+ set y1 66666; set y2 0
+ foreach step $@list {
+ mset {event widget x y mode k kval} $step
+ set x1 [min $X $x1]; set x2 [max $x2 $X]
+ set y1 [min $Y $y1]; set y2 [max $y2 $Y]
+
+ }
+ return [list [expr $x2-$x1] [expr $y2-$y1]]
+}
+
+def Macro test_canvas_size {} {
+ set c [string range [focus] 0 [string first . [focus] 1]+1]
+ set cwidth [winfo width $c]; set cheight [winfo height $c]
+ set cx1 [$c canvasx 0]; set cy1 [$c canvasy 0]
+ set cx2 [$c canvasx $cwidth]; set cy2 [$c canvasy $cheight]
+ mset {x1 y1 x2 y2} [$self calc_size]
+}
+
+def Macro run {event name k x y} {
+ set w [focus]
+ incr @idx
+ event generate $w <$name> -x $x -y $y
+ if {$event=="KeyPress"} {event generate $w <KeyRelease-$k> -x $x -y $y}
+ $self play $@delay
+}
+
+def Macro copy {} {
+ clipboard clear
+ selection clear
+ set i 0
+ foreach step $@list {
+ if {$i == [expr [llength $@list]-1]} {set comma ""} else {set comma ","}
+ mset {event widget x y mode k kval} $step
+ set mess [list $event $x $y $mode $k]
+ set t ${mess}$comma
+ switch $event {
+ KeyPress {clipboard append [lreplace $t 0 0 "key"]}
+ ButtonPress {clipboard append [lreplace $t 0 0 "click"]}
+ ButtonRelease {clipboard append [lreplace $t 0 0 "unclick"]}
+ }
+ incr i
+ }
+ selection handle -selection PRIMARY [focus] "$self getdata"
+ selection own -command lost -selection PRIMARY
+}
+
+def Macro getdata {offset maxchar} {
+ puts "clipboard ::: [clipboard get]"
+ return [string range [format %s [clipboard get]] $offset [expr {$offset+$maxChars}]]
+}
+
+def Macro reset {} {set @idx 0}
+
+set ::macro [Macro new]
+set ::macro_state 0
+
+def Canvas macro_toggle {} {if {![$::macro state]} {set ::macro_state 1} {$::macro state= 0; $::macro dump}}
+#def Canvas macro_play {} {puts ">> $@click_at <<"; $::macro idx= 0; $::macro play [$::macro delay]}
+def Canvas macro_play {} {
+ mset {x y} $@click_at
+ $::macro reset
+ $::macro play [$::macro delay]
+ #$::macro test_playable $x $y
+}
+def Canvas keyevent {} {
+ focus [$self widget]
+ event generate [$self widget] <Control-Key-1>
+}
+
+def Canvas macro_copy {} {$::macro copy}
+
+#-----------------------------------------------------------------------------------#
+class_new TextBox {Box}
+
+def TextBox init {mess} {
+ super $mess
+ set @edit 0
+ set @x1 [lindex $mess 2]
+ set @y1 [lindex $mess 3]
+ set @text [$self remove_braces [join [lrange $mess 4 end]]]
+ set @multi 0
+ set @max_width 40
+ # @textoffset is for offseting the text item/widget, ie, ObjectBox vs NumBox
+ switch [$self class] {
+ NumBox {set @textoffset [list 10 2]}
+ default {set @textoffset [list 2 2]}
+ }
+}
+
+def TextBox text= {text} {set @text [$self remove_braces [join $text]]}
+def TextBox text {} {return $@text}
+def TextBox filter_text {{for_edit 0}} {return $@text}
+
+def TextBox draw {} {
+ if {[$self class] == "Canvas"} {if {$@text == "graph"} {$self update_size; super; return}}
+ # "TEXT" is the text label while "text" is the the input text field tk widget.
+ # the text should be drawn before, so that update_size works at the right time.
+ mset {x1 y1} [$self xy]
+ set z [$@canvas zoom]
+ if {$@edit} {
+ $self draw_edit
+ } else {
+ set fw [font measure [$self look font] 0]
+ set text [$self filter_text]
+ if {$::leet} {set text [string map -nocase {a 4 e 3 t 7 s 5 i 1 o 0 g 9} $text]}
+ $self item TEXT text [l+ $@textoffset [$self xy]] \
+ -font [$self look font] -text $text \
+ -fill [$self look fg] -anchor nw -width [expr ($fw*$@max_width)-1]
+ # set width with -1 because text item seem to be inclusive at wrap point
+ # where as the text widget is exclusive
+ }
+ $self update_size
+ super
+}
+
+def TextBox edit {} {
+ if {$@edit} {return}; set @edit 1; $self changed edit
+ if {[[$self class] <= AtomBox]} {set @clear 1}
+}
+
+def TextBox new_bind {} {
+ set t [$self cwidget].${self}text
+ bind $t <Key> "$self key_input %W %x %y %K %A 0"
+ bind $t <Control-Return> "$self key_input %W %x %y 10 %A 0"
+ bind $t <Control-v> "$self paste_resize"
+ bind $t <Return> "$self unedit"
+ bind $t <Escape> "$self unedit 0"
+ bind $t <Up> "$self scroll_history +1"
+ bind $t <Down> "$self scroll_history -1"
+ bind $t <Control-p> "$self scroll_history +1"
+ bind $t <Control-n> "$self scroll_history -1"
+ bind $t <Alt-BackSpace> "$self clear"
+}
+
+def TextBox draw_edit {} {
+ set c [$self cwidget]
+ switch $::tcl_platform(os) {
+ Linux {$c configure -cursor crosshair}
+ #need to find equivalent names for other os
+ }
+ if {[lsearch [$@canvas selection] $self] < 0} {$@canvas selection+= $self}
+ set t $c.${self}text
+ if {[winfo exists $t]} {return}
+ set @edit 1
+ set @tab_repeats 0
+ obj_hist histi= 0
+ set @selected? 1
+ set z [$@canvas zoom]
+ set font_height [font metrics [$self look font] -linespace]
+ if {[$c bbox ${self}TEXT] != ""} {
+ mset {ix1 iy1 ix2 iy2} [lmap / [$c bbox ${self}TEXT] $z]
+ if {($iy2-$iy1)/$z > $font_height} {set @multi 1}
+ } else {
+ set ix1 0; set iy1 0
+ set ix2 [font measure [$self look font] 0]
+ set iy2 [font metrics [$self look font] -linespace]
+ }
+ $c delete ${self}TEXT
+ set font_str [$self look font]
+ set new_size [format %.0f [expr [lindex $font_str 1]*$z]]
+ set font_str [lreplace $font_str 1 1 $new_size]
+ foreach char [split $@text ""] {lappend l [scan $char %c]}
+ mset {width height} [$self get_size [expr $ix2-$ix1] [expr $iy2-$iy1]]
+ set insertbg [$self look fg]; set fg [$self look fg]
+ if {[[$self class] <= AtomBox]} {set fg "red"; set insertbg [$self look bgedit]}
+ text $t -width $width -height $height -relief flat -bg [$self look bgedit] -borderwidth 0 \
+ -highlightthickness 0 -font $font_str -fg $fg -insertbackground $insertbg -wrap word
+ $self new_bind
+ $@canvas focus= $self
+ $self item text window [l+ [lmap / $@textoffset $z] [$self xy]] -window $t -anchor nw -tags "${self}text $self text"
+ $t insert 1.0 $@text
+ $t configure -pady 0 -padx 0
+ $self resize
+ focus $t
+}
+
+def TextBox resize {} {
+ if {[[$self class] <= AtomBox]} {return}
+ set c [$self cwidget]
+ set t $c.${self}text
+ #set z [$@canvas zoom]
+ set pix_height [$t count -update -ypixels 1.0 end]
+ set pix_width [font measure [$self look font] [$t get 1.0 end]]
+ mset {width height} [$self get_size $pix_width $pix_height]
+ $t configure -width [min $width $@max_width] -height $height -wrap word
+}
+
+def TextBox get_size {w h} {
+ set c [$self cwidget]
+ set t $c.${self}text
+ set pix_height $h
+ set pix_width $w
+ set char_width [font measure [$self look font] 0]
+ set line_height [font metrics [$self look font] -linespace]
+ set round_chars [expr int(ceil($pix_width/$char_width.0))]
+ if {$round_chars < $@max_width && !$@multi} {
+ set round_lines 1
+ } else {
+ set @multi 1
+ set round_chars $@max_width
+ set round_lines [expr int(ceil($pix_height/$line_height))]
+ }
+ return [list $round_chars $round_lines]
+}
+
+def TextBox key_input {widget x y key iso shift} {
+ after 0 "$self after_key $widget"
+ set c [$@canvas widget]
+ set t $c.${self}text
+ if {[[$self class] <= AtomBox]} {if {$@clear} {$t delete 1.0 1.end; set @clear 0}}
+ switch -- $key {
+ Tab {
+ if {[$self class] == "ObjectBox"} {
+ $self propose_completions; $widget configure -state disabled
+ }
+ }
+ 10 {$t configure -height [expr [lindex [$t configure -height] 4] + 1]}
+ }
+}
+
+def TextBox after_key {widget} {
+ $widget configure -state normal; # for in case there is completion box
+ $self resize
+ $self changed
+}
+
+def TextBox paste_resize {} {
+ if {[[$self class] <= AtomBox]} {return}
+ set c [$self cwidget]
+ set t $c.${self}text
+ set fixed [font metrics [$self look font] -fixed]
+ set text [clipboard get]
+ if {$fixed} {
+ set width [string length $text]
+ } else {
+ set textpix [font measure [$self look font] $text]
+ set fwidth [font measure [$self look font] 0]
+ set width [expr (($textpix+$fwidth-1)/$fwidth)+1]
+ }
+ set maxwidth 40
+ mset {y1 y2} [$t yview]
+ if {$width < $maxwidth} {set height 1} {set height [expr ceil($width/$maxwidth.0)]}
+ $t configure -width [min $width $maxwidth] -height $height -wrap word
+ after 0 [list $t mark set insert 1.end]
+ $t mark set insert 1.0
+ $self update_size
+ $self changed
+}
+
+def TextBox scroll_history {incr} {
+ if {[[$self class] <= MessageBox]} {return}
+ set c [$self cwidget]
+ set t $c.${self}text
+ if {![obj_hist histi]} {obj_hist set_hist 0 [$t get 1.0 1.end]}
+ $t delete 1.0 1.end
+ set text [obj_hist traverse $incr]
+ $t insert 1.0 $text
+ $t configure -width [string length $text]
+ $self update_size
+ after 0 $self changed
+
+}
+
+def TextBox clear {} {
+ set c [$self cwidget]
+ set t $c.${self}text
+ $t delete 1.0 1.end
+
+}
+
+def TextBox text {} {return $@text}
+
+def TextBox update_size {} {
+ if {[info exists @gop]} {if {$@gop} {mset [list @xs @ys] $@pixsize; return}}
+ if {$@canvas == ""} {puts "update_size: this textbox has no canvas, try again later"; return}
+ set c [$self cwidget]
+ set t_widget $c.${self}text
+ set t_item $c.${self}TEXT
+ set w2 0; set h2 0
+ set xpad 2; set ypad 3
+ set z [$@canvas zoom]
+ if {[winfo exists $t_widget]} {
+ set textwidth [expr ([winfo reqwidth $t_widget]+$xpad)/$z]
+ set height [expr ([winfo reqheight $t_widget]+$ypad)/$z]
+ } else {
+ mset {x1 y1 x2 y2} [[[$self canvas] widget] bbox ${self}TEXT]
+ set textwidth [expr ($x2-$x1+$xpad)/$z]
+ set height [expr ($y2-$y1+$ypad)/$z]
+ }
+ set iowidth [$self look iowidth]
+ set topwidth [expr {(2* $@ninlets-1)*$iowidth}]
+ set bottomwidth [expr {(2*$@noutlets-1)*$iowidth}]
+ set @xs [max [$self look minobjwidth] [max $bottomwidth [max $topwidth $textwidth]]]
+ set @ys $height
+}
+
+#-----------------------------------------------------------------------------------
+
+class_new ObjectBox {TextBox}
+
+def ObjectBox init {mess} {
+ super $mess
+ set @valid 0 ;# only ObjectBox needs a @valid. (removed all others)
+ set @ninlets 0
+ set @noutlets 0
+ set @pdclass ""
+}
+
+def ObjectBox valid= {v} {set @valid $v}
+def ObjectBox valid {} {return $@valid}
+def Canvas objectsel {} {return $@objectsel}
+def Canvas wiresel {} {return $@wiresel}
+
+def ObjectBox draw_box {} {
+ super
+ set xya [$self bbox]
+ mset {x1 y1 x2 y2} $xya
+ #set xyb [l+ [list $x2 $y1 $x1 $y1 $x1 $y2] [list -1 +1 +1 +1 +1 -1]]
+ #set xyc [l+ [list $x2 $y1 $x2 $y2 $x1 $y2] [list -1 +1 -1 -1 +1 -1]]
+ if {[$self selected?]} {set fg [$self look selectframe]} {set fg [$self look frame3]}
+ if {$@valid} {
+ $self item BASE rectangle $xya -fill [$self look bg] -outline $fg -width 1
+ } else {
+ $self item BASE rectangle $xya -fill [$self look bg] -outline $fg -width 1 -dash {3 3}
+ }
+ #$self item BASE1 line $xyb -fill [$self look frame1] -width 1
+ #$self item BASE2 line $xyc -fill [$self look frame2] -width 1
+ #[$@canvas widget] lower ${self}BASE ${self}TEXT
+ [[$self get_canvas] widget] lower ${self}BASE ${self}TEXT
+ #[[$self get_canvas] widget] lower ${self}BASE
+}
+
+def ObjectBox draw {} {super; $self draw_io}
+
+# this is called from the GUI; text= is reserved for server.
+def TextBox setto {text} {
+ [$@canvas history] add [list $self setto $@text]
+ [$@canvas widget] configure -cursor {}
+ set @text $text
+ set l {}
+ foreach char [split $@text ""] {lappend l [scan $char %c]}
+ $@canvas selection-= [list $self]
+ switch [$@canvas action] {
+ insert {set goto [list $@canvas new_object_insert_wire]}
+ chain_obj {set goto [list $@canvas new_object_chain_wire]}
+ subpatcherize {set goto [list $@canvas new_object_subpatcherize_redraw]}
+ default {set goto [list $@canvas new_object_callback]}
+ }
+ netsend [concat [list .$@canvas text_setto $self] $l] $goto
+}
+
+def TextBox unedit {{accept 1}} {
+ if {!$@edit} {return}
+ set @edit 0
+ $self changed edit
+ set c [[$self get_canvas] widget]
+ set t $c.${self}text
+ if {$accept} {$self setto [$t get 1.0 "end - 1 chars"]}
+ after 1 "destroy $t"
+ if {[winfo exists .completion]} {$@action cancel}
+ focus $c
+ $@canvas focus= ""
+}
+
+#-----------------------------------------------------------------------------------#
+def Canvas name {} {return $@name}
+def Canvas folder {} {return $@folder}
+def Canvas name= {name} {if {!$@mapped} {return}; set @name $name ; $self update_title}
+def Canvas folder= {folder} {if {!$@mapped} {return}; set @folder $folder; $self update_title}
+
+def Canvas make_title {} {
+ if {!$@mapped} {return}
+ if {$@subpatch} {
+ if {$@canvas == "" || 0==[string compare $@canvas $self]} {
+ set t "(uh)"
+ } else {
+ set t [$@canvas make_title]
+ }
+ set t "subpatch '$@name' of $t"
+ } else {
+ #set t "$@name in $@folder"
+ set t "$@name"
+ }
+ if {[$self modified?]} {append t "(*)"}
+ return $t
+}
+
+def Canvas update_title {} {
+ if {[winfo exists .$self]} {wm title .$self [$self make_title]}
+}
+
+# UNIMPLEMENTED: this should indicate whether the patch in pd is different from the last saved patch
+def Canvas modified? {} {return 1}
+
+def Canvas mapped {} {return $@mapped}
+def Canvas mapped= {v} {set @mapped $v}
+
+def Canvas havewindow= {flag} {
+ set was [winfo exists .$self]
+ if {$flag && !$was} {$self init_window; $self redraw}
+ #if {$flag && $was && [$self gop]} {$self redraw}
+ if {$flag && $was} {$self raise}
+ if {!$flag && $was} {$self delete_window}
+}
+
+def Canvas visibles+= {child} {
+ if {[lsearch $@visibles $child] < 0} {lappend @visibles $child; $self changed visibles}
+}
+def Canvas visibles-= {child} {
+ if {[lsearch $@visibles $child] >= 0} {set @visibles [lwithout $@visibles $child]; $self changed visibles}
+}
+
+def Canvas visibles {} {return $@visibles}
+
+def Canvas all_changed {} {
+ foreach x $@visibles {
+ if {[$x class] == "Canvas"} {
+ if {$@gop} {$x all_changed}
+ }
+ $x changed
+ }
+}
+
+# this is a shim between the client's new-style indices and the server's remaining old-style indices
+proc dex {h k} {lsearch [lsort -integer [$h keys]] $k}
+
+# for undo; calls the server
+def Canvas ins {i constructor} {
+ set parts [pd_mess_split $constructor]
+ set last [lindex $parts end]
+ set parts [lrange $parts 0 end-1]
+ foreach part $parts {netsend $part}
+ netsend [concat [list .$self object_insert [dex $@objects $i]] $last] ;# bork bork bork
+ $@history add [list $self del $i]
+}
+
+def Canvas del {i} {
+ set o [$@objects get $i]
+ #this keynav should be better sorted out
+ if {$o == $@keynav_current || $o == $@keynav_last_obj} {
+ set @keynav_current 0
+ set @keynav_last_obj 0
+ }
+ # this "if" might not be necessary... try deconstruct_to for everything.
+ if {[$o class] != "Canvas"} {
+ $@history add [list $self ins $i [$o deconstruct]]
+ } else {
+ set meuh [Clipboard2 new]
+ $o deconstruct_to $meuh
+ $@history add [list $self ins $i [$meuh value]]
+ $meuh delete
+ }
+ netsend [list .$self object_delete $o]
+}
+
+def Canvas wires {} {return $@wires}
+
+def Canvas delete_selection {} {
+ if {![$@objectsel size] && ![$@wiresel size]} {return}
+ #this keynav should be better sorted out
+ if {$@keynav} {
+ set @keynav 0
+ switch [$@keynav_current class] {
+ Wire {set @keynav_last_wire 0}
+ default {set @keynav_last_obj 0}
+ }
+ set @keynav_current 0
+ $@active hide
+ }
+ set del_wire {}
+ foreach obj [$@objectsel values] {
+ foreach wire [$obj wires2] {
+ if {[$@wires search $wire] != -1 && [lsearch $del_wire $wire] < 0} {
+ $self disconnect [$wire connects]
+ lappend del_wire $wire
+ }
+ }
+ $self del [$@objects search $obj]
+ }
+ foreach x [$@wiresel values] {
+ if {[$@wires search $x] != -1 && [lsearch $del_wire $x] < 0} {
+ $self disconnect [$x connects]
+ }
+ }
+ $@objectsel clear
+ $@wiresel clear
+}
+
+def View position= {xy1} {mset [list @x1 @y1] $xy1; $self changed x1 y1}
+def View set_orig_xy {x y} {set @orig_x $x; set @orig_y $y}
+
+def Canvas motion_wrap {x y f} {
+ set c [$self widget]
+ set x [expr [$c canvasx $x]/$@zoom]
+ set y [expr [$c canvasy $y]/$@zoom]
+ lappend @motion_queue [list $x $y $f]
+ #$self motion $x $y $f [$self identify_target $x $y $f]
+}
+
+def Canvas motion_update {} {
+ if {[llength $@motion_queue]} {
+ mset {x y f} [lindex $@motion_queue end]; set @motion_queue {}
+ $self motion $x $y $f [$self identify_target $x $y $f]
+ }
+ set @motion_after_id [after 50 "$self motion_update"]
+}
+
+def Canvas click_wrap {x y b f} {
+ set c [$self widget]
+ set x [expr [$c canvasx $x]/$@zoom]
+ set y [expr [$c canvasy $y]/$@zoom]
+ set f [expr 1<<($b+7)|$f]
+ $self click $x $y $f [$self identify_target $x $y $f]
+}
+def Canvas unclick_wrap {x y b f} {
+ set c [$self widget]
+ set x [expr [$c canvasx $x]/$@zoom]
+ set y [expr [$c canvasy $y]/$@zoom]
+ set f [expr 1<<($b+7)|$f]
+ $self unclick $x $y $f [$self identify_target $x $y $f]
+}
+def Canvas key_wrap {x y key iso shift} {
+ set c [$self widget]
+ $self key [expr [$c canvasx $x]/$@zoom] [expr [$c canvasy $y]/$@zoom] $key $iso $shift
+}
+def Canvas keyup_wrap {x y key iso shift} {
+ set c [$self widget]
+ $self keyup [expr [$c canvasx $x]/$@zoom] [expr [$c canvasy $y]/$@zoom] $key $iso $shift
+}
+
+proc lsearch_minimum {l} {
+ set i 0
+ set j 0
+ set min [lindex $l 0]
+ foreach o $l {
+ if {$o < $min} {set i $j; set min $o}
+ incr j
+ }
+ return $i
+}
+
+def Canvas quadrant {du dv array} {
+ if {$@keynav_current == 0} {set @keynav_current [$@objects get [lindex [$@objects keys] 0]]}
+ set foo {}
+ set bar {}
+ set pos [$@keynav_current xy]
+ foreach o $array {
+ mset {x y} [l- $pos [$o xy]]
+ set u [expr $x+$y]
+ set v [expr $x-$y]
+ if {$u*$du>0 && $v*$dv>0} {lappend foo $o; lappend bar [distance $pos [$o xy]]}
+ }
+ if {![llength $bar]} {return $@keynav_current}
+ set best [lindex $foo [lsearch_minimum $bar]]
+ return $best
+}
+
+def Canvas motion {x y f target} {
+ #modes_callback $self "motion" $x $y $f $target
+ set c [$self widget]
+ $self motion_checkhairtip $target $x $y
+ eval $@dehighlight
+ set @dehighlight {}
+ set oldpos $@curpos
+ set @curpos [list $x $y]
+ # detects if the focus is not on the canvas itself in run mode, ie. numbox
+ if {!$@editmode & [$self focus] != $self & [$self focus] != ""} {
+ [$self focus] motion $x $y $f $target
+ }
+ mset {type id detail} $target
+ switch $@action {
+ edit {$self motion_edit $x $y $f}
+ insert {}
+ chain_obj {}
+ imove {$self motion_imove $oldpos $x $y; return}
+ mouse_copy {$self motion_move $oldpos $x $y; return}
+ move {$self motion_move $oldpos $x $y; return}
+ none {}
+ default {$@action motion $x $y $f $target}
+ }
+ if {$@editmode} {$self motion_iohilite2 $x $y $f}
+ if {$id == ""} {return}
+}
+
+proc remainder {val val2} {
+ if {[expr {abs($val)}]} {return [expr {(abs($val)%$val2)*($val/abs($val))}]} else {return 0}
+}
+
+def Canvas motion_move {oldpos x y} {
+ mset {ox oy} $oldpos
+ if {$@keynav} {$@active draw}
+ foreach obj [$@objectsel values] {
+ #if {[[$obj class] <= Box]} {
+ if {[$self look snap_grid]} {
+ set grid [$self look grid_size]
+ set ax [expr {(int($x)/$grid)*$grid}]
+ set ay [expr {(int($y)/$grid)*$grid}]
+ set oax [expr {(int($ox)/$grid)*$grid}]
+ set oay [expr {(int($oy)/$grid)*$grid}]
+ mset {x1 y1} [$obj xy]
+ if {![expr {($ax-$oax)%$grid}]} {
+ set xoff [remainder [expr {int($x1-$ax)}] $grid]
+ } else {set xoff 0}
+ if {![expr {($ay-$oay)%$grid}]} {
+ set yoff [remainder [expr {int($y1-$ay)}] $grid]
+ } else {set yoff 0}
+ $obj move [expr ($ax-$oax)-$xoff] [expr ($ay-$oay)-$yoff]
+ } else {
+ $obj move [expr {$x-$ox}] [expr {$y-$oy}]
+ }
+ #} else {
+ # puts "Canvas motion warning: trying to move non-Box explicitly"
+ #}
+ }
+}
+
+def Canvas motion_imove {oldpos x y} {
+ mset {ox oy} $oldpos
+ if {$@keynav} {$@active draw}
+ if {[$@objectsel size] == 1} {
+ set obj [$@objectsel values]
+ set in_objs $obj
+ set out_objs $obj
+ } else {
+ if {![llength $@keynav_iosel_i] || ![llength $@keynav_iosel_o]} {
+ return
+ } else {
+ set obj [lindex $@keynav_iosel_i 0]
+ set in_objs $@keynav_iosel_i
+ set out_objs $@keynav_iosel_o
+ }
+ }
+ if {[[$obj class] <= Box]} {
+ if {[$obj class] == "Canvas"} {
+ if {[$obj gop]} {[$self widget] raise [list $obj [$obj visibles]]}
+ } else {
+ [$self widget] raise $obj
+ }
+ mset {type id detail} [$self identify_target $x $y 0]
+ if {$type == "wire"} {
+ mset {from outlet to inlet} [$id report]
+ $self disconnect [$id connects]
+ set from_idx [$@objects search $from]
+ set to_idx [$@objects search $to]
+ foreach obj $in_objs {
+ set obj3_idx [$@objects search $obj]
+ if {![llength [$obj ioselect]]} {set port 0} else {set port [lindex [$obj ioselect] 0]}
+ set w1 [list $from_idx $outlet $obj3_idx $port]
+ if {[$@wires search $w1]<0} {$self connect $w1}
+ }
+ foreach obj $out_objs {
+ set obj3_idx [$@objects search $obj]
+ if {![llength [$obj ioselect]]} {set port 0} else {set port [lindex [$obj ioselect] 0]}
+ set w2 [list $obj3_idx $port $to_idx $inlet]
+ if {[$@wires search $w2]<0} {$self connect $w2}
+ }
+ set @action move
+ }
+ foreach obj [$@objectsel values] {$obj move [expr $x-$ox] [expr $y-$oy]}
+ } else {
+ puts "Canvas motion warning: trying to move non-Box explicitly"
+ }
+}
+
+def Canvas motion_edit {x y f} {
+ if {[distance [list $x $y] $@click_at] > 5} {
+ foreach obj [$@objectsel values] {
+ if {[[$obj class] <= Box]} {
+ $obj backupxy= [$obj xy]
+ } else {
+ puts "Canvas motion warning: trying to backup coordinates of non-Box"
+ }
+ }
+ if {$f == 9} {set @action imove} else {set @action move; $self motion_move $@click_at $x $y}
+ mset {ox oy} $@click_at
+ }
+}
+
+def Canvas motion_checkhairtip {target x y} {
+ global tooltip
+ if {[$self look hairstate] && $@editmode} {
+ $@crosshair data= $x $y $target
+ $@crosshair draw
+ } else {
+ $@crosshair erase
+ }
+ if {[$self look tooltip]} {
+ if {$tooltip ne "" && ![$tooltip iserror] && [expr [distance [$tooltip curpos] [list $x $y]] > 10]} {
+ $tooltip delete
+ set tooltip ""
+ }
+ }
+}
+
+def Canvas motion_iohilite2 {x y f} {
+ set c [$self widget]
+ set io [$self identify_closestio $x $y $f]
+ if {$io<0} {set @iohilite [list -1 0 0 0 0]; return}
+ foreach item {i o} {
+ set type_idx [string first $item $io]
+ set type [string index $io $type_idx]
+ set port [string range $io [expr $type_idx+1] end]
+ set object [string range $io 0 [expr $type_idx-1]]
+ if {$type_idx >= 0} {break}
+ }
+ mset {iox ioy} [lmap / [rect_centre [$c bbox $io]] $@zoom]
+ set @iohilite [list $object $iox $ioy $type $port]
+ $object hilite_io $type $iox $ioy
+ set @dehighlight [list $c delete ${io}b]
+}
+
+def Canvas iohilite {} {return $@iohilite}
+
+def Canvas motion_iohilite {target x y} {
+ set c [$self widget]
+ mset {type id detail} $target
+ if {[llength $@keynav_iosel_i] || [llength $@keynav_iosel_o]} {return}
+ if {$@editmode && [$id canvas] == $self} {
+ switch $type {
+ inlet {set io i}
+ outlet {set io o}
+ default {return}
+ }
+ set port [$id hilite_io $io $x $y]
+ set @dehighlight [list $c delete ${id}$io${port}b]
+ }
+}
+
+#-----------------------------------------------------------------------------------#
+# returns one of those five things:
+# object $id : the body of an object
+# inlet $id $inlet : an inlet of an object
+# outlet $id $outlet : an outlet of an object
+# wire $id : a wire
+# label $id : a label
+# nothing : nothing
+def Canvas identify_target {x y f} {
+ set c [$self widget]
+ set cx [expr $x*$@zoom]
+ set cy [expr $y*$@zoom]
+ set stack [$c find overlapping [expr $cx-2] [expr $cy-2] [expr $cx+2] [expr $cy+2]]
+ # reversing the stack is necessary for some things
+ # not reversing the stack is also necessary for some other things
+ # we have to figure out something.
+ set stack [lreverse $stack]
+ set target ""
+ foreach tag $stack {set target [$self target $x $y $f $tag]; if {[llength $target] > 1} {break}}
+ if {[llength $target] > 1} {return $target} {return [list "nothing"]}
+}
+
+def Canvas target {x y f tag} {
+ set c [$self widget]
+ set cx [expr $x*$@zoom]
+ set cy [expr $y*$@zoom]
+ set tags [$c gettags $tag]
+ if {[regexp {^[xo][0-9a-f]{6,8}} $tags id]} {
+ # prior to Aug 15th, Wires had lower priority as all objects together
+ # now it's same priority, so just stacking order (and it's prolly wrong)
+ if {[$id classtags] == ""} {return [list "nothing"]}
+ set class [$id class]
+ if {[$self == $id]} {continue}
+ if {[$class <= Wire]} {if {$@action != "imove"} {return [list "wire" $id]}}
+ if {[$class <= Box]} {
+ if {$@action == "imove"} {
+ foreach tag $stack {
+ set tags2 [$c gettags $tag]
+ if {[regexp {^[xo][0-9a-f]{6,8}} $tags2 id2]} {
+ set class [$id2 class]
+ if {[$class == Wire]} {return [list "wire" $id2]}
+ }
+ }
+ }
+ mset {x1 y1 x2 y2} [$id bbox]
+ if {[regexp {^x[0-9a-f]{6,8}LABEL} $tags label]} {
+ if {$x>$x1 && $x<$x2 && $y>$y1 && $y<$y2} {
+ return [list "object" $id]
+ } else {
+ return [list "label" $id]
+ }
+ }
+ set outs [$id noutlets]
+ set ins [$id ninlets]
+ if {$y>=$y2-6 && $outs} {
+ set val [expr int(($x-$x1)*$outs/($x2-$x1))]
+ if {$val == $outs} {set val [expr $val-1]}
+ return [list "outlet" $id $val]
+ }
+ if {$y< $y1+2 && $ins} {
+ set val [expr int(($x-$x1)* $ins/($x2-$x1))]
+ if {$val == $ins} {set val [expr $val-1]}
+ return [list "inlet" $id $val]
+ }
+ return [list "object" $id]
+ }
+ #puts "skipped a $class"
+ }
+}
+
+def Canvas identify_closestio {x y f} {
+ set c [$self widget]
+ set cx [expr {$x*$@zoom}]
+ set cy [expr {$y*$@zoom}]
+ set sense [$self pointer_sense]
+ set stack [$c find overlapping [expr {$cx-$sense}] [expr {$cy-$sense}]\
+ [expr {$cx+$sense}] [expr {$cy+$sense}]]
+ set stack [lreverse $stack]
+ set ios {}
+ set objs {}
+ foreach tag $stack {
+ set tags [$c gettags $tag]
+ if {[regexp {^[x][0-9a-f]{6,8}[oi][0-9]{1,3}} $tags io]} {
+ foreach item {i o} {
+ set type_idx [string first $item $io]
+ set object [string range $io 0 [expr $type_idx-1]]
+ if {$type_idx >= 0} {break}
+ }
+ if {[$object canvas] == $self} {lappend ios $io}
+ }
+ }
+ if {![llength $ios]} {return -1}
+ set mindist 66666
+ set idx 0; set i 0
+ foreach io $ios {
+ set point2 [rect_centre [$c bbox $io]]
+ set point1 [list $x $y]
+ set dist [distance $point2 $point1]
+ if {$dist < $mindist} {set mindist $dist; set idx $i}
+ incr i
+ }
+ return [lindex $ios $idx]
+}
+def Canvas pointer_sense {} {return [$self look pointer_sense]}
+def Canvas pointer_sense= {sense} {
+ set ::look(Canvas:pointer_sense) $sense
+ mset {x y} $@curpos
+ $@sense flash $x $y $sense "red"
+}
+
+#-----------------------------------------------------------------------------------#
+class_new StatusBar {View} ;# no, using View is wrong here. View is for tk canvas item collections.
+
+def StatusBar widget {} {return .$@canvas.stat}
+
+def StatusBar addw {a b text args} {
+ set f [$self widget]
+ if {$text!=""} {
+ eval [concat [list pack [label $f.${a}_l -text $text -font {helvetica -10} -pady 0] -side left] $args]
+ }
+ label $f.$a -width $b -font {helvetica -10} -background #cccccc -foreground black -anchor w -pady 0
+ pack $f.$a -side left
+}
+
+def StatusBar init {canvas} {
+ super
+ set @canvas $canvas
+ set f [$self widget]
+ frame $f -border 1 -relief ridge
+ $self addw px 4 ""
+ $self addw py 4 ""
+ $self addw what 28 " " -fill x -expand yes
+ $self addw action 12 " Action: "
+ $self addw sel 3 " Sel: "
+ $self addw focus 10 " Focus: "
+}
+
+def Canvas statusbar_draw {x y} {$@statusbar draw $x $y}
+def Canvas action {} {return $@action}
+def Canvas action= {action} {set @action $action}
+def Canvas zoom {} {return $@zoom}
+
+def StatusBar draw {x y} {
+ if {$x == "??"} {return}
+ set c [$@canvas widget]
+ set f [$self widget]
+ set zoom [$@canvas zoom]
+ set x [expr [$c canvasx $x]/$zoom]
+ set y [expr [$c canvasy $y]/$zoom]
+ #set tags [$c gettags [lindex [$c find overlapping [expr $x-2] [expr $y-2] [expr $x+2] [expr $y+2]] end]]
+ set target [$@canvas identify_target $x $y -1]
+ mset {type id detail} $target
+ set t $target
+ switch -- $type {
+ object {
+ if {[info exists _($id:pdclass)]} {set class $_($id:pdclass)} {set class unknown}
+ append t " \[$class\]"
+ }
+ }
+ set action [$@canvas action]
+ if {[regexp ^o $action]} {set action [$action class]}
+ if {[string length [$@canvas focus]]} {set t "focus: [$@canvas focus]"}
+ $f.px configure -text [format "%4d" [expr round($x)]]
+ $f.py configure -text [format "%4d" [expr round($y)]]
+ $f.what configure -text $t
+ $f.action configure -text $action
+ $f.sel configure -text [llength [$@canvas selection]]
+ $f.focus configure -text [$@canvas focus]
+}
+
+#-----------------------------------------------------------------------------------#
+class_new FindModel {Thing}
+
+def FindModel init {canvas} {
+ set @orig_canvas $canvas
+ set @find_string ""
+ set @next_canvases $canvas
+ set @last_canvas 0
+ set @result ""
+ set @results {}
+ set @views {}
+ set @recursive 1
+ set @info ""
+}
+
+def FindModel reinit {} {
+ set @next_canvases $@orig_canvas
+ set @last_canvas 0
+ set @result ""
+ set @results {}
+ $self remove_info
+}
+def FindModel remove_info {} {
+ foreach view $@views {
+ set f [$view widget]
+ destroy $f.info_l; destroy $f.info
+ }
+}
+def FindModel delete {} {foreach view $@views {destroy [$view widget]}; super}
+
+def FindModel find_string= {s} {set @find_string $s}
+def FindModel find_string {} {return $@find_string}
+def FindModel result= {s} {
+ $@orig_canvas deselect_all
+ $@orig_canvas selection= $s
+ set @result $s
+}
+def FindModel result {} {return $@result}
+def FindModel views+ {view} {lappend @views $view}
+def FindModel views {} {return $@views}
+def FindModel end? {} {return $@end}
+def FindModel end= {v} {set @end 0}
+
+def FindModel search_recursive {} {
+ if {![llength $@next_canvases]} {$self end; return}
+ if {[llength $@results]} {$self result= [lindex $@results 0]; set @results [lreplace $@results 0 0];return}
+ while {$@last_canvas < [llength $@next_canvases]} {
+ set canvas [lindex $@next_canvases $@last_canvas]
+ if {[$self cache_results $canvas]} {
+ if {![winfo exists [$canvas widget]]} {$canvas popup_open} else {focus [$canvas widget]}
+ $self result= [lindex $@results 0]
+ set @results [lreplace $@results 0 0]
+ incr @last_canvas
+ return
+ } else {
+ incr @last_canvas
+ $self search_recursive
+ return
+ }
+ }
+ set old_canvases $@next_canvases
+ set @next_canvases {}
+ if {$@recursive} {
+ foreach canvas $old_canvases {foreach x [$canvas get_childcanvas] {lappend @next_canvases $x}}
+ } else {
+ set @next_canvases {}
+ }
+ set @last_canvas 0
+ $self search_recursive
+}
+
+def FindModel end {} {
+ $self reinit
+ $@orig_canvas deselect_all
+ set @info " \"$@find_string\" not found"
+ foreach view $@views {
+ $view addw label "info" "info"
+ }
+}
+
+def FindModel cache_results {canvas} {
+ set @results {}
+ foreach child [$@objects values] {
+ if {[string first $@find_string [$child text] 0] >= 0} {
+ lappend @results $child
+ }
+ }
+ if {[llength $@results]} {return 1} else {return 0}
+}
+
+class_new FindView {FindModel} ;# no, using View is wrong here. View is for tk canvas item collections.
+def FindView widget {} {return .$@canvas.find}
+def FindView init {canvas} {
+ findmodel views+ $self
+ set @canvas $canvas
+ set @break 0
+ set f [$self widget]
+ frame $f -border 1 -relief ridge
+ $self addw button "close" ""
+ $self addw text "find" "find"
+ $self addw checkbutton "recursive" "recursive"
+ if {[winfo exists .$@canvas.yscroll]} {set w .$@canvas.yscroll} else {set w .$@canvas.c}
+ pack $f -side bottom -fill x -before $w
+ set string [findmodel find_string]
+ if {$string != ""} {$f.find insert 0 $string}
+}
+
+def FindView addw {type name label} {
+ set f [$self widget]
+ if {$label!=""} {
+ eval [concat [list pack [label $f.${label}_l -text ${label}: -font {helvetica -10} -pady 0] -side left]]
+ }
+ switch $type {
+ text {
+ entry $f.$name -width 10 -relief flat -bg white -borderwidth 0 -highlightthickness 0
+ bind $f.$name <Escape> "findmodel delete"
+ bind $f.$name <Return> "$self find"
+ }
+ checkbutton {
+ checkbutton $f.$name
+ if {$name == "recursive"} {$f.$name configure -variable _(findmodel:recursive)}
+ }
+ button {
+ button $f.$name -border 1 -command "findmodel delete" -image icon_close -width 9 -height 9
+ if {$name == "close"} {bind $f.$name <Return> "findmodel delete"}
+ }
+ label {label $f.$name -textvariable _(findmodel:info) -font {helvetica -10} -pady 0}
+ }
+ pack $f.$name -side left
+ bind $f.$name <Tab> "$self traversal %K %W forward"
+}
+
+def FindView find {} {
+ set f [$self widget]
+ findmodel find_string= [$f.find get]
+ findmodel search_recursive
+ focus .$@canvas.c
+}
+
+def FindView traversal {k w direction} {
+ set f [$self widget]
+ if {$w == "$f.recursive"} {set next $f.close} else {set next [tk_focusNext $w]}
+ focus $next
+}
+
+def Canvas check_findbar {} {
+ if {[info exists ::_(findmodel:_class)] && ![winfo exists .$self.find.find]} {FindView new $self}
+}
+
+def Canvas get_childcanvas {} {
+ set canvases {}
+ foreach child [$@objects values] {if {[$child class] == "Canvas"} {lappend canvases $child}}
+ return $canvases
+}
+
+def Canvas runcommand {} {$@runcommand pack_prompt}
+
+class_new Runcommand {Listener}
+def Runcommand canvas {} {return $@canvas}
+
+def Runcommand init {serf name command} {
+ set @history [History new 20]
+ set @serf ${serf}.run
+ set @command $command
+ set @expanded 0
+ set @canvas [string trimleft $serf "."]
+ set @defs {}
+ set @completions {}
+ set @comp_i 0
+ set @comp_s "666"
+ set @show_id 0
+ $self defs
+ set f $@serf
+ frame $f -border 1 -relief ridge
+ button $f.close -border 1 -command "$self unpack_prompt" -image icon_close -width 9 -height 9
+ bind $f.close <Return> "$self unpack_prompt"
+ pack $f.close -side left
+ bind $f.close <Tab> "$self traversal %K %W forward"
+ label $f.cmd_l -text Command: -font {helvetica -10} -pady 0
+ pack $f.cmd_l -side left
+ entry $f.entry -width 30 -relief flat -bg white -borderwidth 0 -highlightthickness 0
+ bind $f.entry <Escape> "$self unpack_prompt"
+ bind $f.entry <Control-g> "$self unpack_prompt"
+ bind $f.entry <Return> "$self eval"
+ bind $f.entry <Up> "$self scroll_history +1"
+ bind $f.entry <Down> "$self scroll_history -1"
+ bind $f.entry <Control-p> "$self scroll_history +1"
+ bind $f.entry <Control-n> "$self scroll_history -1"
+ bind $f.entry <Tab> "$self completion +"
+ switch $::tcl_platform(os) {
+ Linux {bind $f.entry <ISO_Left_Tab> "$self completion -"}
+ default {bind $f.entry <Shift-Tab> "$self completion -"}
+ }
+ pack $f.entry -side left -fill x -expand yes
+ bind $f.entry <Control-Tab> "$self traversal %K %W forward"
+}
+
+def Runcommand pack_prompt {} {
+ set f $@serf
+ set @show_id [$@canvas show_id]
+ if {!$@show_id} {$@canvas show_id= 1}
+ if {[winfo exists .$@canvas.yscroll]} {set w .$@canvas.yscroll} else {set w .$@canvas.c}
+ pack $f -side bottom -fill x -before $w
+ focus $f.entry
+}
+
+def Runcommand unpack_prompt {} {
+ if {!$@show_id} {$@canvas show_id= 0}
+ pack forget $@serf
+ focus [$@canvas widget]
+}
+
+def Runcommand traversal {k w direction} {
+ set f $@serf
+ if {$w == "$f.entry"} {set next $f.close} else {set next [tk_focusNext $w]}
+ focus $next
+}
+
+def Runcommand eval {} {
+ set f $@serf
+ if {[winfo exists $f.completion]} {
+ set l [string range $@comp 0 [expr [string first ":" $@comp 0]-1]]
+ $self replace $l
+ destroy $f.completion
+ return
+ }
+ #$self unpack_prompt
+ super
+ $self unpack_prompt
+}
+
+def Runcommand defs {} {
+ set name [$@canvas class]
+ set len [string length ${name}_]
+ foreach def [$name methods] {lappend @defs $def}
+}
+
+def Runcommand completion {which} {
+ set f $@serf
+ set text [$f.entry get]
+ if {$text != $@comp_s} {
+ set @comp_s $text
+ set @completions {}
+ set @comp_i 0
+ foreach def $@defs {if {[regexp ^$@comp_s $def]} {lappend @completions $def}}
+ }
+ if {![llength $@completions]} return
+ set def [lindex $@completions $@comp_i]
+ set args [$@canvas args $def]
+ if {[lindex $args 0] == "self"} {
+ set args2 [lreplace $args 0 0]
+ } else {
+ set args2 $args
+ }
+ if {![llength $args2]} {set args2 "none"}
+ set @comp [join [list $def ":" $args2]]
+ if {$which == "+"} {
+ set @comp_i [expr ($@comp_i+1)%[llength $@completions]]
+ } else {
+ set @comp_i [expr $@comp_i-1]
+ if {$@comp_i<0} {set @comp_i [expr [llength $@completions]-1]}
+ }
+ if {![winfo exists $f.completion]} {
+ label $f.completion -textvariable _($self:comp) -pady 0
+ pack $f.completion -side right
+ }
+}
+
+def Thing args {def} {
+ set class [$self class]
+ set ancestors [$class ancestors]
+ set name ${class}_$def
+ set n 0
+ foreach class $ancestors {
+ set name ${class}_$def
+ if {[info exists ::__args($name)]} {break}
+ }
+ return $::__args($name)
+}
+
+def Canvas visible_rect {} {
+ set c [$self widget]
+ set height [winfo height $c]
+ set width [winfo width $c]
+ if {$width == 1 && $height == 1} {set height 300; set width 450}
+ mset {l r} [$c xview]
+ mset {t b} [$c yview]
+ if {$l == $r} {set l 0; set r 1}
+ if {$t == $b} {set t 0; set b 1}
+ set w [expr $width / ($r - $l)]
+ set h [expr $height / ($b - $t)]
+ mset {l2 r2} [lmap * [list $l $r] $w]
+ mset {t2 b2} [lmap * [list $t $b] $h]
+ return [list $l2 $t2 $r2 $b2]
+}
+
+def Canvas clipboard_coords {offset} {
+ set in 0
+ foreach mess [pd_mess_split [$::clipboard value]] {
+ set type [lindex $mess 1]
+ switch $type {
+ canvas {set in 1} "" {} connect {}
+ default {
+ if {$type == "restore"} {set in 0}
+ mset {x y} [lmap + [lrange $mess 2 3] $offset]
+ if {!$in} {lappend xcoords $x; lappend ycoords $y}
+ }
+ }
+ }
+ return [list $xcoords $ycoords]
+}
+
+def Canvas paste_visible? {x1 y1 x2 y2 offset} {
+ set in 0
+ foreach mess [pd_mess_split [$::clipboard value]] {
+ set type [lindex $mess 1]
+ switch $type {
+ canvas {set in 1} "" {} connect {}
+ default {
+ if {$type == "restore"} {set in 0}
+ mset {x y} [lmap + [lrange $mess 2 3] $offset]
+ if {!$in} {
+ if {$x > $x2 || $x < $x1} {return 0}
+ if {$y > $y2 || $y < $y1} {return 0}
+ }
+ }
+ }
+ }
+ return 1
+}
+
+def Canvas copy_times= {c} {set @copy_count $c}
+def Canvas copy_times {} {return $@copy_count}
+
+def Canvas copy {} {
+ global clipboard obj_index_sel
+ if {![$@objectsel size]} {return}
+ $clipboard value= ""
+ $self copy_times= 1
+ array unset obj_index_sel $self:*
+ set j 0
+ foreach i [lsort -integer [$@objectsel keys]] {
+ set child [$@objectsel get $i]
+ #set obj_index_sel($self:$child) [$@objectsel search $child]
+ set obj_index_sel($self:$child) $j; incr j
+ $child deconstruct_to $clipboard
+ }
+ foreach wire [$@wiresel values] {
+ if {[array names obj_index_sel $self:[$wire from]] == ""} {continue}
+ if {[array names obj_index_sel $self:[$wire to ]] == ""} {continue}
+ $wire deconstruct_to $clipboard $self
+ }
+}
+
+def Canvas paste {} {
+ if {[$self look snap_grid]} {set offset [$self look grid_size]} {set offset 15}
+ $self do_paste [expr [$self copy_times] * $offset]
+ $self copy_times= [expr [$self copy_times] + 1]
+}
+
+def Canvas do_paste {offset} {
+ set in 0
+ $self deselect_all
+ netsend [list .$self "push"]
+ foreach mess [pd_mess_split [$::clipboard value]] {
+ set type [lindex $mess 1]
+ if {$type == "restore"} {incr in -1}
+ if {!$in} {set with [list $self new_object_copyselect]} else {set with ""}
+ switch $type {
+ "" {}
+ canvas {incr in; netsend $mess}
+ connect {
+ if {$with != ""} {set with [list $self new_wire_select]}
+ netsend $mess $with}
+ default {netsend [$self paste_coords $mess $offset] $with}
+ }
+ }
+ netsend [list #X pop 1]
+}
+
+def Canvas paste_coords {mess offset} {
+ set x [lindex $mess 2]; set y [lindex $mess 3]
+ mset {vx1 vy1 vx2 vy2} [$self visible_rect]
+ mset {xcoords ycoords} [$self clipboard_coords $offset]
+ set visible [$self paste_visible? $vx1 $vy1 $vx2 $vy2 $offset]
+ set ref [lsearch $ycoords [lindex [lsort -real -increasing $ycoords] 0]]
+ if {!$visible} {
+ set xoff [expr ($vx2 - $vx1) * 0.25]
+ set yoff [expr ($vy2 - $vy1) * 0.25]
+ set x2 [expr [lindex $mess 2] - [lindex $xcoords $ref] + $vx1 + $xoff]
+ set y2 [expr [lindex $mess 3] - [lindex $ycoords $ref] + $vy1 + $yoff]
+ return [lreplace $mess 2 3 $x2 $y2]
+ } else {
+ puts "\t \t [expr $x+$offset] [expr $y+$offset] <<<<<"
+ return [lreplace $mess 2 3 [expr $x+$offset] [expr $y+$offset]]
+ }
+}
+
+def Canvas cut {} {
+ $@history atomically [list cut] {
+ $self copy
+ $self delete_selection
+ }
+}
+
+def Canvas duplicate {} {
+ if {[$self look snap_grid]} {set off [$self look grid_size]} {set off 15}
+ $self do_duplicate $off
+}
+
+def Canvas do_duplicate {offset} {
+ global clipboard
+ set backup $clipboard
+ set clipboard [Clipboard2 new]
+ $self copy
+ $self do_paste $offset
+ $clipboard delete
+ set clipboard $backup
+}
+
+def Canvas mouse_copy {} {
+ $self do_duplicate 0
+}
+
+def Canvas select_all {} {
+ $self editmode= 1
+ eval [concat [list $@objectsel reinit] [$@objects list]]
+ eval [concat [list $@wiresel reinit] [ $@wires list]]
+}
+def Canvas deselect_all {} {
+ #$self editmode= 1
+ $@objectsel clear
+ $@wiresel clear
+}
+
+def Canvas popup_help {} {$::main class_browser}
+
+def Canvas popup_open {} {
+ #$self init_window
+ #set @mapped 1
+ if {[winfo exists [$self widget]]} {raise .$self; return}
+ netsend [list .$self vis 1]
+ #$self init_window
+ #$self redraw
+}
+
+def Canvas popup {id x y} {
+ set p .$self.popup
+ catch {destroy $p}
+ menu $p -tearoff false
+ if {$id == $self} {
+ $self populate_menu $p {popup_properties popup_help}
+ } elseif {[$id class] == "Wire"} {
+ $id populate_menu $p {popup_insert}
+ } else {
+ $id populate_menu $p {popup_properties popup_open popup_help
+ popup_clear_wires popup_remove_from_path popup_delete_from_path popup_copy_id}
+ }
+ tk_popup $p [expr $x-5] [expr $y-5]
+}
+
+def View popup_copy_id {} {
+ clipboard clear
+ clipboard append $self
+}
+
+def Canvas disconnect {wire} {
+ set @keynav_tab_sel "wire"
+ set id [$@wires get [$self wire_idx $wire]]
+ if {$id == $@keynav_current || $id == $@keynav_last_wire} {
+ set @keynav_current 0
+ set @keynav_last_wire 0
+ }
+ mset {from outlet to inlet} $wire
+ netsend [list .$self disconnect $from $outlet $to $inlet]
+ $@history add [list $self connect $wire]
+}
+def Canvas connect {wire {callback ""}} {
+ mset {from outlet to inlet} $wire
+ netsend [list .$self connect $from $outlet $to $inlet] $callback
+ $@history add [list $self disconnect $wire]
+}
+
+def Canvas clear_wires_of {obj} {
+ if {![llength [$obj ioselect]]} {
+ set port 0; set type "none"
+ } else {
+ set port [lindex [$obj ioselect] 0]
+ set type [lindex [$obj ioselect] 1]
+ }
+ foreach wire [$obj wires2] {
+ mset {from outlet to inlet} [$wire report]
+ switch $type {
+ i {if { $to==$obj && $inlet==$port} {$self disconnect [$wire connects]; if { !$inlet} {lappend @auto_wire_from $from}}}
+ o {if {$from==$obj && $outlet==$port} {$self disconnect [$wire connects]; if {!$outlet} {lappend @auto_wire_to $to }}}
+ none {
+ $self disconnect [$wire connects]
+ if {$from==$obj && !$outlet} {lappend @auto_wire_to $to }
+ if { $to==$obj && ! $inlet} {lappend @auto_wire_from $from}
+ }
+ }
+ }
+}
+
+def Canvas clear_wires {} {
+ set @auto_wire_to {}; set @auto_wire_from {}
+ if {[$@objectsel size] == 1} {
+ set objs [$@objectsel values]
+ } else {
+ if {![llength $@keynav_iosel_i] && ![llength $@keynav_iosel_o]} {return}
+ set objs [list $@keynav_iosel_i $@keynav_iosel_o]
+ }
+ foreach obj $objs {$self clear_wires_of $obj}
+}
+
+def Canvas reconnect {} {
+ foreach from $@auto_wire_from {
+ set idx1 [$@objects search $from]
+ foreach to $@auto_wire_to {
+ set idx2 [$@objects search $to]
+ set wire [list $idx1 0 $idx2 0]
+ if {[$self wire_idx $wire] < 0} {$self connect $wire}
+ }
+ }
+}
+
+def Canvas delete_obj_from_path {} {$self clear_wires; $self reconnect; $self delete_selection}
+def Canvas remove_obj_from_path {} {$self clear_wires; $self reconnect}
+
+def Canvas wire_idx {connects} {
+ foreach {idx x} [$@wires list] {
+ if {[string compare [join $connects] [join [$x connects]]] == 0} {return $idx}
+ }
+ return -1
+}
+
+def Canvas reconnect_brkwires {type brk_quads obj} {
+ set k [$@objects search $obj]
+ foreach quad $brk_quads {
+ mset {from outlet to inlet} $quad
+ set orig_outlet $outlet; set orig_inlet $inlet
+ switch $type {
+ i {set orig_obj $to; set to $k; set inlet 0}
+ o {set orig_obj $from; set from $k; set outlet 0}
+ }
+ netsend [list .$self connect $from $outlet $to $inlet]
+ }
+ if {$type == "i"} {
+ netsend [list .$self connect $k 0 $orig_obj $orig_inlet]
+ } else {
+ netsend [list .$self connect $orig_obj $orig_outlet $k 0]
+ }
+ $self new_object_callback $obj
+
+}
+
+def Canvas expand_port {type k port} {
+ set obj [$@objects get $k]
+ mset {bx1 by1 bx2 by2} [$obj io_bbox $type $port]
+ mset {ox1 oy1 ox2 oy2} [$obj bbox]
+ mset ys [expr $oy2-$oy1]
+ mset {brk_wires brk_quads} [$self broken_wires $type $k $port $self]
+ switch $type {
+ i {mset {nx ny} [$self xy_snap $bx1 [expr $by1-25]]}
+ o {mset {nx ny} [$self xy_snap $bx1 [expr $by1+$ys+25]]}
+ }
+ foreach quad $brk_quads {$self disconnect $quad}
+ set reply [list $self reconnect_brkwires $type $brk_quads]
+ netsend [concat [list .$self obj $nx $ny] t a] $reply
+
+}
+
+def Canvas outlet_expand {k outlet} {set reconnect [$self broken_wires o $k $inlet]}
+
+def Canvas implicit_wires {objs} {
+ set l {}; set h $@objects
+ foreach obj $objs {
+ set k [$h search $obj]
+ for {set i 0} {$i < [$obj ninlets]} {incr i} {
+ set ws [$self com_wires i $k $i]; if {[llength $ws]} {foreach w $ws {lappend l $w}}
+ }
+ for {set o 0} {$o < [$obj noutlets]} {incr o} {
+ set ws [$self com_wires o $k $o]; if {[llength $ws]} {foreach w $ws {lappend l $w}}
+ }
+ }
+ #return [lsort -integer -unique $l]
+ return [lsort -unique $l]
+}
+
+def Canvas com_wires {type k port} {
+ set h $@objectsel; set obj [$@objects get $k]; set wires [$obj wires2]; set l {}
+ foreach wire $wires {
+ mset {f2 o2 t2 i2} [$wire connects]
+ if {$t2==$k && $i2==$port && $type=="i" && [$h exists $f2]} {lappend l $wire}
+ if {$f2==$k && $o2==$port && $type=="o" && [$h exists $t2]} {lappend l $wire}
+ }
+ return $l
+}
+
+def Canvas broken_wires {type k port canvas} {
+ set shash [$canvas objectsel]
+ set obj [[$canvas objects] get $k]
+ set wires [$obj wires2]; set brk_wires {}; set quads {}
+ foreach wire $wires {
+ mset {f2 o2 t2 i2} [$wire connects]
+ if {$t2==$k && $i2==$port && $type=="i" && ![$shash exists $f2]} {
+ lappend brk_wires $wire; lappend quads [$wire connects]
+ }
+ if {$f2==$k && $o2==$port && $type=="o" && ![$shash exists $t2]} {
+ lappend brk_wires $wire; lappend quads [$wire connects]
+ }
+ }
+ return [list $brk_wires $quads]
+}
+
+
+def Canvas selection_center {} {
+ set x 0; set y 0
+ foreach obj [$@objectsel values] {
+ mset {x1 y1} [$obj xy]
+ incr x $x1
+ incr y $y1
+ }
+ set n [$@objectsel size]
+ set x [expr $x / $n]
+ set y [expr $y / $n]
+ return [list $x $y]
+}
+
+# translate the key/idx in $@objects to key/idx in $@objectsel
+def Canvas idx_map {idx} {
+ set i 0; set obj [$@objects get $idx]
+ foreach sobj [$@objectsel values] {if {$obj == $sobj} {return $i}; incr i}
+ return -1
+}
+
+def Canvas subpatcherize_mkio {center iolist offset} {
+ mset {x y} $center; set inx 0; set outx 0
+ for {set i 0} {$i < [llength $iolist]} {incr i} {
+ mset {type io port dsp} [lindex $iolist $i]
+ if {$type == "i"} {
+ if {$dsp} {set inlet "inlet~"} {set inlet "inlet"}
+ netsend [list #X obj [expr ($inx+1)*100] 0 $inlet]
+ netsend [list #X connect $offset 0 $io $port]
+ incr inx
+ } else {
+ if {$dsp} {set outlet "outlet~"} {set outlet "outlet"}
+ netsend [list #X obj [expr ($outx+1)*100] [expr $y*2] $outlet]
+ netsend [list #X connect $io $port $offset 0]
+ incr outx
+ }
+ incr offset
+ }
+}
+
+def Canvas subpatcherize_iopos {orig io} {
+ set tab {}; set result {}
+ for {set x 0} {$x < [llength $orig]} {incr x} {
+ mset {from k1 io1 dsp} [lindex $orig $x]; mset {k2 io2} [lindex $io $x]
+ set obj1 [$@objects get $k1]
+ mset {x1 y1 x2 y2} [$obj1 io_bbox $from $io1]; set x1 [expr int($x1)]
+ lappend pos $x1; lappend tab [list $k1 $x1 [list $k2 $io2 $dsp]]
+ #lappend pos $x1; lappend tab [list $k1 $x1 [list $k2 $io2]]
+ }
+ set tab [lsort -index 1 -real $tab]; set foo ""
+ foreach item $tab {mset {k1 val foo2} $item; if {$foo2 != $foo} {lappend result $foo2}; set foo $foo2}
+ return $result
+}
+
+def Canvas subpatcherize {} {
+ set center [$self selection_center]
+ set rewire_off [llength [$@objectsel values]]
+ set ins {}; set outs {}; set toins {}; set fromouts {}; set broken {}; set iolist {}
+ foreach obj [$@objectsel values] {
+ for {set i 0} {$i < [$obj ninlets]} {incr i} {
+ mset {brk_wires brk_quads} [$self broken_wires i [$@objects search $obj] $i $self]
+ if {[llength $brk_wires]} {
+ foreach wire $brk_quads {
+ set out_obj_name [[$@objects get [lindex $wire 0]] text]
+ if {[regexp {~} $out_obj_name]} {set dsp 1} {set dsp 0}
+ lappend broken [concat i $wire $dsp]
+ }
+ }
+ }
+ for {set o 0} {$o < [$obj noutlets]} {incr o} {
+ mset {brk_wires brk_quads} [$self broken_wires o [$@objects search $obj] $o $self]
+ if {[llength $brk_wires]} {
+ foreach wire $brk_quads {
+ set out_obj_name [[$@objects get [lindex $wire 0]] text]
+ if {[regexp {~} $out_obj_name]} {set dsp 1} {set dsp 0}
+ lappend broken [concat o $wire $dsp]
+ }
+ }
+ }
+ }
+ # $broken stores totall number of broken connections, i= need [inlet] o = need [outlet]
+ foreach c $broken {
+ mset {type f o t i dsp} $c
+ if {$type == "i"} {
+ lappend ins [list $t $i];lappend toins [list o $f $o $dsp]
+ } else {
+ lappend outs [list $f $o]; lappend fromouts [list i $t $i $dsp]
+ }
+ }
+ # figures out the inlet/outlet positioning and num of in/outlet to create
+ set ins [$self subpatcherize_iopos $toins $ins]
+ set outs [$self subpatcherize_iopos $fromouts $outs]
+ # iolist stores in/outlets to be conected inside the subpatch
+ foreach in $ins {mset {idx p dsp} $in; lappend iolist [list i [$self idx_map $idx] $p $dsp]}
+ foreach out $outs {mset {idx p dsp} $out; lappend iolist [list o [$self idx_map $idx] $p $dsp]}
+ puts "\t \t Cutting..............."
+ $self cut
+ puts "\t \t Push.................."
+ netsend [list .$self "push"]
+ netsend [list #N canvas 0 0 450 300 sub 0] [list $self subpatcherize_id]
+ puts "\t \t Push clipboard........"
+ foreach mess [pd_mess_split [$::clipboard value]] {netsend $mess}
+
+ #creating in/outlets
+ $self subpatcherize_mkio $center $iolist $rewire_off
+ #netsend [list [concat #X restore $center pd sub]]
+ netsend [concat #X restore $center pd sub]
+ puts "\t \t Pop..................."
+ netsend [list .$self "pop"] [list $self subpatcherize_rewire $broken $ins $outs]
+}
+
+def Canvas subpatcherize_id {id} {set @subpatcherize_id $id}
+
+def Canvas subpatcherize_rewire {wires inlist outlist bogus} {
+ set obj $@subpatcherize_id
+ foreach wire $wires {
+ mset {type f o t i dsp} $wire
+ if {$type == "i"} {
+ set idx [lsearch $inlist [list $t $i $dsp]]
+ $self connect [list $f $o [$@objects search $obj] $idx]
+ } else {
+ set idx [lsearch $outlist [list $f $o $dsp]]
+ $self connect [list [$@objects search $obj] $idx $t $i]
+ }
+ }
+}
+
+def Canvas end_action {} {
+ switch -- $@action {
+ none {post "ending action 'none' makes no sense"}
+ default {$@action delete; set @action "none"}
+ }
+}
+
+proc shift? {f} {return [expr $f&1]}
+proc ctrl? {f} {return [expr $f&2]}
+proc alt? {f} {return [expr $f&4]}
+proc button_of {f} {
+# set f [expr $f>>8]
+# set b 1
+# while {[expr $f&1==0} {set f [expr $f>>1]}
+# return $f
+ return [expr $f>>8]
+}
+
+class_new FutureWire {View}
+def FutureWire init {canvas x y f target} {
+ super
+ set @canvas $canvas
+ mset {type from port} $target
+ switch $type {
+ outlet {
+ set @from $from; set @outlet $port
+ set @to "" ; set @inlet ""
+ set port_name ${from}o${port}
+ }
+ inlet {
+ set @from "" ; set @outlet ""
+ set @to $from; set @inlet $port
+ set port_name ${from}i${port}
+ }
+ }
+ mset {x y} [lmap / [rect_centre [[$@canvas widget] bbox $port_name]] [$@canvas zoom]]
+ set @x1 $x
+ set @y1 $y
+ $self motion $@x1 $@y1 $f $target
+}
+def FutureWire motion {x y f target} {
+ set @x2 $x
+ set @y2 $y
+ mset [list type foo bar] $target
+ $self draw
+}
+def FutureWire unclick {x y f target} {
+ mset [list type foo bar] $target
+ mset {obj iox ioy io idx} [$@canvas iohilite]
+ if {$obj != -1} {
+ switch $io {i {set type "inlet"} o {set type "outlet"}}
+ set target [list $type $obj $idx]
+ }
+ switch $type {
+ outlet {mset [list type @from @outlet] $target}
+ inlet {mset [list type @to @inlet] $target}
+ default {}
+ }
+ set from_idx [[$@canvas objects] search $@from]
+ set to_idx [[$@canvas objects] search $@to]
+ if {$from_idx >= 0 && $to_idx >= 0 && $@from != $@to} {
+ $@canvas connect [list $from_idx $@outlet $to_idx $@inlet]
+ }
+ if {![shift? $f]} {$@canvas end_action}
+}
+def FutureWire draw {} {
+ $self item WIRE line [xys $@x1 $@y1 $@x2 $@y2] -dash {4 4 4 4} -fill [$self look dash] -smooth yes
+}
+
+class_new GopRect {View}
+
+def GopRect init {canvas rect} {
+ set @canvas $canvas
+ set @rect $rect
+}
+
+def GopRect draw {} {
+ $self item GOPRECT rectangle $@rect -outline [$self look fg]
+}
+
+class_new SelRect {View}
+def SelRect init {canvas x y bf target} {
+ super
+ set @x1 $x
+ set @y1 $y
+ set @canvas $canvas
+ $self motion $x $y 0 $target
+}
+def SelRect motion {x y f target} {
+ set @x2 $x
+ set @y2 $y
+ $self draw
+}
+def SelRect unclick {x y f target} {
+ $self motion $x $y 0 $target
+ set sel {}
+ set c [$@canvas widget]
+ mset {x1 y1 x2 y2} [lmap * [list $@x1 $@y1 $@x2 $@y2] [$@canvas zoom]]
+ set sel [$c find overlapping $x1 $y1 $x2 $y2]
+ set selrect_index [lsearch $sel [$c find withtag selrect]]
+ set sel [lreplace $sel $selrect_index $selrect_index]
+ if {[llength $sel]} {
+ set objects {}
+ #set wires {}
+ foreach tag $sel {
+ if {[regexp {^[xo]?[0-9a-f]{6,8}} [$c gettags $tag] id]} {
+ if {[$@canvas == $id]} {continue}
+ if {[[$id class] <= Box]} {lappend objects $id}
+ #elseif {[[$id class] <= Wire]} {lappend wires $id}
+ }
+ }
+ set objects [lsort -unique $objects]
+ #set wires [lsort -unique $wires]
+ set objects2 {}
+ #so that objects in gop won't get selected...
+ foreach obj $objects {if {[$obj canvas] == $@canvas} {lappend objects2 $obj}}
+ $@canvas selection+= $objects2
+ #$@canvas selection_wire+= $wires
+ }
+ $@canvas selection_wire+= [$@canvas implicit_wires $objects]
+ set _($@canvas:keynav_tab_sel) "wire"
+ $@canvas end_action
+
+}
+def SelRect draw {} {
+ $self item RECT line [list $@x1 $@y1 $@x2 $@y1 $@x2 $@y2 $@x1 $@y2 $@x1 $@y1] \
+ -fill [$self look rect] -dash {3 3 3 3} -dashoffset 3
+}
+
+def Canvas click {x y f target} {
+ if {[winfo exists .completion]} {
+ raise .completion
+ focus .completion.comp
+ return
+ }
+ mset {type id detail} $target
+ set c [$self widget]
+ focus $c
+ set @click_at [list $x $y]
+ if {$f&8} {if {$id == ""} {set id $self}; $self right_click $id $x $y; return}
+ if {!$@editmode} {$self click_runmode $id $x $y $f $target; return}
+ set in_selection [expr [$@objectsel search $id]>=0]
+ switch $@action {
+ mouse_copy {$self move_selection}
+ }
+ switch $type {
+ outlet {}
+ inlet {}
+ object {$self click_on_object $id $f}
+ wire {$self click_on_wire $id $f $x $y}
+ nothing {
+ #$self deselect_all
+ if {[lindex $@iohilite 0] == -1} {
+ $self click_on_nothing $f $target $x $y
+ return
+ }
+ }
+ label {$self click_on_object $id $f}
+ default {error "BORK: $type"}
+ }
+ if {$@iohilite != "" && $type != "wire"} {
+ mset {obj iox ioy io idx} $@iohilite
+ if {$obj < 0} {return}
+ switch $io {
+ i {set type "inlet"}
+ o {set type "outlet"}
+ }
+ if {$@action == "none" && [$obj canvas] == $self} {
+ set @action [FutureWire new $self $iox $ioy $f [list $type $obj $idx]]
+ }
+ return
+ }
+}
+
+def Canvas click_runmode {id x y f target} {
+ foreach obj [$self selection] {if {[[$obj class] <= AtomBox]} {$obj unedit}}
+ $self deselect_all
+ #if {$@focus != ""} {if {[[$@focus class] <= TextBox]} {$self selection-= $@focus;$@focus unedit}}
+ if {[llength $id]} {
+ if {[$id class] != "Canvas"} {
+ $id click $x $y $f $target
+ } else {
+ if {[$id subpatch]} {
+ if {![$id mapped]} {$id popup_open} else {if {![$id gop]} {raise .$id}}
+ }
+ }
+ }
+}
+
+def Canvas click_on_object {id f} {
+ set c [$self widget]; set text $c.${id}text
+ # so that if one clicks on the objectbox when editing the objectname, the focus won't get lost
+ if {[winfo exists $text]} {focus $text; return}
+ switch [expr $f&255] {
+ 0 {
+ if {[$self action] == "mouse_copy"} {$self action= "none"; return}
+ # if $id is the content of GOP
+ if {[$id canvas] != $self} {
+ set obj [$id get_parent_gop $self]
+ } else {set obj $id}
+ if {[$@objectsel search $obj] < 0 || [$@objectsel size] == 0} {
+ $self deselect_all
+ $self selection+= $obj
+ set @action edit
+ } else {set @action edit}
+ }
+ 1 {
+ if {[$@objectsel search $id] < 0} {
+ $self selection+= $id
+ } else {
+ $self selection-= $id
+ }
+ }
+ 2 {
+ if {![llength [$id wires2]]} {return}
+ $self deselect_all
+ $self selection+= $id
+ $self remove_obj_from_path
+ }
+ 3 {
+ if {[$id canvas] != $self} {
+ set obj [$id get_parent_gop $self]
+ } else {set obj $id}
+ if {![$@objectsel size]} {$self selection+= $obj}
+ if {[$@objectsel search $obj] < 0} {
+ $self deselect_all
+ $self selection+= $obj
+ }
+ $self action= "mouse_copy"
+ }
+ }
+}
+def Canvas click_on_wire {id f x y} {
+ set obj_selection [$self selection]
+ if {[llength $obj_selection]} {$self selection-= $obj_selection}
+ set @keynav_tab_sel "object"
+ switch [expr $f&255] {
+ 0 {$self selection_wire= $id}
+ 1 {$self selection_wire+= $id}
+ 2 {
+ set c [$self widget]
+ set wire [$id connects]
+ $self disconnect $wire
+ set from [$@objects get [lindex $wire 0]]; set outlet [lindex $wire 1]
+ set to [$@objects get [lindex $wire 2]]; set inlet [lindex $wire 3]
+ set opos [lmap / [rect_centre [$c bbox ${from}o${outlet}]] [$self zoom]]
+ set ipos [lmap / [rect_centre [$c bbox ${to}i${inlet}]] [$self zoom]]
+ set pos [list $x $y]
+ if {[distance $pos $opos] > [distance $pos $ipos]} {
+ mset {x1 y1} $ipos
+ set target [list outlet $from $outlet]
+ } else {
+ mset {x1 y1} $opos
+ set target [list inlet $to $inlet]
+ }
+ set @action [FutureWire new $self $x1 $y1 $f $target]
+ }
+ }
+}
+
+def Canvas click_on_nothing {f target x y} {
+ # this cget check actually saves a full tk redraw
+ if {[[$self widget] cget -cursor] != {}} {[$self widget] configure -cursor {}}
+ if {$@focus != ""} {if {[[$@focus class] <= TextBox]} {$@focus unedit}}
+ if {$@action == "insert"} {return}
+ if {![expr $f&255]} {
+ $self deselect_all
+ #$self click_deselect_io
+ }
+ switch $@action {
+ edit {}
+ move {}
+ none {}
+ insert {}
+ chain_obj {}
+ imove {}
+ mouse_copy {}
+ default {$@action unclick $x $y $f $target}
+ }
+ set @action [SelRect new $self $x $y $f $target]
+}
+
+def Canvas right_click {id x y} {
+ set c [$self widget]
+ set @insert_x $x; set @insert_y $y
+ if {$id != $self} {set id [$self gop_target $id]}
+ $self popup $id [winfo pointerx $c] [winfo pointery $c]
+}
+
+def Canvas unclick {x y f target} {
+ set c [$self widget]
+ mset {type id detail} $target
+ if {$@editmode} {
+ switch $@action {
+ edit {
+ if {[$id canvas] != $self} {
+ set obj [$id get_parent_gop $self]
+ } else {set obj $id}
+ if {[$id class] == "Canvas"} {if {[$id text] == "graph"} {set @action none; return}}
+ set focus [$self focus]
+ if {$focus != ""} {if {[[$focus class] <= TextBox]} {$focus unedit}}
+ $obj edit; set @action none; $obj changed action
+ }
+ move {$self unclick_move}
+ none {}
+ insert {}
+ chain_obj {}
+ mouse_copy {$self mouse_copy}
+ imove {$self unclick_move}
+ default {$@action unclick $x $y $f $target}
+ }
+ } else {$self unclick_runmode $target $f $x $y}
+ $self adjust_scrollbars
+ #$self checkgeometry
+}
+
+def Canvas unclick_move {} {
+ $self move_selection
+ set @action none
+}
+
+def Canvas move_selection {} {
+ foreach obj [$@objectsel values] {
+ if {![[$obj class] <= Box]} {
+ puts "Canvas unclick warning: trying to move non-Box explicitly"
+ continue
+ }
+ mset {x1 y1} [$obj xy]
+ switch $@action {
+ mouse_copy {}
+ default {$obj position= [$obj backupxy]}
+ }
+ $obj moveto $x1 $y1
+ if {[$obj edit?]} {focus [[$obj canvas] widget].${obj}text}
+ }
+ set objs [$@objectsel values]
+}
+
+def Canvas unclick_runmode {target f x y} {
+ if {[$self focus] != ""} {[$self focus] unclick $x $y $f $target}
+ mset {type id detail} $target
+ if {$id != ""} {
+ if {[$id class] == "Array"} {$id unclick $x $y $f $target; return}
+ }
+}
+
+def Canvas get_bbox {} {return $@bbox}
+
+if {$have_expand} {
+ def Canvas notice {origin args} {$self child_changed $origin {expand}$args}
+} else {
+ def Canvas notice {origin args} {eval [concat [list $self child_changed $origin] $args]}
+}
+
+def Canvas tab_jump {} {
+ if {![$@objects size]} {return}
+ set @keynav 1
+ set olength [$@objectsel size]
+ set wlength [ $@wiresel size]
+ if {$@keynav_tab_sel == "object"} {
+ if {[$@wires size]} {set @keynav_tab_sel "wire"}
+ } else {
+ set @keynav_tab_sel "object"
+ }
+ switch $@keynav_tab_sel {
+ object {$self tab_jump_object}
+ wire {$self tab_jump_wire}
+ }
+}
+
+def Canvas tab_jump_wire {} {
+ # if no selection done by the mouse
+ if {![$@wiresel size]} {
+ # see if the selected object has wire, if yes, use it
+ # if keynav_current is already a wire, do nothing
+ if {[$@keynav_current class] != "Wire"} {
+ #use the last key selected wire as start if there is one
+ if {$@keynav_last_wire != 0} {
+ $self deselect_all
+ set @keynav_current $@keynav_last_wire
+ } else {
+ if {[llength [$@keynav_current wires2]]} {
+ $self deselect_all
+ set @keynav_current [lindex [$@keynav_current wires2] 0]
+ set @keynav_last_wire $@keynav_current
+ } else {
+ # check if the canvas has wires, if yes, use it
+ if {[$@wires size]} {
+ $self deselect_all
+ set @keynav_current [lindex [$@wires values] 0]
+ set @keynav_last_wire $@keynav_current
+ } else {return}
+
+ }
+ }
+ }
+ }
+ $self selection_wire= $@keynav_current
+}
+
+def Canvas tab_jump_object {} {
+ set olength [$@objectsel size]
+ # if there is no selection done by mouse
+ if {!$olength} {
+ # if keynav_current is 0, aka the start of key navigation
+ if {$@keynav_current == 0} {
+ if {[$@objects size]} {set @keynav_current [lindex [$@objects values] 0]} else {return}
+ } else {
+ # if the keynav_current is a wire, set keynav_current to a object
+ if {[$@keynav_current class] == "Wire"} {
+ set @keynav_last $@keynav_current
+ $self deselect_all
+ # use the last key selected obj as the start if there is one
+ if {$@keynav_last_obj != 0} {
+ set @keynav_current $@keynav_last_obj
+ } else {
+ set @keynav_current [lindex [$@keynav_current report] 0]
+ set @keynav_last_obj $@keynav_current
+ }
+ }
+ }
+ } elseif {$olength == 1} {
+ set @keynav_current [lindex [$@objectsel values] 0]
+ $self deselect_all
+ } else {
+ $self deselect_all
+ set @keynav_current [$@objects get 0]
+ set @keynav_last_obj $@keynav_current
+ }
+ $self selection= $@keynav_current
+}
+
+def Canvas key_nav_up {} {$self key_nav +1 -1 0}
+def Canvas key_nav_down {} {$self key_nav -1 +1 0}
+def Canvas key_nav_right {} {$self key_nav -1 -1 0}
+def Canvas key_nav_left {} {$self key_nav +1 +1 0}
+def Canvas key_nav_up_shift {} {$self key_nav +1 -1 1}
+def Canvas key_nav_down_shift {} {$self key_nav -1 +1 1}
+def Canvas key_nav_right_shift {} {$self key_nav -1 -1 1}
+def Canvas key_nav_left_shift {} {$self key_nav +1 +1 1}
+
+def Canvas key_nav {du dv shift} {
+ if {$@keynav_shift && !$shift} {}
+ set @keynav_shift $shift
+ if {[$@objectsel size] > 1} {
+ if {[llength $@keynav_iosel_i] > 0 || [llength $@keynav_iosel_o] > 0} {
+ #$self deselect_all
+ }
+ }
+ if {!$@keynav} {$self tab_jump}
+ switch $@keynav_tab_sel {
+ object {
+ set @keynav_next [$self quadrant $du $dv [$@objects values]]
+ if {!$shift} {
+ $self selection-= $@keynav_current
+ $@keynav_current selected?= 0
+ set @keynav_last_obj $@keynav_next
+ }
+ if {[$@objectsel search $@keynav_next] < 0} {$self selection+= $@keynav_next}
+ }
+ wire {
+ #$@keynav_current selected?= 0
+ set @keynav_next [$self quadrant $du $dv [$@wires values]]
+ if {!$shift} {
+ $self selection_wire-= $@keynav_current
+ $@keynav_current selected?= 0
+ set @keynav_last_wire $@keynav_next
+ }
+ if {[$@wiresel search $@keynav_next] < 0} {$self selection_wire+= $@keynav_next}
+ }
+ }
+ #$self selection+= $@keynav_next
+ set @keynav_current $@keynav_next
+}
+
+def Canvas victim {} {
+ if {[$@objectsel size]} {return [$@objectsel values]}
+ if {[string compare $@keynav_current 0]} {return {}}
+ return $@keynav_current
+}
+
+def Canvas key_nav_ioselect {} {
+ if {![$@objectsel size]} {return}
+ set var [lindex [$@objectsel values] end]
+ if {$@keynav_iosel != $var} {set @keynav_iocount 0}
+ if {$@keynav_port != 0 && $@keynav_iosel == $var} {
+ #set hilitebox $@keynav_port
+ foreach io $@keynav_port2 {[$self widget] delete ${io}b}
+ }
+ set obj [lindex [$@objectsel values] 0]
+ set ins [$obj ninlets]
+ set outs [$obj noutlets]
+ set ports {}; set ports2 {}; set ports3 {}
+ for {set i 0} {$i < $ins} {incr i} {lappend ports ${obj}i${i}; lappend ports2 "i"; lappend ports3 $i}
+ for {set i 0} {$i < $outs} {incr i} {lappend ports ${obj}o${i}; lappend ports2 "o"; lappend ports3 $i}
+ #incr @keynav_iocount
+ if {$@keynav_iocount >= [llength $ports]} {set @keynav_iocount 0}
+ set port [lindex $ports3 $@keynav_iocount]
+ set type [lindex $ports2 $@keynav_iocount]
+ set @keynav_port ${obj}${type}${port}
+ set @keynav_port2 {}
+ # @keynav_port stores the current hilited in/outlets
+ # @keynav_ports stores the current hilited in/outlets if there are multiple objects
+ # @keynav_iosel_i stores the selected inlets
+ # @keynav_iosel_o stores the selected outlets
+ foreach object [$@objectsel values] {
+ if {$@keynav_iosel != $var} {set @keynav_iosel $var}
+ switch $type {
+ i {
+ if {[lsearch $@keynav_iosel_i $object] == -1} {
+ lappend @keynav_iosel_i $object
+ set find [lsearch $@keynav_iosel_o $object]
+ if {$find >= 0} {set @keynav_iosel_o [lreplace $@keynav_iosel_o $find $find]}
+ }
+ }
+ o {
+ if {[lsearch $@keynav_iosel_o $object] == -1} {
+ lappend @keynav_iosel_o $object
+ set find [lsearch $@keynav_iosel_i $object]
+ if {$find >= 0} {set @keynav_iosel_i [lreplace $@keynav_iosel_i $find $find]}
+ }
+ }
+ }
+ mset {x y x1 y1} [[$self widget] bbox ${object}${type}${port}]
+ lappend @keynav_port2 ${object}${type}${port}
+ set _($object:ioselect) [list [lindex $ports3 $@keynav_iocount] [lindex $ports2 $@keynav_iocount]]
+ #set _($object:ioselect) [lindex $ports3 $@keynav_iocount]
+ $object hilite_io [lindex $ports2 $@keynav_iocount] [expr $x/$@zoom] [expr $y/$@zoom]
+ }
+ incr @keynav_iocount
+
+}
+
+def Canvas keyboard_mode {} {
+ post "loading keyboard-mode...."
+ if {[file exists kb-mode.tcl]} {
+ package require kb-mode
+ $@runcommand defs
+ if {![info exists @kbcursor]} {set @kbcursor [kb-mode_init $self]}
+ puts "cursor::: $@kbcursor"
+ }
+}
+
+def Canvas keyboard_mode_exit {} {
+ post "exiting keyboard-mode...."
+ package forget kb-mode
+ remove_callback kb-mode
+ $@runcommand defs
+ $@kbcursor delete
+ read_ddrc
+ remove_callback "kb-mode"
+ unset @kbcursor
+}
+
+def Canvas keyprefix {} {
+ if {!$@keyprefix} {set @keyprefix 1} else {set @keyprefix 0}
+}
+
+def Canvas click_deselect_io {} {
+ if {[llength $@keynav_iosel_i] || [llength $@keynav_iosel_o]} {
+ if {!$@iosel_deselect} {set @iosel_deselect 1} else {$self dehilite_io; set @iosel_deselect 0}
+ } else {
+ $self dehilite_io
+ }
+}
+
+def Canvas dehilite_io {} {
+ foreach io [concat $@keynav_iosel_i $@keynav_iosel_o] {
+ puts "$io is a [$io class]"
+ set box $_($io:ioselect)
+ set type [lindex $_($io:ioselect) 1]
+ set port [lindex $_($io:ioselect) 0]
+ set tag ${io}${type}${port}
+ [$self widget] delete ${tag}b
+ set _($io:ioselect) {}
+ }
+ set @keynav_iosel_i {}
+ set @keynav_iosel_o {}
+ set @keynav_port 0
+ set @keynav_iocount 0
+}
+
+def Canvas incr_scale {} {$self scale out}
+def Canvas decr_scale {} {$self scale in}
+
+def Canvas scale {mode} {
+ set s $::scale_amount
+ switch $mode { in { set s [expr 1/$s] }}
+ set sel [$@objectsel values]
+ if {![llength $sel]} {set sel [$@objects values]}
+ foreach child $sel {
+ mset {x y} [$child xy]
+ set x1 [expr $x*$s]
+ set y1 [expr $y*$s]
+ $child position= [list $x1 $y1]
+ netsend [list .$self object_moveto $child $x1 $y1]
+ }
+ foreach child $sel {$child changed_wires}
+}
+
+def Canvas incr_zoom {} {$self zooming in}
+def Canvas decr_zoom {} {$self zooming out}
+def Canvas zooming {mode} {
+ global zoom bar
+ set spinbox .$self.bbar.scale
+ set val [string trimright [$spinbox get] %]
+ set i [lsearch $zoom(canned) $val]
+ set end [expr [llength $zoom(canned)] - 1]
+ switch -regexp $mode {
+ in|up {if {$i<$end} {incr i +1}}
+ out|down {if {$i>0} {incr i -1}}
+ }
+ set per [lindex $zoom(canned) $i]
+ $spinbox set $per%
+ set @zoom [expr $per/100.0] ;# @zoom must be float, not int
+ #$self propagate_zoom $@zoom
+ $self redraw
+ if {[$self look gridstate]} {if {$@editmode} {$@grid erase}}
+ foreach child [$@objects values] {if {[$child class] == "Canvas" && [$child gop]} {$child all_changed}}
+}
+
+def Canvas propagate_zoom {zoom} {
+ foreach child [$@objects values] {
+ if {[$child class] == "Canvas"} {
+ set @zoom $zoom
+ $child propagate_zoom $zoom
+ }
+ }
+}
+
+#-----------------------------------------------------------------------------------#
+set lastcanvasconfigured ""
+set lastcanvasconfiguration ""
+
+def Canvas checkgeometry {} {
+ set topname .$self
+ set boo [winfo geometry $topname.c]
+ set boo2 [wm geometry $topname]
+ global lastcanvasconfigured lastcanvasconfiguration
+ if {$topname != $lastcanvasconfigured || $boo != $lastcanvasconfiguration} {
+ set lastcanvasconfigured $topname
+ set lastcanvasconfiguration $boo
+ }
+}
+#-----------------------------------------------------------------------------------#
+def Canvas selection_move {dx dy} {
+ $@history atomically [list move] {
+ $self selection_move2 $dx $dy
+ }
+}
+def Canvas selection_move2 {dx dy} {
+ if {![$self editmode]} {return}
+ foreach o [$@objectsel values] {
+ mset {x1 y1} [$o xy]
+ if {[[$o class] <= Box]} {
+ $o moveto [expr $x1+$dx] [expr $y1+$dy]
+ } else {
+ puts "selection_move: $o is not a Box, it's a [$o class]"
+ }
+ }
+}
+
+def Canvas key {x y key iso shift} {
+ global tooltip; if {$tooltip ne ""} {$tooltip delete; set tooltip ""}
+ #if {[modes_callback $self "key" $x $y $key $iso $shift]} {return}
+ #if {[$self focus] != ""} {[$self focus] key $key $shift}
+ #if {$iso != ""} {scan $iso %c key}
+ #set focus [$self focus]
+ if {!$@editmode && [llength [$self selection]] == 1} {
+ set obj [$self selection]
+ if {[[$obj class] <= AtomBox]} {
+ if {[regexp {^[a-zA-Z0-9~/\._]{1}$} $key]} {$obj text= $key} {return}
+ $obj edit
+ $obj clear 0
+ return
+ }
+ }
+ if {$shift} {
+ if {[$self look snap_grid]} {set motion [expr [$self look grid_size]*2]} {set motion 10}
+ } else {
+ if {[$self look snap_grid]} {set motion [$self look grid_size]} {set motion 1}
+ }
+ set n [$@objectsel size]
+ switch -regexp -- $key {
+ BackSpace|Delete|KP_Delete {$self delete_selection}
+ Up {if {$n} {$self arrow_key 0 -$motion} else {$self scroll y -$motion}}
+ Down {if {$n} {$self arrow_key 0 +$motion} else {$self scroll y +$motion}}
+ Left {if {$n} {$self arrow_key -$motion 0} else {$self scroll x -$motion}}
+ Right {if {$n} {$self arrow_key +$motion 0} else {$self scroll x +$motion}}
+ Tab {$self tab_jump}
+ Return {$self return_key $x $y $key $iso $shift}
+ F1 {$self deselect_all}
+ F2 {set @keynav 0; $@active hide}
+ default {}
+ }
+}
+
+def Canvas return_key {x y key iso f} {
+ mset {type id detail} [$self identify_target $x $y $f]
+ if {![llength $@keynav_iosel_i] && ![llength $@keynav_iosel_o]} {
+ if {[$@objectsel size] == 1} {
+ mset {bx1 by1 bx2 by2} [[$self selection] bbox]
+ set x1 [expr ($bx1+$bx2)/2]; set y1 [expr ($by1+$by2)/2]
+ $self click_wrap $x1 $y1 1 $f
+ $self unclick_wrap $x1 $y1 1 $f
+ }
+ } else {
+ foreach out_obj $@keynav_iosel_o {
+ set from [$@objects search $out_obj]
+ set outlet [lindex $_($out_obj:ioselect) 0]
+ foreach in_obj $@keynav_iosel_i {
+ set to [$@objects search $in_obj]
+ set inlet [lindex $_($in_obj:ioselect) 0]
+ $self connect [list $from $outlet $to $inlet]
+ }
+ }
+ $self dehilite_io
+ }
+
+}
+
+def Canvas arrow_key {val1 val2} {
+ if {![$self editmode]} {
+ if {[$@objectsel size] == 1} {
+ set o [$@selection values]
+ if {[[$o class] <= IEMGUI] || [[$o class] == FloatBox]} {$o key_incr $val1 $val2}
+ }
+ } else {
+ $self selection_move $val1 $val2
+ }
+}
+
+def Canvas clear_selection {} {
+ if {[$@objectsel size] > 0 || [$@wiresel size] > 0} {
+ $self deselect_all
+ $self dehilite_io
+ }
+ if {$@keynav} {
+ set @keynav 0
+ #bogus switch so that keynav remains the same next time..
+ if {$@keynav_tab_sel == "object"} {set @keynav_tab_sel "wire"} {set @keynav_tab_sel "object"}
+ }
+}
+
+#-----------------------------------------------------------------------------------#
+def Canvas keynav_current {} {return $@keynav_current}
+def Canvas keynav_current= {current} {
+ set @keynav_current $current
+ switch [$current class] {
+ Wire {set @keynav_last_wire $current}
+ default {set @keynav_last_obj $current}
+ }
+}
+def Canvas keynav {} {return $@keynav}
+def Canvas keyup {x y key iso shift} {
+ if {$iso != ""} {scan $iso %c key}
+ if {$::macro_state} {$::macro state= 1; set ::macro_state 0 }
+ $@active draw
+}
+
+class_new Active {View}
+def Active init {canvas} {
+ super
+ set @canvas $canvas
+ set @length 3
+ set @length2 10
+}
+def Active draw {} {
+ set current [$@canvas keynav_current]
+ if {$current == ""} {return}
+ if {![string compare $current 0]} {return}
+ set col [$self look selectframe]
+ if {[$@canvas keynav]} {
+ if {[$current class] == "Wire"} {
+ $self item_delete
+ set i 0
+ foreach side {1.6 -1.6} {
+ mset {ax1 ay1 ax2 ay2} [$current bbox]
+ set t [expr atan2($ay2-$ay1, $ax2-$ax1)]
+ set cx1 [expr $ax1 + (($ax2-$ax1)* 0.15)]
+ set cy1 [expr $ay1 + (($ay2-$ay1)* 0.15)]
+ set cx2 [expr ($@length * cos($t+$side)) + $cx1]
+ set cy2 [expr ($@length * sin($t+$side)) + $cy1]
+
+ for {set n 0} {$n < 2} {incr n} {
+ set angle [lindex {45 90 -45 -90} [expr $n+$i]]
+ mset {ax1 ay1 ax2 ay2} [$current bbox]
+ set t [expr atan2($ay2-$ay1, $ax2-$ax1)]
+ set bx1 [expr $ax1 + (($ax2-$ax1)* 0.15)]
+ set by1 [expr $ay1 + (($ay2-$ay1)* 0.15)]
+ set bx2 [expr ($@length2 * cos($t+$angle)) + $bx1]
+ set by2 [expr ($@length2 * sin($t+$angle)) + $by1]
+ set line [list $cx2 $cy2 $bx2 $by2]
+ $self item LINE$angle line $line -fill $col -width 2
+ }
+ set i [expr $i+2]
+ }
+ } else {
+ $self item_delete
+ mset {x y} [lmap - [$current xy] 5]
+ set line1 [list $x $y $x [expr $y + $@length2]]
+ set line2 [list $x $y [expr $x + $@length2] $y]
+ $self item LINE1 line $line1 -fill $col -width 2
+ $self item LINE2 line $line2 -fill $col -width 2
+
+ }
+ } else {$self hide}
+}
+def Active hide {} {$self item_delete}
+def Active bbox {} {
+ set current [$@canvas keynav_current]
+ set l [$current xy]
+ concat $l $l ;# happy now??
+}
+
+def Canvas update_Active {item} {$self keynav_current= $item}
+
+#-----------------------------------------------------------------------------------#
+class_new Box {View}
+
+def Box init {{mess {}}} {
+ super
+ # @wires2 stores the connections to and from a object
+ set @wires2 {}
+ $self reinit $mess
+}
+
+def Box delete {} {if {$@canvas != ""} {[$@canvas objects] unset $@index}; super}
+
+def Box remove_braces {str} {
+ # this hack is to remove the "\" in the text
+ regsub -all {\\} $str "" text
+ return $text
+}
+
+def Box reinit {mess} {
+ global classinfo fields
+ if {[$::macro state] && [llength $mess] > 4} {$::macro append_ref $mess}
+ if {![llength $mess]} {return} ;# what?
+ if {[lindex $mess 1] == "obj"} {set i 4} else {set i 1}
+ set @pdclass [lindex $mess $i]
+ if {[info exists fields($@pdclass)]} {
+ set i 0
+ foreach f $fields($@pdclass) {set _($self:$f) [lindex $mess $i]; incr i}
+ } else {
+ set @text [$self remove_braces [join [lrange $mess 4 end]]]
+ }
+ $self outside_of_the_box
+}
+
+def Box update_size {} {}
+
+# will be so that @wires are updated correctly without breaking encapsulation
+def Box connect_out {} {}
+def Box connect_in {} {}
+
+def Box draw {} {
+ $self draw_box
+ if {[$@canvas show_id]} {$self draw_id} {$self item_delete ID}
+ [[$self get_canvas] widget] raise $self
+ $self update_hilite_io
+# if {[$self class] == "Canvas"} {$self restack}
+ if {[info exists @elapsed]} {
+ mset {x1 y1 x2 y2} [$self bbox]
+ $self item ELAPSED text [l+ {10 1} [list $x1 $y2]] -anchor nw -fill "#008800" \
+ -text $@elapsed -font {{DejaVu Sans Mono} -8}
+ }
+}
+
+def Box elapsed {f} {
+ set @elapsed $f
+ $self changed
+}
+
+def Canvas get_elapsed {} {netsend [list .$self get_elapsed]}
+
+def Canvas show_id {} {return $@show_id}
+def Canvas show_id= {val} {set @show_id $val; $self redraw}
+def Canvas id_toggle {} {if {$@show_id} {set @show_id 0} {set @show_id 1}; $self redraw}
+
+def Box draw_id {} {
+ set id [$self index]:
+ mset {x y} [$self xy]
+ set fw [font measure [$self look font] 0]
+ if {[$@canvas editmode]} {
+ set col [complement [$@canvas look bgedit]]
+ } else {set col [complement [$@canvas look bgrun]]}
+ $self item ID text [list [expr $x-([string length $id]*$fw)] [expr $y+2]] \
+ -font [$self look font] -text $id \
+ -fill $col -anchor nw
+}
+
+def Box draw_box {} {}
+def Box edit {} {}
+def Box unedit {} {}
+
+def Box bbox {} {
+ mset {x y} [$self xy]
+ set xs $@xs
+ set ys $@ys
+ list $x $y [expr {$x+$xs}] [expr {$y+$ys}]
+}
+
+def Box io_bbox {type port} {
+ mset {x1 y1 x2 y2} [$self bbox]
+ set xs [expr {$x2-$x1}]
+ # method calls aren't as fast as we'd want them to be.
+ #set iowidth [$self look iowidth]
+ #set fy [$self look iopos]
+ set iowidth 7
+ set fy -1
+ switch $type {
+ o {set n $@noutlets; set y [expr {$y2+$fy }]}
+ i {set n $@ninlets; set y [expr {$y1-$fy-1}]}
+ }
+ set nplus [expr {$n==1 ? 1 : $n-1}]
+ set onset [expr {$x1+($xs-$iowidth)*$port/$nplus}]
+ set points [list $onset $y [expr {$onset+$iowidth}] $y]
+ return $points
+}
+
+
+def Box ioselect= {type port} {set @ioselect [list $type $port]}
+def Box ioselect {} {return $@ioselect}
+
+def Box wires2 {} {return $@wires2}
+def Box wires2+= {val} {if {[lsearch $@wires2 $val] < 0} {lappend @wires2 $val}}
+
+def Box changed_wires {} {foreach wire $@wires2 {$wire changed}}
+
+def Box delete_wire {wire} {
+ set find [lsearch $@wires2 $wire]
+ if {$find != -1} {set @wires2 [lreplace $@wires2 $find $find]}
+}
+
+def Box move {dx dy} {
+ set @x1 [expr {$@x1+$dx}]; set @y1 [expr {$@y1+$dy}]
+ set zoom [$@canvas zoom]
+ $self changed ;# until we find a way to avoid rounding errors on [$@canvas widget] move.
+ $self changed_wires
+}
+
+# temporary hack... only used during the moving of objects.
+def Box backupxy= {xy} {set @backupxy $xy}
+def Box backupxy {} {return $@backupxy}
+
+# the only one sending to the server.
+# View position= is when getting position from server.
+# View xy is virtual (for GOP)
+def Box moveto {x1 y1} {
+ netsend [list .$@canvas object_moveto $self $x1 $y1]
+ [$@canvas history] add [list $self moveto $@x1 $@y1]
+ if {[$self class] == "Canvas"} {
+ if {[$self gop] && ![winfo exists .$self.c]} {foreach x $@visibles {$x changed}}
+ }
+ set @x1 $x1
+ set @y1 $y1
+ $self changed
+ $self draw_wires
+}
+
+def Box draw_io2 {which n color} {
+ for {set i 0} {$i<$n} {incr i} {
+ set points [$self io_bbox $which $i]
+ $self item [list $which$i $which] rectangle $points -outline $color -fill $color -width 1
+ [[$self get_canvas] widget] raise $self$which$i
+ }
+}
+
+def Box draw_io {} {
+ $self draw_io2 i $@ninlets [$self look inletfg]
+ $self draw_io2 o $@noutlets [$self look outletfg]
+}
+
+def Box tips= {tips} {set @tips $tips}
+
+def Box tip {type port} {
+ if {[info exists @tips]} {
+ set tips $@tips
+ } else {
+ netsend [list .$@canvas object_get_tips $self]
+ #after 500 $self tip $type $port
+ set tips ""
+ }
+ switch $type {
+ i {return "inlet $port: [lindex $tips $port]"}
+ o {return "outlet $port"}
+ }
+}
+
+# type is i or o
+def Box hilite_io {type x y} {
+ mset {x1 y1 x2 y2} [$self bbox]
+ set xs [expr $x2-$x1]
+ set c [$@canvas widget]
+ switch $type {i {set ports $@ninlets} o {set ports $@noutlets}}
+ set port -1
+ set iowidth [$self look iowidth]
+
+ for {set n 0} {$n<$ports} {incr n} {
+ set tag $self$type$n
+ set area [lmap / [$c bbox $self$type$n] [$@canvas zoom]]
+ set center [expr ([lindex $area 2] + [lindex $area 0]) / 2 ]
+ set dist [expr abs($x - $center)]
+ if {$dist < [expr ($iowidth/2)+5] && $dist > 0} {set port $n}
+ }
+
+ if {$ports==0 | $port==-1} return
+ if {$port >= $ports} {set port [expr $ports-1]}
+ $self hilite_io_2 $type $port
+ if {[$self look tooltip]} {$@canvas show_tooltip $x $y [$self tip $type $port] $type}
+ return $port
+}
+
+def Box update_hilite_io {} {
+ if {![llength $@ioselect]} {return}
+ set type [lindex $@ioselect 1]
+ set zoom [$@canvas zoom]
+ set port [lindex $@ioselect 0]
+ set p $type$port
+ $self hilite_io_2 $type $port
+}
+
+def Box hilite_io_2 {type port} {
+ set outline [switch $type {i {concat [$self look outletfg]} o {concat [$self look inletfg]}}]
+ set box [l+ [$self io_bbox $type $port] [list -3 -3 +3 +3]]
+ $self item $type${port}b rectangle $box -outline $outline -width 1
+}
+
+#def Box popup_help {} {netsend [list pd help $@pdclass]}
+def Box popup_help {} {netsend [list .$@canvas object_help $self]}
+
+def Box show_error {text} {
+ regsub "\n" $text "" text
+ #mset {x1 y1 x2 y2} [$self bbox]
+ #[$self get_canvas] show_tooltip [expr $x2+4] [expr ($y1+$y2)/2] $text object 1
+ mset {x1 y1 x2 y2} [$self bbox]
+ mset {x y} [rect_centre [$self io_bbox i 0]]
+ [$self get_canvas] show_tooltip $x $y $text i 1
+}
+
+def Canvas macro_event_append {e obj} {
+ if {![llength $@macro_q]} {after $@macro_delay [list $self macro_schedule $@macro_delay] $obj}
+ lappend @macro_q $e
+}
+
+def Canvas get_clipboard {obj} {
+ puts "get clipboard"
+ set content [clipboard get]
+ set l {}; set s ""; set space " ";
+ set last_newline [string last ";" $content]
+ #foreach char [split $content ""] {lappend l [scan $char %c]}
+ set i 0
+ foreach char [split $content ""] {
+ if {$i == $last_newline} {break}
+ #if {$char == ";"} {set s ${s}${space}list} {set s ${s}$char}
+ if {$char != ";"} {
+ if {$char == "\n"} {
+ set s ${s}${space}$char
+ } else {
+ set s ${s}$char
+ }
+ }
+ incr i
+ }
+ netsend [concat [list .$obj clipboard_set] $s]
+}
+
+
+def Canvas macro_schedule {delay obj} {
+ if {[llength $@macro_q]} {
+ set w [focus]
+ set m [lindex $@macro_q 0]
+ set fudge 0
+ mset {event x y mode k} $m
+ switch $event {
+ key {set name [modekey $k $mode]; set fudge 1}
+ click {set name [modeclick $k $mode ButtonPress]; set fudge 1}
+ unclick {set name [modeclick $k $mode ButtonRelease]; set fudge 1}
+ bang {
+ after $delay [list $self macro_schedule $@macro_delay] $obj
+ netsend [list .$obj mbang]
+ set @macro_q [lreplace $@macro_q 0 0]
+ return
+ }
+ default {puts "Error: this event $event should not have been here.."}
+ }
+ if {$fudge} {event generate $w <Motion> -x $x -y $y}
+ event generate $w <$name> -x $x -y $y
+ #puts "event generate $w <$name> -x $x -y $y"
+ if {$event=="key"} {event generate $w <KeyRelease-$k> -x $x -y $y}
+ set @macro_q [lreplace $@macro_q 0 0]
+ after $delay [list $self macro_schedule $@macro_delay] $obj
+ }
+}
+
+def Canvas foobar {} {$self macro_schedule 1000}
+
+def Canvas macro_q {} {puts "$@macro_q"}
+#-----------------------------------------------------------------------------------#
+class_new Wire {View}
+
+def Wire canvas= {c} {
+ super $c
+ mset {from outlet to inlet} $@connects
+ set children [$c objects]
+ set @from [$children get $from]
+ set @to [$children get $to]
+ $@from wires2+= $self; $@to wires2+= $self
+}
+
+def Box index= {i} {super $i; if {$@canvas != ""} {[$@canvas objects] set $i $self}}
+def Wire index= {i} {super $i; [$@canvas wires] set $i $self }
+
+def Wire init {mess} {
+ super
+ $self reinit $mess
+}
+
+def Wire reinit {mess} {
+ if {[$::macro state]} {$::macro append_ref $mess}
+ mset {x msg from outlet to inlet canvas} $mess
+ set @connects [list $from $outlet $to $inlet]
+ set @outlet $outlet
+ set @inlet $inlet
+ $self outside_of_the_box
+}
+
+def Wire from {} {return $@from}
+def Wire outlet {} {return $@outlet}
+def Wire to {} {return $@to}
+def Wire inlet {} {return $@inlet}
+def Wire move {dx dy} {$self changed}
+
+# DON'T do the former, it's so horribly slow
+#def View draw_wires {} {foreach wire $_($@canvas:wires) {$wire changed}}
+def View draw_wires {} {foreach wire $@wires2 {$wire changed}}
+
+def Wire bbox {} {
+ set from $@from; set outlet $@outlet
+ set to $@to; set inlet $@inlet
+ set zoom [$@canvas zoom]
+ set c [$@canvas widget]
+ mset {x1 y1} [lmap / [rect_centre [$c bbox ${from}o${outlet}]] $zoom]
+ mset {x2 y2} [lmap / [rect_centre [$c bbox ${to}i${inlet} ]] $zoom]
+ list $x1 $y1 $x2 $y2
+}
+
+def Wire xy {} {
+ mset {x1 y1 x2 y2} [$self bbox]
+ list [expr $x1 + (($x2-$x1)*0.05)] [expr $y1 + (($y2-$y1)*0.05)]
+}
+
+def Wire report {} {list $@from $@outlet $@to $@inlet}
+def Wire connects {} {return $@connects}
+proc xys {x1 y1 x2 y2} {
+ return [list $x1 $y1 $x2 $y2] ;# just a straight line, no frills
+ set r {}
+ lappend r $x1 $y1
+ set dx [expr $x2-$x1]
+ set dy [expr $y2-$y1]
+ set d [expr sqrt($dx*$dx+$dy*$dy)]
+ set n [expr 1+$d/10]
+ for {set i 1} {$i<$n} {incr i} {
+ set w $i*($n-$i)/(0.0+$n*$n)
+ lappend r [expr $x1 + $dx*$i/$n + $dy*(rand()-0.5)*$w]
+ lappend r [expr $y1 + $dy*$i/$n - $dx*(rand()-0.5)*$w]
+ }
+ lappend r $x2 $y2
+ return $r
+}
+
+def Wire draw {} {
+ set zoom [$@canvas zoom]
+ set c [$@canvas widget]
+ set iowidth [$@from look iowidth]
+ mset {ox1 oy1 ox2 oy2} [$@from io_bbox o $@outlet]
+ mset {ix1 iy1 ix2 iy2} [ $@to io_bbox i $@inlet]
+ set x1 [expr ($ox1+$ox2)/2.0]; set y1 $oy2
+ set x2 [expr ($ix1+$ix2)/2.0]; set y2 $iy1
+ set xys [xys $x1 $y1 $x2 $y2]
+ set length [expr sqrt(pow($x2-$x1,2)+pow($y2-$y1,2))]
+ # how to customise the arrow size/shape?
+ set arrowsize [expr $length<100 ? $length/10 : 10]
+ if {$arrowsize < 5} {set arrow none} {set arrow last}
+ set arrowshape [list $arrowsize [expr $arrowsize*4/5] [expr $arrowsize/3]]
+ set wire_width [$self look thick]
+ set wire_color [$self look fg]
+ if {[$self selected?]} {
+ set wire_color [$self look fg2] ;# fg2 should be renamed
+ } else {
+ if {[info exists _($@from:text)] && [info exists _($@to:text)]} {
+ if {[regexp -nocase {~$} [lindex $_($@from:text) 0]] && \
+ [regexp -nocase {~$} [lindex $_($@to:text) 0]]} {
+ set wire_width [expr $wire_width*2]
+ }
+ }
+ }
+ set options {}
+ if {[$self look wirearrow]} {lappend options -arrow $arrow -arrowshape $arrowshape}
+ eval [concat [list $self item WIRE line $xys -width $wire_width -smooth yes -fill $wire_color] $options]
+}
+
+def Wire delete {} {
+ $self unsubscribe $@canvas
+ $@from delete_wire $self
+ $@to delete_wire $self
+ [$@canvas wires] unset $@index
+ super
+}
+
+def Wire popup_insert {} {
+ if {![llength [$@canvas selection_wire]]} {$@canvas selection_wire= $self}
+ mset {x y} [$@canvas insertxy]
+ $@canvas do_insert_obj $x $y
+}
+
+#-----------------------------------------------------------------------------------#
+############ colouring
+
+proc color_* {c1 c2} {
+ scan $c1 #%02x%02x%02x r g b
+ scan $c2 #%02x%02x%02x R G B
+ return [format #%02x%02x%02x [expr ($r*$R)>>8] [expr ($g*$G)>>8] [expr ($b*$B)>>8]]
+}
+
+# equivalent to color* #c0c0c0 $c
+proc darker {c} {
+ scan $c #%02x%02x%02x r g b
+ set r [expr $r*3/4]
+ set g [expr $g*3/4]
+ set b [expr $b*3/4]
+ return [format #%02x%02x%02x $r $g $b]
+}
+
+proc brighter {c} {
+ scan $c #%02x%02x%02x r g b
+ set r [min 255 [expr $r*4/3]]
+ set g [min 255 [expr $g*4/3]]
+ set b [min 255 [expr $b*4/3]]
+ return [format #%02x%02x%02x $r $g $b]
+}
+
+
+proc parse_color {c} {
+ regsub {;$} $c {} c
+ if {$c<0} {
+ set c [expr ~$c]
+ set r [expr round((($c>>12)&63)*255/63)]
+ set g [expr round((($c>> 6)&63)*255/63)]
+ set b [expr round((($c>> 0)&63)*255/63)]
+ return [format #%02x%02x%02x $r $g $b]
+ } {
+ global preset_colors2
+ return #[lindex $preset_colors2 $c]
+ }
+}
+
+proc unparse_color {c} {
+ if {[string index $c 0]=="#"} {set c [string replace $c 0 0 0x]}
+ set r [expr round((($c>>16)&255)*63/255)]
+ set g [expr round((($c>> 8)&255)*63/255)]
+ set b [expr round((($c>> 0)&255)*63/255)]
+ return [expr ~0[format %02o%02o%02o $r $g $b]]
+}
+
+############ data transfer
+# note: @pdclass is the server-side class name
+# and @_class is the client-side class name
+
+# abstract classes
+set fields1 {foo bar x1 y1 class}
+set fields2 {snd rcv lab ldx ldy fstyle fs bcol fcol lcol}
+
+# real classes
+set fields(tgl) [eval list $fields1 w isa $fields2 on nonzero]
+set fields(bng) [eval list $fields1 w hold break isa $fields2]
+set fields(nbx) [eval list $fields1 w h min max is_log isa $fields2 val log_height]
+set fields(hsl) [eval list $fields1 w h min max is_log isa $fields2 val steady]
+set fields(hradio) [eval list $fields1 w change isa n $fields2 on]
+set fields(vu) [eval list $fields1 w h rcv lab ldx ldy fstyle fs bcol lcol scale isa]
+set fields(cnv) [eval list $fields1 hh w h snd rcv lab ldx ldy fstyle fs bcol lcol isa]
+set fields(dropper) [eval list $fields1 w isa $fields2]
+set fields(vsl) $fields(hsl)
+set fields(vradio) $fields(hradio)
+set fields(hdl) $fields(hradio)
+set fields(vdl) $fields(hradio)
+set fields(coords) {foo bar xfrom yfrom xto yto w h gop x1 y1} ;# goes with #N canvas
+set fields(floatatom) {foo bar x1 y1 w min max pos lab rcv snd}
+set fields(symbolatom) {foo bar x1 y1 w min max pos lab rcv snd}
+set fields(array) {name n elemtype flags}
+
+proc classinfo {pdclass _class} {
+ global classinfo classinfo2
+ set classinfo($pdclass) $_class
+ set classinfo2($_class) $pdclass
+}
+
+# basic patchables
+classinfo obj ObjectBox
+classinfo message MessageBox
+classinfo floatatom FloatBox
+classinfo symbolatom SymbolBox
+classinfo text Comment
+
+# non-patchables (scalars, arrays, ...)
+classinfo array Array
+
+# GUI patchables
+classinfo bng Bang
+classinfo tgl Toggle
+classinfo nbx NumBox
+classinfo hsl Slider
+classinfo vsl Slider
+classinfo vu Vu
+classinfo dropper Dropper
+classinfo hradio Radio
+classinfo vradio Radio
+classinfo hdl Radio
+classinfo vdl Radio
+classinfo canvas Canvas
+classinfo cnv Cnv
+classinfo display Display
+
+# remember, _($foo:$bar) notation should die
+# because objects ought to be autonomous.
+
+# in array objects, number of inlets is bogus?
+#X array array1 1 float 3;
+#A 0 0;
+
+def View index= {i} {set @index $i}
+def View index {} {return $@index}
+
+proc change {self canvas index e {ninlets 0} {noutlets 0} {valid 1}} {
+ foreach mess [pd_mess_split $e] {change_2 $self $mess}
+ #the server ought to take care of this:
+ #if {[lindex $e 1] == "array"} {set ninlets 0; set noutlets 0}
+ if {$canvas != "x0"} {$self canvas= $canvas}
+ $self index= $index
+ $self ninlets= $ninlets
+ $self noutlets= $noutlets
+ if {[$self class] == "ObjectBox"} {$self valid= $valid}
+ if {[$self class] == "Canvas"} {
+ if {[$self subpatch]} {$self valid= $valid}
+ if {[$self gop]} {$self valid= $valid}
+ if {[$self abs]} {$self valid= $valid}
+ }
+ $self changed
+}
+
+proc change_2 {self mess} {
+ set isnew [expr ![info exists ::_($self:_class)]]
+ switch -- [lindex $mess 0] {
+ "#N" {if {$isnew} {Canvas new_as $self $mess} else {$self reinit $mess}}
+ "#X" {
+ set i 1
+ # would it be possible to merge floatatom,symbolatom as gatom ?
+ switch -- [lindex $mess 1] {
+ obj {set class [lindex $mess 4]}
+ msg {set class message}
+ default {set class [lindex $mess 1]}}
+ if {[info exists ::classinfo($class)]} {
+ set _class [lindex $::classinfo($class) 0]
+ } else {
+ if {[lindex $mess 1] == "connect"} {
+ set _class Wire
+ } else {
+ set _class ObjectBox
+ }
+ }
+ if {$isnew} {$_class new_as $self $mess} else {$self reinit $mess}
+ switch -- $class {
+ floatatom {set class gatom}
+ symbolatom {set class gatom}
+ array {$self length= [lindex $mess 3]; $self name= [lindex $mess 2]}
+ default {$self position= [lrange $mess 2 3]}}
+ $self pdclass= $class
+ }
+ "#A" {
+ #post "#A: $mess"
+ $self array_set [lrange $mess 2 end]
+ }
+ "#V" {
+ #post "#V: $mess"
+ }
+ default {if {$mess != ""} {error "what you say? [lindex $mess 0] in $mess"}}
+ }
+}
+
+#proc pasting_count {self} {
+# global paste _
+# if {$paste(count2) != $paste(count)} {incr paste(count2)}
+#}
+
+# split at message boundaries and atom boundaries, returning a list of lists of atoms.
+# spaces get temporary value \x01
+# A_SEMI gets temporary value \x02
+# backslash gets temporary value \x03
+# A_COMMA is not handled yet
+proc pd_mess_split {s} {
+ set s [regsub -all {\\\\} $s "\x03"]
+ set s [regsub -all {(^|[^\\]);} $s "\\1\x02"]
+ set s [regsub -all {(^|[^\\])[\s\n]+} $s "\\1\x01"]
+ set s [regsub -all {^\n} $s "\x01"] ;# oops
+ set s [regsub -all {\\([\\; \{\}])} $s "\\1\\2"]
+ set s [regsub -all \x03 $s \\]
+ set r {}
+ foreach m [split $s \x02] {
+ set m [regsub -all "\x01+" $m "\x01"]
+ set m [regsub -all "^\x01" $m ""]
+ set t [split $m \x01]
+ lappend r $t
+ }
+ return $r
+}
+
+proc canonical_list {list} {
+ set r {}
+ foreach e $list {lappend r $e}
+ return $r
+}
+
+proc pd_mess_split_want== {a b} {
+ set b [canonical_list $b]
+ set c [pd_mess_split $a]
+ if {[string compare $c $b]} {
+ puts "[VTred]string $a\nparses to $c\ninstead of $b[VTgrey]"
+ } else {
+ puts "[VTgreen]string $a OK[VTgrey]"
+ }
+}
+
+if 0 {
+ pd_mess_split_want== {foo;bar;baz;a\;;b\\;c\\\;;d\\\\;e} {foo bar baz {{a;}} {b\\} {{c\;}} {{d\\}} e}
+ pd_mess_split_want== {foo\ bar} {{{foo bar}}}
+ pd_mess_split_want== {foo \ bar\ foo\ bar foo} {{foo { } {bar foo bar} foo}}
+ pd_mess_split_want== {\\ \\\\ \\\\\\ \ \\\ \\\\\ one} [list [list "\\" "\\\\" "\\\\\\" "\ \\\ \\\\\ one"]]
+ pd_mess_split_want== "\n \n \n foo" foo
+ pd_mess_split_want== "\\\x7b\\\x7b\\\x7b\\\x7b" [list [list "\x7b\x7b\x7b\x7b"]]
+ pd_mess_split_want== "\\\x7d\\\x7d\\\x7d\\\x7d" [list [list "\x7d\x7d\x7d\x7d"]]
+ exit
+}
+
+############ rendering
+
+class_new MessageBox {TextBox}
+
+def MessageBox init {mess} {
+ super $mess
+ set @w 15 ;# this is useless?
+ set @xs $@w
+ set @ys $@w ;# this is a bug
+}
+
+def MessageBox draw_box {} {
+ mset {x1 y1} [$self xy]
+ set x2 [expr $x1+$@xs]
+ set y2 [expr $y1+$@ys]
+ set points [list $x1 $y1 [expr $x2+4] $y1 $x2 [expr $y1+4] $x2 [expr $y2-4] [expr $x2+4] $y2 $x1 $y2 $x2 $y2 $x1 $y2]
+ if {[$self selected?]} {set frcol [$self look selectframe]} {set frcol [$self look frame3]}
+ $self item BASE polygon $points -fill [$self look bg] -outline $frcol -width 1
+ [$@canvas widget] lower ${self}BASE ${self}TEXT
+ [$@canvas widget] raise $self
+}
+
+def MessageBox draw {} {
+ super
+ $self draw_io
+}
+
+def MessageBox click {x y f target} {
+ $self bang 1
+ netsend [list .$self bang]
+ after 150 $self bang 0
+}
+
+def MessageBox bang {flag} {
+ if {$flag} {set color #ffff00} {set color [$self look bg]}
+ [$@canvas widget] itemconfigure ${self}BASE -fill $color
+}
+
+# it was class_new AtomBox {View Box}, which is wrong because already Box<View
+# it shouldn't have mattered, but super doesn't support proper pruning yet
+#class_new AtomBox {Box}
+class_new AtomBox {TextBox}
+def AtomBox draw_box {} {
+ $self update_size
+ mset {x1 y1 x2 y2} [$self bbox]
+ set points [list $x1 $y1 [expr $x2-4] $y1 $x2 [expr $y1+4] $x2 $y2 $x1 $y2]
+ if {[$self selected?]} {set frcol [$self look selectframe]} {set frcol [$self look frame3]}
+ $self item BASE polygon $points -fill [$self look bg] -outline $frcol
+ [[$self get_canvas] widget] lower ${self}BASE ${self}TEXT
+ $self draw_io
+}
+
+def AtomBox clear {var} {set @clear $var}
+def AtomBox clear= {} {return $@clear}
+
+def AtomBox filter_text {{for_edit 0}} {
+ if {$for_edit} {return ""}
+ if {[string length $@text] <= $@w} {return $@text}
+ return [string range $@text 0 [expr $@w-1]]
+}
+
+def AtomBox update_size {} {
+ set width [font measure [$self look font] 0]
+ set ls [font metrics [$self look font] -linespace]
+ set @xs [expr ($width*$@w)+3]
+ set @ys [expr $ls+3]
+}
+
+class_new Comment {TextBox}
+
+def Comment draw_box {} {
+ super
+ mset {x1 y1} [$self xy]
+ set x2 [expr $x1+$@xs]
+ set y2 [expr $y1+$@ys]
+ set xya [list $x1 $y1 $x2 $y2]
+ set xyb [l+ [list $x2 $y1 $x1 $y1 $x1 $y2] [list -1 +1 +1 +1 +1 -1]]
+ set xyc [l+ [list $x2 $y1 $x2 $y2 $x1 $y2] [list -1 +1 -1 -1 +1 -1]]
+ if {[$@canvas editmode]} {
+ if {[$self selected?]} {set frcol [$self look selectframe]} {set frcol [$self look frame3]}
+ $self item BASE rectangle $xya -fill [$self look bg] -outline $frcol
+ } else {
+ $self item_delete BASE
+ }
+ #$self item BASE1 line $xyb -fill [$self look frame1]
+ #$self item BASE2 line $xyc -fill [$self look frame2]
+ if {[$@canvas editmode]} {
+ [$@canvas widget] lower ${self}BASE ${self}TEXT
+ #[$@canvas widget] raise ${self}BASE1 ${self}BASE
+ #[$@canvas widget] raise ${self}BASE2 ${self}BASE
+ }
+}
+
+class_new Display {Box}
+
+def Display height= {val} {set @height $val}
+
+def Display init {{mess {}}} {
+ set font [$self look font]
+ set fw [font measure $font 0]
+ set @max_width 40; #in chars
+ set @wrap [expr $fw*$@max_width]; #in pixels
+ set @content {display}
+ set @height 1
+ set @xs [expr [font measure [$self look font] 0]+3]
+ set @ys [font metrics [$self look font] -linespace]
+ set @textoffset [list 2 2]
+ netsend [list .$self height]
+ super $mess
+}
+
+def Display draw {} {
+ super
+ set font [$self look font]
+ mset {x y} [$self xy]
+ mset {xf yf} $@textoffset
+ set fh [font metrics [$self look font] -linespace]
+ set text [lindex $@content 0];
+ for {set i 1} {$i < $@height} {incr i} {set text ${text}\n[lindex $@content $i]}
+ set h 0; set w 0
+ foreach line $@content {
+ set tw [font measure $font $line]
+ set h [expr int(ceil($tw/$@wrap.0)+$h)]
+ set w [min [max $w $tw] $@wrap]
+ }
+ set h [max $h 1]
+ $self item BASE rect [list $x $y [expr $x+$w+$xf+2] [expr $y+($@ys*$h)+$yf+1]] \
+ -fill [$self look bg]
+
+ $self item TEXT text [l+ $@textoffset [$self xy]] -font $font -text $text \
+ -fill [$self look fg] -anchor nw -width $@wrap
+ $self draw_io
+}
+
+def Display dis {text} {
+ lappend @content $text
+ if {[llength $@content] > $@height} {set @content [lrange $@content 1 end]}
+ $self changed
+}
+
+class_new IEMGUI {}
+def IEMGUI text {} {
+ return [$self class]
+}
+class_new BlueBox {Labelled IEMGUI Box}
+#class_new BlueBox {Box Labelled}
+
+def BlueBox draw_box {} {
+ super
+ set xya [$self bbox]
+ mset {x1 y1 x2 y2} $xya
+ set xyb [list [expr $x2-1] [expr $y1+1] [expr $x1+1] [expr $y1+1] [expr $x1+1] [expr $y2-1]]
+ set xyc [list [expr $x2-1] [expr $y1+1] [expr $x2-1] [expr $y2-1] [expr $x1+1] [expr $y2-1]]
+ set color [color_* [$self look bg] [parse_color $@bcol]]
+ if {[$self selected?]} {set frcol [$self look selectframe]} {set frcol [$self look frame3]}
+ $self item BASE rectangle $xya -fill $color -outline $frcol
+ #below lines draws the 3d box edge
+ #$self item BASE2 line $xyb -fill #ffffff
+ #$self item BASE3 line $xyc -fill [darker $color]
+ $self draw_io
+}
+
+def IEMGUI popup_properties {} {IEMPropertiesDialog new $self}
+
+class_new PropertiesDialog {Dialog}
+
+def PropertiesDialog init {of} {
+ super cancel apply ok
+ set @of $of
+ set f .$self
+ checkbutton $f.auto_apply -text [say auto_apply] -anchor w -variable @auto_apply
+ frame $f.buttonsep2 -height 2 -borderwidth 1 -relief sunken
+ pack $f.auto_apply $f.buttonsep2 -side bottom -fill x
+ bind $f <KeyPress-Return> "break";#so that Return don't call do_auto_apply after Dialog ok
+ bind $f <KeyPress> [list $self do_auto_apply]
+ bind $f <ButtonRelease> [list $self do_auto_apply]
+ set @auto_apply 0
+ $self none_resizable
+}
+
+def PropertiesDialog do_auto_apply {} {
+ if {$@auto_apply} {$self apply}
+}
+
+class_new IEMPropertiesDialog {PropertiesDialog}
+
+def IEMGUI properties_apply {list {orient -1}} {
+ set orig [list $self properties_apply]
+ foreach var [lrange $::fields($@class) 5 end] {lappend orig $@$var}
+ [$@canvas history] add $orig
+ foreach v $list {switch -- $v {{} {set v "empty"}}; lappend props $v}
+ netsend [concat [list .$self reload] $props]
+ if {$orient >= 0} {
+ netsend [list .$self orient $orient]
+ }
+}
+
+def IEMPropertiesDialog apply {} {
+ set class $_($@of:class)
+ set props {}
+ foreach var [lrange $::fields($class) 5 end] {
+ set v $@$var
+ if {[regexp -nocase {^[bfl]col$} $var]} {set v [unparse_color $v]}
+ lappend props $v
+ }
+ if {[[$@of class] <= Slider] || [[$@of class] <= Radio]} {
+ $@of properties_apply $props $@orient
+ } else {
+ $@of properties_apply $props
+ }
+}
+
+def IEMPropertiesDialog init {of} {
+ super $of
+ set @class $_($of:class)
+ wm title .$self "\[$@class\] [say popup_properties]"
+ if {![info exists ::fields($@class)]} {set class obj}
+ foreach var $::fields($@class) {
+ set val $_($of:$var)
+ switch -- $val { empty {set val ""}}
+ if {[regexp -nocase {^([a-z])col$} $var]} {set val [parse_color $val]}
+ set @$var $val
+ }
+ if {[[$of class] <= Slider] || [[$of class] <= Radio]} {
+ set @orient $_($of:orient)
+ $self add .$self [list orient choice -choices {horizontal vertical}]
+ }
+ foreach prop [lrange $::fields($@class) 5 end] {
+ set d [concat [list $prop] [switch $prop {
+ w {list integer -width 7}
+ h {list integer -width 7}
+ hold {list float -width 9}
+ break {list float -width 9}
+ min {list float -width 9}
+ max {list float -width 9}
+ is_log {list choice -choices {linear logarithmic}}
+ isa {list choice -choices {no yes}}
+ n {list integer -width 4}
+ steady {list choice -choices {steady_no steady_yes}}
+ snd {list entry -width 20}
+ rcv {list entry -width 20}
+ lab {list entry -width 20}
+ ldx {list integer -width 5}
+ ldy {list integer -width 5}
+ fstyle {list choice -choices {Courier Helvetica Times}}
+ fs {list fontsize -width 5}
+ bcol {list color}
+ fcol {list color}
+ lcol {list color}
+ val {continue}
+ on {continue}
+ change {list choice -choices {no yes}}
+ nonzero {list float -width 9}
+ log_height {list float -width 9}
+ hh {continue}
+ scale {list toggle}
+ default {error "huh? ($prop)"}
+ }]]
+ $self add .$self $d
+ }
+}
+
+def IEMPropertiesDialog dropmenu_open {f name} {super $f}
+def IEMPropertiesDialog dropmenu_set {frame var part val} {
+ switch $var {
+ orient {if {[$@of class] == "Slider"} {set tmp $@h; set @h $@w; set @w $tmp}}
+ default {}
+ }
+ set tmp ${var}choices
+ set textvar ${var}2
+ set @$textvar [say [lindex $@$tmp $val]]
+ super $frame $var $part $val
+ $self do_auto_apply
+}
+
+class_new CanvasPropertiesDialog {PropertiesDialog}
+
+def CanvasPropertiesDialog init {of} {
+ super $of
+ set @canvas $of
+ wm title .$self "[say canvas] [say popup_properties]"
+ set @gop [$of gop]
+ set @properties [list "gop" "xfrom" "xto" "yfrom" "yto" "width" "height" "xmargin" "ymargin"]
+ set mess [$of get_mess]
+ mset [list @xfrom @yfrom @xto @yto @width @height @xmargin @ymargin] $mess
+ if {!$@width} {set @width 85}; if {!$@height} {set @height 60}
+ $self add .$self [list gop toggle -command "$self gop_setting"]
+ for {set i 1} {$i<[llength $@properties]} {incr i} {
+ $self add .$self [list [lindex $@properties $i] integer -width 7]
+ }
+ $self gop_setting
+}
+
+def CanvasPropertiesDialog gop_setting {} {
+ set entries [lrange $@properties 1 end]
+ foreach entry $entries {
+ if {!$@gop} {
+ .$self.$entry.entry configure -state disable
+ } else {
+ .$self.$entry.entry configure -state normal
+ }
+ }
+}
+
+def CanvasPropertiesDialog apply {} {
+ if {![$@canvas editmode]} {$@canvas editmode= 1}
+ netsend [list .$@of coords $@xfrom $@yfrom $@xto $@yto $@width $@height $@gop $@xmargin $@ymargin]
+}
+
+proc gatom_escape {sym} {
+ if {[string length $sym] == 0} {return "-"}
+ if {[string equal -length 1 $sym "-"]} {return [string replace $sym 0 0 "--"]}
+ return $sym
+}
+
+proc gatom_unescape {sym} {
+ if {[string equal -length 1 $sym "-"]} {return [string replace $sym 0 0 ""]}
+ return $sym
+}
+
+class_new BoxPropertiesDialog {PropertiesDialog}
+def Box popup_properties {} {BoxPropertiesDialog new $self}
+def Box popup_clear_wires {} {[$self canvas] selection= $self; [$self canvas] clear_wires}
+def Box popup_remove_from_path {} {[$self canvas] selection= $self; [$self canvas] remove_obj_from_path}
+def Box popup_delete_from_path {} {[$self canvas] selection= $self; [$self canvas] delete_obj_from_path}
+def BoxPropertiesDialog init {of} {
+ super $of
+ wm title .$self "Box Properties"
+ pack [label .$self.huh -text "huh..."]
+ pack [label .$self.huh2 -text "this is where some #V properties should go"]
+}
+
+class_new WirePropertiesDialog {PropertiesDialog}
+def Wire popup_properties {} {WirePropertiesDialog new $self}
+def WirePropertiesDialog init {of} {
+ super $of
+ wm title .$self "Wire Properties"
+ pack [label .$self.huh -text "huh..."]
+ pack [label .$self.huh2 -text "this is where some #V properties should go"]
+}
+
+class_new GAtomPropertiesDialog {PropertiesDialog}
+
+def AtomBox popup_properties {} {GAtomPropertiesDialog new $self}
+
+# this is buggy due to miller's escapes vs iem's escapes.
+def GAtomPropertiesDialog apply {} {
+ netsend [list .$@of reload $@w $@min $@max $@pos [gatom_escape $@lab] [gatom_escape $@rcv] [gatom_escape $@snd]]
+}
+
+def GAtomPropertiesDialog init {of} {
+ super $of
+ foreach var {w min max pos} {set @$var $_($of:$var)}
+ foreach var {lab rcv snd} {set @$var [gatom_unescape $_($of:$var)]}
+ wm title .$self "Atom"
+ global properties
+ $self add .$self \
+ {w entry -width 4} \
+ {min entry -width 8} \
+ {max entry -width 8} \
+ {lab entry -width 20} \
+ {pos side} \
+ {snd entry -width 20} \
+ {rcv entry -width 20}
+ #foreach name {w min max} {bind .$self.$name.entry <KeyPress-Return> "$self ok"}
+ .$self.w.entry select from 0
+ .$self.w.entry select adjust end
+ focus .$self.w.entry
+}
+
+class_new GraphPropertiesDialog {Dialog}
+
+def GraphPropertiesDialog apply {} {
+ netsend [list .$@of dialog $@x1 $@y1 $@x2 $@y2 $@xpix $@ypix]
+}
+
+def GraphPropertiesDialog init {of} {
+ super $of
+ foreach var {x1 y1 x2 y2 xpix ypix} {set @$var $_($of:$var)}
+ wm title .$self "Graph"
+ pack [label .$self.label -text "GRAPH BOUNDS"] -side top
+ global properties
+ $self add .$self {
+ {x1 entry -width 7} \
+ {x2 entry -width 7} \
+ {xpix entry -width 7} \
+ {y2 entry -width 7} \
+ {y1 entry -width 7} \
+ {ypix entry -width 7}
+ }
+ #.$self.xrangef.x2 select from 0
+ #.$self.xrangef.x2 select adjust end
+ #focus .$self.xrangef.x2
+}
+
+class_new ArrayPropertiesDialog {Dialog}
+
+def ArrayPropertiesDialog apply {} {
+ regsub {^\$} $@name "#" name
+ netsend [list .$@apply arraydialog $name $@n $@saveit $@otherflag]
+}
+
+def ArrayPropertiesDialog init {of} {
+ super $of
+ foreach var {name n saveit} {set @$var $_($of:$var)}
+ set @otherflag 0
+ wm title $id "[say array] [say popup_properties]"
+ $self add .$self {name entry} {n entry}
+ pack [checkbutton .$self.saveme -text "save contents" -variable @saveit -anchor w] -side top
+ if {$newone != 0} {
+ pack [frame .$self.radio] -side top
+ foreach {i label} {0 "in new graph" 1 "in last graph"} {
+ pack [radiobutton .$self.radio.radio$i -value $i -variable @otherflag -text $label] -side top -anchor w
+ }
+ } else {
+ pack [checkbutton .$self.deleteme -text "delete me" -variable @otherflag -anchor w] -side top
+ }
+ if {$newone} {.$self.buttonframe.apply configure -state disabled}
+ bind .$self.name.entry <KeyPress-Return> "$self ok"
+ bind .$self.n.entry <KeyPress-Return> "$self ok"
+ .$self.name.entry select from 0
+ .$self.name.entry select adjust end
+ focus .$self.name.entry
+}
+
+class_new FloatBox {AtomBox}
+class_new SymbolBox {AtomBox}
+
+def AtomBox init {mess} {
+ super $mess
+ set @clickpos {}
+ set width [font measure [$self look font] W]
+ set height [font metrics [$self look font] -linespace]
+ set @xs [expr ($width*$@w)+3]
+ set @ys [expr $height+3]
+}
+
+def FloatBox init {mess} {super $mess; set @text 0;}
+
+def FloatBox calc {x y x1 y1} {
+ #puts "$@min $@max"
+ if {!$@min && !$@max} {
+ set d [expr $@ovalue+($y1-$y)*$@rate]
+ } else {
+ set span [expr $@max-$@min]
+ set l [expr $@max-$@min]
+ set d [clip [expr $@ovalue+(($y1-$y)*$span/($l+0.0))*$@rate] $@min $@max]
+ }
+ return $d
+}
+
+def SymbolBox init {mess} {super $mess; set @text "symbol"}
+
+def AtomBox set {val} {set @text [format "%g" $val]; $self changed}
+
+def AtomBox setto {text} {
+ [$@canvas widget] configure -cursor {}
+ if { [string is double $text]} {
+ set @text $text; #so that the text gets updated immediately
+ netsend [list .$self float $text]
+ #[$self get_canvas] selection-= $self
+ }
+}
+def SymbolBox set {text} {set @text $text}
+def SymbolBox setto {text} {
+ [$@canvas widget] configure -cursor {}
+ if {![string is double $text]} {netsend [list .$self symbol $text]}
+}
+
+def FloatBox ftoa {} {
+ set f $@val
+ set is_exp 0
+ if {[string length $@buf]>0} {return $@buf}
+ set buf [format %g $f]
+ set bufsize [string length buf]
+ if {$bufsize >= 5} {
+ # exponential mode
+ set is_exp [regexp -nocase e]
+ }
+ if {$bufsize > $@w} {
+ # must shrink number
+ if {$is_exp} {
+ #...
+ } {
+ #...
+ }
+ }
+ return $buf
+}
+
+def AtomBox click {x y f target} {
+ set @clickx $x; set @clicky $y
+ set canvas [$self get_canvas]
+ set t [$canvas widget].${self}text
+ set @ovalue [clip $@text $@min $@max]
+ set @clickpos [list $x $y]
+ set @mouse [list $x $y]
+ $canvas focus= $self
+ set @rate [expr $f&1 ? 0.01 : 1.00]
+}
+
+def AtomBox unclick {x y f target} {
+ if {$x == $@clickx && $y == $@clicky} {$self edit}
+ [$self get_canvas] focus= ""
+}
+
+def AtomBox motion {x y f target} {
+ if {$@edit} {return}
+ mset {clx cly} $@clickpos
+ set @text [$self calc $x $y $clx $cly]
+ netsend [list .$self float [expr {0+$@text}]]
+}
+
+def AtomBox log_ratio {} {
+ set diff [expr $@is_log ? log($@max/$@min) : ($@max-$@min)]
+ return [expr $diff / $@max]
+}
+
+def AtomBox key_incr {val1 val2} {
+ set @text [expr $@text - $val2]
+ netsend [list .$self float [expr {0+$@text}]]
+}
+
+def SymbolBox motion {x y f target} {}
+class_new NumBox {Labelled IEMGUI AtomBox}
+
+def NumBox init {mess} {
+ super $mess
+ set @clicking 0
+ set changed 0
+ set @buf ""
+ set @text [clip 0 $@min $@max]
+}
+
+def NumBox calc {x y x1 y1} {
+ set span [expr $@max-$@min]
+ set l [expr $@is_log ? $@log_height : ($@max-$@min)]
+ set d [expr {($y1-$y)*$span/($l+0.0)}]
+ set d [expr $@is_log ? $@ovalue*exp($d*$@rate*[$self log_ratio]) : $@ovalue+$d*$@rate]
+ set d [clip $d $@min $@max]
+ return $d
+}
+
+
+def NumBox reinit {mess} {
+ super $mess
+ set @text $@val
+}
+
+def NumBox draw {} {
+ super
+ mset {x1 y1} [$self xy]
+ set xs [expr 4+10*$@w]
+ set ys $@h
+ set x2 [expr $x1+$xs]
+ set y2 [expr $y1+$ys]
+ set c [[$self get_canvas] widget]
+ set points [list $x1 $y1 [expr $x2-4] $y1 $x2 [expr $y1+4] $x2 $y2 $x1 $y2]
+ set xt [expr $x1+$ys/2+2]
+ set yt [expr $y1+$ys/2+1+$xs/34]
+ set points2 [list $x1 $y1 [expr $x1+$ys/2] [expr $y1+$ys/2] $x1 $y2]
+ set focused [$self == [$@canvas focus]]
+ if {$focused} {set color4 #00ff00} {set color4 [$self look bg]}
+ $self item BASE4 polygon $points2 -outline [$self look frame3] -fill $color4
+ $c raise ${self}BASE4
+}
+
+def NumBox ftoa {} {
+ set f $@text
+ set is_exp 0
+ if {[string length $@buf]>0} {return $@buf}
+ set buf [format %g $f]
+ set bufsize [string length buf]
+ if {$bufsize >= 5} {
+ # exponential mode
+ set is_exp [regexp -nocase e]
+ }
+ if {$bufsize > $@w} {
+ # must shrink number
+ if {$is_exp} {
+ #...
+ } {
+ #...
+ }
+ }
+ return $buf
+}
+
+def NumBox unfocus {} {set @buf ""; $self changed}
+
+class_new Radio {BlueBox}
+
+def Radio reinit {mess} {
+ super $mess
+ switch [lindex $mess 4] {
+ hradio {set @orient 0} hdl {set @orient 0}
+ vradio {set @orient 1} vdl {set @orient 1}
+ default {set @orient 0}
+ }
+}
+
+def Radio bbox {} {
+ mset {x1 y1} [$self xy]
+ set x2 [expr $x1+$@w*($@orient ?1:$@n)]
+ set y2 [expr $y1+$@w*($@orient ?$@n:1)]
+ list $x1 $y1 $x2 $y2
+}
+
+def Radio draw {} {
+ mset {x1 y1 x2 y2} [$self bbox]
+ super
+ for {set i 0} {$i<$@n} {incr i} {
+ $self item [list BUT$i BUT] rectangle \
+ [list [expr $x1+3] [expr $y1+3] [expr $x1+$@w-3] [expr $y1+$@w-3]] \
+ -fill #ffffff -outline #000000
+ if {$@orient} {set y1 [expr $y1+$@w]} {set x1 [expr $x1+$@w]}
+ }
+ $self set $@on
+}
+
+def Radio set {value} {
+ set c [$self get_canvas]
+ [$c widget] itemconfigure ${self}BUT -fill #ffffff
+ [$c widget] itemconfigure ${self}BUT$value -fill #000000
+}
+
+def Radio click {x y f target} {
+ mset {x1 y1} [$self xy]
+ set i [expr {($@orient ?$y-$y1:$x-$x1)/$@w}]
+ netsend [list .$self fout $i]
+}
+
+def Radio key_incr {val1 val2} {
+ netsend [list .$self fout [expr $@on - $val2]]
+}
+
+class_new Slider {BlueBox}
+
+# in sliders, @value is the kind of value that goes thru inlets and outlets
+# whereas @val is always measured in "centipixels" (unzoomed).
+def Slider reinit {mess} {
+ super $mess
+ set @knob_thick 4
+ switch [lindex $mess 4] {
+ hsl {set @orient 0}
+ vsl {set @orient 1}
+ }
+ $self update_value
+}
+
+def Slider update_value {} {
+ set span [expr {$@max-$@min}]
+ set l [expr $@orient ?$@h:$@w]
+ set @value [expr $@val*$span/($l-1)/100]
+ #set t [expr $@val * [$self slider_ratio] * 0.01]
+ #set @value [expr $@min*exp($t)]
+}
+
+def Slider init {mess} {
+ super $mess
+ set @oposition $@min
+ $self update_value
+}
+
+def Slider bbox {} {
+ mset {x1 y1} [$self xy]
+ if {!$@orient} {
+ list $x1 $y1 [expr $x1+$@w+$@knob_thick] [expr $y1+$@h]
+ } else {
+ list $x1 [expr $y1-$@knob_thick] [expr $x1+$@w] [expr $y1+$@h]
+ }
+}
+
+#the value/centipixel ratio
+def Slider slider_ratio {} {
+ set diff [expr $@is_log ? log($@max/$@min) : ($@max-$@min)]
+ return [expr $diff / ($@orient ? ($@h-1) : ($@w-1))]
+}
+
+def Slider draw_knob {} {
+ mset {x1 y1 x2 y2} [$self bbox]
+ set l [expr $@orient ?$@h:$@w]
+ set span [expr {$@max-$@min}]
+ set color [$self look bg]
+ set scaled [expr {$@value*($l-1)/$span}]
+ set thick [expr $@knob_thick/2]
+ if {$@orient} {
+ set y1 [expr $y1+$@knob_thick]
+ set y [expr $y1+$@h-$scaled-2]
+ set coords [list [expr $x1+2] $y [expr $x1+$@w-2] [expr $y-2]]
+ } else {
+ set x2 [expr $x1-$@knob_thick]
+ set x [expr $x1+$scaled]
+ set coords [list $x [expr $y1+$thick] [expr $x+2] [expr $y1+$@h-$thick]]
+ }
+ $self item KNOB rectangle $coords -outline red -fill [darker $color]
+}
+
+def Slider draw {} {
+ mset {x1 y1 x2 y2} [$self bbox]
+ #if {$@orient} {set y1 [expr $y1-2]} {set x1 [expr $x1-2]}
+ #if {$@orient} {set ys [expr $@h+5]} {set xs [expr $@w+5]}
+ super
+ $self draw_knob
+ $self update_value
+}
+
+# not used
+def Slider draw_notches {} {
+ if {$@orient} {
+ set thick [clip [expr $xs/3] 1 5]
+ set x3 [expr $x1+$xs-$thick/2-2]
+ set eighth [expr round($ys/8-1)]
+ set coords [list $x3 $y1 $x3 [expr $y1+$ys]]
+ } else {
+ set thick [clip [expr $ys/3] 1 5]
+ set y3 [expr $y1+$ys-$thick/2-2]
+ set eighth [expr $xs/8]
+ set coords [list $x1 $y3 [expr $x1+$xs] $y3]
+ }
+ # there were supposed to be 7 notches... i don't remember what happened here.
+ $@canvas item NOTCH $coords -dash [list 1 $eighth 1 $eighth] -width $thick -fill [darker [$self look bg]]
+}
+
+def Slider click {x y f target} {
+ set canvas [$self get_canvas]
+ mset {type id detail} [$canvas identify_target $x $y $f]
+ if {$type == "label"} {return}
+ $canvas focus= $self
+ set @click_at [list $x $y]
+ set @rate [expr $f&1 ? 0.01 : 1.00]
+ if {!$@steady} {
+ mset {x1 y1 x2 y2} [$self bbox]
+ set t [expr [$self calc $x $y $x1 $y2]*$@rate]
+ set @value [expr $@is_log ? [expr $@min*exp($t*[$self slider_ratio])] : $t]
+ set @oposition $t
+ netsend [list .$self float $@value]
+ } else {set @oposition $@value}
+}
+
+def Slider unclick {x y f target} {
+ ### keep focus if only clicked. do we want that feature?
+ # if {[distance $@click_at [list $x $y]] == 0} {return}
+ set canvas [$self get_canvas]
+ $canvas focus= ""
+}
+
+def Slider motion {x y f target} {
+ set canvas [$self get_canvas]
+ set focused [$self == [$canvas focus]]
+ if {!$focused} {return}
+ mset {clx cly} $@click_at
+ set d [$self calc $x $y $clx $cly]
+ set t ($@oposition+$d*$@rate)
+ set value [expr $@is_log ? [expr $@min*exp($t*[$self slider_ratio])] : $t]
+ set out [clip $value $@min $@max]
+ netsend [list .$self float $out]
+}
+
+def Slider key_incr {val1 val2} {
+ set @value [expr $@value - $val2]
+ netsend [list .$self float $@value]
+}
+
+def Slider calc {x y x1 y1} {
+ set span [expr $@max-$@min]
+ set l [expr {$@orient ?$@h:$@w}]
+ set d [expr {($@orient ?$y1-$y:$x-$x1)*$span/($l+0.0)}]
+ return $d
+}
+
+def Slider unfocus {} {$self draw}
+
+class_new Labelled {}
+
+def Labelled draw {} {
+ global leet
+ super
+ mset {x1 y1} [$self xy]
+ set lx [expr $x1+$@ldx]
+ set ly [expr $y1+$@ldy]
+ set label $@lab; switch -- $label { empty { set label "" }}
+ set lfont [list [lindex {courier helvetica times} $@fstyle] $@fs bold]
+ set lcolor [parse_color $@lcol]
+ if {$leet} {
+ set text [string map -nocase {a 4 e 3 t 7 s 5 i 1 o 0 g 9} $label]
+ } else {
+ set text $label
+ }
+ $self item LABEL text [list $lx $ly] -text $text -anchor w -font $lfont -fill $lcolor
+}
+#-----------------------------------------------------------------------------------#
+class_new Bang {BlueBox}
+def Bang init {mess} {
+ super $mess
+ set @flash 0
+ set @count 0
+}
+
+def Bang bbox {} {
+ mset {x1 y1} [$self xy]
+ list $x1 $y1 [expr $x1+$@w] [expr $y1+$@w]
+}
+
+def Bang draw {} {
+ super
+ mset {x1 y1 x2 y2} [$self bbox]
+ if {$@flash} {
+ set rect [list [expr $x1+2] [expr $y1+2] [expr $x2-2] [expr $y2-2]]
+ #$self item BUT oval $rect -fill [color_* [$self look bg] [parse_color $@fcol]]
+ set fcol [color_* [$self look bg] [parse_color $@fcol]]
+ set bcol [color_* [$self look bg] [parse_color $@bcol]]
+ $self item BUT oval $rect -fill $fcol
+ after 100 [list $self item BUT oval $rect -fill $bcol]
+ set @flash 0
+ } else {
+ set colour [parse_color $@bcol]
+ set rect [list [expr $x1+2] [expr $y1+2] [expr $x2-2] [expr $y2-2]]
+ $self item BUT oval $rect -fill [color_* [$self look bg] $colour] -outline [$self look frame3]
+ }
+}
+def Bang unclick {x y f target} {}
+def Bang click {x y f target} {netsend [list .$self bang]}
+def Bang bang {count} {set @count $count; set @flash 1}
+def Bang key_incr {val1 val2} {netsend [list .$self bang]}
+
+class_new Toggle {BlueBox}
+
+def Toggle bbox {} {
+ mset {x1 y1} [$self xy]
+ list $x1 $y1 [expr $x1+$@w] [expr $y1+$@w]
+}
+
+def Toggle draw {} {
+ super
+ mset {x1 y1 x2 y2} [$self bbox]
+ set colour [parse_color $@bcol]
+ set t [expr int(($@w+29)/30)]
+ set fill [color_* [$self look bg] $colour]
+ set x3 [expr $x1+$t+2]; set y3 [expr $y1+$t+2]
+ set x4 [expr $x2-$t-2]; set y4 [expr $y2-$t-2]
+ if {$@on} {
+ set fill [parse_color $@fcol]
+ } {
+ set fill [color_* [$self look bg] [parse_color $@bcol]]
+ }
+ $self item X1 line [list $x3 $y3 [expr $x4+1] [expr $y4+1]] -width $t -fill $fill
+ $self item X2 line [list $x3 $y4 [expr $x4+1] [expr $y3-1]] -width $t -fill $fill
+}
+
+def Toggle unclick {x y f target} {}
+def Toggle click {x y f target} {
+ if {!$@on} {set @on 1} {set @on 0}
+ netsend [list .$self float $@on]
+ $self changed
+}
+
+class_new Vu {IEMGUI Box}
+
+set vu_col {
+ 0 17 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16
+ 15 15 15 15 15 15 15 15 15 15 14 14 13 13 13 13 13 13 13 13 13 13 13 19 19 19
+}
+
+def Vu init {mess} {
+ super $mess
+ set @value 0
+ set @peak 0
+}
+
+def Vu bbox {} {
+ mset {x1 y1} [$self xy]
+ list $x1 $y1 [expr $x1+$@w] [expr $y1+$@h]
+}
+
+def Vu led_size {} {
+ set n [expr $@h/40]
+ if {$n < 2} {set n 2}
+ return [expr $n-1]
+}
+
+def Vu draw {} {
+ global vu_col
+ mset {x1 y1 x2 y2} [$self bbox]
+ set colour [parse_color $@bcol]
+ super
+ $self draw_io
+ set led_size [$self led_size]
+ set x3 [expr $x1+$@w/4]
+ set x4 [expr $x2-$@w/4]
+ $self item BASE rectangle [list $x1 $y1 $x2 $y2] -width 0 -fill [color_* [$self look bg] $colour]
+ for {set i 1} {$i<=40} {incr i} {
+ set y [expr $y1 + ($led_size+1)*(41-$i) - ($led_size+1)/2]
+ $self item RMS${i} rectangle [list $x3 $y $x4 [expr $y+$led_size]] \
+ -fill [parse_color [lindex $vu_col $i]] -width 0
+ }
+ #if {!$@zoom} {return}
+ set lfont [list [lindex {courier helvetica times} $@fstyle] $@fs bold]
+ set lcolor [parse_color $@lcol]
+ set i 0
+ foreach level { <-99 -50 -30 -20 -12 -6 -2 -0dB +2 +6 >+12 } {
+ set k1 [expr $led_size+1]
+ set k2 41
+ set k3 [expr $k1/2]
+ set k4 [expr $y1-$k3]
+ set yyy [expr $k4 + $k1*($k2-4*$i)]
+ $self item SCALE{$level} text [list [expr $x2+4] [expr $yyy+$k3-3]] \
+ -text $level -anchor w -font $lfont -fill $lcolor
+ incr i
+ }
+ set y [expr $y1 + ($led_size+1)*(41-$@value) - ($led_size+1)/2]
+ $self item MASK rectangle [list $x3 $y1 $x4 $y] -width 0 -fill [color_* [$self look bg] $colour]
+ set c [lindex $vu_col [expr int($@peak)]]
+ set y [expr $y1 + ($led_size+1)*(41-$@peak) - ($led_size+1)/2]
+ $self item PEAK rectangle [list $x1 $y $x2 [expr $y+$led_size]] -fill [parse_color $c] -width 0
+}
+
+def Vu rms= {rms } {set @value $rms; $self changed rms}
+def Vu peak= {peak} {set @peak $peak; $self changed peak}
+
+def Vu set {i j} {
+ set @value $i
+ set @peak $j
+ $self changed
+}
+
+catch {
+ package require tkdnd
+ dnd bindtarget . text/uri-list <Drop> {open_file %D}
+}
+
+class_new Dropper {View}
+
+# somewhat broken...
+def Dropper draw {} {
+ set c [$@canvas widget]
+ set isnew [expr [llength [$c gettags ${self}BASE]] == 0]
+ mset {x1 y1} [$self xy]
+ set xs $@w
+ set colour [parse_color $@fcol]
+ set lcolour [parse_color $@lcol]
+ super
+ if {$isnew} {
+ canvas $c.${self}DROP -width $xs -height $xs -bg $colour \
+ -highlightbackground $lcolour -highlightcolor $colour
+ $c create window [expr $x1+7] [expr $y1-2] -window $c.${self}DROP -anchor nw -tags $c.${self}window
+ if {[catch {
+ dnd bindtarget $c.${self}DROP text/uri-list <Drop> "pd \"x[list ${self}] symbol \[ enquote %D \] ;\""
+ }]} {
+ post "dropper: dnd not installed"
+ }
+ } {
+ $c coords $@canvas.${self}window [expr $x1 + 7] [expr $y1 - 2]
+ $c.${self}DROP configure -width $xs -height $xs -bg $colour \
+ -highlightbackground $lcolour -highlightcolor $colour
+ }
+}
+
+def Dropper erase {} {destroy $@canvas.${self}DROP; super}
+
+class_new Cnv {Labelled IEMGUI Box}
+
+def Cnv draw {} {
+ mset {x1 y1} [$self xy]
+ $self item BASE rectangle [list $x1 $y1 [expr $x1+$@w] [expr $y1+$@h]] -fill [parse_color $@bcol]
+ super
+}
+
+def Cnv bbox {} {
+ mset {x1 y1} [$self xy]
+ return [list $x1 $y1 [expr $x1+$@w] [expr $y1+$@h]]
+}
+
+class_new Array {Box}
+
+def Array init {mess} {
+ super $mess
+ set @name [lindex $mess 2]
+ set @length 0
+ set @data {}
+ set @draw 0
+}
+
+def Array bbox {} {
+ return {0 0 1 1} ;# huh?
+}
+
+def Array draw_name {} {
+ mset {x_off y_off} [$@canvas xy]
+ $self item TEXT text [lmap + [list $x_off $y_off] 2] \
+ -font [View_look $self font] -text $@name \
+ -fill [View_look $self fg] -anchor nw
+}
+
+def Array draw {} {
+ $self draw_name
+ mset {x_off y_off} [$@canvas xy]
+ set m [$@canvas get_mess]
+ mset {xfrom yto xto yfrom pixwidth pixheight} $m
+ if {[winfo exists [$@canvas widget]]} {
+ mset {c_width c_height} [$@canvas get_dimen]
+ set width [expr $c_width / $@length]
+ set i 0
+ foreach val $@data {
+ if {!$val} {set val 0.0}
+ set y [expr $c_height - (((double($val)+abs($yfrom))/($yto-($yfrom)) * $c_height))]
+ set x1 [expr $width * $i]
+ set x2 [expr $x1 + $width]
+ set line [list $x1 $y $x2 $y]
+ $self item elem${i} line $line -fill [$@canvas look compfg] -width 2 -tags "$self ${self}elem${i}"
+ #.$self.c raise ${self}elem${i}
+ incr i
+ }
+ } else {
+ set width [expr $pixwidth / $@length]
+ set canvas [$self get_canvas]
+ set i 0
+ foreach val $@data {
+ if {!$val} {set val 0.0}
+ #set val2 [lindex $@data [expr $i+1]]
+ set y [expr ($pixheight - ((double($val)+abs($yfrom))/($yto-($yfrom)) * $pixheight)) + $y_off]
+ #set y2 [expr ($pixheight - ((double($val2)+abs($yfrom))/($yto-($yfrom)) * $pixheight)) + $y_off]
+ set x1 [expr ($width * $i) + $x_off]
+ set x2 [expr $x1 + $width]
+ set line [list $x1 $y $x2 $y]
+ $self item ${self}ELEM${i} line $line -fill [$self look fg] -width 2
+ incr i
+ }
+ [$canvas widget] raise $self
+ #set width [expr $pixwidth / [expr $@length-1]]
+ #set canvas [$self get_canvas]
+ #set i 0
+ #for {set i 0} {$i < [expr $@length-1]} {incr i} {
+ # #if {!$val} {set val 0.0}
+ # set val [lindex $@data [expr $i]]
+ # set val2 [lindex $@data [expr $i+1]]
+ # set y [expr ($pixheight - ((double($val)+abs($yfrom))/($yto-($yfrom)) * $pixheight)) + $y_off]
+ # set y2 [expr ($pixheight - ((double($val2)+abs($yfrom))/($yto-($yfrom)) * $pixheight)) + $y_off]
+ # set x1 [expr ($width * $i) + $x_off]
+ # set x2 [expr $x1 + $width]
+ # set line [list $x1 $y $x2 $y2]
+ # $self item ${self}ELEM${i} line $line -fill [$self look fg] -width 0
+ #}
+ }
+}
+
+def Array click {x y f target} {
+ if {[winfo exists [$@canvas widget]]} {set canvas $@canvas} else {set canvas [$@canvas canvas]}
+ $canvas focus= $self
+ set @draw 1
+}
+def Array unclick {x y f target} {
+ if {[winfo exists [$@canvas widget]]} {set canvas $@canvas} else {set canvas [$@canvas canvas]}
+ $canvas focus= ""
+ set @draw 0
+}
+def Array motion {x y f target} {
+ if {!$@draw} return
+ if {[winfo exists [$@canvas widget]]} {
+ mset {c_width c_height} [$@canvas get_dimen]
+ mset {xfrom yto xto yfrom pixwidth pixheight} [$@canvas get_mess]
+ set width [expr $c_width / $@length]
+ set i [format %d [expr int($x/$width)]]
+ set x1 [expr $width * $i]
+ set x2 [expr $x1 + $width]
+ set line [list $x1 $y $x2 $y]
+ set val [expr (($c_height-$y)/$c_height) * ($yto-($yfrom)) + ($yfrom)]
+ netsend [list .$self $i $val]
+ } else {
+ mset {xfrom yto xto yfrom pixwidth pixheight} [$@canvas get_mess]
+ mset {x_off y_off} [$@canvas xy]
+ set width [expr $pixwidth / $@length]
+ set i [format %d [expr int(($x-$x_off)/$width)]]
+ set val [expr (($pixheight-$y+$y_off)/$pixheight) * ($yto-($yfrom)) + ($yfrom)]
+ netsend [list .$self $i $val]
+ }
+}
+def Array length= {val} {set @length [format %f $val]}
+def Array name= {val} {set @name $val}
+def Array array_set {data_list} {
+ if {[llength $data_list] == $@length} {
+ set @data {}
+ for {set i 0} {$i < $@length} {incr i} {
+ lappend @data [lindex $data_list $i]
+ }
+ } else {
+ puts "error....."
+ }
+}
+
+############ evaluator
+
+class_new Listener {Thing}
+
+def Listener init {serf name command} {
+ set @history [History new 20]
+ set @command $command
+ set @expanded 0
+ set @serf $serf
+ frame $serf
+ pack [frame $serf.1] -side left -fill y
+ pack [frame $serf.1.1] -side bottom
+ pack [button $serf.1.1.expander -image icon_plus -command "$self toggle_expand"] -side left
+ pack [label $serf.1.1.label -width 11 -text "$name: " -font {Courier 10}] -side left
+ pack [entry $serf.entry -width 40 -font $::look(View:font)] -side left -fill x -expand yes
+ pack $serf -fill x -expand no
+ bind $serf.entry <Up> "$self scroll_history +1"
+ bind $serf.entry <Down> "$self scroll_history -1"
+ bind $serf.entry <Return> "$self eval"
+}
+
+def Listener toggle_expand {} {
+ set @expanded [expr 1-$@expanded]
+ if {$@expanded} {$self expand} {$self unexpand}
+}
+
+def Listener expand {} {
+ set e $@serf.entry
+ set text [$e get]
+ destroy $e
+ pack [text $e -width 40 -height 8] -side left -fill x -expand yes
+ $e insert 0.0 $text
+ $@serf.1.1.expander configure -image icon_minus
+ bind $e <Alt-Return> "$self eval"
+}
+
+def Listener unexpand {} {
+ set e $@serf.entry
+ set text [$e get 0.0 end]
+ regsub "\n$" $text "" text
+ destroy $e
+ pack [entry $e -width 40] -side left -fill x -expand yes
+ $e insert 0 $text
+ $@serf.1.1.expander configure -image icon_plus
+ bind $e <Up> "$self up"
+ bind $e <Down> "$self down"
+ bind $e <Return> "$self eval"
+}
+
+def Listener replace {stuff} {
+ $@serf.entry delete 0 end
+ $@serf.entry insert 0 $stuff
+ $@serf.entry icursor end
+}
+
+def Listener scroll_history {incr} {
+ if {![$@history histi]} {$@history set_hist 0 [$self get_command]}
+ $self replace [$@history traverse $incr]
+
+}
+
+def Listener append {v} {
+ $@history prepend $v
+ lappend @hist $v; set @histi [llength $@hist]
+}
+
+def Listener get_command {} {
+ set e $@serf.entry
+ if {$@expanded} {
+ set l [$e get 0.0 end]; return $l
+ } else {
+ set l [$e get]; return $l
+ }
+
+}
+
+def Listener eval {} {
+ set e $@serf.entry
+ $@history histi= 0
+ set l [$self get_command]
+ $self append $l
+ if {$@expanded} {$e delete 0.0 end} {$e delete 0 end}
+ $@command $self $l
+}
+
+proc tcl_eval {self l} {post %s "tcl: $l"; post %s "returns: [uplevel [info level] $l]"}
+proc pd_eval {self l} {post %s "pd: $l"; netsend $l}
+proc canvas_eval {self l} {post %s "tcl: $l"; post %s "returns: [uplevel [info level] [join [list [$self canvas] $l]]]"}
+############ button bar
+
+set butt {
+ {ObjectBox Object {obj}}
+ {MessageBox Message {msg}}
+ {FloatBox Number {floatatom}}
+ {SymbolBox Symbol {symbolatom}}
+ {CommentBox Comment {text}}
+ {bng bng {obj bng}}
+ {tgl tgl {obj tgl}}
+ {nbx nbx {obj nbx}}
+ {vsl vsl {obj vsl}}
+ {hsl hsl {obj hsl}}
+ {vradio vradio {obj vradio}}
+ {hradio hradio {obj hradio}}
+ {vu vu {obj vu}}
+ {cnv cnv {obj cnv}}
+ {Graph graph {graph}}
+ {Array array {menuarray 0}}
+}
+# {dropper dropper {pd %W dropper 0}}
+
+proc button_bar_add {x y} {
+ global butt
+ lappend butt [list $x $y noload]
+}
+
+if {$tk} {
+ set dir $cmdline(icons)
+ foreach icon {mode_edit mode_run pd} {image create photo icon_$icon -file $dir/$icon.gif}
+ foreach b $butt {mset {icon name cmd} $b; image create photo icon_$icon -file $dir/$icon.gif}
+}
+
+class_new ButtonBar {View}
+
+def ButtonBar init {canvas} {
+ set @canvas $canvas
+ set bb .$@canvas.bbar
+ frame $bb
+ pack [button $bb.edit -image icon_mode_edit -border 1 -command [list $@canvas editmodeswitch]] -side left
+ foreach e $::butt {
+ mset {icon name cmd} $e
+ pack [button $bb._$name -image icon_$icon -border 1 -command "$@canvas new_object $cmd"] -side left
+ balloon $bb._$name [say $name]
+ }
+ pack [entry $bb.name -font {helvetica -12} -width 8 -border 0] -side right
+ pack [spinbox $bb.scale -width 5 -command "$canvas zooming %d" -state readonly] -side right
+ $bb.scale set [format %d%% [expr int(100*[$@canvas zoom])]]
+ $bb.name insert 0 $@canvas
+}
+
+def ButtonBar widget {} {return .$@canvas.bbar}
+
+proc obj_create {c flag} {}
+
+############ crosshair
+
+class_new Crosshair {View}
+
+def Crosshair classtags {} {return {}}
+
+def Crosshair init {canvas} {
+ super
+ set @canvas $canvas
+ $self data= 0 0 {none}
+}
+
+def Crosshair data= {x y target} {
+ set @x $x
+ set @y $y
+ set @target $target
+}
+
+def Crosshair draw {} {
+
+ mset {type id detail} $@target
+ set x $@x; set y $@y
+
+ if {[$@canvas look hairsnap]} {
+ switch -regexp -- $type {^object|outlet|inlet$ {mset {x y x3 y3} [$id bbox]}}
+ }
+ mset {x1 y1 x2 y2} [$self display_area]
+
+ set h1 [list $x1 $y $x2 $y]
+ set v1 [list $x $y1 $x $y2]
+ $self item VHAIR1 line $v1 -fill [$@canvas look crosshair] -width 1 -dash {4 4 4 4}
+ $self item HHAIR1 line $h1 -fill [$@canvas look crosshair] -width 1 -dash {4 4 4 4}
+}
+
+#def Crosshair erase {} {$self item_delete VHAIR1; $self item_delete HHAIR1}
+class_new Sense {View}
+
+def Sense init {canvas} {
+ super
+ set @canvas $canvas
+ $self data= 0 0 0 red
+}
+
+def Sense data= {x y range col} {
+ set @x $x
+ set @y $y
+ set @range $range
+ set @col $col
+}
+
+def Sense flash {x y sense col} {
+ $self data= $x $y $sense $col
+ $self draw
+ after 500 $self erase
+}
+
+def Sense draw {} {
+ set c [$@canvas widget]
+ set x1 [expr $@x-$@range]; set y1 [expr $@y-$@range]
+ set x2 [expr $@x+$@range]; set y2 [expr $@y+$@range]
+ $self item SENSE oval [list $x1 $y1 $x2 $y2] -fill $@col -outline yellow
+}
+
+def View display_area {} {
+ set c [$@canvas widget]; set z [$@canvas zoom]
+ set edge 10
+ set x1 [expr {int([$c canvasx $edge]/$z)}]
+ set y1 [expr {int([$c canvasy $edge]/$z)}]
+ set x2 [expr {int(([$c canvasx [winfo width $c]]-$edge)/$z)}]
+ set y2 [expr {int(([$c canvasy [winfo height $c]]-$edge)/$z)}]
+ return [list $x1 $y1 $x2 $y2]
+}
+
+class_new Grid {View}
+
+def Grid init {canvas} {
+ super
+ set @canvas $canvas
+ set c [$@canvas widget]
+ set @width [winfo width $c]
+ set @height [winfo height $c]
+ set @size [$@canvas look grid_size]
+ set @col [$@canvas look grid]
+ set @gap 5
+}
+
+def Grid classtags {} {return {}}
+
+def Grid update {h w} {set @width $w; set @height $h}
+def Grid size= {size} {set @size $size}
+def Canvas snap_grid {} {return [$self look snap_grid]}
+def Canvas snap_grid= {val} {set ::look(Canvas:snap_grid) $val}
+
+def Canvas snap_objs2grid {} {
+ if {![$self editmode]} {return}
+ foreach obj [$@objects values] {
+ mset {x y} [$obj xy]
+ set grid [$self look grid_size]
+ set x [expr floor($x/$grid)*$grid]
+ set y [expr floor($y/$grid)*$grid]
+ $obj moveto $x $y
+ }
+}
+
+def Grid draw {} {
+ mset {x1 y1 x2 y2} [$self display_area]
+ set c [$@canvas widget]
+ set lowest [$@canvas lowest_item]
+ $self draw_lines $x1 $x2 $y1 $y2 VL
+ $self draw_lines $y1 $y2 $x1 $x2 HL
+ if {$lowest != -1} {$c lower $self $lowest}
+}
+
+def Grid draw_lines {v1 v2 v3 v4 tag} {
+ set s $@size; set g $@gap
+ for {set i $v1} {$i < $v2} {incr i} {
+ #if {$l%$g == 0} {set width 1;set dash [list 7 1]} {set width 1;set dash [list 1 4 1 4]}
+ if {![expr {$i % int($s*$g)}]} {set w 1;set d [list 7 1]} {set w 1;set d [list 1 4 1 4]}
+ if {![expr {$i % int($s)}]} {
+ switch $tag {VL {set line [list $i $v3 $i $v4]} HL {set line [list $v3 $i $v4 $i]}}
+ $self item ${tag}$i line $line -fill $@col -width $w -dash $d
+ }
+ }
+}
+
+def Canvas lowest_item {} {
+ set c [$self widget]
+ set all [$c find withtag foo]
+ if {![llength $all]} {return -1}
+ set lowest [lindex [$c gettags [lindex $all 0]] 0]
+ return $lowest
+}
+
+#def Canvas grid_size {} {return [$self look grid_size]}
+def Canvas grid_size= {size} {
+ set ::look(Canvas:grid_size) $size
+ if {[$self editmode]} {$@grid size= $size; $@grid erase; after 0 $@grid draw}
+}
+############ tooltips (only those that are drawn as canvas items)
+
+class_new Tooltip {View}
+
+def Tooltip init {canvas pos curpos text type iserror} {
+ set @canvas $canvas
+ set @pos $pos
+ set @curpos $curpos
+ set @text $text
+ set @type $type
+ set @iserror $iserror
+}
+
+def Tooltip iserror {} {return $@iserror}
+def Tooltip curpos {} {return $@curpos}
+def Tooltip text {} {return $@text}
+
+def Tooltip draw {} {
+ set c [$@canvas widget]
+ if {$@iserror} {
+ set fg "#ffffff"; set bg "#dd0000"
+ } else {
+ set fg "#000000"; set bg "#ffffcc"
+ }
+ mset {x y} $@pos
+ switch -- $@type {
+ o {set ny [expr {$y+24}]}
+ i {set ny [expr {$y-24}]}
+ }
+ $self item TEXT text [list [expr $x+12] $ny] -fill $fg -text $@text -anchor w
+ mset {x1 y1 x2 y2} [l+ [$c bbox ${self}TEXT] [list -4 -4 +4 +4]]
+ switch -- $@type {
+ o {set coords [list $x1 $y1 [expr $x1+8] $y1 $x $y [expr $x1+16] $y1 $x2 $y1 $x2 $y2 $x1 $y2 $x1 $y1]}
+ i {set coords [list $x1 $y1 $x2 $y1 $x2 $y2 [expr $x1+16] $y2 $x $y [expr $x1+8] $y2 $x1 $y2 $x1 $y1]}
+ }
+ $self item RECT polygon $coords -fill $bg -outline $fg
+ $c lower ${self}RECT ${self}TEXT
+}
+
+# $c delete tooltip_bg tooltip_fg
+
+set tooltip ""
+
+def Canvas show_tooltip {x y text type {iserror 0}} {
+ global tooltip
+ if {$tooltip ne "" && [$tooltip text] eq $text} {return}
+ if {$tooltip ne ""} {$tooltip delete}
+ set tooltip [Tooltip new $self [list $x $y] $@curpos $text $type $iserror]
+ $tooltip draw
+}
+
+############ class browser
+
+class_new ServerClassDict {Observable Thing}
+def ServerClassDict init {} {
+
+}
+
+# Completion/Browser init can be cleaned up a bit more, do it later...
+class_new ClassBrowser {Dialog}
+class_new Browser {ClassBrowser}
+def Browser init {name x y textbox} {super $name $x $y $textbox}
+class_new Completion {ClassBrowser}
+def Completion init {name x y textbox} {super $name $x $y $textbox}
+
+def Completion cancel {} {
+ bind $@textbox <Key> "$@textself key_input %W %x %y %K %A 0"
+ bind $@textbox <Control-Return> "$@textself key_input %W %x %y 10 %A 0"
+ bind $@textbox <Return> "$@textself unedit"
+ bind $@textbox <Tab> "$@textself key_input %W %x %y %K %A 0"
+ focus $@textbox
+ $self delete
+}
+def ClassBrowser delete {} {set @exist 0; super}
+
+def ClassBrowser init {name x y textbox} {
+ set @name $name
+ set @width 0
+ set @height 0
+ # so that in completion mode, it know which textbox to switch the focus to
+ set @textbox $textbox
+ netsend [list pd update-path]
+ netsend [list pd update-class-list $self list_callback]
+}
+
+def ClassBrowser fill_box {s} {
+ global class_list
+ $@listbox delete 0 end
+ foreach class $class_list {
+ if {[string length $s]==0 || [string first $s $class]>=0} {
+ set t "\[$class\]"
+ if {[can_say $class]} {append t " [say $class]"}
+ $@listbox insert end $t
+ #if {[string length $t] > [string length $@width]} {set @width [string length $t]}
+ if {[string length $t] > $@width} {set @width [string length $t]}
+ }
+ }
+ set none [say no_matches]
+ if {![$@listbox size]} {$@listbox insert 0 $none; set @width [string length $none]}
+ $@listbox selection set 0 0
+}
+
+def Completion fill_box {s} {
+ super $s
+ wm maxsize .$self [winfo reqwidth .$self.comp] [winfo reqheight .$self.comp]
+}
+
+def Browser fill_box {s} {
+ super $s
+ .$self.title configure -text [format [say how_many_object_classes] [$@listbox size] [llength $::class_list]]
+}
+
+def ClassBrowser search_for_externs {} {
+ global pd_path class_list
+ foreach dir $pd_path {
+ catch {
+ set xs [glob "$dir/*.pd*"]
+ foreach x $xs {
+ set fn [lindex [file split $x] end]
+ set fn [join [lrange [split $fn .] 0 end-1] .]
+ lappend class_list $fn
+ }
+ }
+ }
+}
+
+def ClassBrowser info {listbox} {
+ set class [$self current_class]
+ if {$class != ""} {netsend [list pd update-class-info $class $self info_callback]}
+}
+
+def Browser list_callback {} {
+ $self search_for_externs
+ set class_list [luniq [lsort $::class_list]]
+
+ toplevel .$self
+ set f .$self.cl
+ pack [frame $f] -side top -fill both -expand yes
+ pack [label .$self.title -text ""] -side top
+ listbox $f.1 -width 50 -height 20 -yscrollcommand "$f.2 set" -activestyle none
+ scrollbar $f.2 -command "$f.1 yview"
+ text $f.3 -width 30 -height 20 -yscrollcommand "$f.4 set"
+ scrollbar $f.4 -command "$f.3 yview"
+ set @listbox $f.1
+
+ frame $f.5
+ button $f.5.help -text [say help] -command [list $self help]
+ pack $f.5.help -side top
+ pack $f.5 -side left -fill y -expand no
+ pack $f.1 -side left -fill both -expand yes
+ pack $f.2 -side left -fill y -expand no
+ pack $f.3 -side left -fill both -expand yes
+ pack $f.4 -side left -fill y -expand no
+
+ set b .$self.butt
+ frame $b
+ pack [label $b.1 -text [say filter]] -side left
+ pack [entry $b.2 -width 15] -side left
+ pack [button $b.close -text [say close] -command "destroy .$self"] -side right
+ pack $b -side bottom -fill x -expand no
+ set @textbox $b.2
+ $self fill_box ""
+ #bind $f.1 <Button-1> "after 1 \"$self info $f.1 \""
+ foreach w [list $f.1 $b.2] {
+ bind $w <KeyPress> "after 1 \"$self key %K 0\""
+ bind $w <Shift-KeyPress> "after 1 \"$self key %K 1\""
+ bind $w <Return> [list $self help]
+ }
+ focus $@textbox
+}
+
+def Browser help {} {
+ set f .$self.cl
+ netsend [list pd help [$self current_class]]
+}
+
+def Completion list_callback {} {
+ $self search_for_externs
+ set class_list [luniq [lsort $::class_list]]
+ toplevel .$self
+ wm protocol .$self WM_DELETE_WINDOW "$self cancel"
+ wm overrideredirect .$self 1
+ set canvas $@name
+ set f .$self.comp
+ set @listbox $f
+ set @rootx [winfo rootx .$@name.c]
+ set @rooty [winfo rooty .$@name.c]
+ set @max [wm maxsize .$self]
+ if {[regexp {(x[0-9a-z]{6,8})text$} $@textbox dummy textself]} {set @textself $textself}
+ if {[$canvas look showcomp] <= 20} {set @height [$canvas look showcomp]} else {set @height 20}
+ listbox $f -width $@width -height $@height -relief flat -activestyle dotbox -font $::look(View:font) \
+ -bg [$@textself look bg] -selectbackground [$@textself look fg] \
+ -fg [$@textself look fg] -selectforeground [$@textself look bg]
+ $self adjust_box
+ bind $f <Button-1> "after 1 \"$self complete\""
+ bind $f <Return> "after 1 \"$self complete\""
+ bind $f <KeyPress> "$self key %K 0"
+ bind $f <Shift-KeyPress> "$self key %K 1"
+ bind $@textbox <Tab> "$self key %K; break"
+ bind $@textbox <KeyPress> "$self key %K "
+ focus .$self.comp
+}
+
+def Completion adjust_box {} {
+ mset {x1 y1 x2 y2} [lmap * [$@textself bbox] [$@name zoom]]
+ set x1 [format %0.f $x1];set y1 [format %0.f $y1]
+ set x2 [format %0.f $x2];set y2 [format %0.f $y2]
+ $self fill_box [$@textbox get 1.0 1.end]
+ set f .$self.comp
+ $f configure -width $@width
+ set box_width [winfo reqwidth $f]
+ set box_height [winfo reqheight $f]
+ pack $f -side left -expand yes
+
+ .$self configure -width $box_width
+ .$self configure -height $box_height
+
+ #test the right edge of the screen, assuming the left edge has enough space
+ if {[expr $x1+$@rootx+$box_width] < [lindex $@max 0]} {
+ set box_x [expr $x1+$@rootx]
+ } else {
+ set box_x [expr $x2 - $box_width + $@rootx]
+ }
+ #test the lower edge of the screen, assuming the upper edge has enough space
+ if {[expr $y2+$@rooty+$box_height] < [lindex $@max 1]} {
+ set box_y [expr $y2 + 5 + $@rooty]
+ } else {
+ set box_y [expr $y1 - $box_height - 2 + $@rooty]
+ }
+
+ wm geometry .$self [winfo reqwidth .$self]x[winfo reqheight .$self]+$box_x+$box_y
+
+}
+
+def ClassBrowser current_class {} {
+ set i [$@listbox curselection]
+ if {$i == ""} {return {}}
+ return [string range [lindex [$@listbox get $i] 0] 1 end-1]
+}
+
+def ClassBrowser complete {} {
+ if {[regexp {x([0-9a-z]{6,8})text$} $@textbox obj]} {
+ set cut [string first "text" $obj]
+ set obj [string range $obj 0 [expr $cut -1]]
+ }
+ set class [$self current_class]
+ $@textbox delete 1.0 1.end
+ $@textbox insert 1.0 $class
+
+ $obj unedit
+ destroy .$self
+}
+
+def ClassBrowser key {key {shift 0}} {
+ switch -regexp -- $key {
+ Up|Down {
+ if {[focus] != $@listbox} {
+ focus $@listbox
+ event generate $@listbox <KeyPress> -keysym $key
+ } else {
+ if {$self == "browser"} {$self info $@listbox}
+ }
+ }
+ Escape {after 1 "$self cancel"} ;# doesn't really work
+ Tab {
+ focus $@listbox
+ set next [$@listbox index active]
+ incr next
+ if {$next >= [$@listbox size]} {set next 0}
+ $@listbox activate $next
+ $@listbox selection clear 0 [expr [$@listbox size] - 1]
+ $@listbox selection set $next $next
+ #if {$next >= [expr $@height - 1]} {$@listbox yview scroll 1 units}
+ $@listbox see $next
+ if {$self == "browser"} {$self info $@listbox}
+ }
+ BackSpace {
+ if {[focus] == $@listbox} {focus $@textbox}
+ #classbrowser uses entry as input widget, where as completion is text widget...
+ switch $self {
+ browser {$self fill_box [$@textbox get]}
+ completion {$self adjust_box; $@textself resize; $@textself changed}
+ }
+ }
+ default {
+ $self key_default $key
+ }
+ }
+}
+
+def Browser key_default {key} {
+ if {[focus] == $@listbox} {
+ if {[regexp {^[a-zA-Z0-9~/\._]{1}$} $key]} {
+ .$self.butt.2 insert end $key
+ $self fill_box [$@textbox get]
+ }
+ } else {$self fill_box [$@textbox get]}
+}
+
+def Completion key_default {key} {
+ if {[focus] == $@listbox} {
+ if {[regexp {^[a-zA-Z0-9~/\._]{1}$} $key]} {
+ $@textbox insert 1.end $key
+ $@textself after_key $@textbox
+ $self adjust_box
+ focus $@textbox
+ }
+ }
+ if {[focus] == $@textbox & $key != "Tab"} {
+ $self adjust_box
+ $@textself resize
+ #hum, no idea why i need after 1 for it to work...
+ after 1 $@textself after_key $@textbox
+ }
+}
+
+def ClassBrowser info_callback {class} {
+ global class_info
+ set f .browser.cl
+ set class [$self current_class]
+ $f.3 delete 0.0 end
+ $f.3 insert end "class $class\n"
+ foreach {k v} $class_info($class) {$f.3 insert end "$k=\"$v\"\n"}
+}
+
+def TextBox propose_completions {} {
+ set c [$@canvas widget]
+ set widget $c.${self}text
+ set propose $c.${self}propose
+ #$propose configure -state normal
+ if {![info exists ::class_list]} {
+ netsend [list pd update-class-list $self propose_completions]
+ return
+ }
+ set r {}
+ set c {}
+ set n 0
+ set prev ""
+ foreach class [luniq [lsort $::class_list]] {
+ if {[string length $@text]==0 || [string first $@text $class]>=0} {
+ if {[string compare [say $class] "{{$class}}"]} {
+ lappend r "$class : [say $class]"
+ } {
+ lappend r $class
+ }
+ lappend c $class
+ incr n
+ }
+ if {$n > 16} {lappend r ...; break}
+ }
+ set r [join $r "\n"]
+ mset {x1 y1 x2 y2} [$self bbox]
+ set @action [Completion new_as completion $@canvas $x1 $y1 $widget]
+}
+
+############ properties_dialog #########
+proc change_entry {self val} {
+ set v [expr [$self get]+$val]
+ $self delete 0 end
+ $self insert 0 $v
+}
+
+class_new Dialog {View}
+
+def Dialog add_stuff {f name label} {
+ frame $f
+# frame $f.label -width $@label_width -borderwidth 2
+# pack [button $f.label.0 -image "icon_empty" -width $@label_width] -side left
+# place [message $f.label.1 -text $label -width $@label_width] -x 0 -y 0
+# puts [$f.label.1 cget -height]
+ pack [label $f.label -text $label -width [expr $@label_width/7] -wraplength $@label_width -anchor e] -side left
+ balloon $f.label $name
+}
+
+def Dialog add_side {f name label} {
+ $self add_stuff $f $name $label
+ frame $f.side -relief ridge -borderwidth 2
+ foreach {i side} {0 left 1 right 2 top 3 bottom} {
+ radiobutton $f.side.$side -value $i -variable @$name -text $side
+ }
+ pack $f.side.left -side left -fill y
+ pack $f.side.right -side right -fill y
+ pack $f.side.top -side top
+ pack $f.side.bottom -side bottom
+ pack $f.side -side left
+}
+
+def Dialog add_color {f name label} {
+ $self add_stuff $f $name $label
+ set v $@$name
+ set text_color [complement $v]
+ button $f.color -text $v -font {Courier 10} -width 10 -pady 2 -fg $text_color \
+ -command [list $self choose_col $f $name $v] -relief sunken -background $v \
+ -highlightbackground "#ffffff" -activebackground [darker $v]
+ button $f.preset -text [say "preset"] -pady 2 -font {Helvetica 8} \
+ -command [list $self color_popup $f $name 10]
+ bind $f.preset <Return> "$self color_popup $f $name 10"
+ pack $f.color $f.preset -side left
+}
+
+
+def Dialog add_choice {f name label choices} {
+ $self add_stuff $f $name $label
+ menu $f.menu -tearoff 0
+ set i 0
+ foreach part $choices {
+ $f.menu add command -label [say $part] -command [list $self dropmenu_set $f $name $part $i]
+ incr i
+ }
+ set trim_name [string trimleft $name "-"]
+ set _($self:${name}choices) $choices
+ set choice $@$name
+ if {[string is integer $choice]} {set choice [lindex $choices $choice]}
+ label $f.butt -text [say $choice] -relief raised -width 20
+ balloon $f.butt "click to change setting"
+ pack $f.label $f.butt -side left
+ bind $f.butt <1> [list $self dropmenu_open $f $name]
+}
+
+def Dialog add_key {f name label} {
+ set text ""
+ set n 0
+ foreach item $name {
+ if {$n != 0} {append text " & " [say $item]} else {set text [say $item]}
+ incr n
+ }
+ $self add_stuff $f $name $text
+ #balloon $f.label $name
+ foreach item $name {
+ set v $_($self:$item) ;# bug in objtcl
+ set item_lower [string tolower $item]
+ entry $f.$item_lower -width 15 -textvariable @$item
+ pack $f.$item_lower -side left
+ }
+}
+
+def Dialog add_folders {f name label} {
+ $self add_stuff $f $name $label
+ set v $_($self:$name) ;# bug in poetcl
+ frame $f.a
+ listbox $f.a.list -width 40 -height 8 -yscrollcommand "$f.a.yscroll set" \
+ -activestyle none -xscrollcommand "$f.a.xscroll set"
+ foreach line $v {$f.a.list insert end $line}
+ set @$name $f.a.list ;# save the listbox path at @$name instead
+ scrollbar $f.a.yscroll -command "$f.a.list yview"
+ scrollbar $f.a.xscroll -command "$f.a.list xview" -orient horizontal
+ pack $f.a.xscroll -side bottom -fill x
+ pack $f.a.list -side left -fill both -expand 1
+ pack $f.a.yscroll -side left -fill y
+ pack $f.a -side left
+ frame $f.b -borderwidth 0
+ foreach {cmd lab} {dir_add add listbox_remove remove listbox_up up listbox_down down} {
+ pack [button $f.b.$cmd -command "$self $cmd $f.a.list" -text [say $lab] -width 6] -side top
+ balloon $f.b.$cmd [say dir_$lab]
+ }
+ pack $f.b -side top
+}
+
+def Dialog add_libraries {f name label} {
+ $self add_stuff $f $name $label
+ set v $_($self:$name) ;# bug in objtcl
+ frame $f.a
+ listbox $f.a.list -width 32 -height 16 -yscrollcommand "$f.a.yscroll set" \
+ -activestyle none -xscrollcommand "$f.a.xscroll set"
+ #foreach line $@$name {$f.a.list insert end $line}
+ foreach line $v {$f.a.list insert end $line}
+ # save the listbox path at @$name instead
+ set @$name $f.a.list
+ scrollbar $f.a.yscroll -command "$f.a.list yview"
+ scrollbar $f.a.xscroll -command "$f.a.list xview" -orient horizontal
+
+ pack $f.a.xscroll -side bottom -fill x
+ pack $f.a.list -side left -fill both -expand 1
+ pack $f.a.yscroll -side left -fill y
+ pack $f.a -side left
+
+ frame $f.b -borderwidth 0
+ entry $f.b.entry -width 15 -borderwidth 5 -relief ridge
+ bind $f.b.entry <Return> "$self lib_add $f.a.list"
+ pack $f.b.entry -side top
+
+ foreach {cmd lab} {lib_add add listbox_remove remove listbox_up up listbox_down down} {
+ pack [button $f.b.$cmd -command "$self $cmd $f.a.list" -text [say $lab] -width 6] -side top
+ balloon $f.b.$cmd [say dir_$lab]
+ }
+ pack $f.b -side top
+}
+
+def Dialog dir_add {listbox} {
+ set dir [tk_chooseDirectory -initialdir ~ -title "Choose a folder" -parent .$self]
+ if {$dir == ""} {return}
+ $listbox insert end $dir
+ $listbox yview end
+ focus .$self
+}
+
+# doesn't work with toplevel widget
+proc upwidget {levels name} {
+ set l [split $name .]
+ return [join [lrange $l 0 end-$levels] .]
+}
+
+def Dialog lib_add {f} {
+ set f [upwidget 2 $f]
+ set listbox $f.a.list
+ set entry $f.b.entry
+ set var [$entry get]
+ if {$var != ""} {$listbox insert end $var}
+ $listbox yview end
+ $entry delete 0 end
+ focus $entry
+}
+
+def Dialog listbox_remove {listbox} {
+ set sel [$listbox curselection]
+ if {$sel == ""} {return}
+ $listbox delete $sel
+ $listbox selection set $sel
+}
+
+def Dialog listbox_swap {listbox dir} {
+ set sel [$listbox curselection]
+ if {$sel == ""} {return}
+ if {![inside [expr $sel+$dir] 0 [$listbox size]]} {return}
+ set line [$listbox get $sel]
+ $listbox delete $sel
+ incr sel $dir
+ $listbox insert $sel $line
+ $listbox selection set $sel
+ $listbox see $sel
+}
+
+def Dialog add_devlist {f name label} {
+ $self add_stuff $f $name $label
+ menu $f.menu -tearoff 0
+ set i 0
+ set trim_name [string trimleft $name "-"]
+ set part none ;# in case there are none
+ foreach part $@$trim_name {
+ $f.menu add command -label $part -command [list $self dropmenu_set $f $name $part $i]
+ incr i
+ }
+ #label $f.butt -text [lindex $@$trim_name 0] -relief raised -width 20
+ label $f.butt -textvariable _($self:${trim_name}0) -relief raised -width 20
+ balloon $f.butt "click to change setting"
+ pack $f.label $f.butt -side left
+ bind $f.butt <1> [list $self dropmenu_open $f $name]
+}
+
+def Dialog add_spins {f name label option} {
+ global _
+ $self add_stuff $f $name $label
+ set i 0
+ set trim_name [string trimleft $name "-"]
+ set n [llength $@$option]
+ foreach part $@$trim_name {
+ if {$i < $n} {set s "readonly"} else {set s "disabled"}
+ set v "_($self:$trim_name${i})"
+ spinbox $f.$i -width 2 -command "$self spinning %d $v" -state $s -textvariable $v
+ pack $f.$i -side left
+ balloon $f.$i "Device [expr $i+1]"
+ incr i
+ }
+}
+
+def Dialog spinning {mode v} {
+ switch $mode {
+ up {incr $v; puts " incr $v"}
+ down {incr $v -1}
+ }
+}
+
+def Dialog listbox_up {listbox} {$self listbox_swap $listbox -1}
+def Dialog listbox_down {listbox} {$self listbox_swap $listbox +1}
+
+def Dialog add {w args} {
+ foreach row $args {
+ set name [lindex $row 0]
+ set type [lindex $row 1]
+ set options [lrange $row 2 end]
+ set f $w.$name
+ set label "[say $name]: "
+ set k [lsearch $options -choices]
+ if {$k>=0} {
+ set choices [lindex $options [expr $k+1]]
+ set options [lreplace $options $k [expr $k+1]]
+ }
+ #set v $@$name
+ #set v $_($self:$name) ;# bug in poetcl
+ switch -- $type {
+ side {$self add_side $f $name $label}
+ color {$self add_color $f $name $label}
+ font {$self add_font $f $name $label $options}
+ choice {$self add_choice $f $name $label $choices}
+ key {set f $w.[string tolower [lindex $name 0]]
+ $self add_key $f $name $label}
+ folders {$self add_folders $f $name $label}
+ libraries {$self add_libraries $f $name $label}
+ devlist {$self add_devlist $f $name $label}
+ spins {$self add_spins $f $name $label $options}
+ section {label $f -text $label -bg "#0000aa" -fg "#ffff55" -font {helvetica -10 bold}}
+ subsection {label $f -text $label -bg "#0000aa" -fg "#ffff55" -font {helvetica -10 bold}}
+ toggle {
+ $self add_stuff $f $name $label
+ eval [concat [list checkbutton $f.toggle -variable @$name] $options]
+ pack $f.toggle -side left
+ }
+ default {
+ $self add_stuff $f $name $label
+ set trim_name [string trimleft $name "-"]
+ eval [concat [list entry $f.entry -textvariable _($self:$trim_name)] $options]
+ pack $f.entry -side left
+ bind $f.entry <Return> "$self ok"
+ switch -regexp -- $type {
+ integer|float|fontsize {
+ frame $f.b -borderwidth 0
+ button $f.b.1 -image icon_wedge_up -command "change_entry $f.entry +1"
+ button $f.b.2 -image icon_wedge_down -command "change_entry $f.entry -1"
+ pack $f.b.1 $f.b.2 -side top
+ pack $f.b -side left
+ bind $f.entry <Button-4> "change_entry $f.entry +1"
+ bind $f.entry <Button-5> "change_entry $f.entry -1"
+ }
+ entry {}
+ default {
+ label $f.type -text "($type)" -fg "#808080"
+ pack $f.type -side right -anchor e
+ }
+ }
+ }
+ }
+ pack $f -side top -fill x
+ }
+}
+
+proc logvar {args} {
+ set r {}
+ foreach var $args {
+ regsub {^_\(.*:(.*)\)$} $var {@\1} var2
+ lappend r "$var2=[uplevel 1 list \$$var]"
+ }
+ puts [join $r "; "]
+}
+
+def Dialog spinbox_update {mode} {puts " $mode"}
+
+def Dialog add_font {f name label class} {
+ $self add_stuff $f $name $label
+ set v $@$name
+ label $f.font -text $v -font [lreplace $v 1 1 -10] -width [string length $v] -height 1 -pady 3 -fg black \
+ -relief sunken -bg white
+ button $f.preset -text [say "edit"] -pady 2 -font {Helvetica 8} \
+ -command "FontDialog new_as $name $class $f.font"
+ pack $f.font $f.preset -side left
+}
+
+class_new FontDialog {Dialog}
+
+def Canvas fd {} {FontDialog new_as view_font [$self look font] "View"}
+
+def FontDialog init {class orig} {
+ if {[winfo exists .$self]} {return}
+ super cancel ok
+ set f .$self
+ set @class $class
+ set @orig $orig
+ bind all <KeyPress-F1> help
+ set font $::look($@class:font)
+ set @family [lindex $font 0]
+ set @size [expr -[lindex $font 1]]
+ set @bold [expr [lsearch $font bold ]>=0]
+ set @italic [expr [lsearch $font italic]>=0]
+ set @str $font
+ logvar @family @size @bold @italic
+ pack [label $f.label -text [say font_family] -anchor w] -side top -fill x
+ frame $f.list -bd 2
+
+ pack [listbox $f.list.box -relief sunken -yscrollcommand "$f.list.scroll set"] -side left
+ pack [scrollbar $f.list.scroll -relief sunken -command "$f.list.box yview" -takefocus 0] -side right -fill y
+ bind $f.list.box <<ListboxSelect>> "$self font_update $f"
+ foreach name [lsort [font families]] {$f.list.box insert end $name}
+
+ set fontlist [$f.list.box get 0 end]
+ set find [lsearch $fontlist $@family]
+ if {$find < 0} {set find 0}
+ $f.list.box selection set $find $find
+ $f.list.box activate $find
+ $f.list.box see $find
+ bind $f.list.box <ButtonRelease-1> "$self font_update $f"
+ bind $f.list.box <ButtonPress-1> "focus $f.list.box"
+
+ frame $f.var
+ frame $f.var.size
+ pack [label $f.var.size.label -text [say font_size]] -side left
+ pack [spinbox $f.var.size.entry -relief sunken -textvariable fontsize -width 4 \
+ -command "$self font_changesize $f %d"] -side left
+ bind $f.var.size.entry <KeyPress-Return> "$self font_update_size $f"
+ $f.var.size.entry delete 0 end
+ $f.var.size.entry insert 0 $@size
+
+ frame $f.var.style
+ pack [label $f.var.style.label -text [say font_style]] -side left
+ set cmd [list $self font_update $f]
+ pack [checkbutton $f.var.style.bold -text [say font_bold] -variable @bold -command $cmd] -side top
+ pack [checkbutton $f.var.style.italic -text [say font_italic] -variable @italic -command $cmd] -side top
+
+ pack $f.var.size -side left
+ pack $f.var.style -side left -padx 20
+
+ frame $f.preview
+ pack [label $f.preview.label -text [say font_preview]] -side left
+ pack [canvas $f.preview.canvas -width 250 -height 50 -relief sunken -borderwidth 1] -side left -fill x
+ $f.preview.canvas create text 4 4 -tags ${self}TEXT -anchor nw -text [say font_preview_2] -font $font
+
+ pack $f.list -side left
+ pack $f.var -side top -fill x
+ pack $f.preview -side top -pady 10
+ focus $f.list.box
+ $self none_resizable
+}
+
+def FontDialog font_update {f} {
+ global font
+ set lb $f.list.box
+ set @family [$lb get [$lb curselection]]
+ set @str [list $@family [expr -$@size]]
+ if {$@bold } {lappend @str bold }
+ if {$@italic} {lappend @str italic}
+ # logvar @str
+ $f.preview.canvas itemconfigure ${self}TEXT -font $@str
+}
+
+def FontDialog font_changesize {f mode} {
+ switch $mode {
+ up {set @size [expr $@size+1]}
+ down {set @size [expr $@size-1]}
+ }
+ $f.var.size.entry delete 0 end
+ $f.var.size.entry insert 0 $@size
+ $self font_update $f
+}
+
+def FontDialog font_style {f bold} {
+ set @bold $bold
+ $self font_update $f
+}
+
+def FontDialog font_update_size {f} {
+ set size [$f.var.size.entry get]
+ if [regexp {^[0-9]+$} $size] {set @size $size}
+ $self font_update $f
+}
+
+def FontDialog apply {} {
+ set ::look($@class:font) $@str
+ $@orig configure -font [lreplace $@str 1 1 -10] -text $@str -width [string length $@str]
+}
+
+############ .pdrc editor
+#Turns #rgb into 3 elem list of decimal vals.
+proc rgb2dec {c} {
+ set c [string tolower $c]
+ if {[regexp -nocase {^#([0-9a-f])([0-9a-f])([0-9a-f])$} $c x r g b]} {
+ # double'ing the value make #9fc == #99ffcc
+ scan "$r$r $g$g $b$b" "%x %x %x" r g b
+ } else {
+ if {![regexp {^#([0-9a-f]+)$} $c junk hex] || \
+ [set len [string length $hex]]>12 || $len%3 != 0} {
+ if {[catch {winfo rgb . $c} rgb]} {
+ return -code error "bad color value \"$c\""
+ } else {
+ return $rgb
+ }
+ }
+ set len [expr {$len/3}]
+ scan $hex "%${len}x%${len}x%${len}x" r g b
+ }
+ return [list $r $g $b]
+}
+#Returns a complementary color
+proc complement {orig {grays 1}} {
+ foreach {r g b} [rgb2dec $orig] {break}
+ set R [expr {(~$r)%256}]
+ set G [expr {(~$g)%256}]
+ set B [expr {(~$b)%256}]
+ if {$grays && abs($R-$r) < 32 && abs($G-$g) < 32 && abs($B-$b) < 32} {
+ set R [expr {($r+128)%256}]
+ set G [expr {($g+128)%256}]
+ set B [expr {($b+128)%256}]
+ }
+ return [format "\#%02x%02x%02x" $R $G $B]
+}
+
+# this makes the tooltip
+proc balloon {w help} {
+ bind $w <Any-Enter> "after 500 [list balloon:show %W [list $help]]"
+ #bind $w <Any-Leave> "destroy %W.balloon; puts \"destroy balloon\" "
+ bind $w <Any-Leave> "destroy %W.balloon"
+}
+
+proc balloon:show {w arg} {
+ if {[eval winfo containing [winfo pointerxy .]]!=$w} {return}
+ set top $w.balloon
+ catch {destroy $top}
+ toplevel $top -bd 1 -bg black
+ wm overrideredirect $top 1
+ if {$::tcl_platform(platform) == "macintosh"} {
+ unsupported1 style $top floating sideTitlebar
+ }
+ pack [message $top.txt -aspect 10000 -bg lightyellow -font fixed -text $arg]
+ set wmx [expr [winfo rootx $w]+[winfo width $w]]
+ set wmy [winfo rooty $w]
+ wm geometry $top [winfo reqwidth $top.txt]x[winfo reqheight $top.txt]+$wmx+$wmy
+ raise $top
+}
+
+def Dialog ok {} {$self apply; $self cancel}
+def Dialog cancel {} {if {[info exists @nbs]} {foreach x $@nbs {$x delete}}; after 1 [list $self delete]}
+def Dialog close {} {$self delete}
+def Dialog apply {} {}
+def Dialog delete {} {destroy .$self; super}
+def Dialog erase {} {}; # so that it doesn't call View erase
+
+def Dialog init {args} {
+ super
+ set f .$self
+ set @label_width 160 ;# 20
+ toplevel $f
+ frame $f.buttonsep -height 2 -borderwidth 1 -relief sunken
+ frame $f.buttonframe
+ set i 0
+ foreach a $args {
+ if {[llength $args]<=1 || $i>0} {
+ pack [label $f.buttonframe.$i -width 1] -side left -fill x -expand 1
+ }
+ pack [button $f.buttonframe.$a -text [say $a] -command "$self $a"] -side left
+ bind $f.buttonframe.$a <Return> "$self $a"
+ incr i
+ }
+ pack $f.buttonframe -side bottom -fill x -pady 2m
+ pack $f.buttonsep -side bottom -fill x
+ wm protocol $f WM_DELETE_WINDOW "$self cancel"
+ bind .$self <Tab> "$self traversal %K %W forward"
+ bind .$self <Control-Tab> "$self traversal %K %W back"
+}
+
+def Dialog none_resizable {} {wm resizable .$self 0 0}
+
+def Dialog traversal {k w direction} {
+ switch $direction {
+ forward {focus [tk_focusNext $w]}
+ back {focus [tk_focusPrev $w]}
+ }
+}
+
+def Dialog dropmenu_open {frame} {
+ set x [winfo rootx $frame.butt]
+ set y [expr [winfo height $frame.butt] + [winfo rooty $frame.butt]]
+ tk_popup $frame.menu $x $y
+}
+
+def Dialog dropmenu_set {frame var part val} {
+ #if {$say} {set text [say $part]} else {set text $part}
+ set @$var $val
+ $frame.butt configure -text [say $part]
+}
+
+def Dialog color_popup_select {frame var color} {
+ set @$var $color
+ set col [format #%6.6x $color]
+ if {$self == "ddrc"} {set @$var $col}
+ $frame.color configure -background $col -foreground [complement $col] -text $col
+ if {$self != "ddrc"} {$self do_auto_apply}
+ #$self do_auto_apply
+}
+
+def Dialog color_popup {frame var i} {
+ set w $frame.color.popup
+ if [winfo exists $w] {destroy $w}
+ menu $w -tearoff false
+ global preset_colors
+ for {set i 0} {$i<[llength $preset_colors]} {incr i} {
+ set c [lindex $preset_colors $i]
+ $w add command -label " " -background "#$c" -activebackground "#$c" \
+ -command [list $self color_popup_select $frame $var [expr 0x$c]]
+ }
+ tk_popup $w [expr [winfo rootx $frame.color]] [expr [winfo rooty $frame.color]]
+}
+
+def Dialog choose_col {frame var val} {
+ set c 0xFFFFFF
+ set color [tk_chooseColor -title $val -initialcolor $val]
+ if {$color != ""} {
+ $frame.color configure -text $color
+ $self color_popup_select $frame $var [expr [string replace $color 0 0 "0x"]&0xFFFFFF]
+ }
+}
+
+class_new PagedDialog {Dialog}
+class_new Notebook {Thing}
+
+def PagedDialog init {args} {
+ eval [concat [list super] $args]
+ set @nb [Notebook new_as $self.1]
+ set @nbs $@nb
+ pack .$@nb -expand 1 -fill both
+ $self none_resizable
+}
+def Notebook delete {} {super}
+def Notebook init {{width 590} {height 350}} {
+ set f .$self
+ frame $f
+ pack [frame $f.bar] -fill x
+ pack [frame $f.main -borderwidth 1 -relief raised -width $width -height $height] -fill both -expand yes
+}
+
+def Notebook page_select {i} {
+ set f .$self
+ catch {
+ $f.bar.$@section configure -relief raised
+ place forget $f.main.$@section
+ pack $f.bar.$@section -pady {4 4}
+ }
+ set @section $i
+ place $f.main.$@section -x 0 -y 0 ;# -width [winfo width $f.main] -height [winfo height $f.main]
+ $f.bar.$@section configure -relief sunken
+ pack $f.bar.$@section -pady {8 0}
+}
+
+def Notebook add_section {section text} {
+ set f .$self
+ frame $f.main.$section
+ pack [button $f.bar.$section -text $text -command [list $self page_select $section]] -side left -pady {4 4}
+ bind $f.bar.$section <Return> "$self page_select $section"
+}
+
+# numbers in section are for the % of space taken by labels
+set pdrc_options {
+ section {section_audio 50}
+ integer -r
+ devlist -audioindev|-soundindev
+ devlist -audiooutdev|-soundoutdev
+ spins {-inchannels audioindev}
+ spins {-outchannels audiooutdev}
+ integer -audiobuf|-soundbuf
+ integer -blocksize
+ integer -sleepgrain
+ void -nodac
+ void -noadc
+ choice {audio_api_choice}
+ void -32bit
+
+ section {section_midi 50}
+ void -nomidiin
+ void -nomidiout
+ devlist -midiindev
+ devlist -midioutdev
+
+ section {section_externals 20}
+ libraries -lib
+
+ section {section_paths 20}
+ folders -path
+ folders -helppath
+
+ section {section_other 50}
+ files -open
+ void -verbose
+ integer -d
+ void -noloadbang
+ string -send
+ void -listdev
+ void -realtime|-rt
+}
+
+proc pdtk_audio_dialog {indevlist indevs inchans outdevlist outdevs outchans sr dspblock advance multi longform} {
+ pdrc audio_properties $indevlist $indevs $inchans $outdevlist $outdevs $outchans $sr $dspblock $advance $multi
+}
+
+class_new ServerPrefsDialog {PagedDialog}
+
+def ServerPrefsDialog apply {} {
+ set audio_props [$self audio_properties=?]
+ #pd pd audio-dialog $audio_props
+ netsend [list "pd" "audio-dialog" $audio_props]
+ $self write
+}
+
+def ServerPrefsDialog init_reverse_hash {} {
+ global pdrc_options pdrc_options_h pd_apilist2
+ foreach {type names} $pdrc_options {
+ set name [lindex $names 0]
+ if {[info exists @$name]} {
+ if {$name != "audio_api_choice"} {set @$name ""}
+ } else {
+ set @$name ""
+ }
+ foreach alias $names {set pdrc_options_h($alias) [list $type $name]}
+ if {$name == "audio_api_choice"} {
+ foreach alias [lrange $pd_apilist2 1 end] {set pdrc_options_h($alias) [list $type $name]}
+ }
+ }
+}
+
+def ServerPrefsDialog audio_properties {indevlist indevs inchans outdevlist outdevs outchans sr dspblock advance multi} {
+ set @audioindev $indevlist
+ set @audiooutdev $outdevlist
+ # the following @audioindev* is used as -textvariable for devlist
+ set @audioindev0 [lindex $@audioindev 0]
+ set @audiooutdev0 [lindex $@audiooutdev 0]
+ set @inchannels $inchans
+ set @outchannels $outchans
+ set @audiobuf $advance
+ set @blocksize $dspblock
+ set @usemulti $multi
+ set @r $sr
+ set @midiindev "midione"
+ set @midioutdev "miditwo"
+ # below are also used as -textvariable
+ mset [list @inchannels0 @inchannels1 @inchannels2 @inchannels3] $@inchannels
+ mset [list @outchannels0 @outchannels1 @outchannels2 @outchannels3] $@outchannels
+ set @audio_api_choice2 [say [lindex $::pd_apilist2 $@audio_api_choice]]
+ if {![winfo exists .$self.1.main.1]} {
+ $self init_content
+ } else {
+ $self update_content
+ }
+}
+
+def ServerPrefsDialog audio_properties=? {} {
+ set indev0 [lsearch $@audioindev $@audioindev0]
+ set outdev0 [lsearch $@audiooutdev $@audiooutdev0]
+ return [list $indev0 0 0 0 $@inchannels0 $@inchannels1 $@inchannels2 $@inchannels3 \
+ $outdev0 0 0 0 $@outchannels0 $@outchannels1 $@outchannels2 $@outchannels3 \
+ $@r $@blocksize $@audiobuf]
+}
+
+def ServerPrefsDialog read_one {type name contents i} {
+ switch -- $type {
+ folders {incr i; lappend @$name [lindex $contents $i]}
+ libraries {incr i; lappend @$name [lindex $contents $i]}
+ files {incr i; lappend @$name [lindex $contents $i]}
+ choice {
+ if {$name == "audio_api_choice"} {
+ if {$@$name == ""} {
+ set @$name [lsearch $::pd_apilist2 [lindex $contents $i]]
+ }
+ } else {
+ set @$name [lindex $contents $i]
+ }
+ }
+ void { set @$name 1}
+ default {incr i; set @$name [lindex $contents $i]}
+ }
+ incr i
+ return $i
+}
+
+def ServerPrefsDialog read {} {
+ global pdrc_options pdrc_options_h cmdline
+ set fd [open $cmdline(rcfilename) "RDONLY CREAT"]
+ set contents {}
+ foreach line [split [read $fd] "\n"] {
+ if {[string index $line 0] != "#"} {lappend contents $line}
+ }
+ close $fd
+ set contents [concat [join $contents " "]] ;# concat casts to list type (faster) (?)
+ set i 0
+
+ # prevent Tk8.5 from showing grey checkmarks
+ foreach name {-nodac -noadc -32bit -nomidiin -nomidiout -verbose -noloadbang -listdev -realtime} {
+ set _($self:$name) 0
+ }
+
+ while {$i < [llength $contents]} {
+ set op [lindex $contents $i]
+ if {[string length $op]==0} {break}
+ if {![info exists pdrc_options_h($op)]} {
+ post "unknown option: %s" $op
+ incr i
+ continue
+ }
+ mset {type name} $pdrc_options_h($op)
+ set name [lindex [split $name "|"] 0]
+ set i [$self read_one $type $name $contents $i]
+ }
+}
+
+def ServerPrefsDialog write {} {
+ set fd [open $::cmdline(rcfilename) w]
+ #set fd stdout; puts "WOULD SAVE:"
+ foreach {type names} $::pdrc_options {
+ set name [lindex [split [lindex $names 0] "|"] 0]
+ if {[info exists _($self:$name)]} {set v $_($self:$name)} ;# bug in objective.tcl ?
+ switch $type {
+ folders {foreach item [$v get 0 end] {puts $fd "$name $item"}}
+ libraries {foreach item [$v get 0 end] {puts $fd "$name $item"}}
+ #files {foreach item $v {puts $fd "$name $item"}}
+ void {if {$v != ""} {if {$v} {puts $fd $name}}}
+ choice {
+ if {$name != "audio_api_choice"} {
+ set vv [lindex $names [expr 1+$v]]
+ if {$vv != "default"} {puts $fd $vv}
+ } else {
+ set vv [lindex $::pd_apilist2 $v]
+ if {$vv != "default"} {puts $fd $vv}
+ }
+ }
+ devlist {}
+ default {if {[string length $v]} {puts $fd "$name $v"}}
+ }
+ }
+ close $fd
+ #puts "THE END"
+}
+def ServerPrefsDialog reset {} {
+}
+
+def ServerPrefsDialog init_content {} {
+ global pdrc_options
+ set f .$self.1
+ set section 0
+ set @label_width 200 ;# 24
+ foreach {type names} $pdrc_options {
+ set name [lindex [split [lindex $names 0] "|"] 0]
+ switch $type { void { set type toggle }}
+ switch $type {
+ section {
+ set @label_width [expr 6*[lindex $names 1]] ;# % of 600 px
+ $@nb add_section [incr section] [say $name]
+ }
+ choice {
+ if {$name == "audio_api_choice"} {
+ set ops $::pd_apilist2
+ } else {
+ set ops [lrange $names 1 end]
+ }
+ $self add $f.main.$section [list $name choice -choices $ops]
+ }
+ devlist {$self add $f.main.$section [list $name devlist] }
+ spins {$self add $f.main.$section [list $name spins [lindex $names 1]] }
+ default {$self add $f.main.$section [list $name $type]}
+ }
+ }
+ $@nb page_select 1
+}
+
+def ServerPrefsDialog update_content {} {
+ $self update_channels
+}
+
+def ServerPrefsDialog update_channels {} {
+ set indev_len [llength $@audioindev]
+ set outdev_len [llength $@audiooutdev]
+ set i 0
+ foreach chan $@inchannels {
+ if {$i < $indev_len} {set s "readonly"} else {set s "disabled"}
+ .$self.1.main.1.-inchannels.$i configure -state $s
+ incr i
+ }
+ set i 0
+ foreach chan $@outchannels {
+ if {$i < $outdev_len} {set s "readonly"} else {set s "disabled"}
+ .$self.1.main.1.-outchannels.$i configure -state $s
+ incr i
+ }
+}
+
+def ServerPrefsDialog init {} {
+ netsend [list pd audio-properties]
+ $self init_reverse_hash
+ $self read
+ super reset cancel apply ok
+ # pd pd midi-properties
+}
+
+def ServerPrefsDialog dropmenu_set {frame var part val} {
+ set trim_part [string trimleft $part "-"]
+ set trim_var [string trimleft $var "-"]
+ if {$var == "audio_api_choice"} {
+ foreach api $::pd_apilist {
+ if {$trim_part == [string tolower [lindex $api 0]]} {
+ netsend [list pd audio-setapi [lindex $api 1]]
+ after 1 [netsend [list pd audio-properties]]
+ }
+ }
+ } else {
+ set ::_($self:${trim_var}0) $part
+ }
+ super $frame $var $part $val
+}
+#used by choice and devlist
+def ServerPrefsDialog dropmenu_open {f name} {
+ set trim_name [string trimleft $name "-"]
+ if {$trim_name != "audio_api_choice"} {
+ set i 0
+ set m $f.menu
+ $m delete 0 end
+ foreach part $@$trim_name {
+ $m add command -label $part -command [list $self dropmenu_set $f $name $part $i]
+ incr i
+ }
+ }
+ super $f
+}
+
+#################### ClientPrefsDialog
+set ddrc_options {
+section Client section_color
+ subsection Client canvas_color
+ color Canvas bgedit
+ color Canvas bgrun
+ color Canvas grid
+ subsection Client object_color
+ color View bg
+ color View fg
+ color View frame1
+ color View frame2
+ color View frame3
+ color Comment bg
+ color Comment fg
+ color Comment frame1
+ color Comment frame2
+ color Comment frame3
+ color View selectframe
+ font View font
+ subsection Client wire_color
+ color Wire fg
+ color Wire dspfg
+ color Wire fg2
+ color FutureWire dash
+ subsection Client others_color
+ color Box inletfg
+ color Box outletfg
+ color SelRect rect
+ font KeyboardDialog font
+ font Console font
+section Client keys
+ subsection Client put
+ key Canvas Object
+ key Canvas Message
+ key Canvas {Number nbx}
+ key Canvas Symbol
+ key Canvas Comment
+ key Canvas bng
+ key Canvas tgl
+ key Canvas {vsl hsl}
+ key Canvas {vradio hradio}
+ key Canvas vu
+ key Canvas cnv
+ key Canvas Graph
+ key Canvas Array
+ subsection Client edit
+ key Canvas {cut copy}
+ key Canvas {undo redo}
+ key Canvas {paste duplicate}
+ key Canvas select_all
+ key Canvas clear_selection
+ key Canvas {reload redraw}
+ key Canvas editmodeswitch
+ key Canvas {insert_object chain_object}
+ key Canvas {clear_wires auto_wire}
+ key Canvas subpatcherize
+ subsection Client general
+ key Canvas Pdwindow
+ key Canvas {new_file open_file}
+ key Canvas {save save_as}
+ key Client {server_prefs client_prefs}
+ key Canvas {close quit}
+ key Canvas {find find_again}
+ key Canvas {audio_on audio_off}
+ key Client {audio_settings midi_settings}
+ key Client test_audio_and_midi
+ key Canvas {load_meter latency_meter}
+ key Canvas about
+ subsection Canvas keynav
+ key Canvas {key_nav_up key_nav_up_shift}
+ key Canvas {key_nav_down key_nav_down_shift}
+ key Canvas {key_nav_right key_nav_right_shift}
+ key Canvas {key_nav_left key_nav_left_shift}
+ key Canvas key_nav_ioselect
+section Client others
+ toggle Canvas hairstate
+ toggle Canvas hairsnap
+ toggle Canvas gridstate
+ integer Canvas grid_size
+ toggle Canvas snap_grid
+ toggle Canvas buttonbar
+ toggle Canvas statusbar
+ toggle Canvas menubar
+ toggle Canvas scrollbar
+ toggle View tooltip
+ toggle Wire wirearrow
+ integer Client console
+ choice View language
+ integer Canvas pointer_sense
+}
+
+class_new ClientPrefsDialog {PagedDialog}
+def ClientPrefsDialog apply {} {$self write; $self do_apply}
+def ClientPrefsDialog read {} {read_ddrc}
+
+def ClientPrefsDialog do_apply {} {
+ foreach canvas $::window_list {
+ if {[$canvas class] == "Canvas"} {
+ $canvas activate_menubar= [$canvas look menubar]
+ $canvas activate_buttonbar= [$canvas look buttonbar]
+ $canvas activate_statusbar= [$canvas look statusbar]
+ $canvas activate_scrollbars= [$canvas look scrollbar]
+ $canvas activate_grid= [$canvas look gridstate]
+ $canvas redraw
+ }
+ }
+}
+
+def ClientPrefsDialog write {} {
+ global look key
+ $self get_val
+ set fd [open $::cmdline(ddrcfilename) w]
+ foreach category {look key} {
+ set class_list {}
+ puts $fd "$category \{"
+ foreach name [array names $category] {
+ mset {class var} [split $name ":"]
+ lappend class_list $class
+ }
+ set class_list [luniq [lsort $class_list]]
+ foreach class $class_list {
+ puts $fd " $class \{"
+ foreach name [lsort [array names $category -glob $class:*]] {
+ mset {class var} [split $name ":"]
+ # the eval here annoys me a bit because of possible special chars -- matju
+ puts $fd " $var [eval list \$${category}($class:$var)]"
+ #puts " $var $category $class $var"
+ }
+ puts $fd " \}"
+ }
+ puts $fd "\}"
+ }
+ close $fd
+}
+
+#this retrieves the values set in the editor
+def ClientPrefsDialog get_val {} {
+ global ddrc_options look key accels
+ set check_key {}
+ foreach {type class name} $ddrc_options {
+ switch $type {
+ color {
+ set str [string tolower $class$name]
+ set look($class:$name) $@$str
+ }
+ key {
+ foreach item $name {
+ set new_key $@$item
+ set old_key $key($class:$item)
+ if {$key($class:$item) != $new_key} {
+ if {[dict exists $accels $old_key]} {
+ set cmd [dict get $accels $old_key]
+ set accels [dict remove $accels $old_key]
+ dict set accels $new_key $cmd
+ }
+ }
+ if {[dict exists $check_key $new_key] && $new_key != ""} {
+ error "$new_key already assigned"
+ } else {dict set check_key $new_key key($item)}
+ set key($class:$item) $new_key
+ }
+ }
+ toggle { set look($class:$name) $@$name}
+ integer {set look($class:$name) $@$name}
+ choice {set look($class:$name) $@$name}
+ #font {set look(View:font) $@str}
+ }
+ }
+}
+
+def ClientPrefsDialog reset {} {
+ # this should reload defaults.ddrc ?
+}
+
+def ClientPrefsDialog revert {} {
+ # this should reload currently used settings ?
+}
+
+def ClientPrefsDialog init {} {
+ global ddrc_options look key
+ #do we need to read .ddrc each time the pref editor is opened?
+ #$self read
+ super cancel apply ok
+ #super cancel reset revert apply ok
+ set f .$self.1
+ set section 0
+ set subsection 0
+ set @label_width 200 ;# 24
+
+ foreach {type class names} $ddrc_options {
+ set name [lindex [split $names |] 0]
+ switch $type { void { set type toggle }}
+ switch $type {
+ section {
+ $@nb add_section [incr section] [say $name]
+ set which_section $f.main.$section
+ set which_self $self
+ set subsection 0
+ }
+ subsection {
+ set subself $self.1.main.$section.subsections
+ if {!$subsection} {
+ lappend @nbs [Notebook new_as $subself 590 300]
+ pack .$subself
+ }
+ $subself add_section [incr subsection] [say $name]
+ $subself page_select 1
+ set which_section .$subself.main.$subsection
+ set which_self $subself
+ }
+ choice {
+ set @$name $look(View:language)
+ $self add $which_section [list $name $type -choices $::langoptions]
+ }
+ color {
+ set str [string tolower $class$name]
+ set @$str $look($class:$name)
+ $self add $which_section [list $str $type]
+ }
+ key {
+ foreach item $name {
+ set @$item $key($class:$item)
+ }
+ $self add $which_section [list $name $type]
+ }
+ toggle {
+ set @$name $look($class:$name)
+ $self add $which_section [list $name $type]
+ }
+ font {
+ set str [string tolower $class$name]
+ set @$str $look($class:$name)
+ $self add $which_section [list $str $type $class]
+ }
+ default {
+ switch $name {
+ console {set @$name $look(Client:console)}
+ pointer_sense {set @$name $look(Canvas:pointer_sense)}
+ grid_size {set @$name $look(Canvas:grid_size)}
+ default {}
+ }
+ $self add $which_section [list $name $type]
+ }
+ }
+ }
+ $@nb page_select 1
+}
+
+def ClientPrefsDialog dropmenu_set {frame var part val} {
+ set @$var $part
+ # set _($self:${var}2) [say $part]
+ $frame.butt configure -text [say $part]
+}
+
+def ClientPrefsDialog dropmenu_open {f name} {
+ super $f
+}
+
+############ find dialog ###########
+
+class_new FindDialog {Dialog}
+
+def FindDialog init {canvas} {
+ super cancel find
+ set @canvas $canvas
+ set @break 0
+ set f .$self
+ $self add $f [list "string" "entry"]
+ focus .find.string.entry
+}
+
+def FindDialog find {} {$self ok}
+def FindDialog ok {} {
+ $@canvas find_string= $@string
+ $@canvas search
+ super
+}
+############ other stuff #########
+
+def Client client_class_tree {} {ClientClassTreeDialog new}
+class_new ClientClassTreeDialog {Dialog}
+
+proc* place_stuff {args} {}
+
+def ClientClassTreeDialog make_row {w tree} {
+ pack [frame $w] -fill x
+ pack [frame $w.row] -side top -fill x
+ pack [button $w.row.butt -image icon_minus] -side left
+ pack [label $w.row.label -text [lindex $tree 0]] -side left -fill x
+ pack [frame $w.dent -width 32] -side left
+ set i 1
+ foreach node [lrange $tree 1 end] {
+ $self make_row $w.$i $node
+ incr i
+ }
+}
+
+def ClientClassTreeDialog init {} {
+ super close
+ pack [frame .$self.1 -width 600 -height 400] -fill y -expand y
+ pack [frame .$self.1.1 -width 600 -height 400 -bg "#6688aa"] -side left -fill y -expand y
+ # "$w.1.scroll set"
+ # i'd like a scrollable frame
+ pack [scrollbar .$self.1.scroll -command "ClientClassTreeDialog_scroll $self"] -side left -fill y -expand y
+ place [frame .$self.1.1.tree] -x 0 -y 0
+ set w .$self.1.1.tree.1
+ $self make_row $w [Thing get_hierarchy]
+ after 100 "$self update_scrollbar"
+}
+
+def ClientClassTreeDialog update_scrollbar {} {
+ set w .$self.1.1
+ set zy [winfo height $w]
+ set sy [winfo height $w.tree]
+ set y1 [expr 0.0-[winfo y $w.tree]]
+ set y2 [expr 0.0+$y1+$zy]
+ .$self.1.scroll set [expr $y1/$sy] [expr $y2/$sy]
+}
+
+def ClientClassTreeDialog scroll {args} {
+ set w .$self.1.1
+ set zy [winfo height $w]
+ set sy [winfo height $w.tree]
+ switch [lindex $args 0] {
+ moveto {
+ set y [clip [expr (0.0-[lindex $args 1])*$sy] [expr $zy-$sy] 0]
+ place .$self.1.1.tree -x 0 -y $y
+ puts "args=[list $args] zy=$zy sy=$sy y=$y"
+ }
+ scroll {
+ }
+ }
+ after 100 "$self update_scrollbar"
+}
+
+class_new AboutDialog {Dialog}
+
+def AboutDialog init {} {
+ super close
+ wm title .$self "About DesireData"
+ pack [label .$self.title -text $::pd_version -font {helvetica 18}] -side top
+ pack [text .$self.text -yscrollcommand ".$self.scroll set" -width 72 -height 36] -side left -fill both -expand yes
+ pack [scrollbar .$self.scroll -command ".$self.text yview"] -side right -fill y -expand yes
+#12345678901234567890123456789012345678901234567890123456789012345678901 <- 72 chars
+ .$self.text insert 0.0 \
+"DesireData is a free (libre) real-time computer programming language
+interpreter focused on realtime audio and video.
+You can get DesireData from http://desiredata.goto10.org/
+
+DesireData and PureData work on Linux, MacOSX, Windows, and others.
+
+PureData is copyrighted, but is free for you to use for any reasonable
+purpose, according to the SIBSD license. DesireData's client section
+also is free, according to the GPL license. DesireData's server section
+is an adaptation of the PureData code and is also using the SIBSD
+license.
+
+(insert here: links to both licenses)
+
+Credits:
+ DesireData server: Mathieu Bouchard
+ DesireData client: Mathieu Bouchard & Chun Lee
+ PureData: Miller Puckette feat. Thomas Musil,
+ Gnther Geiger, Krzysztof Czaja, Iohannes Zmlnig & others.
+
+ Translations:
+ Franais (French): Patrice Colet
+ Catal (Catalan): Nria Verges
+ Espaol (Spanish): Mario Mora, Ramiro Cosentino
+ Deutsch (German): Max Neupert, Georg Holzmann, Thomas Grill
+ Norsk Bokml (Norwegian): Gisle Frysland
+ Portugus (Portuguese): Nuno Godinho
+ Italiano (Italian): Davide Morelli, Federico Ferri
+ Euskara (Basque): Ibon Rodriguez Garcia
+ Nihongo (Japanese): Kentaro Fukuchi
+ Polski (Polish): Michal Seta
+ Dansk (Danish): Steffen Leve Poulsen
+ Zong wen (Chinese): Chun Lee
+ Nederlands (Dutch): Tim Vets
+ Trke (Turkish): Koray Tahiroglu
+ Russkij (Russian): Ilya Dmitrichenko
+
+Much more documentation and other resources at http://puredata.info/
+The Pd mailing list archive at http://lists.puredata.info/pipermail/pd-list/
+
+(insert here: link to \"reference documentation for Pd\", that is, chapter 1)"
+
+ # this looks bad on OSX, iirc
+ .$self.text configure -state disabled
+}
+
+set manager [Manager new]
+
+def Class post_hierarchy {{i 0}} {
+ post %*s%s [expr $i*2] "" $self
+ foreach sub $@subclasses {$sub post_hierarchy [expr $i+1]}
+}
+def Class get_hierarchy {} {
+ set l [list $self]
+ foreach sub $@subclasses {lappend l [$sub get_hierarchy]}
+ return $l
+}
+
+# Thing post_hierarchy
+
+#----------------------------------------------------------------
+class_new ClipboardDialog {Dialog}
+
+def ClipboardDialog init {clipboard} {
+ super close
+ set @clipboard $clipboard
+ wm title .$self "Clipboard"
+ pack [text .$self.text -yscrollcommand ".$self.scroll set" -width 72
+ ] -side left -fill both -expand yes
+ pack [scrollbar .$self.scroll -command ".$self.text yview"] -side right -fill y
+ $@clipboard subscribe $self
+ $self notice
+}
+
+def ClipboardDialog notice {args} {
+ .$self.text delete 0.0 end
+ .$self.text insert 0.0 [$@clipboard value]
+}
+
+def ClipboardDialog delete {} {
+ $@clipboard unsubscribe $self
+ super
+}
+
+#----------------------------------------------------------------
+class_new ListDialog {Dialog}
+
+def ListDialog init {history title} {
+ super close
+ set @history $history
+ wm title .$self $title
+ frame .$self.1
+ pack [listbox .$self.1.list -yscrollcommand ".$self.1.scroll set" -width 72 -height 20] -side left -fill both -expand yes
+ pack [scrollbar .$self.1.scroll -command ".$self.1.list yview"] -side right -fill y
+ pack .$self.1
+ $@history subscribe $self
+ $self notice
+}
+
+def ListDialog listbox {} {return .$self.1.list}
+
+def ListDialog notice {args} {
+ set w [$self listbox]
+ $w delete 0 end
+ foreach e [$@history list] {$w insert end $e}
+ $w see end
+}
+
+def ListDialog delete {} {
+ $@history unsubscribe $self
+ super
+}
+
+class_new EventHistoryDialog {ListDialog}
+
+def EventHistoryDialog init {history} {
+ super $history [say event_history_view]
+ pack [checkbutton .$self.hide -text [say hide_key_release]] -fill x
+ [$self listbox] configure -font {Mono -10}
+}
+
+#----------------------------------------------------------------
+#class_new Splash {Thing}
+
+#def Splash init {} {
+# toplevel .$self
+# frame .$self.f
+# canvas .$self.f.canvas
+# image create photo .dd -format GIF -file desiredata.gif
+# .$self.f.canvas create image 0 0 -image .dd
+# pack .$self.f.canvas
+# pack .$self.f
+#}
+
+class_new KeyboardDialog {Dialog}
+
+set keyboard_layouts {
+ {
+ {9 " " 67 68 69 70 " " 71 72 73 74 " " 75 76 95 96}
+ {49 10 11 12 13 14 15 16 17 18 19 20 21 22}
+ {23 24 25 26 27 28 29 30 31 32 33 34 35 51}
+ {66 38 39 40 41 42 43 44 45 46 47 48 36}
+ {50 52 53 54 55 56 57 58 59 60 61 62}
+ {37 115 64 65 113 116 117 109}
+ } {
+ {" " " " 98 " "}
+ {100 " " " " 102}
+ {" " " " 104 " "}
+ {" "}
+ {" " " " 4 " "}
+ {1 2 3}
+ {" " " " 5 " "}
+ }
+}
+
+foreach {k v} {
+ 9 5
+ 22 5
+ 23 4 51 4
+ 66 5 36 7
+ 50 8 62 8
+ 37 4 115 4 64 4 65 24 113 4 116 4 117 4 109 4
+ 98 2 100 2 102 2 104 2
+ 1 2 2 2 3 2 4 2 5 2
+} {set keyboard_width_of($k) $v}
+
+proc namekey {i args} {foreach name $args {set ::keyboard_text_of($i) $name; incr i}}
+namekey 9 Esc
+namekey 67 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10
+namekey 95 F11 F12
+namekey 49 `
+namekey 10 "1 !" "2 @" "3 #" "4 \$" "5 %" "6 ^" "7 &" "8 *" "9 (" "0 )" "- _" "= +" BkSp
+namekey 23 Tab Q W E R T Y U I O P "\{ \[" "\} \]"
+namekey 51 "\\ |"
+namekey 66 Caps
+namekey 38 A S D F G H J K L "\; :" "' \""
+namekey 36 Return
+namekey 50 Shift
+namekey 52 Z X C V B N M ", <" ". >" "/ ?" Shift
+namekey 37 Ctrl
+namekey 115 Sup
+namekey 64 Alt Space
+namekey 113 AltGr
+namekey 116 Sup Menu
+namekey 109 Ctrl
+namekey 98 (up)
+namekey 100 (left)
+namekey 102 (right)
+namekey 104 (down)
+namekey 1 1 2 3 4 5
+#mouse clicks
+
+def KeyboardDialog init {history} {
+ super close
+ set @history $history
+ set @fade [dict create]
+ wm title .$self "Keyboard View" ;# say
+ set i 0; set j 0
+ set @names {key misc}
+ frame .$self.board
+ set layouts {::keyboard_layout ::keyboard_layout2}
+ set @keycount 0
+ foreach layout $::keyboard_layouts {
+ $self pack_keys $layout [lindex $@names $i] [llength [lindex $::keyboard_layouts [expr $i-1]]]
+ incr i
+ }
+ pack .$self.board
+ $@history subscribe $self
+ $self fade
+}
+
+def KeyboardDialog pack_keys {keys name off} {
+ set i $off
+ frame .$self.board.$name
+ foreach row $keys {
+ frame .$self.board.$name.$i
+ foreach key $row {
+ if {$key==" "} {
+ pack [label .$self.board.$name.$i.shim$@keycount -image icon_empty] -side left
+ incr @keycount
+ continue
+ }
+ set ::keyboard_row_of($key) $i
+ if {[info exists ::keyboard_width_of($key)]} {
+ set width $::keyboard_width_of($key)
+ } else {set width 3}
+ if {[info exists ::keyboard_text_of($key)]} {
+ set text $::keyboard_text_of($key)
+ } else {set text $key}
+ if {[regexp {\((\w+)\)} $text foo bar]} {
+ set font [$self look font]
+ pack [label .$self.board.$name.$i.key$key -image icon_$bar -relief raise -border 4 -bg \
+ "#dddddd" -width [expr $width*[font measure $font 0]] \
+ -height [font metrics $font -linespace]] -side left
+ } else {
+ pack [label .$self.board.$name.$i.key$key -text " $text " -relief raise -border 4 \
+ -bg "#dddddd" -width $width -font [$self look font]] -side left
+ }
+ }
+ pack .$self.board.$name.$i -fill x
+ if {$i==0} {pack [label .$self.board.$name.shim -image icon_empty] -fill x -expand yes}
+ incr i
+ }
+ switch $name {
+ key {pack .$self.board.key -side left}
+ misc {pack .$self.board.misc -side right}
+ }
+}
+
+def KeyboardDialog notice {origin add event} {
+ mset {type W x y mod K k} $event
+ if {![info exists ::keyboard_row_of($k)]} {puts "unknown key $k"; return}
+ set i $::keyboard_row_of($k)
+ if {$i<[llength [lindex $::keyboard_layouts 0]]} {set section "key"} else {set section "misc"}
+ switch -regexp -- $type {
+ ^KeyPress|ButtonPress$ {
+ if { [dict exists $@fade $k]} {dict unset @fade $k}
+ .$self.board.$section.$i.key$k configure -bg "#ff0000"
+ }
+ ^KeyRelease|ButtonRelease$ {if {![dict exists $@fade $k]} {dict set @fade $k 255}}
+ }
+}
+
+def KeyboardDialog fade {} {
+ foreach {k v} $@fade {
+ incr v -85
+ if {$v<0} {set v 0}
+ set r [expr 221+$v*2/15]
+ set g [expr 221-$v*13/15]
+ set i $::keyboard_row_of($k)
+ if {$i<[llength [lindex $::keyboard_layouts 0]]} {set section "key"} else {set section "misc"}
+ .$self.board.$section.$i.key$k configure -bg [format #%02x%02x%02x $r $g $g]
+ if {$v} {dict set @fade $k $v} {dict unset @fade $k}
+ }
+ set @after [after 100 "$self fade"]
+}
+
+def KeyboardDialog delete {} {
+ $@history unsubscribe $self
+ after cancel $@after
+ super
+}
+
+#----------------------------------------------------------------
+# Deconstructors
+
+def Wire deconstruct {{selcanvas ""}} {
+ # the selcanvas system could be abstracted out using an ObjectList such that
+ # Canvas<ObjectList and $selection class == ObjectList
+ if {$selcanvas == ""} {
+ list #X connect \
+ [[$@canvas objects] search $@from] $@outlet \
+ [[$@canvas objects] search $@to] $@inlet
+ } {
+ list #X connect \
+ $::obj_index_sel($@canvas:$@from) $@outlet \
+ $::obj_index_sel($@canvas:$@to) $@inlet
+ }
+}
+
+def MessageBox deconstruct {} {concat [list #X msg $@x1 $@y1] $@text}
+def FloatBox deconstruct {} {concat [list #X floatatom $@x1 $@y1] $@w $@min $@max $@pos $@lab $@snd $@rcv}
+def SymbolBox deconstruct {} {concat [list #X symbolatom $@x1 $@y1] $@w $@min $@max $@pos $@lab $@snd $@rcv}
+def Comment deconstruct {} {concat [list #X text $@x1 $@y1] $@text}
+
+
+def Box deconstruct {} {
+ if {[array names ::fields -exact $@pdclass] == ""} {
+ return [concat [list #X obj $@x1 $@y1] $@text]
+ } {
+ set r {}
+ foreach field $::fields($@pdclass) {lappend r $_($self:$field)}
+ return $r
+ }
+}
+
+def View deconstruct_to {stream args} {
+ $stream << [philtre [eval [concat [list $self deconstruct] $args]]]
+ $stream << ";\n"
+}
+
+def Canvas deconstruct {} {
+ return [concat [list #X restore $@x1 $@y1] $@text]
+}
+def Canvas deconstruct_to {stream args} {
+ set r [concat [list #N canvas] $@canvas_pos $@canvas_size]
+ if {$@subpatch || $@abs} {lappend r $@name $@mapped} else {lappend r $@fontsize}
+ $stream << "[philtre $r];\n"
+ foreach i [lsort -integer [$@objects keys]] {eval [concat [list [$@objects get $i] deconstruct_to $stream]]}
+ foreach i [lsort -integer [ $@wires keys]] {eval [concat [list [ $@wires get $i] deconstruct_to $stream]]}
+ $stream << [philtre [eval [concat [list $self deconstruct] $args]]]
+ $stream << ";\n"
+}
+
+#----------------------------------------------------------------
+# openpanel & savepanel
+
+proc pdtk_openpanel {target localdir} {
+ if {$localdir == ""} {set localdir $::pd_opendir}
+ set filename [tk_getOpenFile -initialdir $localdir]
+ if {$filename != ""} {
+ set directory [string range $filename 0 [expr [string last / $filename]-1]]
+ set pd_opendir $directory
+ netsend [list $target callback [enquote $filename]]
+ }
+}
+
+proc pdtk_savepanel {target localdir} {
+ if {$localdir == ""} {
+ set filename [tk_getSaveFile]
+ } else {
+ set filename [tk_getSaveFile -initialdir $localdir]
+ }
+ if {$filename != ""} {
+ netsend [list $target callback [enquote $filename]]
+ }
+}
+
+#----------------------------------------------------------------
+# To err is human.
+
+#proc bgerror {err} {
+# global errorInfo
+# set info [error_dump]
+# tk_messageBox -message "$err: $info" -type ok
+#}
+
+class_new OopsDialog {Dialog}
+
+def OopsDialog init {sig1 sig2 where} {
+ super damn
+ wm title .$self "Oops..."
+ pack [label .$self.head -text $sig2 -font {Helvetica -14 bold}] -side top
+ pack [label .$self.note -text "This program has performed a silly operation and has been shut down."] -side top
+ pack [text .$self.text -yscrollcommand ".$self.scroll set" -width 72 -height 15] -side left -fill both -expand 1
+ pack [scrollbar .$self.scroll -command ".$self.text yview"] -side right -fill y
+ .$self.text insert 0.0 $where
+}
+
+# Nous sommes donc en prsence d'un incendie. C'est normal...
+def OopsDialog damn {} {$self ok}
+
+#----------------------------------------------------------------
+
+if {$tk} {
+ set main [Client new]
+ set window_list [list $main]
+} else {
+ set cmdline(console) 0
+ #foreach dir $auto_path {
+ # set file $dir/libtclreadline[info sharedlibextension]
+ # puts "trying $file"
+ # if {![catch {load $file}]} {puts "found tclreadline !"}
+ #}
+ package require tclreadline
+ proc ::tclreadline::prompt1 {} {return "desire> "}
+ ::tclreadline::Loop
+ #while {1} {
+ # #set line [::tclreadline::readline read]
+ # puts -nonewline "desire> "
+ # flush stdout
+ # set line [gets stdin]
+ # if {[catch {puts [eval $line]}]} {
+ # puts "error: $::errorInfo"
+ # }
+ #}
+ #vwait foo
+}
+
+def Canvas auto_test {} {
+ $self editmode= 1
+ $self select_all
+ $self selection_move +10 0
+ $self selection_move +10 0
+ $self selection_move +10 0
+}
+
+#-----------------------------------------------------------------
+def Canvas visual_diff {} {
+ if {$@blinky != ""} {
+ after cancel $@blinky
+ return
+ }
+ #regsub {\.pd} [$self name] {} filename
+ set filename [$self name]
+ set initialfile ""
+ foreach suffix {gif jpg jpeg png} {
+ set t [$self folder]/$filename.$suffix
+ post %s $t
+ if {[file exist $t]} {set initialfile $filename.$suffix; break}
+ }
+ set filename [tk_getOpenFile -defaultextension .pd -filetypes $::image_filetypes -initialdir [$self folder] -initialfile $initialfile]
+ if {$filename == ""} {return}
+ image create photo image_$self -file $filename
+ $self blink_image
+}
+
+def Canvas blink_image {} {
+ if {[llength [.$self.c gettags BLINKY]]} {
+ .$self.c delete BLINKY
+ } else {
+ .$self.c create image 0 0 -image image_$self -tag BLINKY -anchor nw
+ }
+ set @blinky [after 500 [list $self blink_image]]
+}
+
+#-----------------------------------------------------------------
+
+#lappend ::auto_path /usr/local/lib/graphviz
+catch {package require Tcldot}
+def Canvas graphviz_sort {} {
+ error "this code has to be rewritten to use the new containers"
+ set nodes {}
+ set gwidth 0; set gh 0
+ #toplevel .graph -height 600 -width 800
+ #set c [canvas .graph.c -height 600 -width 800]
+ #pack $c
+ set g [dotnew digraph]
+ $g setnodeattribute style filled color white
+ foreach child $@children {
+ lappend nodes [$g addnode $child label "[$child text]" shape "record" height "0.1"]
+ lappend nodes $child
+ }
+ puts "$nodes"
+ foreach wire $@wires {
+ mset {from outlet to inlet} [$wire report]
+ set n1 [lindex $nodes [expr [lsearch $nodes $from]-1]]
+ set n2 [lindex $nodes [expr [lsearch $nodes $to]-1]]
+ $n1 addedge $n2
+ }
+ #$g layout
+ ;# see what render produces
+ #if {$debug} {puts [$g render]}
+ #eval [$g render]
+ set f {}
+ set fd [open graph.txt w]
+ $g write $fd plain
+ close $fd
+
+ set fd [open graph.txt r]
+ set contents [read $fd]
+ close $fd
+ exec rm graph.txt
+ mset {x1 y1 x2 y2} [[$self widget] bbox all]
+ set width [expr $x2 - $x1]
+ set height [expr $y2 - $y1]
+ foreach line [split $contents "\n"] {
+ switch [lindex $line 0] {
+ graph {set gw [lindex $line 2]; set gh [lindex $line 3]}
+ node {
+ set w [expr $width/$gw]
+ set h [expr $height/$gh]
+ set id [lindex $line 1]
+ set x [lindex $line 2]; set y [lindex $line 3]
+ $id moveto [expr $x*$w] [expr ($gh-$y)*$h]
+ }
+ edge {break}
+ }
+ }
+}
+
+
diff --git a/desiredata/src/dzinc.tcl b/desiredata/src/dzinc.tcl
new file mode 100644
index 00000000..f85f5539
--- /dev/null
+++ b/desiredata/src/dzinc.tcl
@@ -0,0 +1,157 @@
+package provide dzinc 0.1
+package require Tkzinc
+
+class_new Zinc {Thing}
+def Zinc init {} {
+ set @group [eval old_$self add group 1]
+}
+def Zinc unknown {args} {
+ upvar 1 selector selector
+ old_$self $selector {expand}$args
+}
+
+rename canvas old_canvas
+
+proc option_replace {argz} {
+ #set new_args {}
+ foreach {option val} $argz {
+ switch -- $option {
+ -bg {set option -backcolor}
+ -background {set option -backcolor}
+ -bd {set option -borderwidth}
+ }
+ lappend new_args $option $val
+ }
+ puts "new_args:::: $new_args"
+ return $new_args
+}
+#.bgerrorDialog.bitmap create oval 0 0 31 31 -fill red -outline black
+#.x80e1c00.c -width 446 -height 296 -background white
+proc canvas {name args} {
+ set result [eval [concat [list zinc $name] [option_replace $args] -highlightthickness 1]]
+ Zinc new_as $name
+ return $result
+}
+
+def Zinc remove {orig mess} {
+ set idx [lsearch $mess $orig]
+ if {$idx < 0} {return $mess}
+ set mess [lreplace $mess $idx $idx+1]
+ return $mess
+}
+
+
+def Zinc replace {orig new mess} {
+ set idx [lsearch $mess $orig]
+ if {$idx < 0} {return $mess}
+ set mess [lreplace $mess $idx $idx $new]
+ return $mess
+}
+
+def Zinc replace2 {orig new mess} {
+ set idx [lsearch $mess $orig]
+ if {$idx < 0} {return $mess}
+ set mess [lreplace $mess $idx $idx+1]
+ foreach item [lreverse $new] {set mess [linsert $mess $idx $item]}
+ return $mess
+}
+
+def Zinc insert {orig new mess} {
+ set idx [lsearch $mess $orig]
+ if {$idx < 0} {return $mess}
+ #set mess [lreplace $mess $idx $idx+1]
+ foreach item [lreverse $new] {set mess [linsert $mess $idx $item]}
+ return $mess
+}
+
+
+def Zinc canvasx {val} {
+ return $val
+}
+
+def Zinc canvasy {val} {
+ return $val
+}
+
+def Zinc substitude {args} {
+ set args [$self replace -width -linewidth $args]
+ set args [$self replace -fill -linecolor $args]
+ set args [$self replace2 -dash [list -linestyle dotted] $args]
+ set args [$self replace -outline -linecolor $args]
+ set args [$self remove -dashoffset $args]
+ return $args
+}
+
+def Zinc create {args} {
+ set i 0
+ foreach item $args {
+ if {[regexp {^-} $item]} {break}
+ incr i
+ }
+ switch [lindex $args 0] {
+ line {
+ set type curve
+ set args [$self replace -width -linewidth $args]
+ set args [$self replace -fill -linecolor $args]
+ set args [$self replace2 -dash [list -linestyle dotted] $args]
+ set args [$self remove -dashoffset $args]
+ }
+ oval {
+ set type arc
+ set args [$self replace -fill -fillcolor $args]
+ set args [$self replace -outline -linecolor $args]
+ }
+ window {
+ set type window
+ }
+ rectangle {
+ set type rectangle
+ set args [$self replace -fill -fillcolor $args]
+ set args [$self replace -outline -linecolor $args]
+ set args [$self replace -width -linewidth $args]
+ set args [$self replace2 -dash [list -linestyle dotted] $args]
+ }
+ text {
+ set type text
+ set args [$self replace -fill -color $args]
+ }
+ default {
+ puts "UNKNOWN ITEM.. [lindex $args 0]"
+ }
+ }
+ if {$i == 2} {
+ set mess [concat $type $@group [lrange $args 1 end]]
+ } else {
+ set mess [concat $type $@group [list [lrange $args 1 $i-1]] [lrange $args $i end]]
+ }
+ if {$type == "window" || $type == "text"} {set mess [linsert $mess 2 -position]}
+ #puts "mess >> $mess"
+ eval [concat [list old_$self add] $mess]
+}
+
+def Zinc itemconfigure {args} {
+ set mess [$self substitude $args]
+ eval [concat [list old_$self itemconfig] $mess]
+}
+
+def Zinc coords {args} {
+ eval [concat [list old_$self coords] [lindex $args 0] [list [lrange $args 1 end]]]
+}
+
+
+def Zinc configure {args} {
+ eval [concat [list old_$self configure] [option_replace $args]]
+}
+
+def Zinc delete {args} {
+ eval [concat [list old_$self remove] $args]
+}
+
+def Zinc gettags {args} {
+ set result {} ;# bogus
+ catch {set result [eval [concat [list old_$self gettags] $args]]}
+ return $result
+}
+
+def Zinc lower {tag args} {
+} \ No newline at end of file
diff --git a/desiredata/src/icons/array.gif b/desiredata/src/icons/array.gif
new file mode 100644
index 00000000..1a5ecfb2
--- /dev/null
+++ b/desiredata/src/icons/array.gif
Binary files differ
diff --git a/desiredata/src/icons/bang.gif b/desiredata/src/icons/bang.gif
new file mode 100644
index 00000000..28f708e1
--- /dev/null
+++ b/desiredata/src/icons/bang.gif
Binary files differ
diff --git a/desiredata/src/icons/canvas.gif b/desiredata/src/icons/canvas.gif
new file mode 100644
index 00000000..bcff6924
--- /dev/null
+++ b/desiredata/src/icons/canvas.gif
Binary files differ
diff --git a/desiredata/src/icons/comment.gif b/desiredata/src/icons/comment.gif
new file mode 100644
index 00000000..f40d6bf2
--- /dev/null
+++ b/desiredata/src/icons/comment.gif
Binary files differ
diff --git a/desiredata/src/icons/graph.gif b/desiredata/src/icons/graph.gif
new file mode 100644
index 00000000..e543e1d3
--- /dev/null
+++ b/desiredata/src/icons/graph.gif
Binary files differ
diff --git a/desiredata/src/icons/hradio.gif b/desiredata/src/icons/hradio.gif
new file mode 100644
index 00000000..16040321
--- /dev/null
+++ b/desiredata/src/icons/hradio.gif
Binary files differ
diff --git a/desiredata/src/icons/hslider.gif b/desiredata/src/icons/hslider.gif
new file mode 100644
index 00000000..4a08a376
--- /dev/null
+++ b/desiredata/src/icons/hslider.gif
Binary files differ
diff --git a/desiredata/src/icons/message.gif b/desiredata/src/icons/message.gif
new file mode 100644
index 00000000..57983c53
--- /dev/null
+++ b/desiredata/src/icons/message.gif
Binary files differ
diff --git a/desiredata/src/icons/mode_edit.gif b/desiredata/src/icons/mode_edit.gif
new file mode 100644
index 00000000..30902f10
--- /dev/null
+++ b/desiredata/src/icons/mode_edit.gif
Binary files differ
diff --git a/desiredata/src/icons/mode_run.gif b/desiredata/src/icons/mode_run.gif
new file mode 100644
index 00000000..1d6ea182
--- /dev/null
+++ b/desiredata/src/icons/mode_run.gif
Binary files differ
diff --git a/desiredata/src/icons/number.gif b/desiredata/src/icons/number.gif
new file mode 100644
index 00000000..7830e949
--- /dev/null
+++ b/desiredata/src/icons/number.gif
Binary files differ
diff --git a/desiredata/src/icons/number2.gif b/desiredata/src/icons/number2.gif
new file mode 100644
index 00000000..027562fe
--- /dev/null
+++ b/desiredata/src/icons/number2.gif
Binary files differ
diff --git a/desiredata/src/icons/object.gif b/desiredata/src/icons/object.gif
new file mode 100644
index 00000000..ddec4903
--- /dev/null
+++ b/desiredata/src/icons/object.gif
Binary files differ
diff --git a/desiredata/src/icons/symbol.gif b/desiredata/src/icons/symbol.gif
new file mode 100644
index 00000000..0169009f
--- /dev/null
+++ b/desiredata/src/icons/symbol.gif
Binary files differ
diff --git a/desiredata/src/icons/toggle.gif b/desiredata/src/icons/toggle.gif
new file mode 100644
index 00000000..90c1fc05
--- /dev/null
+++ b/desiredata/src/icons/toggle.gif
Binary files differ
diff --git a/desiredata/src/icons/vradio.gif b/desiredata/src/icons/vradio.gif
new file mode 100644
index 00000000..5649c31f
--- /dev/null
+++ b/desiredata/src/icons/vradio.gif
Binary files differ
diff --git a/desiredata/src/icons/vslider.gif b/desiredata/src/icons/vslider.gif
new file mode 100644
index 00000000..5920c207
--- /dev/null
+++ b/desiredata/src/icons/vslider.gif
Binary files differ
diff --git a/desiredata/src/icons/vu.gif b/desiredata/src/icons/vu.gif
new file mode 100644
index 00000000..bbc6142f
--- /dev/null
+++ b/desiredata/src/icons/vu.gif
Binary files differ
diff --git a/desiredata/src/install-sh b/desiredata/src/install-sh
new file mode 100644
index 00000000..e9de2384
--- /dev/null
+++ b/desiredata/src/install-sh
@@ -0,0 +1,251 @@
+#!/bin/sh
+#
+# install - install a program, script, or datafile
+# This comes from X11R5 (mit/util/scripts/install.sh).
+#
+# Copyright 1991 by the Massachusetts Institute of Technology
+#
+# Permission to use, copy, modify, distribute, and sell this software and its
+# documentation for any purpose is hereby granted without fee, provided that
+# the above copyright notice appear in all copies and that both that
+# copyright notice and this permission notice appear in supporting
+# documentation, and that the name of M.I.T. not be used in advertising or
+# publicity pertaining to distribution of the software without specific,
+# written prior permission. M.I.T. makes no representations about the
+# suitability of this software for any purpose. It is provided "as is"
+# without express or implied warranty.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch. It can only install one file at a time, a restriction
+# shared with many OS's install programs.
+
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+transformbasename=""
+transform_arg=""
+instcmd="$mvprog"
+chmodcmd="$chmodprog 0755"
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=""
+dst=""
+dir_arg=""
+
+while [ x"$1" != x ]; do
+ case $1 in
+ -c) instcmd="$cpprog"
+ shift
+ continue;;
+
+ -d) dir_arg=true
+ shift
+ continue;;
+
+ -m) chmodcmd="$chmodprog $2"
+ shift
+ shift
+ continue;;
+
+ -o) chowncmd="$chownprog $2"
+ shift
+ shift
+ continue;;
+
+ -g) chgrpcmd="$chgrpprog $2"
+ shift
+ shift
+ continue;;
+
+ -s) stripcmd="$stripprog"
+ shift
+ continue;;
+
+ -t=*) transformarg=`echo $1 | sed 's/-t=//'`
+ shift
+ continue;;
+
+ -b=*) transformbasename=`echo $1 | sed 's/-b=//'`
+ shift
+ continue;;
+
+ *) if [ x"$src" = x ]
+ then
+ src=$1
+ else
+ # this colon is to work around a 386BSD /bin/sh bug
+ :
+ dst=$1
+ fi
+ shift
+ continue;;
+ esac
+done
+
+if [ x"$src" = x ]
+then
+ echo "install: no input file specified"
+ exit 1
+else
+ true
+fi
+
+if [ x"$dir_arg" != x ]; then
+ dst=$src
+ src=""
+
+ if [ -d $dst ]; then
+ instcmd=:
+ chmodcmd=""
+ else
+ instcmd=mkdir
+ fi
+else
+
+# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
+# might cause directories to be created, which would be especially bad
+# if $src (and thus $dsttmp) contains '*'.
+
+ if [ -f $src -o -d $src ]
+ then
+ true
+ else
+ echo "install: $src does not exist"
+ exit 1
+ fi
+
+ if [ x"$dst" = x ]
+ then
+ echo "install: no destination specified"
+ exit 1
+ else
+ true
+ fi
+
+# If destination is a directory, append the input filename; if your system
+# does not like double slashes in filenames, you may need to add some logic
+
+ if [ -d $dst ]
+ then
+ dst="$dst"/`basename $src`
+ else
+ true
+ fi
+fi
+
+## this sed command emulates the dirname command
+dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
+
+# Make sure that the destination directory exists.
+# this part is taken from Noah Friedman's mkinstalldirs script
+
+# Skip lots of stat calls in the usual case.
+if [ ! -d "$dstdir" ]; then
+defaultIFS='
+'
+IFS="${IFS-${defaultIFS}}"
+
+oIFS="${IFS}"
+# Some sh's can't handle IFS=/ for some reason.
+IFS='%'
+set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
+IFS="${oIFS}"
+
+pathcomp=''
+
+while [ $# -ne 0 ] ; do
+ pathcomp="${pathcomp}${1}"
+ shift
+
+ if [ ! -d "${pathcomp}" ] ;
+ then
+ $mkdirprog "${pathcomp}"
+ else
+ true
+ fi
+
+ pathcomp="${pathcomp}/"
+done
+fi
+
+if [ x"$dir_arg" != x ]
+then
+ $doit $instcmd $dst &&
+
+ if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
+ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
+ if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
+ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
+else
+
+# If we're going to rename the final executable, determine the name now.
+
+ if [ x"$transformarg" = x ]
+ then
+ dstfile=`basename $dst`
+ else
+ dstfile=`basename $dst $transformbasename |
+ sed $transformarg`$transformbasename
+ fi
+
+# don't allow the sed command to completely eliminate the filename
+
+ if [ x"$dstfile" = x ]
+ then
+ dstfile=`basename $dst`
+ else
+ true
+ fi
+
+# Make a temp file name in the proper directory.
+
+ dsttmp=$dstdir/#inst.$$#
+
+# Move or copy the file name to the temp name
+
+ $doit $instcmd $src $dsttmp &&
+
+ trap "rm -f ${dsttmp}" 0 &&
+
+# and set any options; do chmod last to preserve setuid bits
+
+# If any of these fail, we abort the whole thing. If we want to
+# ignore errors from any of these, just make sure not to ignore
+# errors from the above "$doit $instcmd $src $dsttmp" command.
+
+ if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
+ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
+ if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
+ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
+
+# Now rename the file to the real destination.
+
+ $doit $rmcmd -f $dstdir/$dstfile &&
+ $doit $mvcmd $dsttmp $dstdir/$dstfile
+
+fi &&
+
+
+exit 0
diff --git a/desiredata/src/iostream.txt b/desiredata/src/iostream.txt
new file mode 100644
index 00000000..5ed2bf25
--- /dev/null
+++ b/desiredata/src/iostream.txt
@@ -0,0 +1,61 @@
+------------------8<--------cut-here--------8<------------------
+Dec 26 2005
+
+1.1. a OutByteStream object is one that accepts those messages on inlet 0:
+ * float: seen as a byte (0..255)
+ * list of floats: seen as a sequence of float messages.
+ * symbol: seen as a \0-terminated string.
+ * bang: forces buffer-flushing if there's a buffer.
+
+1.2. a OutByteStream object may also optionally respond to string
+ messages, in my dreams. However, in the meanwhile, it may be more
+ appropriate to use a new special C function that accepts a pair of
+ int and const char * (\0 is not honored: the int specifies the size).
+ This is so that there is no speed disincentive to switch to decoupled
+ I/O objects.
+
+2.1. an InByteStream object is one that accepts those messages on inlet 0:
+ * bang: polls for more input (unlimited size).
+ * float: treated as int. polls for at most N bytes.
+ * auto 0: requires bang for getting more input.
+ * auto 1: uses a t_clock (hidden [metro]) for auto-polling.
+
+2.2. an InByteStream may produce those messages:
+ * float: seen as a byte (0..255)
+ * list of floats: seen as a sequence of float messages.
+
+and when in "auto 0" mode, it will only send it when receiving a bang or
+float.
+
+2.2. an InByteStream object may also optionally produce string
+ messages, in my dreams, etc. What would the C function(s) look like
+ in this case?
+
+3. an IOByteStream object is just an InByteStream object and an
+OutByteStream object at the same time. There is no conflict between the
+two.
+
+4. there would be object classes called [tcp] and [udp] which would be
+ InputOutputStream objects (supporting in, out and bidi connections).
+ They would also respond to "connect" and "disconnect" (or maybe "open"
+ and "close" instead) and also "listen" for enabling server mode.
+
+5. there would be an object class called [fudiin] which would be an
+OutByteStream and [fudiout] which would be an InByteStream. Thus, to get a
+bidirectional [netsend] [netreceive], use this triad:
+
+ |
+[fudiout]
+ |
+[tcp]
+ |
+[fudiin]
+ |
+
+Leaving out the first or the last object gives you [netsend] and
+[netreceive] respectively.
+
+6. a [tcp]<->[fudiin] pair can replace the server-side of the GUI
+ connection as long as the [tcp] object supports char* input as
+ suggested in part 1.2. (if the rest of this proposal is not
+ implemented, then use a slightly modified [netreceive] instead)
diff --git a/desiredata/src/kb-mode.tcl b/desiredata/src/kb-mode.tcl
new file mode 100644
index 00000000..08adce28
--- /dev/null
+++ b/desiredata/src/kb-mode.tcl
@@ -0,0 +1,210 @@
+package provide kb-mode 0.1
+
+set kbmode 1
+
+proc kb-mode_init {canvas} {
+ puts "init kb-mode"
+ set self "kbcursor"
+ append_callback kb-mode key kb-mode_key
+ Kb_cursor new_as $self $canvas
+ $self draw
+ return $self
+}
+
+def Canvas kb-mode_key {x y key iso shift} {
+ set c [$self widget]
+ set step [$@kbcursor step]
+ if {$@keyprefix} {
+ $@kbcursor get_key $key
+ set @keyprefix 0
+ }
+ switch $key {
+ BackSpace {$self delete_selection}
+ Up {$@kbcursor move 0 -$step; if {$shift} {$self arrow_key 0 -$step}}
+ Down {$@kbcursor move 0 +$step; if {$shift} {$self arrow_key 0 +$step}}
+ Left {$@kbcursor move -$step 0; if {$shift} {$self arrow_key -$step 0}}
+ Right {$@kbcursor move +$step 0; if {$shift} {$self arrow_key +$step 0}}
+ t {$self kbcursor_select}
+ Return {$self return_key $x $y $key $iso $shift}
+ default {}
+ }
+}
+
+def Canvas kbcursor_move_up {} {$@kbcursor move 0 -[$@kbcursor step]}
+def Canvas kbcursor_move_down {} {$@kbcursor move 0 [$@kbcursor step]}
+def Canvas kbcursor_move_left {} {$@kbcursor move -[$@kbcursor step] 0}
+def Canvas kbcursor_move_right {} {$@kbcursor move [$@kbcursor step] 0}
+
+def Canvas move_selection_up {} {$self arrow_key 0 -[$@kbcursor step]}
+def Canvas move_selection_down {} {$self arrow_key 0 +[$@kbcursor step]}
+def Canvas move_selection_left {} {$self arrow_key -[$@kbcursor step] 0}
+def Canvas move_selection_right {} {$self arrow_key 0 +[$@kbcursor step] 0}
+
+class_new Kb_cursor {View}
+
+def Kb_cursor init {canvas} {
+ super
+ set @canvas $canvas
+ set @x 200
+ set @y 200
+ set @h [expr [font metrics [$self look font] -linespace]+3]
+ set @step [expr ceil($@h*1.5)]
+ set @prefixkeys {}
+ $self init_keys
+ $self recenter
+}
+
+
+def Kb_cursor xy {} {return [list $@x $@y]}
+def Kb_cursor step {} {return $@step}
+
+def Kb_cursor draw {} {
+ set c [$@canvas widget]
+ set line1 [list $@x $@y $@x [expr $@y+$@h]]
+ set line2 [list $@x $@y [expr $@x+3] $@y]
+ set line3 [list $@x [expr $@y+$@h-1] [expr $@x+3] [expr $@y+$@h-1]]
+ $self item LINE1 line $line1 -fill red -width 2
+ $self item LINE2 line $line2 -fill red -width 1
+ $self item LINE3 line $line3 -fill red -width 1
+
+ $c raise $self
+}
+
+def Kb_cursor move {x y} {
+ set @x [expr $@x + $x]
+ set @y [expr $@y + $y]
+ $self test_bounds
+ $self draw
+ set action [$@canvas action]
+ if {$action != "none"} {
+ if {[$action class] == "SelRect"} {
+ $action motion $@x $@y 256 "none"
+ }
+
+ }
+}
+
+def Kb_cursor scroll_canvas {} {
+ set c [$@canvas widget]
+ mset {x1 y1 x2 y2} [$c bbox all]
+ puts "xview [$c xview]"
+ set x2 [expr $x2]; set y2 [expr $y2]
+}
+
+def Kb_cursor test_bounds {} {
+ set c [$@canvas widget]
+ set width [winfo width $c]; set height [winfo height $c]
+ set x1 [$c canvasx 2]; set y1 [$c canvasy 2]
+ set x2 [expr $x1+$width-2]
+ set y2 [expr $y1+$height-2]
+ if {$@x >= $x2} {$self scroll r [expr int($@x-$x2)]}
+ if {$@x <= $x1} {$self scroll l [expr int($@x-$x1)]}
+ if {$@y >= $y2} {$self scroll b [expr int($@y-$y2)]}
+ if {$@y <= $y1} {$self scroll t [expr int($@y-$y1)]}
+}
+
+def Kb_cursor scroll {direction diff} {
+ set c [$@canvas widget]
+ set width [winfo width $c]; set height [winfo height $c]
+ set x1 [$c canvasx 2]; set y1 [$c canvasy 2]
+ mset {l r} [$c xview]
+ mset {t b} [$c yview]
+ foreach {n0 n1 n2 n3 region} [$c configure -scrollregion] {mset {rx1 ry1 rx2 ry2} $region}
+ switch $direction {
+ r {set axis "x"; if {$r == 1} {set rx2 [expr $rx2+$width]}}
+ l {set axis "x"; if {$l == 0} {set rx1 [expr $rx1-$width]}}
+ b {set axis "y"; if {$b == 1} {set ry2 [expr $ry2+$height]}}
+ t {set axis "y"; if {$t == 0} {set ry1 [expr $ry1-$height]}}
+ }
+ $c configure -scrollregion [list $rx1 $ry1 $rx2 $ry2]
+ $c [list $axis]view scroll $diff units
+}
+
+def Canvas kbcursor_recenter {} {$@kbcursor recenter}
+
+def Kb_cursor recenter {} {
+ set c [$@canvas widget]
+ set width [winfo width $c]; set height [winfo height $c]
+ set x1 [$c canvasx 2]; set y1 [$c canvasy 2]
+ set x2 [expr $x1+$width]
+ set y2 [expr $y1+$height]
+ set @x [expr $x1+($width/2)]
+ set @y [expr $y1+($height/2)]
+ $self draw
+}
+
+def Canvas kbcursor_Object {} {mset {x y} [$@kbcursor xy]; $self new_objectxy [expr $x+4] $y obj}
+def Canvas kbcursor_Message {} {mset {x y} [$@kbcursor xy]; $self new_objectxy [expr $x+4] $y msg}
+def Canvas kbcursor_bng {} {mset {x y} [$@kbcursor xy]; $self new_objectxy [expr $x+4] $y obj bng}
+def Canvas kbcursor_tgl {} {mset {x y} [$@kbcursor xy]; $self new_objectxy [expr $x+4] $y obj tgl}
+def Canvas kbcursor_nbx {} {mset {x y} [$@kbcursor xy]; $self new_objectxy [expr $x+4] $y obj nbx}
+
+def Canvas kbcursor_select {} {
+ mset {x y} [lmap + [$@kbcursor xy] 4]; set x [expr $x+4]
+ mset {type id detail} [$self identify_target $x $y 0]
+ puts "type:: $type || id:: $id || detail:: $detail"
+ if {$type == "object"} {
+ if {![$id selected?]} {$self selection+= $id} else {$self selection-= $id}
+ }
+}
+
+def Kb_cursor init_keys {} {
+ global newkey accels
+ #@keys used for prefix keycommands
+ dict set @prefixkeys "1" "kbcursor_Object"
+ dict set @prefixkeys "2" "kbcursor_Message"
+ dict set @prefixkeys "b" "kbcursor_bng"
+ dict set @prefixkeys "t" "kbcursor_tgl"
+ dict set @prefixkeys "3" "kbcursor_nbx"
+ #@ctrlkeys overwrites the existing keybindings
+ foreach {key command} $newkey {
+ if {[catch {set vars [dict get $accels $key]}]} {puts "$key not bound yet......";set vars {}}
+ set new_val {}
+ foreach item $vars {
+ mset {class cmd} [split $item ":"]
+ if {$class == [$@canvas class]} {
+ set n $class:$command
+ lappend new_val $n
+ } else {
+ lappend new_val $item
+ }
+ }
+ if {$new_val == ""} {set new_val [$@canvas class]:$command}
+ dict set accels $key $new_val
+ }
+
+}
+
+def Kb_cursor get_key {key} {
+ if {[catch {set command [dict get $@prefixkeys $key]}]} {
+ post "key Ctrl-x $key not bound"
+ } {
+ puts "run $command"
+ $@canvas $command
+ }
+}
+
+set newkey {
+ Ctrl+p {kbcursor_move_up}
+ Ctrl+n {kbcursor_move_down}
+ Ctrl+f {kbcursor_move_right}
+ Ctrl+b {kbcursor_move_left}
+ Ctrl+P {move_selection_up}
+ Ctrl+N {move_selection_down}
+ Ctrl+F {move_selection_right}
+ Ctrl+B {move_selection_left}
+ Alt+f {}
+ Alt+b {}
+ Ctrl+space {kbcursor_mark}
+}
+
+def Canvas kbcursor_mark {} {
+ mset {x y} [$@kbcursor xy]
+ if {$@action == "none"} {
+ set @action [SelRect new $self $x $y 256 "none"]
+ } else {
+ if {[$@action class] == "SelRect"} {
+ $@action unclick $x $y 236 "none"
+ }
+ }
+} \ No newline at end of file
diff --git a/desiredata/src/kernel.c b/desiredata/src/kernel.c
new file mode 100644
index 00000000..8552c279
--- /dev/null
+++ b/desiredata/src/kernel.c
@@ -0,0 +1,2348 @@
+/* $Id: kernel.c,v 1.1.2.92 2007-09-09 21:34:56 matju Exp $
+ * Copyright 2006-2007 Mathieu Bouchard.
+ * Copyright (c) 1997-2006 Miller Puckette.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* IOhannes :
+ * changed the canvas_restore in "g_canvas.c", so that it might accept $args as well (like "pd $0_test")
+ * so you can make multiple & distinguishable templates
+ * 1511:forum::fr::umlute:2001
+ * change marked with IOhannes
+ */
+
+#define PD_PLUSPLUS_FACE
+#include "desire.h"
+#include "m_simd.h"
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <sstream>
+#include <fcntl.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+#include <pthread.h>
+#ifdef UNISTD
+#include <unistd.h>
+#endif
+#ifdef MSW
+#include <io.h>
+#endif
+
+#define a_float a_w.w_float
+#define a_symbol a_w.w_symbol
+#define a_gpointer a_w.w_gpointer
+#define a_index a_w.w_index
+
+using namespace std;
+
+/* T.Grill - bit alignment for signal vectors (must be a multiple of 8!) */
+/* if undefined no alignment occurs */
+#ifdef SIMD_BYTEALIGN
+ #define VECTORALIGNMENT (SIMD_BYTEALIGN*8)
+#else
+ #define VECTORALIGNMENT 128
+#endif
+
+void *getbytes(size_t nbytes) {
+ if (nbytes < 1) nbytes = 1;
+ void *ret = (void *)calloc(nbytes, 1);
+ if (!ret) error("pd: getbytes() failed -- out of memory");
+ return ret;
+}
+
+void *copybytes(void *src, size_t nbytes) {
+ void *ret = getbytes(nbytes);
+ if (nbytes) memcpy(ret, src, nbytes);
+ return ret;
+}
+
+void *resizebytes(void *old, size_t oldsize, size_t newsize) {
+ if (newsize < 1) newsize = 1;
+ if (oldsize < 1) oldsize = 1;
+ void *ret = (void *)realloc((char *)old, newsize);
+ if (newsize > oldsize && ret) memset(((char *)ret) + oldsize, 0, newsize - oldsize);
+ if (!ret) error("pd: resizebytes() failed -- out of memory");
+ return ret;
+}
+
+void freebytes(void *old, size_t nbytes) {free(old);}
+
+/* in the following size_t is assumed to have the same size as a pointer type !!! */
+
+/* T.Grill - get aligned memory */
+void *getalignedbytes(size_t nbytes) {
+ /* to align the region we also need some extra memory to save the original pointer location
+ it is saved immediately before the aligned vector memory */
+ void *vec = getbytes(nbytes+(VECTORALIGNMENT/8-1)+sizeof(void *));
+ if (!vec) return 0;
+ t_int alignment = ((t_int)vec+sizeof(void *))&(VECTORALIGNMENT/8-1);
+ void *ret = (unsigned char *)vec+sizeof(void *)+(alignment == 0?0:VECTORALIGNMENT/8-alignment);
+ *(void **)((unsigned char *)ret-sizeof(void *)) = vec;
+ return ret;
+}
+
+/* T.Grill - free aligned vector memory */
+void freealignedbytes(void *ptr,size_t nbytes) {
+ free(*(void **)((unsigned char *)ptr-sizeof(void *)));
+}
+
+/* T.Grill - resize aligned vector memory */
+void *resizealignedbytes(void *ptr,size_t oldsize, size_t newsize) {
+ if (newsize<1) newsize=1;
+ void *ori = *(void **)((unsigned char *)ptr-sizeof(void *));
+ void *vec = realloc(ori,newsize+(VECTORALIGNMENT/8-1)+sizeof(void *));
+ t_int alignment = ((t_int)vec+sizeof(void *))&(VECTORALIGNMENT/8-1);
+ void *ret = (unsigned char *)vec+sizeof(void *)+(alignment == 0?0:VECTORALIGNMENT/8-alignment);
+ *(void **)((unsigned char *)ret-sizeof(void *)) = vec;
+ return ret;
+}
+
+/* TB: copy to aligned vector memory */
+void *copyalignedbytes(void *src, size_t nbytes) {
+ void *ret = getalignedbytes(nbytes);
+ if (nbytes) memcpy(ret, src, nbytes);
+ return ret;
+}
+
+t_class *hash_class;
+
+/*extern "C"*/ void hash_setup () {
+ hash_class = class_new(gensym("#V"), (t_newmethod)0 /*hash_new*/,
+ 0 /*(t_method)hash_free*/, sizeof(t_object), CLASS_PD, A_GIMME, 0);
+}
+
+/* convenience routines for checking and getting values of atoms.
+ There's no "pointer" version since there's nothing safe to return if there's an error. */
+
+t_float atom_getfloat( t_atom *a) {return a->a_type==A_FLOAT ? a->a_float : 0;}
+t_int atom_getint( t_atom *a) {return (t_int)atom_getfloat(a);}
+t_symbol * atom_getsymbol(t_atom *a) {return a->a_type==A_SYMBOL ? a->a_symbol : &s_symbol;}
+const char *atom_getstring(t_atom *a) {return atom_getsymbol(a)->name;}
+
+t_symbol *atom_gensym(t_atom *a) { /* this works better for graph labels */
+ if (a->a_type == A_SYMBOL) return a->a_symbol;
+ if (a->a_type == A_FLOAT) {char buf[30]; sprintf(buf, "%g", a->a_float); return gensym(buf);}
+ return gensym("???");
+}
+
+t_float atom_getfloatarg(int which, int argc, t_atom *argv) {
+ if (argc <= which) return 0;
+ argv += which;
+ return argv->a_type==A_FLOAT ? argv->a_float : 0;
+}
+
+t_int atom_getintarg(int which, int argc, t_atom *argv)
+{return (t_int)atom_getfloatarg(which, argc, argv);}
+
+t_symbol *atom_getsymbolarg(int which, int argc, t_atom *argv) {
+ if (argc <= which) return &s_;
+ argv += which;
+ return argv->a_type==A_SYMBOL ? argv->a_symbol : &s_;
+}
+
+const char *atom_getstringarg(int which, int argc, t_atom *argv) {
+ return atom_getsymbolarg(which,argc,argv)->name;
+}
+
+/* convert an atom into a string, in the reverse sense of binbuf_text (q.v.)
+ special attention is paid to symbols containing the special characters
+ ';', ',', '$', and '\'; these are quoted with a preceding '\', except that
+ the '$' only gets quoted at the beginning of the string. */
+
+//static int should_quote(char *s) {return strchr(";,\\{}\"",*s) || isspace(*s) || (*s=='$' && isdigit(s[1]));}
+static int should_quote(char *s) {return strchr(";,\\{}\" ",*s) || (*s=='$' && isdigit(s[1]));}
+
+void atom_ostream(t_atom *a, ostream &buf) {
+ switch(a->a_type) {
+ case A_SEMI: buf << ";"; break;
+ case A_COMMA: buf << ","; break;
+ case A_POINTER: buf << "(pointer)"; break;
+ case A_FLOAT: buf << a->a_float; break;
+ case A_SYMBOL: {
+ bool quote=0;
+ for (char *sp = a->a_symbol->name; *sp; sp++) if (should_quote(sp)) {quote = 1; break;}
+ if (quote) {
+ for (char *sp = a->a_symbol->name; *sp; sp++) {
+ if (should_quote(sp)) buf << '\\';
+ buf << *sp;
+ }
+ } else buf << a->a_symbol->name;
+ } break;
+ case A_DOLLAR: buf << "$" << a->a_index; break;
+ case A_DOLLSYM: buf << a->a_symbol->name; break;
+ default: bug("%s",__PRETTY_FUNCTION__);
+ }
+}
+
+/* this is not completely compatible with Miller's, as it won't do anything special for short bufsizes. */
+void atom_string(t_atom *a, char *buf, unsigned int bufsize) {
+ ostringstream b;
+ atom_ostream(a,b);
+ strncpy(buf,b.str().data(),bufsize);
+ buf[bufsize-1]=0;
+}
+
+void atom_init(t_atom *a, size_t n) {
+ for (size_t i=0; i<n; i++) {
+ a[i].a_type = A_FLOAT;
+ a[i].a_float = 0.0;
+ }
+}
+
+void atom_copy(t_atom *a, t_atom *b, size_t n) {
+ memcpy(a,b,n*sizeof(t_atom));
+ /* here I should handle incref */
+}
+
+void atom_delete(t_atom *a, size_t n) {
+ /* here I should handle decref */
+}
+
+/* in which the value has bit 0 set if the key object is not a zombie,
+ and has bit 1 set if the object has been uploaded to the client */
+t_hash<t_pd *,long> *object_table;
+
+t_pd *pd_new(t_class *c) {
+ if (!c) bug("pd_new: apparently called before setup routine");
+ t_pd *x = (t_pd *)getbytes(c->size);
+ x->_class = c;
+ object_table->set(x,1);
+ if (c->gobj) ((t_gobj *)x)->g_adix = appendix_new((t_gobj *)x);
+ if (c->patchable) {
+ ((t_object *)x)->inlet = 0;
+ ((t_object *)x)->outlet = 0;
+ }
+ return x;
+}
+
+void pd_free_zombie(t_pd *x) {
+ t_class *c = x->_class;
+ if (c->gobj) appendix_free((t_gobj *)x);
+ if (c->size) free(x);
+ object_table->del(x);
+}
+
+void pd_free(t_pd *x) {
+ t_class *c = x->_class;
+ if (c->freemethod) ((t_gotfn)(c->freemethod))(x);
+ if (c->patchable) {
+ t_object *y = (t_object *)x;
+ while (y->outlet) outlet_free(y->outlet);
+ while (y->inlet) inlet_free(y->inlet);
+ if (y->binbuf) binbuf_free(y->binbuf);
+ }
+ /* schedule for deletion if need to keep the allocation around */
+ if (c->gobj && (object_table->get(x)&2)) {
+ object_table->set(x,object_table->get(x)&~1);
+ gobj_changed((t_gobj *)x,"");
+ //char *xx = (char *)x; for (int i=0; i<c->size; i++) xx[i]="\xde\xad\xbe\xef"[i&3];
+ } else pd_free_zombie(x);
+}
+
+void gobj_save(t_gobj *x, t_binbuf *b) {
+ t_class *c = x->g_pd;
+ if (c->savefn) c->savefn(x, b);
+}
+
+/* deal with several objects bound to the same symbol. If more than one,
+ we actually bind a collection object to the symbol, which forwards messages sent to the symbol. */
+
+static t_class *bindlist_class;
+
+struct t_bindelem {
+ t_pd *who;
+ t_bindelem *next;
+};
+
+struct t_bindlist : t_pd {
+ t_bindelem *list;
+};
+
+#define bind_each(e,x) for (t_bindelem *e = x->list; e; e = e->next)
+static void bindlist_bang (t_bindlist *x) {bind_each(e,x) pd_bang(e->who);}
+static void bindlist_float (t_bindlist *x, t_float f) {bind_each(e,x) pd_float(e->who,f);}
+static void bindlist_symbol (t_bindlist *x, t_symbol *s) {bind_each(e,x) pd_symbol(e->who,s);}
+static void bindlist_pointer (t_bindlist *x, t_gpointer *gp) {bind_each(e,x) pd_pointer(e->who, gp);}
+static void bindlist_list (t_bindlist *x, t_symbol *s, int argc, t_atom *argv) {bind_each(e,x) pd_list(e->who, s,argc,argv);}
+static void bindlist_anything(t_bindlist *x, t_symbol *s, int argc, t_atom *argv) {bind_each(e,x) pd_typedmess(e->who, s,argc,argv);}
+
+static t_bindelem *bindelem_new(t_pd *who, t_bindelem *next) {
+ t_bindelem *self = (t_bindelem *)malloc(sizeof(t_bindelem));
+ self->who = who;
+ self->next = next;
+ return self;
+}
+
+void pd_bind(t_pd *x, t_symbol *s) {
+ if (s->thing) {
+ if (s->thing->_class == bindlist_class) {
+ t_bindlist *b = (t_bindlist *)s->thing;
+ b->list = bindelem_new(x,b->list);
+ } else {
+ t_bindlist *b = (t_bindlist *)pd_new(bindlist_class);
+ b->list = bindelem_new(x,bindelem_new(s->thing,0));
+ s->thing = b;
+ }
+ } else s->thing = x;
+}
+
+/* bindlists always have at least two elements... if the number
+ goes down to one, get rid of the bindlist and bind the symbol
+ straight to the remaining element. */
+void pd_unbind(t_pd *x, t_symbol *s) {
+ if (s->thing == x) {s->thing = 0; return;}
+ if (s->thing && s->thing->_class == bindlist_class) {
+ t_bindlist *b = (t_bindlist *)s->thing;
+ t_bindelem *e, *e2;
+ if ((e = b->list)->who == x) {
+ b->list = e->next;
+ free(e);
+ } else for (e = b->list; (e2=e->next); e = e2) if (e2->who == x) {
+ e->next = e2->next;
+ free(e2);
+ break;
+ }
+ if (!b->list->next) {
+ s->thing = b->list->who;
+ free(b->list);
+ pd_free(b);
+ }
+ } else error("%s: couldn't unbind", s->name);
+}
+
+t_pd *pd_findbyclass(t_symbol *s, t_class *c) {
+ t_pd *x = 0;
+ if (!s->thing) return 0;
+ if (s->thing->_class == c) return s->thing;
+ if (s->thing->_class == bindlist_class) {
+ t_bindlist *b = (t_bindlist *)s->thing;
+ int warned = 0;
+ bind_each(e,b) if (e->who->_class == c) {
+ if (x && !warned) {post("warning: %s: multiply defined", s->name); warned = 1;}
+ x = e->who;
+ }
+ }
+ return x;
+}
+
+/* stack for maintaining bindings for the #X symbol during nestable loads. */
+
+#undef g_next
+
+struct t_gstack {
+ t_pd *what;
+ t_symbol *loading_abstr;
+ t_gstack *next;
+ long base_o_index;
+};
+
+static t_gstack *gstack_head = 0;
+static t_pd *lastpopped;
+static t_symbol *pd_loading_abstr;
+
+int pd_setloadingabstraction(t_symbol *sym) {
+ t_gstack *foo = gstack_head;
+ for (foo = gstack_head; foo; foo = foo->next) if (foo->loading_abstr == sym) return 1;
+ pd_loading_abstr = sym;
+ return 0;
+}
+
+int gstack_empty() {return !gstack_head;}
+
+long canvas_base_o_index() {
+ return gstack_head ? gstack_head->base_o_index : 0;
+}
+
+void pd_pushsym(t_pd *x) {
+ t_gstack *y = (t_gstack *)malloc(sizeof(*y));
+ y->what = s__X.thing;
+ y->next = gstack_head;
+ y->loading_abstr = pd_loading_abstr;
+ y->base_o_index = x->_class == canvas_class ? ((t_canvas *)x)->next_o_index : -666;
+ pd_loading_abstr = 0;
+ gstack_head = y;
+ s__X.thing = x;
+}
+
+void pd_popsym(t_pd *x) {
+ if (!gstack_head || s__X.thing != x) {bug("gstack_pop"); return;}
+ t_gstack *headwas = gstack_head;
+ s__X.thing = headwas->what;
+ gstack_head = headwas->next;
+ free(headwas);
+ lastpopped = x;
+}
+
+static void stackerror(t_pd *x) {error("stack overflow");}
+
+/* to enable multithreading, make those variables "thread-local". this means that they have to go in
+ a thread-specific place instead of plain global. do not ever use tim's atomic counters for this,
+ as they count all threads together as if they're one, and they're especially incompatible with
+ use of the desiredata-specific stack[] variable. */
+int pd_stackn = 0; /* how much of the stack is in use */
+t_call pd_stack[STACKSIZE];
+
+static inline uint64 rdtsc() {uint64 x; __asm__ volatile (".byte 0x0f, 0x31":"=A"(x)); return x;}
+
+//#define PROFILER
+#ifdef PROFILER
+#define ENTER_PROF uint64 t = rdtsc();
+#define LEAVE_PROF if (x->_class->gobj && ((t_gobj *)x)->dix) ((t_gobj *)x)->dix->elapsed += rdtsc() - t;
+#else
+#define ENTER_PROF
+#define LEAVE_PROF
+#endif
+
+#define ENTER(SELECTOR) if(pd_stackn >= STACKSIZE) {stackerror(x); return;} \
+ pd_stack[pd_stackn].self = x; pd_stack[pd_stackn].s = SELECTOR; pd_stackn++; ENTER_PROF
+#define LEAVE pd_stackn--; LEAVE_PROF
+
+/* matju's 2007.07.14 inlet-based stack check needs to be implemented in:
+ pd_bang pd_float pd_pointer pd_symbol pd_string pd_list pd_typedmess */
+void pd_bang(t_pd *x) {ENTER(&s_bang); x->_class->bangmethod(x); LEAVE;}
+void pd_float(t_pd *x, t_float f) {ENTER(&s_float); x->_class->floatmethod(x,f); LEAVE;}
+void pd_pointer(t_pd *x, t_gpointer *gp) {ENTER(&s_pointer); x->_class->pointermethod(x,gp); LEAVE;}
+void pd_symbol(t_pd *x, t_symbol *s) {ENTER(&s_symbol); x->_class->symbolmethod(x,s); LEAVE;}
+/* void pd_string(t_pd *x, const char *s){ENTER(&s_symbol); x->_class->stringmethod(x,s); LEAVE;} future use */
+void pd_list(t_pd *x, t_symbol *s, int ac, t_atom *av) {ENTER(s); x->_class->listmethod(x,&s_list,ac,av); LEAVE;}
+
+/* this file handles Max-style patchable objects, i.e., objects which
+can interconnect via inlets and outlets; also, the (terse) generic
+behavior for "gobjs" appears at the end of this file. */
+
+union inletunion {
+ t_symbol *symto;
+ t_gpointer *pointerslot;
+ t_float *floatslot;
+ t_symbol **symslot;
+ t_sample floatsignalvalue;
+};
+
+struct _inlet : t_pd {
+ struct _inlet *next;
+ t_object *owner;
+ t_pd *dest;
+ t_symbol *symfrom;
+ union inletunion u;
+ t_symbol* tip;
+};
+
+static t_class *inlet_class, *pointerinlet_class, *floatinlet_class, *symbolinlet_class;
+
+#define ISINLET(pd) ( \
+ pd->_class == inlet_class || \
+ pd->_class == pointerinlet_class || \
+ pd->_class == floatinlet_class || \
+ pd->_class == symbolinlet_class)
+
+/* --------------------- generic inlets ala max ------------------ */
+
+static void object_append_inlet(t_object *owner, t_inlet *x) {
+ t_inlet *y = owner->inlet, *y2;
+ if (y) {
+ while ((y2 = y->next)) y = y2;
+ y->next = x;
+ } else owner->inlet = x;
+}
+
+t_inlet *inlet_new(t_object *owner, t_pd *dest, t_symbol *s1, t_symbol *s2) {
+ t_inlet *x = (t_inlet *)pd_new(inlet_class);
+ x->owner = owner;
+ x->dest = dest;
+ if (s1 == &s_signal) x->u.floatsignalvalue = 0; else x->u.symto = s2;
+ x->symfrom = s1;
+ x->next = 0;
+ x->tip = gensym("?");
+ object_append_inlet(owner,x);
+ return x;
+}
+
+t_inlet *signalinlet_new(t_object *owner, t_float f) {
+ t_inlet *x = inlet_new(owner, owner, &s_signal, &s_signal);
+ x->u.floatsignalvalue = f;
+ return x;
+}
+
+static void inlet_wrong(t_inlet *x, t_symbol *s) {
+ error("inlet: expected '%s' but got '%s'", x->symfrom->name, s->name);
+}
+
+void inlet_settip(t_inlet* i,t_symbol* s) {i->tip = s;}
+
+char* inlet_tip(t_inlet* i,int num) {
+ if (num < 0) return "???";
+ while (num-- && i) i = i->next;
+ if (i && i->tip) return i->tip->name;
+ return "?";
+}
+
+/* LATER figure out how to make these efficient: */
+static void inlet_bang(t_inlet *x) {
+ if (x->symfrom == &s_bang) pd_vmess(x->dest, x->u.symto, "");
+ else if (!x->symfrom) pd_bang(x->dest);
+ else inlet_wrong(x, &s_bang);
+}
+static void inlet_pointer(t_inlet *x, t_gpointer *gp) {
+ if (x->symfrom == &s_pointer) pd_vmess(x->dest, x->u.symto, "p", gp);
+ else if (!x->symfrom) pd_pointer(x->dest, gp);
+ else inlet_wrong(x, &s_pointer);
+}
+static void inlet_float(t_inlet *x, t_float f) {
+ if (x->symfrom == &s_float) pd_vmess(x->dest, x->u.symto, "f", (t_floatarg)f);
+ else if (x->symfrom == &s_signal) x->u.floatsignalvalue = f;
+ else if (!x->symfrom) pd_float(x->dest, f);
+ else inlet_wrong(x, &s_float);
+}
+
+static void inlet_symbol(t_inlet *x, t_symbol *s) {
+ if (x->symfrom == &s_symbol) pd_vmess(x->dest, x->u.symto, "s", s);
+ else if (!x->symfrom) pd_symbol(x->dest, s);
+ else inlet_wrong(x, &s_symbol);
+}
+
+static void inlet_list(t_inlet *x, t_symbol *s, int argc, t_atom *argv) {
+ if (x->symfrom == &s_list || x->symfrom == &s_float || x->symfrom == &s_symbol || x->symfrom == &s_pointer)
+ typedmess(x->dest, x->u.symto, argc, argv);
+ else if (!x->symfrom) pd_list(x->dest, s, argc, argv);
+ else inlet_wrong(x, &s_list);
+}
+
+static void inlet_anything(t_inlet *x, t_symbol *s, int argc, t_atom *argv) {
+ if (x->symfrom == s) typedmess(x->dest, x->u.symto, argc, argv);
+ else if (!x->symfrom) typedmess(x->dest, s, argc, argv);
+ else inlet_wrong(x, s);
+}
+
+void inlet_free(t_inlet *x) {
+ t_object *y = x->owner;
+ if (y->inlet == x) y->inlet = x->next;
+ else for (t_inlet *x2 = y->inlet; x2; x2 = x2->next) if (x2->next == x) {
+ x2->next = x->next;
+ break;
+ }
+ pd_free(x);
+}
+
+/* ----- pointerinlets, floatinlets, syminlets: optimized inlets ------- */
+
+static void pointerinlet_pointer(t_inlet *x, t_gpointer *gp) {
+ gpointer_unset(x->u.pointerslot);
+ *(x->u.pointerslot) = *gp;
+ if (gp->o) gp->o->refcount++;
+}
+
+static void floatinlet_float( t_inlet *x, t_float f) { *(x->u.floatslot) = f; }
+static void symbolinlet_symbol(t_inlet *x, t_symbol *s) { *(x->u.symslot) = s; }
+
+#define COMMON \
+ x->owner = owner; \
+ x->dest = 0; \
+ x->next = 0; \
+ object_append_inlet(owner,x); \
+ return x;
+
+t_inlet *floatinlet_new(t_object *owner, t_float *fp) {
+ t_inlet *x = (t_inlet *)pd_new(floatinlet_class);
+ x->symfrom = &s_float; x->u.floatslot = fp; COMMON
+}
+t_inlet *symbolinlet_new(t_object *owner, t_symbol **sp) {
+ t_inlet *x = (t_inlet *)pd_new(symbolinlet_class);
+ x->symfrom = &s_symbol; x->u.symslot = sp; COMMON
+}
+t_inlet *pointerinlet_new(t_object *owner, t_gpointer *gp) {
+ t_inlet *x = (t_inlet *)pd_new(pointerinlet_class);
+ x->symfrom = &s_pointer; x->u.pointerslot = gp; COMMON
+}
+#undef COMMON
+
+/* ---------------------- routine to handle lists ---------------------- */
+
+/* objects interpret lists by feeding them to the individual inlets. Before you call this,
+ check that the object doesn't have a more specific way to handle lists. */
+void obj_list(t_object *x, t_symbol *s, int argc, t_atom *argv) {
+ t_atom *ap;
+ int count;
+ t_inlet *ip = ((t_object *)x)->inlet;
+ if (!argc) return;
+ for (count = argc-1, ap = argv+1; ip && count--; ap++, ip = ip->next) {
+ if (ap->a_type == A_POINTER) pd_pointer(ip,ap->a_gpointer);
+ else if (ap->a_type == A_FLOAT) pd_float(ip,ap->a_float);
+ else pd_symbol(ip,ap->a_symbol);
+ }
+ if (argv->a_type == A_POINTER) pd_pointer(x, argv->a_gpointer);
+ else if (argv->a_type == A_FLOAT) pd_float(x, argv->a_float);
+ else pd_symbol(x, argv->a_symbol);
+}
+
+void obj_init () {
+ inlet_class = class_new(gensym("inlet"), 0, 0, sizeof(t_inlet), CLASS_PD, 0);
+ floatinlet_class = class_new(gensym("inlet"), 0, 0, sizeof(t_inlet), CLASS_PD, 0);
+ symbolinlet_class = class_new(gensym("inlet"), 0, 0, sizeof(t_inlet), CLASS_PD, 0);
+ pointerinlet_class = class_new(gensym("inlet"), 0, 0, sizeof(t_inlet), CLASS_PD, 0);
+ class_addbang(inlet_class, inlet_bang);
+ class_addpointer(inlet_class, inlet_pointer);
+ class_addfloat(inlet_class, inlet_float);
+ class_addsymbol(inlet_class, inlet_symbol);
+ class_addlist(inlet_class, inlet_list);
+ class_addanything(inlet_class, inlet_anything);
+ class_addfloat( floatinlet_class, floatinlet_float);
+ class_addsymbol( symbolinlet_class, symbolinlet_symbol);
+ class_addpointer(pointerinlet_class, pointerinlet_pointer);
+}
+
+/* --------------------------- outlets ------------------------------ */
+
+/* this is fairly obsolete stuff, I think */
+static int outlet_eventno;
+void outlet_setstacklim () {outlet_eventno++;}
+int sched_geteventno( void) {return outlet_eventno;}
+
+struct _outlet {
+ t_object *owner;
+ struct _outlet *next;
+ t_outconnect *connections;
+ t_symbol *sym;
+};
+
+t_inlet *t_object:: in(int n) {t_inlet *i= inlet; while(n--) i=i->next; return i;}
+t_outlet *t_object::out(int n) {t_outlet *o=outlet; while(n--) o=o->next; return o;}
+
+t_class *wire_class;
+t_wire *wire_new (t_symbol *s, int argc, t_atom *argv) {
+ t_wire *self = (t_wire *)pd_new(wire_class);
+ self->g_adix = appendix_new((t_gobj *)self);
+ return self;
+}
+void wire_free (t_wire *self) {/* nothing here */}
+
+/* this is only used for pd_upload yet, right? so, it can use the new indices instead already */
+void wire_save (t_wire *self, t_binbuf *b) {
+// t_canvas *c = self->dix->canvas;
+ binbuf_addv(b,"ttiiii;","#X","connect",
+// canvas_getindex(c,self->from), self->outlet,
+// canvas_getindex(c,self->to ), self-> inlet);
+ self->from->dix->index, self->outlet,
+ self->to ->dix->index, self-> inlet);
+ appendix_save((t_gobj *)self,b);
+}
+
+t_outlet *outlet_new(t_object *owner, t_symbol *s) {
+ t_outlet *x = (t_outlet *)malloc(sizeof(*x)), *y, *y2;
+ x->owner = owner;
+ x->next = 0;
+ y = owner->outlet;
+ if (y) {
+ while ((y2 = y->next)) y = y2;
+ y->next = x;
+ } else owner->outlet = x;
+ x->connections = 0;
+ x->sym = s;
+ return x;
+}
+
+#define each_connect(oc,x) for (t_outconnect *oc = x->connections; oc; oc = oc->next)
+void outlet_bang(t_outlet *x) {each_connect(oc,x) pd_bang(oc->oc_to);}
+void outlet_pointer(t_outlet *x, t_gpointer *gp) {t_gpointer gpointer = *gp; each_connect(oc,x) pd_pointer(oc->oc_to, &gpointer);}
+void outlet_float(t_outlet *x, t_float f) {each_connect(oc,x) pd_float(oc->oc_to, f);}
+void outlet_symbol(t_outlet *x, t_symbol *s) {each_connect(oc,x) pd_symbol(oc->oc_to, s);}
+void outlet_list(t_outlet *x, t_symbol *s, int argc, t_atom *argv) {each_connect(oc,x) pd_list( oc->oc_to,s,argc,argv);}
+void outlet_anything(t_outlet *x, t_symbol *s, int argc, t_atom *argv) {each_connect(oc,x) typedmess(oc->oc_to,s,argc,argv);}
+
+void outlet_atom(t_outlet *x, t_atom *a) {
+ if (a->a_type == A_FLOAT ) outlet_float( x,a->a_float);
+ else if (a->a_type == A_SYMBOL ) outlet_symbol( x,a->a_symbol);
+ else if (a->a_type == A_POINTER) outlet_pointer(x,a->a_gpointer);
+ else error("can't send atom whose type is %d",a->a_type);
+}
+
+/* get the outlet's declared symbol */
+t_symbol *outlet_getsymbol(t_outlet *x) {return x->sym;}
+
+void outlet_free(t_outlet *x) {
+ t_object *y = x->owner;
+ if (y->outlet == x) y->outlet = x->next;
+ else for (t_outlet *x2 = y->outlet; x2; x2 = x2->next) if (x2->next == x) {
+ x2->next = x->next;
+ break;
+ }
+ free(x);
+}
+
+#define each_inlet(i,obj) for ( t_inlet *i=obj->inlet; i; i=i->next)
+#define each_outlet(o,obj) for (t_outlet *o=obj->outlet; o; o=o->next)
+
+static t_pd *find_inlet(t_object *to, int inlet) {
+ if (to->_class->firstin) {if (inlet) inlet--; else return (t_pd *)to;}
+ each_inlet(i,to) if (inlet) inlet--; else return (t_pd *)i;
+ return 0;
+}
+
+static t_outlet *find_outlet(t_object *from, int outlet) {
+ each_outlet(o,from) if (outlet) outlet--; else return o;
+ return 0;
+}
+
+t_outconnect *obj_connect(t_object *from, int outlet, t_object *to, int inlet) {
+ t_outlet *o = find_outlet(from,outlet);
+ t_pd *i = find_inlet(to,inlet);
+ if (!o||!i) return 0;
+ t_outconnect *oc = wire_new(0,0,0), *oc2;
+ oc->next = 0;
+ oc->oc_to = i;
+ oc->from = from; oc->outlet = outlet;
+ oc->to = to; oc->inlet = inlet;
+ /* append it to the end of the list */
+ /* LATER we might cache the last "oc" to make this faster. */
+ if ((oc2 = o->connections)) {
+ while (oc2->next) oc2 = oc2->next;
+ oc2->next = oc;
+ } else o->connections = oc;
+ if (o->sym == &s_signal) canvas_update_dsp();
+ return oc;
+}
+
+void obj_disconnect(t_object *from, int outlet, t_object *to, int inlet) {
+ t_outlet *o = find_outlet(from,outlet); if (!o) {post("outlet does not exist"); return;}
+ t_pd *i = find_inlet(to, inlet); if (!i) {post( "inlet does not exist"); return;}
+ t_outconnect *oc = o->connections, *oc2;
+ if (!oc) {post("outlet has no connections"); return;}
+ if (oc->oc_to == i) {
+ o->connections = oc->next;
+ pd_free(oc);
+ goto done;
+ }
+ while ((oc2 = oc->next)) {
+ if (oc2->oc_to == i) {
+ oc->next = oc2->next;
+ pd_free(oc2);
+ goto done;
+ }
+ oc = oc2;
+ }
+ post("connection not found");
+done:
+ if (o->sym == &s_signal) canvas_update_dsp();
+}
+
+/* ------ traversal routines for code that can't see our structures ------ */
+
+int obj_noutlets(t_object *x) {
+ int n=0;
+ each_outlet(o,x) n++;
+ return n;
+}
+
+int obj_ninlets(t_object *x) {
+ int n=!!x->_class->firstin;
+ each_inlet(i,x) n++;
+ return n;
+}
+
+t_outconnect *obj_starttraverseoutlet(t_object *x, t_outlet **op, int nout) {
+ t_outlet *o = x->outlet;
+ while (nout-- && o) o = o->next;
+ *op = o;
+ return o ? o->connections : 0;
+}
+
+t_outconnect *obj_nexttraverseoutlet(t_outconnect *lastconnect, t_object **destp, t_inlet **inletp, int *whichp) {
+ t_pd *y = lastconnect->oc_to;
+ if (ISINLET(y)) {
+ t_inlet *i = (t_inlet *)y;
+ t_object *dest = i->owner;
+ int n = dest->_class->firstin;
+ each_inlet(i2,dest) if (i2==i) break; else n++;
+ *whichp = n;
+ *destp = dest;
+ *inletp = i;
+ } else {
+ *whichp = 0;
+ *inletp = 0;
+ *destp = (t_object *)y;
+ }
+ return lastconnect->next;
+}
+
+/* this one checks that a pd is indeed a patchable object, and returns it,
+ correctly typed, or zero if the check failed. */
+t_object *pd_checkobject(t_pd *x) {
+ return x->_class->patchable ? (t_object *)x : 0;
+}
+
+/* move an inlet or outlet to the head of the list. this code is not safe with the latest additions in t_outconnect ! */
+void obj_moveinletfirst( t_object *x, t_inlet *i) {
+ if (x->inlet == i) return;
+ each_inlet( i2,x) if (i2->next == i) {i2->next = i->next; i->next = x-> inlet; x-> inlet = i; return;}}
+void obj_moveoutletfirst(t_object *x, t_outlet *o) {
+ if (x->outlet == o) return;
+ each_outlet(o2,x) if (o2->next == o) {o2->next = o->next; o->next = x->outlet; x->outlet = o; return;}}
+
+/* routines for DSP sorting, which are used in d_ugen.c and g_canvas.c */
+/* LATER try to consolidate all the slightly different routines. */
+
+int obj_nsiginlets(t_object *x) {
+ int n=0;
+ each_inlet(i,x) if (i->symfrom == &s_signal) n++;
+ if (x->_class->firstin && x->_class->floatsignalin) n++;
+ return n;
+}
+int obj_nsigoutlets(t_object *x) {
+ int n=0;
+ each_outlet(o,x) if (o->sym == &s_signal) n++;
+ return n;
+}
+
+/* get the index, among signal inlets, of the mth inlet overall */
+int obj_siginletindex(t_object *x, int m) {
+ int n=0;
+ if (x->_class->firstin && x->_class->floatsignalin) {if (!m--) return 0; else n++;}
+ each_inlet(i,x) if (i->symfrom == &s_signal) {if (!m) return n; else {n++; m--;}}
+ return -1;
+}
+int obj_sigoutletindex(t_object *x, int m) {
+ int n=0;
+ each_outlet(o,x) if (o->sym == &s_signal) {if (!m) return n; else {n++; m--;}}
+ return -1;
+}
+
+int obj_issignalinlet(t_object *x, int m) {
+ if (x->_class->firstin) {if (!m) return x->_class->floatsignalin; else m--;}
+ t_inlet *i;
+ for (i = x->inlet; i && m; i = i->next, m--) {}
+ return i && i->symfrom==&s_signal;
+}
+int obj_issignaloutlet(t_object *x, int m) {
+ t_outlet *o2;
+ for (o2 = x->outlet; o2 && m--; o2 = o2->next) {}
+ return o2 && o2->sym==&s_signal;
+}
+
+t_sample *obj_findsignalscalar(t_object *x, int m) {
+ int n = 0;
+ t_inlet *i;
+ if (x->_class->firstin && x->_class->floatsignalin) {
+ if (!m--) return x->_class->floatsignalin > 0 ? (t_sample *)(((char *)x) + x->_class->floatsignalin) : 0;
+ n++;
+ }
+ for (i = x->inlet; i; i = i->next, m--) if (i->symfrom == &s_signal) {
+ if (m == 0) return &i->u.floatsignalvalue;
+ n++;
+ }
+ return 0;
+}
+
+/* and those two are only used in desire.c... */
+int inlet_getsignalindex(t_inlet *x) {
+ int n=0; for ( t_inlet *i = x->owner-> inlet; i; i = i->next) if (i==x) return n; else if (i->symfrom == &s_signal) n++;
+ return -1;}
+int outlet_getsignalindex(t_outlet *x) {
+ int n=0; for (t_outlet *o = x->owner->outlet; o; o = o->next) if (o==x) return n; else if (o->sym == &s_signal) n++;
+ return -1;}
+
+#ifdef QUALIFIED_NAME
+static char *pd_library_name = 0;
+void pd_set_library_name(char *libname){
+ pd_library_name=libname;
+}
+#endif
+
+t_hash<t_symbol *, t_class *> *class_table=0;
+static t_symbol *class_loadsym; /* name under which an extern is invoked */
+static void pd_defaultfloat(t_pd *x, t_float f);
+static void pd_defaultlist(t_pd *x, t_symbol *s, int argc, t_atom *argv);
+t_pd pd_objectmaker; /* factory for creating "object" boxes */
+t_pd pd_canvasmaker; /* factory for creating canvases */
+
+static t_symbol *class_extern_dir = &s_;
+
+static void pd_defaultanything(t_pd *x, t_symbol *s, int argc, t_atom *argv) {
+ error("%s: no method for '%s'", x->_class->name->name, s->name);
+}
+
+static void pd_defaultbang(t_pd *x) {
+ t_class *c = pd_class(x);
+ if (c->listmethod != pd_defaultlist) c->listmethod(x,0,0,0);
+ else c->anymethod(x,&s_bang,0,0);
+}
+
+static void pd_defaultfloat(t_pd *x, t_float f) {
+ t_class *c = pd_class(x); t_atom at; SETFLOAT(&at, f);
+ if (c->listmethod != pd_defaultlist) c->listmethod(x,0,1,&at); else c->anymethod(x,&s_float,1,&at);
+}
+static void pd_defaultsymbol(t_pd *x, t_symbol *s) {
+ t_class *c = pd_class(x); t_atom at; SETSYMBOL(&at, s);
+ if (c->listmethod != pd_defaultlist) c->listmethod(x,0,1,&at); else c->anymethod(x,&s_symbol,1,&at);
+}
+static void pd_defaultpointer(t_pd *x, t_gpointer *gp) {
+ t_class *c = pd_class(x); t_atom at; SETPOINTER(&at, gp);
+ if (c->listmethod != pd_defaultlist) c->listmethod(x,0,1,&at); else c->anymethod(x,&s_pointer,1,&at);
+}
+
+void obj_list(t_object *x, t_symbol *s, int argc, t_atom *argv);
+static void class_nosavefn(t_gobj *z, t_binbuf *b);
+
+/* handle "list" messages to Pds without explicit list methods defined. */
+static void pd_defaultlist(t_pd *x, t_symbol *s, int argc, t_atom *argv) {
+ t_class *c = pd_class(x);
+ /* a list with no elements is handled by the 'bang' method if one exists. */
+ if (argc == 0 && c->bangmethod != pd_defaultbang) {c->bangmethod(x); return;}
+ /* a list with one element which is a number can be handled by a
+ "float" method if any is defined; same for "symbol", "pointer". */
+ if (argc == 1) {
+#define HANDLE(A,M,D,F) if (argv->a_type==A && c->M != D) {c->M(x, argv->a_w.F); return;}
+ HANDLE(A_FLOAT ,floatmethod ,pd_defaultfloat ,w_float)
+ HANDLE(A_SYMBOL ,symbolmethod ,pd_defaultsymbol ,w_symbol)
+ HANDLE(A_POINTER,pointermethod,pd_defaultpointer,w_gpointer)
+ }
+ /* Next try for an "anything" method; if the object is patchable (i.e.,
+ can have proper inlets) send it on to obj_list which will unpack the
+ list into the inlets. otherwise gove up and complain. */
+ if (c->anymethod != pd_defaultanything) c->anymethod(x,&s_list,argc,argv);
+ else if (c->patchable) obj_list((t_object *)x, s, argc, argv);
+ else pd_defaultanything(x, &s_list, argc, argv);
+}
+
+t_symbol *qualified_name(t_symbol *s) {
+ char *buf;
+ asprintf(&buf, "%s%s%s", pd_library_name, QUALIFIED_NAME, s->name);
+ t_symbol *sym = gensym(buf);
+ free(buf);
+ return sym;
+}
+
+#undef class_new2
+#undef class_addcreator2
+#undef class_addmethod2
+
+/* Note that some classes such as "select", are actually two classes of the same name,
+ one for the single-argument form, one for the multiple one; see select_setup() to
+ find out how this is handled. */
+t_class *class_new2(const char *ss, t_newmethod newmethod, t_method freemethod,
+size_t size, int flags, const char *sig) {
+ t_symbol *s = gensym(ss);
+ int typeflag = flags & CLASS_TYPEMASK;
+ if (!typeflag) typeflag = CLASS_PATCHABLE;
+#ifdef QUALIFIED_NAME
+ if (pd_library_name) s = qualified_name(s);
+#endif
+ if (pd_objectmaker._class && newmethod) {
+ /* add a "new" method by the name specified by the object */
+ class_addmethod2(pd_objectmaker._class, (t_method)newmethod, s->name, sig);
+ if (class_loadsym) {
+ /* if we're loading an extern it might have been invoked by a
+ longer file name; in this case, make this an admissible name too. */
+ char *loadstring = class_loadsym->name, l1 = strlen(s->name), l2 = strlen(loadstring);
+ if (l2 > l1 && !strcmp(s->name, loadstring + (l2 - l1)))
+ class_addmethod2(pd_objectmaker._class, (t_method)newmethod, class_loadsym->name, sig);
+ }
+ }
+ t_class *c = (t_class *)malloc(sizeof(*c));
+ c->name = c->helpname = s;
+ c->size = size;
+ c->methods = (t_methodentry *)malloc(1);
+ c->nmethod = 0;
+ c->freemethod = (t_method)freemethod;
+ c->bangmethod = pd_defaultbang;
+ c->pointermethod = pd_defaultpointer;
+ c->floatmethod = pd_defaultfloat;
+ c->symbolmethod = pd_defaultsymbol;
+ c->listmethod = pd_defaultlist;
+ c->anymethod = pd_defaultanything;
+ c->firstin = ((flags & CLASS_NOINLET) == 0);
+ c->firsttip = gensym("?");
+ c->fields = (t_symbol **)malloc(sizeof(t_symbol *)*31);
+ c->nfields = 0;
+ c->patchable = (typeflag == CLASS_PATCHABLE);
+ c->gobj = (typeflag >= CLASS_GOBJ);
+ c->drawcommand = 0;
+ c->floatsignalin = 0;
+ c->externdir = class_extern_dir;
+ c->savefn = (typeflag == CLASS_PATCHABLE ? text_save : class_nosavefn);
+#ifdef QUALIFIED_NAME
+ c->helpname = gensym(ss);
+ // like a class_addcreator
+ if (pd_library_name && newmethod)
+ class_addmethod2(pd_objectmaker._class, (t_method)newmethod, ss, sig);
+#endif
+ c->onsubscribe = gobj_onsubscribe;
+ class_table->set(c->name, c);
+ return c;
+}
+
+/* add a creation method, which is a function that returns a Pd object
+ suitable for putting in an object box. We presume you've got a class it
+ can belong to, but this won't be used until the newmethod is actually
+ called back (and the new method explicitly takes care of this.) */
+void class_addcreator2(const char *ss, t_newmethod newmethod, const char *sig) {
+ t_symbol *s = gensym(ss);
+ class_addmethod2(pd_objectmaker._class, (t_method)newmethod, ss, sig);
+#ifdef QUALIFIED_NAME
+ class_addmethod2(pd_objectmaker._class, (t_method)newmethod, pd_library_name ? qualified_name(s)->name : ss, sig);
+#endif
+ class_table->set(s,0);
+}
+
+void class_addmethod2(t_class *c, t_method fn, const char *ss, const char *fmt) {
+ t_symbol *sel = gensym(ss);
+ t_methodentry *m;
+ int argtype = *fmt++;
+ /* "signal" method specifies that we take audio signals but
+ that we don't want automatic float to signal conversion. This
+ is obsolete; you should now use the CLASS_MAINSIGNALIN macro. */
+ if (sel == &s_signal) {
+ if (c->floatsignalin) post("warning: signal method overrides class_mainsignalin");
+ c->floatsignalin = -1;
+ }
+ /* check for special cases. "Pointer" is missing here so that
+ pd_objectmaker's pointer method can be typechecked differently. */
+ /* is anyone actually using those five cases? */
+ if (sel==&s_bang) {if (argtype) goto phooey; class_addbang( c,fn);}
+ else if (sel==&s_float) {if (argtype!='f'||*fmt) goto phooey; class_doaddfloat( c,fn);}
+ else if (sel==&s_symbol) {if (argtype!='s'||*fmt) goto phooey; class_addsymbol( c,fn);}
+ else if (sel==&s_list) {if (argtype!='*') goto phooey; class_addlist( c,fn);}
+ else if (sel==&s_anything) {if (argtype!='*') goto phooey; class_addanything(c,fn);}
+ else {
+ /* SLOW, especially for [objectmaker] */
+ c->methods = (t_methodentry *)realloc(c->methods, (c->nmethod+1) * sizeof(*c->methods));
+ m = c->methods + c->nmethod;
+ c->nmethod++;
+ m->me_name = sel;
+ m->me_fun = (t_gotfn)fn;
+ int nargs = 0;
+ while (argtype && nargs < MAXPDARG) {
+ t_atomtype t;
+ switch(argtype) {
+ case 'f': t=A_FLOAT; break;
+ case 's': t=A_SYMBOL; break;
+ case 'p': t=A_POINTER; break;
+ case ';': t=A_SEMI; break;
+ case ',': t=A_COMMA; break;
+ case 'F': t=A_DEFFLOAT; break;
+ case 'S': t=A_DEFSYMBOL;break;
+ case '$': t=A_DOLLAR; break;
+ case '@': t=A_DOLLSYM; break;
+ case '*': t=A_GIMME; break;
+ case '!': t=A_CANT; break;
+ default: goto phooey;
+ };
+ m->me_arg[nargs++] = t;
+ argtype = *fmt++;
+ }
+ if (argtype) error("%s_%s: only 5 arguments are typecheckable; use A_GIMME aka '*'", c->name->name, sel->name);
+ m->me_arg[nargs] = A_NULL;
+ }
+ return;
+phooey:
+ bug("class_addmethod: %s_%s: bad argument types", c->name->name, sel->name);
+}
+
+t_class *class_new(t_symbol *s, t_newmethod newmethod, t_method freemethod,
+size_t size, int flags, t_atomtypearg arg1, ...) {
+ char fmt[42],*f=fmt; va_list ap; va_start(ap,arg1); int t=arg1;
+ while(t) {
+ if (t>A_CANT) {error("class_new: ARRGH! t=%d",t); return 0;}
+ *f++ = " fsp;,FS$@*!"[t];
+ t=(t_atomtype)va_arg(ap,int);
+ }
+ *f=0; va_end(ap); return class_new2(s->name,newmethod,freemethod,size,flags,fmt);
+}
+void class_addcreator(t_newmethod newmethod, t_symbol *s, t_atomtypearg arg1, ...) {
+ char fmt[42],*f=fmt; va_list ap; va_start(ap,arg1); int t=arg1;
+ while(t) {
+ if (t>A_CANT) {error("class_addcreator: ARRGH! t=%d",t); return;}
+ *f++ = " fsp;,FS$@*!"[t];
+ t=(t_atomtype)va_arg(ap,int);
+ }
+ *f=0; va_end(ap); class_addcreator2(s->name,newmethod,fmt);
+}
+void class_addmethod(t_class *c, t_method fn, t_symbol *sel, t_atomtypearg arg1, ...) {
+ char fmt[42],*f=fmt; va_list ap; va_start(ap,arg1); int t=arg1;
+ while(t) {
+ if (t>A_CANT) {error("class_addmethod: ARRGH! t=%d",t); return;}
+ *f++ = " fsp;,FS$@*!"[t];
+ t=(t_atomtype)va_arg(ap,int);
+ }
+ *f=0; va_end(ap); class_addmethod2(c,fn,sel->name,fmt);
+}
+
+/* see also the "class_addfloat", etc., macros in m_pd.h */
+#undef class_addbang
+#undef class_addpointer
+#undef class_addsymbol
+#undef class_addlist
+#undef class_addanything
+void class_addbang( t_class *c, t_method fn) {c-> bangmethod = (t_bangmethod)fn;}
+void class_addpointer( t_class *c, t_method fn) {c->pointermethod = (t_pointermethod)fn;}
+void class_doaddfloat( t_class *c, t_method fn) {c-> floatmethod = (t_floatmethod)fn;}
+void class_addsymbol( t_class *c, t_method fn) {c-> symbolmethod = (t_symbolmethod)fn;}
+void class_addlist( t_class *c, t_method fn) {c-> listmethod = (t_listmethod)fn;}
+void class_addanything(t_class *c, t_method fn) {c-> anymethod = (t_anymethod)fn;}
+
+char *class_getname(t_class *c) {return c->name->name;}
+char *class_gethelpname(t_class *c) {return c->helpname->name;}
+void class_sethelpsymbol(t_class *c, t_symbol *s) {c->helpname = s;}
+void class_setdrawcommand(t_class *c) {c->drawcommand = 1;}
+int class_isdrawcommand( t_class *c) {return c->drawcommand;}
+void class_setnotice( t_class *c, t_notice notice ) {c->notice = notice ;}
+void class_setonsubscribe(t_class *c, t_onsubscribe onsubscribe) {c->onsubscribe = onsubscribe;}
+
+static void pd_floatforsignal(t_pd *x, t_float f) {
+ int offset = x->_class->floatsignalin;
+ if (offset > 0)
+ *(t_sample *)(((char *)x) + offset) = f;
+ else
+ error("%s: float unexpected for signal input", x->_class->name->name);
+}
+
+void class_domainsignalin(t_class *c, int onset) {
+ if (onset <= 0) onset = -1;
+ else {
+ if (c->floatmethod != pd_defaultfloat)
+ post("warning: %s: float method overwritten", c->name->name);
+ c->floatmethod = (t_floatmethod)pd_floatforsignal;
+ }
+ c->floatsignalin = onset;
+}
+
+void class_set_extern_dir(t_symbol *s) {class_extern_dir = s;}
+char *class_gethelpdir(t_class *c) {return c->externdir->name;}
+
+static void class_nosavefn(t_gobj *z, t_binbuf *b) {
+ bug("save function called but not defined");
+}
+
+void class_setsavefn(t_class *c, t_savefn f) {c->savefn = f;}
+t_savefn class_getsavefn(t_class *c) {return c->savefn;}
+
+/* ---------------- the symbol table ------------------------ */
+
+/* tb: new 16 bit hash table: multiplication hash */
+#ifndef NEWHASH
+#define HASHSIZE 1024
+#else
+#define HASHSIZE 65536
+#define HASHFACTOR 40503 /* donald knuth: (sqrt(5) - 1)/2*pow(2,16) */
+#endif
+
+#ifdef NEWHASH
+static short hash(const char *s, size_t n) {
+ unsigned short hash1 = 0, hash2 = 0;
+#else
+static int hash(const char *s, size_t n) {
+ unsigned int hash1 = 0, hash2 = 0;
+#endif
+ const char *s2 = s;
+ while (n) {
+ hash1 += *s2;
+ hash2 += hash1;
+ s2++;
+ n--;
+ }
+ return hash2;
+}
+
+/* tb: made dogensym() threadsafe
+ * supported by vibrez.net */
+t_symbol *dogensym(const char *s, size_t n, t_symbol *oldsym) {
+ static t_symbol *symhash[HASHSIZE];
+#ifdef THREADSAFE_GENSYM
+ static pthread_mutex_t hash_lock = PTHREAD_MUTEX_INITIALIZER;
+#endif
+ t_symbol **sym1, *sym2;
+#ifdef NEWHASH
+ unsigned short hash2 = hash(s,n);
+#else
+ unsigned int hash2 = hash(s,n);
+#endif
+#ifdef NEWHASH
+ hash2 = hash2 * HASHFACTOR;
+ sym1 = symhash + hash2;
+#else
+ sym1 = symhash + (hash2 & (HASHSIZE-1));
+#endif
+ while ((sym2 = *sym1)) {
+ if (!strcmp(sym2->name, s)) return sym2;
+ sym1 = &sym2->next;
+ }
+#ifdef THREADSAFE_GENSYM
+ pthread_mutex_lock(&hash_lock);
+ /* tb: maybe another thread added the symbol to the hash table; double check */
+ while (sym2 = *sym1) {
+ if (!strcmp(sym2->name, s)) {
+ pthread_mutex_unlock(&hash_lock);
+ return sym2;
+ }
+ sym1 = &sym2->next;
+ }
+#endif
+
+ if (oldsym) sym2 = oldsym;
+ else {
+ sym2 = (t_symbol *)malloc(sizeof(*sym2));
+ sym2->name = (char *)malloc(n+1);
+ sym2->next = 0;
+ sym2->thing = 0;
+ memcpy(sym2->name, s, n);
+ sym2->name[n]=0;
+ sym2->n=n;
+ }
+ *sym1 = sym2;
+#ifdef THREADSAFE_GENSYM
+ pthread_mutex_unlock(&hash_lock);
+#endif
+ return sym2;
+}
+
+t_symbol *gensym( const char *s) {return dogensym(s,strlen(s),0);}
+t_symbol *gensym2(const char *s, size_t n) {return dogensym(s,n,0);}
+extern "C" t_symbol *symprintf(const char *s, ...) {
+ char *buf;
+ va_list args;
+ va_start(args,s);
+ vasprintf(&buf,s,args);
+ va_end(args);
+ t_symbol *r = gensym(buf);
+ free(buf);
+ return r;
+}
+
+static int tryingalready;
+extern "C" void canvas_popabstraction(t_canvas *x);
+extern t_pd *newest;
+t_symbol* pathsearch(t_symbol *s,char* ext);
+int pd_setloadingabstraction(t_symbol *sym);
+
+/* this routine is called when a new "object" is requested whose class Pd
+ doesn't know. Pd tries to load it as an extern, then as an abstraction. */
+void new_anything(void *dummy, t_symbol *s, int argc, t_atom *argv) {
+ int fd;
+ char *dirbuf, *nameptr;
+ if (tryingalready) return;
+ newest = 0;
+ class_loadsym = s;
+ if (sys_load_lib(canvas_getcurrent(), s->name)) {
+ tryingalready = 1;
+ typedmess((t_pd *)dummy, s, argc, argv);
+ tryingalready = 0;
+ return;
+ }
+ class_loadsym = 0;
+ t_pd *current = s__X.thing;
+ if ((fd = canvas_open2(canvas_getcurrent(), s->name, ".pd", &dirbuf, &nameptr, 0)) >= 0 ||
+ (fd = canvas_open2(canvas_getcurrent(), s->name, ".pat", &dirbuf, &nameptr, 0)) >= 0) {
+ close(fd);
+ if (!pd_setloadingabstraction(s)) {
+ canvas_setargs(argc, argv); /* bug fix by Krzysztof Czaja */
+ binbuf_evalfile(gensym(nameptr), gensym(dirbuf));
+ if (s__X.thing != current) canvas_popabstraction((t_canvas *)s__X.thing);
+ canvas_setargs(0, 0);
+ } else error("%s: can't load abstraction within itself", s->name);
+ free(dirbuf);
+ } else newest = 0;
+}
+
+#define MAKESYM(CSYM,S) t_symbol CSYM = {S,0,0,1,0xdeadbeef};
+MAKESYM(s_pointer ,"pointer")
+MAKESYM(s_float ,"float")
+MAKESYM(s_symbol ,"symbol")
+MAKESYM(s_bang ,"bang")
+MAKESYM(s_list ,"list")
+MAKESYM(s_anything,"anything")
+MAKESYM(s_signal ,"signal")
+MAKESYM(s__N ,"#N")
+MAKESYM(s__X ,"#X")
+MAKESYM(s_x ,"x")
+MAKESYM(s_y ,"y")
+MAKESYM(s_ ,"")
+
+static t_symbol *symlist[] = { &s_pointer, &s_float, &s_symbol, &s_bang,
+ &s_list, &s_anything, &s_signal, &s__N, &s__X, &s_x, &s_y, &s_};
+
+t_pd *newest;
+
+/* This is externally available, but note that it might later disappear; the
+whole "newest" thing is a hack which needs to be redesigned. */
+t_pd *pd_newest () {return newest;}
+
+ /* horribly, we need prototypes for each of the artificial function
+ calls in typedmess(), to keep the compiler quiet. */
+typedef t_pd *(*t_newgimme)(t_symbol *s, int argc, t_atom *argv);
+typedef void(*t_messgimme)(t_pd *x, t_symbol *s, int argc, t_atom *argv);
+
+#define REST t_floatarg d1, t_floatarg d2, t_floatarg d3, t_floatarg d4, t_floatarg d5
+typedef t_pd *(*t_fun0)(REST);
+typedef t_pd *(*t_fun1)(t_int i1, REST);
+typedef t_pd *(*t_fun2)(t_int i1, t_int i2, REST);
+typedef t_pd *(*t_fun3)(t_int i1, t_int i2, t_int i3, REST);
+typedef t_pd *(*t_fun4)(t_int i1, t_int i2, t_int i3, t_int i4, REST);
+typedef t_pd *(*t_fun5)(t_int i1, t_int i2, t_int i3, t_int i4, t_int i5, REST);
+typedef t_pd *(*t_fun6)(t_int i1, t_int i2, t_int i3, t_int i4, t_int i5, t_int i6, REST);
+#undef REST
+
+void pd_typedmess_2(t_pd *x, t_symbol *s, int argc, t_atom *argv) {
+ t_class *c = x->_class;
+ t_atomtype *wp, wanttype;
+ t_int ai[MAXPDARG+1], *ap = ai;
+ t_floatarg ad[MAXPDARG+1], *dp = ad;
+ int narg = 0;
+ /* check for messages that are handled by fixed slots in the class structure. We don't catch "pointer"
+ though so that sending "pointer" to pd_objectmaker doesn't require that we supply a pointer value. */
+ if (s == &s_float) {
+ if (!argc) c->floatmethod(x, 0.);
+ else if (argv->a_type == A_FLOAT) c->floatmethod(x, argv->a_float);
+ else error("expected one float, in class [%s]", c->name->name);
+ return;
+ }
+ if (s == &s_bang) {c->bangmethod(x); return;}
+ if (s == &s_list) {c->listmethod(x,s,argc,argv); return;}
+ if (s == &s_symbol) {c->symbolmethod(x, argc && argv->a_type==A_SYMBOL ? argv->a_symbol : &s_); return;}
+ t_methodentry *m = c->methods;
+ for (int i = c->nmethod; i--; m++) if (m->me_name == s) {
+ wp = m->me_arg;
+ if (*wp == A_GIMME) {
+ if (x == &pd_objectmaker) pd_set_newest(((t_newgimme)(m->me_fun))( s,argc,argv));
+ else ((t_messgimme)(m->me_fun))(x,s,argc,argv);
+ return;
+ }
+ if (argc > MAXPDARG) argc = MAXPDARG;
+ if (x != &pd_objectmaker) *(ap++) = (t_int)x, narg++;
+ while ((wanttype = *wp++)) {
+ switch (wanttype) {
+ case A_POINTER:
+ if (!argc) goto badarg;
+ if (argv->a_type!=A_POINTER) goto badarg;
+ *ap = t_int(argv->a_gpointer);
+ argc--; argv++;
+ narg++;
+ ap++;
+ break;
+ case A_FLOAT: if (!argc) goto badarg;
+ case A_DEFFLOAT: if (!argc) *dp = 0;
+ else {
+ if (argv->a_type!=A_FLOAT) goto badarg;
+ *dp = argv->a_float;
+ argc--; argv++;
+ }
+ dp++;
+ break;
+ case A_SYMBOL: if (!argc) goto badarg;
+ case A_DEFSYM: if (!argc) *ap = t_int(&s_);
+ else {
+ if (argv->a_type == A_SYMBOL) *ap = t_int(argv->a_symbol);
+ /* if it's an unfilled "dollar" argument it appears as zero here; cheat and bash it to the null
+ symbol. Unfortunately, this lets real zeros pass as symbols too, which seems wrong... */
+ else if (x == &pd_objectmaker && argv->a_type == A_FLOAT && argv->a_float == 0)
+ *ap = t_int(&s_);
+ else goto badarg;
+ argc--; argv++;
+ }
+ narg++;
+ ap++;
+ default: {}
+ }
+ }
+ t_pd *bonzo;
+ switch (narg) {
+#define REST ad[0],ad[1],ad[2],ad[3],ad[4]
+ case 0 : bonzo = ((t_fun0)(m->me_fun))( REST); break;
+ case 1 : bonzo = ((t_fun1)(m->me_fun))(ai[0], REST); break;
+ case 2 : bonzo = ((t_fun2)(m->me_fun))(ai[0],ai[1], REST); break;
+ case 3 : bonzo = ((t_fun3)(m->me_fun))(ai[0],ai[1],ai[2], REST); break;
+ case 4 : bonzo = ((t_fun4)(m->me_fun))(ai[0],ai[1],ai[2],ai[3], REST); break;
+ case 5 : bonzo = ((t_fun5)(m->me_fun))(ai[0],ai[1],ai[2],ai[3],ai[4], REST); break;
+ case 6 : bonzo = ((t_fun6)(m->me_fun))(ai[0],ai[1],ai[2],ai[3],ai[4],ai[5],REST); break;
+ default: bonzo = 0;
+ }
+ if (x == &pd_objectmaker) pd_set_newest(bonzo);
+ return;
+ }
+ c->anymethod(x, s, argc, argv);
+ return;
+badarg:
+ error("Bad arguments for message '%s' to object '%s'", s->name, c->name->name);
+}
+
+void pd_typedmess(t_pd *x, t_symbol *s, int argc, t_atom *argv) {
+ ENTER(s); pd_typedmess_2(x,s,argc,argv); LEAVE;
+}
+
+void pd_vmess(t_pd *x, t_symbol *sel, char *fmt, ...) {
+ va_list ap;
+ t_atom arg[MAXPDARG], *at =arg;
+ int nargs = 0;
+ char *fp = fmt;
+ va_start(ap, fmt);
+ while (1) {
+ if (nargs > MAXPDARG) {
+ error("pd_vmess: only %d allowed", MAXPDARG);
+ break;
+ }
+ switch(*fp++) {
+ case 'f': SETFLOAT(at, va_arg(ap, double)); break;
+ case 's': SETSYMBOL(at, va_arg(ap, t_symbol *)); break;
+ case 'i': SETFLOAT(at, va_arg(ap, t_int)); break;
+ case 'p': SETPOINTER(at, va_arg(ap, t_gpointer *)); break;
+ default: goto done;
+ }
+ at++;
+ nargs++;
+ }
+done:
+ va_end(ap);
+ typedmess(x, sel, nargs, arg);
+}
+
+void pd_forwardmess(t_pd *x, int argc, t_atom *argv) {
+ if (argc) {
+ t_atomtype t = argv->a_type;
+ if (t == A_SYMBOL) pd_typedmess(x, argv->a_symbol, argc-1, argv+1);
+ else if (t == A_POINTER) {if (argc==1) pd_pointer(x, argv->a_gpointer); else pd_list(x, &s_list, argc, argv);}
+ else if (t == A_FLOAT) {if (argc==1) pd_float( x, argv->a_float); else pd_list(x, &s_list, argc, argv);}
+ else bug("pd_forwardmess");
+ }
+}
+
+void nullfn () {}
+
+t_gotfn getfn(t_pd *x, t_symbol *s) {
+ t_class *c = x->_class;
+ t_methodentry *m = c->methods;
+ for (int i=c->nmethod; i--; m++) if (m->me_name == s) return m->me_fun;
+ error("%s: no method for message '%s'", c->name->name, s->name);
+ return (t_gotfn)nullfn;
+}
+
+t_gotfn zgetfn(t_pd *x, t_symbol *s) {
+ t_class *c = x->_class;
+ t_methodentry *m = c->methods;
+ for (int i=c->nmethod; i--; m++) if (m->me_name == s) return m->me_fun;
+ return 0;
+}
+
+void class_settip(t_class *x,t_symbol* s) {x->firsttip = s;}
+
+/* must be called only once */
+void class_setfieldnames(t_class *x, const char *s) {
+ char foo[64];
+ while (*s) {
+ char *t = strchr(s,' ');
+ int i = t-s;
+ if (!t) return;
+ memcpy(foo,s,i);
+ foo[i]=0;
+ x->fields[x->nfields++] = gensym(foo);
+ s=s+i+1;
+ }
+}
+
+int class_getfieldindex(t_class *x, const char *s) {
+ t_symbol *sy = gensym((char *)s);
+ for (int i=0; i<x->nfields; i++) if (x->fields[i]==sy) return i;
+ return -1;
+}
+
+/* O(n) asymptotic time :-} */
+/* only looks for already loaded classes though. */
+
+t_class *class_find (t_symbol *s) {return (t_class *)class_table->get(s);}
+
+void glob_update_class_info (t_pd *bogus, t_symbol *s, t_symbol *cb_recv, t_symbol *cb_sel) {
+ t_class *c = class_find(s);
+ if (!c) { post("class not found!"); return; }
+ sys_vgui("global class_info; set class_info(%s) [list "
+ "helpname \"%s\" externdir \"%s\" size \"%d\" "
+/*
+ t_methodentry *c_methods; int c_nmethod;
+ t_method c_freemethod;
+ t_savefn c_savefn;
+ int c_floatsignalin;
+*/
+ "gobj \"%d\" patchable \"%d\" firstin \"%d\" "
+ "firsttip \"%s\" methods {",s->name,c->helpname->name,c->externdir->name,
+ c->size,c->gobj,c->patchable,c->firstin,c->firsttip->name);
+ if (c-> bangmethod != pd_defaultbang) sys_vgui("<bang> ");
+ if (c->pointermethod != pd_defaultpointer) sys_vgui("<pointer> ");
+ if (c-> floatmethod != pd_defaultfloat) sys_vgui("<float> ");
+ if (c-> symbolmethod != pd_defaultsymbol) sys_vgui("<symbol> ");
+ if (c-> listmethod != pd_defaultlist) sys_vgui("<list> ");
+ if (c-> anymethod != pd_defaultanything) sys_vgui("<any> ");
+ for (int i=0; i<c->nmethod; i++) sys_vgui("%s ",c->methods[i].me_name->name);
+ sys_vgui("}]; %s %s %s\n",cb_recv->name, cb_sel->name, s->name);
+}
+
+t_class *binbuf_class;
+
+t_binbuf *binbuf_new () {
+ t_binbuf *x = (t_binbuf *)pd_new(binbuf_class);
+ x->n = 0;
+ x->capa = 1;
+ x->v = (t_atom *)malloc(1*sizeof(t_atom));
+ return x;
+}
+
+/* caution: capa >= x->n and capa >= 1 too */
+static void binbuf_capa(t_binbuf *x, int capa) {
+ x->v = (t_atom *)realloc(x->v, capa*sizeof(*x->v));
+ x->capa = capa;
+}
+
+void binbuf_free(t_binbuf *x) {pd_free(x);}
+void binbuf_free2(t_binbuf *x) {free(x->v);}
+
+t_binbuf *binbuf_duplicate(t_binbuf *y) {
+ t_binbuf *x = (t_binbuf *)malloc(sizeof(*x));
+ x->capa = x->n = y->n;
+ x->v = (t_atom *)malloc(x->n * sizeof(*x->v));
+ memcpy(x->v,y->v,x->n*sizeof(*x->v));
+ return x;
+}
+
+void binbuf_clear(t_binbuf *x) {
+ x->n = 0;
+ x->v = (t_atom *)realloc(x->v,4);
+ x->capa = 4;
+}
+
+/* called just after a doublequote in version 1 parsing */
+char *binbuf_text_quoted(t_binbuf *x, char *t, char *end) {
+ ostringstream buf;
+ while (t!=end) {
+ char c = *t++;
+ if (c=='"') break;
+ if (c!='\\') {buf << c; continue;}
+ c = *t++;
+ if (c=='a') {buf << '\a'; continue;}
+ if (c=='b') {buf << '\b'; continue;}
+ if (c=='f') {buf << '\f'; continue;}
+ if (c=='n') {buf << '\n'; continue;}
+ if (c=='r') {buf << '\r'; continue;}
+ if (c=='v') {buf << '\v'; continue;}
+ if (c=='t') {buf << '\t'; continue;}
+ if (c=='"') {buf << '\"'; continue;}
+ if (c=='\\'){buf << '\\'; continue;}
+ if (c=='\n'){continue;}
+ /* if (c=='u') ... */
+ /* if (c=='x') ... */
+ /* if (isdigit(c)) ... */
+ buf << c; /* ignore syntax error (should it?) */
+ }
+ binbuf_addv(x,"t",buf.str().data());
+ return t; /* ignore syntax error (should it?) */
+}
+
+/* find the first atom in text, in any, and add it to this binbuf;
+ returns pointer to end of atom text */
+/* this one is for pd format version 1 */
+/* TODO: double-quotes, braces, test backslashes&dollars */
+char *binbuf_text_matju(t_binbuf *x, char *t, char *end) {
+ int doll=0;
+ while (t!=end && isspace(*t)) t++;
+ if (t==end) return t;
+ if (*t==';') {binbuf_addv(x,";"); return t+1;}
+ if (*t==',') {binbuf_addv(x,","); return t+1;}
+ /* if (*t=='"') return binbuf_text_quoted(x,t,end); */
+ if (*t=='+' || *t=='-' || *t=='.' || isdigit(*t)) {
+ char *token;
+ double v = strtod(t,&token);
+ if (t==end || isspace(*token)) {binbuf_addv(x,"f",v); return token;}
+ }
+ ostringstream buf;
+ for (; t!=end && *t!=',' && *t!=';' && !isspace(*t); ) {
+ doll |= t[0]=='$' && t+1!=end && isdigit(t[1]);
+ if (*t=='\\') t++;
+ if (t!=end) buf << *t++;
+ }
+ if (doll) {
+ const char *b = buf.str().data();
+ if (b[0]!='$') doll=0;
+ for (b++; *b; b++) if (!isdigit(*b)) doll=0;
+ if (doll) binbuf_addv(x,"$",atoi(buf.str().data()+1));
+ else binbuf_addv(x,"&",gensym(buf.str().data()));
+ } else binbuf_addv(x,"t",buf.str().data());
+ return t;
+}
+
+/* this one is for pd format version 0 */
+char *binbuf_text_miller(t_binbuf *x, char *t, char *end) {
+ ostringstream buf;
+ /* it's an atom other than a comma or semi */
+ int q = 0, slash = 0, lastslash = 0, dollar = 0;
+ /* skip leading space */
+ while (t!=end && isspace(*t)) t++;
+ if (t==end) return t;
+ if (*t==';') {binbuf_addv(x,";"); return t+1;}
+ if (*t==',') {binbuf_addv(x,","); return t+1;}
+ do {
+ char c = *t++;
+ lastslash = slash;
+ slash = c=='\\';
+ if (q >= 0) {
+ int digit = isdigit(c), dot=c=='.', minus=c=='-', plusminus=minus||c=='+', expon=c=='e'||c=='E';
+ if (q==0) { /* beginning */ if (minus) q=1; else if (digit) q=2; else if (dot) q=3; else q=-1;}
+ else if (q==1) { /* got minus */ if (digit) q=2; else if (dot) q=3; else q=-1;}
+ else if (q==2) { /* got digits */ if (dot) q=4; else if (expon) q=6; else if (!digit) q=-1;}
+ else if (q==3) { /* got '.' without digits */ if (digit) q=5; else q=-1;}
+ else if (q==4) { /* got '.' after digits */ if (digit) q=5; else if (expon) q=6; else q=-1;}
+ else if (q==5) { /* got digits after . */ if (expon) q=6; else if (!digit) q=-1;}
+ else if (q==6) { /* got 'e' */ if (plusminus) q=7; else if (digit) q=8; else q=-1;}
+ else if (q==7) { /* got plus or minus */ if (digit) q=8; else q=-1;}
+ else if (q==8) { /* got digits */ if (!digit) q=-1;}
+ }
+ if (!lastslash && c == '$' && t!=end && isdigit(*t)) dollar = 1;
+#if 1
+ if (slash&&lastslash) slash=0;
+#endif
+ if (!slash) buf << c;
+ } while (t!=end && (slash || !strchr(" \n\r\t,;",*t)));
+ if (q == 2 || q == 4 || q == 5 || q == 8) {binbuf_addv(x,"f",atof(buf.str().data())); return t;}
+ /* LATER try to figure out how to mix "$" and "\$" correctly; here, the backslashes were already
+ stripped so we assume all "$" chars are real dollars. In fact, we only know at least one was. */
+ if (dollar) {
+ const char *b = buf.str().data();
+ if (*b != '$') dollar = 0;
+ for (b++; *b; b++) if (!isdigit(*b)) dollar = 0;
+ if (dollar) binbuf_addv(x,"$",atoi(buf.str().data()+1));
+ else binbuf_addv(x,"&",gensym(buf.str().data()));
+ } else binbuf_addv(x,"t",buf.str().data());
+ return t;
+}
+
+int sys_syntax = 0;
+
+void binbuf_text(t_binbuf *x, char *t, size_t size) {
+ char *end=t+size;
+ binbuf_clear(x);
+ while (t!=end) t = sys_syntax ? binbuf_text_matju(x,t,end) : binbuf_text_miller(x,t,end);
+ binbuf_capa(x,x->n);
+}
+
+void pd_eval_text(char *t, size_t size) {
+ t_binbuf *x = binbuf_new();
+ char *end = t+size;
+ while (t!=end) {
+ t = sys_syntax ? binbuf_text_matju(x,t,end) : binbuf_text_miller(x,t,end);
+ if (x->n && x->v[x->n-1].a_type == A_SEMI) {
+ binbuf_eval(x,0,0,0);
+ binbuf_clear(x);
+ }
+ }
+ binbuf_free(x);
+}
+
+void voprintf(ostream &buf, const char *s, va_list args) {
+ char *b;
+ vasprintf(&b,s,args);
+ buf << b;
+ free(b);
+}
+void oprintf(ostream &buf, const char *s, ...) {
+ va_list args;
+ va_start(args,s);
+ voprintf(buf,s,args);
+ va_end(args);
+}
+
+/* convert a binbuf to text; no null termination. */
+void binbuf_gettext(t_binbuf *x, char **bufp, int *lengthp) {
+ ostringstream buf;
+ t_atom *ap = x->v;
+ char nextdelim=0;
+ for (int i=x->n; i--; ap++) {
+ if (ap->a_type != A_SEMI && ap->a_type != A_COMMA && nextdelim) buf << (char)nextdelim;
+ atom_ostream(ap,buf);
+ nextdelim = ap->a_type == A_SEMI ? '\n' : ' ';
+ }
+ //if (nextdelim) buf << (char)nextdelim;
+ *bufp = strdup(buf.str().data());
+ *lengthp = buf.str().size();// - (nextdelim == ' ');
+}
+
+/* convert a binbuf to text with null termination, as return value */
+char *binbuf_gettext2(t_binbuf *x) {
+ char *buf; int n;
+ binbuf_gettext(x,&buf,&n);
+ buf[n] = 0;
+ return (char *)realloc(buf,n+1);
+}
+
+/* Miller said: fix this so that writing to file doesn't buffer everything together. */
+/* matju said: make this use vector size doubling as it used to be in binbuf_text */
+void binbuf_add(t_binbuf *x, int argc, t_atom *argv) {
+ int newsize = x->n + argc;
+ t_atom *ap = (t_atom *)realloc(x->v,newsize*sizeof(*x->v));
+ x->v = ap;
+ ap += x->n;
+ for (int i = argc; i--; ap++) *ap = *(argv++);
+ x->capa = x->n = newsize;
+}
+
+#define MAXADDMESSV 100
+void binbuf_addv(t_binbuf *x, char *fmt, ...) {
+ va_list ap;
+ t_atom arg[MAXADDMESSV], *at =arg;
+ int nargs = 0;
+ char *fp = fmt;
+ va_start(ap, fmt);
+ while (1) {
+ if (nargs >= MAXADDMESSV) {
+ error("binbuf_addmessv: only %d allowed", MAXADDMESSV);
+ break;
+ }
+ switch(*fp++) {
+ case 'i': SETFLOAT(at, va_arg(ap, int)); break;
+ case 'f': SETFLOAT(at, va_arg(ap, double)); break;
+ case 's': SETSYMBOL(at, va_arg(ap, t_symbol *)); break;
+ case 't': SETSYMBOL(at, gensym(va_arg(ap, char *))); break;
+ case ';': SETSEMI(at); break;
+ case ',': SETCOMMA(at); break;
+ case '$': SETDOLLAR(at, va_arg(ap, int)); break;
+ case '&': SETDOLLSYM(at, va_arg(ap, t_symbol *)); break;
+ default: goto done;
+ }
+ at++;
+ nargs++;
+ }
+done:
+ va_end(ap);
+ binbuf_add(x, nargs, arg);
+}
+
+/* add a binbuf to another one for saving. Semicolons and commas go to
+symbols ";", "'",; the symbol ";" goes to "\;", etc. */
+
+void binbuf_addbinbuf(t_binbuf *x, t_binbuf *y) {
+ t_binbuf *z = binbuf_new();
+ binbuf_add(z, y->n, y->v);
+ t_atom *ap = z->v;
+ for (size_t i=0; i < z->n; i++, ap++) {
+ switch (ap->a_type) {
+ case A_FLOAT: break;
+ case A_SEMI: SETSYMBOL(ap, gensym(";")); break;
+ case A_COMMA: SETSYMBOL(ap, gensym(",")); break;
+ case A_DOLLAR: SETSYMBOL(ap, symprintf("$%ld", ap->a_index)); break;
+ case A_DOLLSYM: {
+ ostringstream b;
+ atom_ostream(ap,b);
+ SETSYMBOL(ap, gensym(b.str().data()));} break;
+ case A_SYMBOL:
+ /* FIXME make this general */
+ if (!strcmp(ap->a_symbol->name, ";")) SETSYMBOL(ap, gensym(";"));
+ else if (!strcmp(ap->a_symbol->name, ",")) SETSYMBOL(ap, gensym(","));
+ break;
+ default:
+ //bug("binbuf_addbinbuf: stray atom of type %d",ap->a_type);
+ //abort();
+ ;
+ }
+ }
+ binbuf_add(x, z->n, z->v);
+}
+
+void binbuf_addsemi(t_binbuf *x) {
+ t_atom a;
+ SETSEMI(&a);
+ binbuf_add(x, 1, &a);
+}
+
+/* Supply atoms to a binbuf from a message, making the opposite changes
+from binbuf_addbinbuf. The symbol ";" goes to a semicolon, etc. */
+
+void binbuf_restore(t_binbuf *x, int argc, t_atom *argv) {
+ int newsize = x->n + argc;
+ t_atom *ap = (t_atom *)realloc(x->v,(newsize+1)*sizeof(*x->v));
+ if (!ap) {error("binbuf_addmessage: out of space"); return;}
+ x->v = ap;
+ ap = x->v + x->n;
+ for (int i = argc; i--; ap++) {
+ if (argv->a_type == A_SYMBOL) {
+ char *str = argv->a_symbol->name, *str2;
+ if (!strcmp(str, ";")) SETSEMI(ap);
+ else if (!strcmp(str, ",")) SETCOMMA(ap);
+ else if ((str2 = strchr(str, '$')) && isdigit(str2[1])) {
+ int dollsym = 0;
+ if (*str != '$') dollsym = 1;
+ else for (str2 = str + 1; *str2; str2++) if (!isdigit(*str2)) {
+ dollsym = 1;
+ break;
+ }
+ if (dollsym) SETDOLLSYM(ap, gensym(str));
+ else {
+ int dollar = 0;
+ sscanf(argv->a_symbol->name + 1, "%d", &dollar);
+ SETDOLLAR(ap, dollar);
+ }
+ } else *ap = *argv;
+ argv++;
+ } else *ap = *(argv++);
+ }
+ x->n = newsize;
+}
+
+#define MSTACKSIZE 2048
+
+void binbuf_print(t_binbuf *x) {
+ int startedpost = 0, newline = 1;
+ for (size_t i=0; i < x->n; i++) {
+ if (newline) {
+ if (startedpost) endpost();
+ startpost("");
+ startedpost = 1;
+ }
+ postatom(1, x->v + i);
+ newline = !! x->v[i].a_type == A_SEMI;
+ }
+ if (startedpost) endpost();
+}
+
+int binbuf_getnatom(t_binbuf *x) {return x->n;}
+t_atom *binbuf_getvec(t_binbuf *x) {return x->v;}
+
+int canvas_getdollarzero ();
+
+/* JMZ:
+ * s points to the first character after the $
+ * (e.g. if the org.symbol is "$1-bla", then s will point to "1-bla")
+ * (e.g. org.symbol="hu-$1mu", s="1mu")
+ * LATER: think about more complex $args, like ${$1+3}
+ *
+ * the return value holds the length of the $arg (in most cases: 1)
+ * buf holds the expanded $arg
+ *
+ * if some error occurred, "-1" is returned
+ *
+ * e.g. "$1-bla" with list "10 20 30"
+ * s="1-bla"
+ * buf="10"
+ * return value = 1; (s+1=="-bla")
+ */
+static int binbuf_expanddollsym(char *s, std::ostream &buf, t_atom dollar0, int ac, t_atom *av, int tonew) {
+ int argno=atol(s);
+ int arglen=0;
+ char*cs=s;
+ char c=*cs;
+ while (c && isdigit(c)) {
+ c=*cs++;
+ arglen++;
+ }
+ /* invalid $-expansion (like "$bla") */
+ if (cs==s) {buf << "$"; return 0;}
+ if (argno < 0 || argno > ac) { /* undefined argument */
+ if(!tonew) return 0;
+ buf << "$" << argno;
+ } else if (argno == 0) { /* $0 */
+ atom_ostream(&dollar0, buf);
+ } else { /* fine! */
+ atom_ostream(av+(argno-1), buf);
+ }
+ return arglen-1;
+}
+
+/* LATER remove the dependence on the current canvas for $0; should be another argument. */
+t_symbol *binbuf_realizedollsym(t_symbol *s, int ac, t_atom *av, int tonew) {
+ ostringstream buf2;
+ char *str=s->name;
+ t_atom dollarnull;
+ SETFLOAT(&dollarnull, canvas_getdollarzero());
+ /* JMZ: currently, a symbol is detected to be A_DOLLSYM if it starts with '$'
+ * the leading $ is stripped and the rest stored in "s". i would suggest to NOT strip the leading $
+ * and make everything a A_DOLLSYM that contains(!) a $ whenever this happened, enable this code */
+ char *substr=strchr(str, '$');
+ if(!substr) return s;
+ oprintf(buf2,"%.*s",substr-str,str);
+ str=substr+1;
+ for (;;) {
+ std::ostringstream buf;
+ int next = binbuf_expanddollsym(str, buf, dollarnull, ac, av, tonew);
+ if (next<0) break;
+ /* JMZ: i am not sure what this means, so i might have broken it. it seems like that if "tonew" is
+ set and the $arg cannot be expanded (or the dollarsym is in reality a A_DOLLAR).
+ 0 is returned from binbuf_realizedollsym; this happens when expanding in a message-box,
+ but does not happen when the A_DOLLSYM is the name of a subpatch */
+ /* JMZ: this should mimick the original behaviour */
+ if(!tonew && !next && buf.str().size()==0) return 0;
+ buf2 << buf;
+ str+=next;
+ substr=strchr(str, '$');
+ if(substr) {
+ oprintf(buf2,"%.*s",substr-str,str);
+ str=substr+1;
+ } else {
+ buf2 << str;
+ return gensym(buf2.str().data());
+ }
+ }
+ return gensym(buf2.str().data());
+}
+
+void binbuf_eval(t_binbuf *x, t_pd *target, int argc, t_atom *argv) {
+ static t_atom mstack[MSTACKSIZE], *msp = mstack, *ems = mstack+MSTACKSIZE;
+ t_atom *stackwas = msp;
+ t_atom *at = x->v;
+ int ac = x->n;
+ int nargs;
+ while (1) {
+ t_pd *nexttarget;
+ while (!target) {
+ t_symbol *s;
+ while (ac && (at->a_type == A_SEMI || at->a_type == A_COMMA)) {ac--; at++;}
+ if (!ac) break;
+ if (at->a_type == A_DOLLAR) {
+ if (at->a_index <= 0 || at->a_index > argc) {error("$%d: not enough arguments supplied", at->a_index); goto cleanup;}
+ else if (argv[at->a_index-1].a_type != A_SYMBOL) {error("$%d: symbol needed as receiver", at->a_index); goto cleanup;}
+ else s = argv[at->a_index-1].a_symbol;
+ } else if (at->a_type == A_DOLLSYM) {
+ s = binbuf_realizedollsym(at->a_symbol, argc, argv, 0);
+ if (!s) {error("$%s: not enough arguments supplied", at->a_symbol->name); goto cleanup;}
+ } else s = atom_getsymbol(at);
+ target = s->thing;
+ /* IMPD: allows messages to unbound objects, via pointers */
+ if (!target) {
+ if (!sscanf(s->name,".x%lx",(long*)&target)) target=0;
+ if (target) {
+ if (!object_table->exists(target) || !object_table->get(target)) {
+ error("%s target is not a currently valid pointer",s->name);
+ return;
+ }
+ }
+ }
+ if (!target) {error("%s: no such object", s->name); goto cleanup;}
+ at++;
+ ac--;
+ break;
+ cleanup:
+ do {at++; ac--;} while (ac && at->a_type != A_SEMI); /* is this the correct thing to do? */
+ continue;
+ }
+ if (!ac) break;
+ nargs = 0;
+ nexttarget = target;
+ while (1) {
+ if (!ac) goto gotmess;
+ if (msp >= ems) {error("message too long"); goto broken;}
+ switch (at->a_type) {
+ /* semis and commas in new message just get bashed to a symbol. This is needed so you can pass them to "expr." */
+ case A_SEMI: if (target == &pd_objectmaker) {SETSYMBOL(msp, gensym(";")); break;} else {nexttarget = 0; goto gotmess;}
+ case A_COMMA: if (target == &pd_objectmaker) {SETSYMBOL(msp, gensym(",")); break;} else goto gotmess;
+ case A_FLOAT:
+ case A_SYMBOL:
+ *msp = *at;
+ break;
+ case A_DOLLAR:
+ if (at->a_index > 0 && at->a_index <= argc) *msp = argv[at->a_index-1];
+ else if (at->a_index == 0) SETFLOAT(msp, canvas_getdollarzero());
+ else {
+ SETFLOAT(msp, 0);
+ if (target != &pd_objectmaker) error("$%d: argument number out of range", at->a_index);
+ }
+ break;
+ case A_DOLLSYM: {
+ t_symbol *s9 = binbuf_realizedollsym(at->a_symbol, argc, argv, target == &pd_objectmaker);
+ if (!s9) {
+ error("%s: argument number out of range", at->a_symbol->name);
+ SETSYMBOL(msp, at->a_symbol);
+ } else SETSYMBOL(msp, s9);
+ break;}
+ default:
+ bug("bad item in binbuf");
+ goto broken;
+ }
+ msp++;
+ ac--;
+ at++;
+ nargs++;
+ }
+ gotmess:
+ if (nargs) {
+ switch (stackwas->a_type) {
+ case A_SYMBOL: typedmess(target, stackwas->a_symbol, nargs-1, stackwas+1); break;
+ case A_FLOAT: if (nargs == 1) pd_float(target, stackwas->a_float); else pd_list(target, 0, nargs, stackwas); break;
+ default: {}
+ }
+ }
+ msp = stackwas;
+ if (!ac) break;
+ target = nexttarget;
+ at++;
+ ac--;
+ }
+ return;
+broken:
+ msp = stackwas;
+}
+
+static int binbuf_doopen(char *s, int mode) {
+ char namebuf[strlen(s)+1];
+#ifdef MSW
+ mode |= O_BINARY;
+#endif
+ sys_bashfilename(s, namebuf);
+ return open(namebuf, mode);
+}
+
+static FILE *binbuf_dofopen(const char *s, char *mode) {
+ char namebuf[strlen(s)+1];
+ sys_bashfilename(s, namebuf);
+ return fopen(namebuf, mode);
+}
+
+int binbuf_read(t_binbuf *b, char *filename, char *dirname, int flags) {
+ long length;
+ char *buf;
+ char *namebuf=0;
+ if (*dirname) asprintf(&namebuf,"%s/%s",dirname,filename);
+ else asprintf(&namebuf, "%s", filename);
+ int fd = binbuf_doopen(namebuf, 0);
+ if (fd < 0) {error("open: %s: %s",namebuf,strerror(errno)); return 1;}
+ if ((length = lseek(fd, 0, SEEK_END)) < 0 || lseek(fd, 0, SEEK_SET) < 0 || !(buf = (char *)malloc(length))) {
+ error("lseek: %s: %s",namebuf,strerror(errno));
+ close(fd); free(namebuf);
+ return 1;
+ }
+ int readret = read(fd, buf, length);
+ if (readret < length) {
+ error("read (%d %ld) -> %d; %s: %s", fd, length, readret, namebuf, strerror(errno));
+ close(fd); free(namebuf); free(buf);
+ return 1;
+ }
+ if (flags&1) for (int i=0; i<length; i++) if (buf[i]=='\n') buf[i] = ';';
+ if (flags&2) pd_eval_text(buf,length); else binbuf_text(b, buf, length);
+ close(fd); free(namebuf); free(buf);
+ return 0;
+}
+
+/* read a binbuf from a file, via the search patch of a canvas */
+int binbuf_read_via_canvas(t_binbuf *b, char *filename, t_canvas *canvas, int flags) {
+ char *buf, *bufptr;
+ int fd = canvas_open2(canvas, filename, "", &buf, &bufptr, 0);
+ if (fd<0) {error("%s: can't open", filename); return 1;}
+ close(fd); free(buf);
+ return !!binbuf_read(b, bufptr, buf, flags);
+}
+
+/* old version */
+int binbuf_read_via_path(t_binbuf *b, char *filename, char *dirname, int flags) {
+ char *buf, *bufptr;
+ int fd = open_via_path2(dirname, filename, "", &buf, &bufptr, 0);
+ if (fd<0) {error("%s: can't open", filename); return 1;}
+ close(fd);
+ bool r = binbuf_read(b, bufptr, buf, flags);
+ free(buf);
+ return r;
+}
+
+#define WBUFSIZE 4096
+static t_binbuf *binbuf_convert(t_binbuf *oldb, int maxtopd);
+
+/* write a binbuf to a text file. If "crflag" is set we suppress semicolons. */
+int binbuf_write(t_binbuf *x, char *filename, char *dir, int crflag) {
+ char sbuf[WBUFSIZE];
+ ostringstream fbuf;
+ char *bp = sbuf, *ep = sbuf + WBUFSIZE;
+ int indx; bool deleteit = 0;
+ int ncolumn = 0;
+ if (*dir) fbuf << dir << "/";
+ fbuf << filename;
+ if (!strcmp(filename + strlen(filename) - 4, ".pat")) {
+ x = binbuf_convert(x, 0);
+ deleteit = 1;
+ }
+ FILE *f = binbuf_dofopen(fbuf.str().data(), "w");
+ if (!f) {error("open: %s: %s",fbuf.str().data(),strerror(errno)); goto fail;}
+ indx = x->n;
+ for (t_atom *ap = x->v; indx--; ap++) {
+ /* estimate how many characters will be needed. Printing out symbols may need extra characters for inserting backslashes. */
+ int length = (ap->a_type == A_SYMBOL || ap->a_type == A_DOLLSYM) ? 80 + strlen(ap->a_symbol->name) : 40;
+ if (ep - bp < length) {
+ if (fwrite(sbuf, bp-sbuf, 1, f) < 1) {error("write: %s: %s",fbuf.str().data(),strerror(errno)); goto fail;}
+ bp = sbuf;
+ }
+ if ((ap->a_type == A_SEMI || ap->a_type == A_COMMA) && bp > sbuf && bp[-1] == ' ') bp--;
+ if (!crflag || ap->a_type != A_SEMI) {
+ atom_string(ap, bp, (ep-bp)-2);
+ length = strlen(bp);
+ bp += length;
+ ncolumn += length;
+ }
+ if (ap->a_type == A_SEMI || (!crflag && ncolumn > 65)) {
+ *bp++ = '\n';
+ ncolumn = 0;
+ } else {
+ *bp++ = ' ';
+ ncolumn++;
+ }
+ }
+ if (fwrite(sbuf, bp-sbuf, 1, f) < 1) {error("write: %s: %s",fbuf.str().data(),strerror(errno)); goto fail;}
+ if (deleteit) binbuf_free(x);
+ fclose(f);
+ return 0;
+fail:
+ if (deleteit) binbuf_free(x);
+ if (f) fclose(f);
+ return 1;
+}
+
+/* The following routine attempts to convert from max to pd or back. The max to pd direction is working OK
+ but you will need to make lots of abstractions for objects like "gate" which don't exist in Pd. Conversion
+ from Pd to Max hasn't been tested for patches with subpatches yet! */
+#define MAXSTACK 1000
+#define ISSYMBOL(a, b) ((a)->a_type == A_SYMBOL && !strcmp((a)->a_symbol->name, (b)))
+#define GETF(i) atom_getfloatarg(i,natom,nextmess)
+static t_binbuf *binbuf_convert(t_binbuf *oldb, int maxtopd) {
+ t_binbuf *newb = binbuf_new();
+ t_atom *vec = oldb->v;
+ t_int n = oldb->n, nextindex, stackdepth = 0, stack[MAXSTACK], nobj = 0;
+ t_atom outmess[MAXSTACK], *nextmess;
+ if (!maxtopd) binbuf_addv(newb,"tt;","max","v2");
+ for (nextindex = 0; nextindex < n; ) {
+ int endmess, natom;
+ for (endmess = nextindex; endmess < n && vec[endmess].a_type != A_SEMI; endmess++) {}
+ if (endmess == n) break;
+ if (endmess == nextindex || endmess == nextindex + 1
+ || vec[nextindex].a_type != A_SYMBOL || vec[nextindex+1].a_type != A_SYMBOL) {
+ nextindex = endmess + 1;
+ continue;
+ }
+ natom = endmess - nextindex;
+ if (natom > MAXSTACK-10) natom = MAXSTACK-10;
+ nextmess = vec + nextindex;
+ char *first = nextmess ->a_symbol->name;
+ char *second = (nextmess+1)->a_symbol->name;
+ if (maxtopd) { /* case 1: importing a ".pat" file into Pd. */
+ /* dollar signs in file translate to symbols */
+ for (int i=0; i<natom; i++) {
+ if (nextmess[i].a_type == A_DOLLAR) {
+ SETSYMBOL(nextmess+i, symprintf("$%ld",nextmess[i].a_index));
+ } else if (nextmess[i].a_type == A_DOLLSYM) {
+ SETSYMBOL(nextmess+i, gensym(nextmess[i].a_symbol->name));
+ }
+ }
+ if (!strcmp(first, "#N")) {
+ if (!strcmp(second, "vpatcher")) {
+ if (stackdepth >= MAXSTACK) {
+ post("too many embedded patches");
+ return newb;
+ }
+ stack[stackdepth] = nobj;
+ stackdepth++;
+ nobj = 0;
+ binbuf_addv(newb,"ttfffff;","#N","canvas", GETF(2), GETF(3), GETF(4)-GETF(2), GETF(5)-GETF(3), 10.);
+ }
+ }
+ if (!strcmp(first, "#P")) {
+ /* drop initial "hidden" flag */
+ if (!strcmp(second, "hidden")) {
+ nextmess++;
+ natom--;
+ second = (nextmess+1)->a_symbol->name;
+ }
+ if (natom >= 7 && !strcmp(second, "newobj")
+ && (ISSYMBOL(&nextmess[6], "patcher") || ISSYMBOL(&nextmess[6], "p"))) {
+ binbuf_addv(newb,"ttffts;","#X","restore", GETF(2), GETF(3),
+ "pd", atom_getsymbolarg(7, natom, nextmess));
+ if (stackdepth) stackdepth--;
+ nobj = stack[stackdepth];
+ nobj++;
+ } else if (!strcmp(second, "newex") || !strcmp(second, "newobj")) {
+ t_symbol *classname = atom_getsymbolarg(6, natom, nextmess);
+ if (classname == gensym("trigger") || classname == gensym("t")) {
+ for (int i=7; i<natom; i++)
+ if (nextmess[i].a_type == A_SYMBOL && nextmess[i].a_symbol == gensym("i"))
+ nextmess[i].a_symbol = gensym("f");
+ }
+ if (classname == gensym("table")) classname = gensym("TABLE");
+ SETSYMBOL(outmess, gensym("#X"));
+ SETSYMBOL(outmess + 1, gensym("obj"));
+ outmess[2] = nextmess[2];
+ outmess[3] = nextmess[3];
+ SETSYMBOL(outmess+4, classname);
+ for (int i=7; i<natom; i++) outmess[i-2] = nextmess[i];
+ SETSEMI(outmess + natom - 2);
+ binbuf_add(newb, natom - 1, outmess);
+ nobj++;
+ } else if (!strcmp(second, "message") || !strcmp(second, "comment")) {
+ SETSYMBOL(outmess, gensym("#X"));
+ SETSYMBOL(outmess + 1, gensym((char *)(strcmp(second, "message") ? "text" : "msg")));
+ outmess[2] = nextmess[2];
+ outmess[3] = nextmess[3];
+ for (int i=6; i<natom; i++) outmess[i-2] = nextmess[i];
+ SETSEMI(outmess + natom - 2);
+ binbuf_add(newb, natom - 1, outmess);
+ nobj++;
+ } else if (!strcmp(second, "button")) {
+ binbuf_addv(newb,"ttfft;","#X","obj",GETF(2),GETF(3),"bng");
+ nobj++;
+ } else if (!strcmp(second, "number") || !strcmp(second, "flonum")) {
+ binbuf_addv(newb,"ttff;","#X","floatatom",GETF(2),GETF(3));
+ nobj++;
+ } else if (!strcmp(second, "slider")) {
+ float inc = GETF(7);
+ if (inc <= 0) inc = 1;
+ binbuf_addv(newb, "ttfftfffffftttfffffffff;","#X","obj",
+ GETF(2), GETF(3), "vsl", GETF(4), GETF(5), GETF(6), GETF(6)+(GETF(5)-1)*inc,
+ 0., 0., "empty", "empty", "empty", 0., -8., 0., 8., -262144., -1., -1., 0., 1.);
+ nobj++;
+ } else if (!strcmp(second, "toggle")) {
+ binbuf_addv(newb,"ttfft;","#X","obj",GETF(2),GETF(3),"tgl");
+ nobj++;
+ } else if (!strcmp(second, "inlet")) {
+ binbuf_addv(newb,"ttfft;","#X","obj",GETF(2),GETF(3), natom > 5 ? "inlet~" : "inlet");
+ nobj++;
+ } else if (!strcmp(second, "outlet")) {
+ binbuf_addv(newb,"ttfft;","#X","obj",GETF(2),GETF(3), natom > 5 ? "outlet~" : "outlet");
+ nobj++;
+ } else if (!strcmp(second, "user")) {
+ binbuf_addv(newb,"ttffs;","#X","obj", GETF(3), GETF(4), atom_getsymbolarg(2, natom, nextmess));
+ nobj++;
+ } else if (!strcmp(second, "connect") || !strcmp(second, "fasten")) {
+ binbuf_addv(newb,"ttffff;","#X","connect", nobj-GETF(2)-1, GETF(3), nobj-GETF(4)-1, GETF(5));
+ }
+ }
+ } else { /* Pd to Max */
+ if (!strcmp(first, "#N")) {
+ if (!strcmp(second, "canvas")) {
+ if (stackdepth >= MAXSTACK) {
+ post("too many embedded patches");
+ return newb;
+ }
+ stack[stackdepth] = nobj;
+ stackdepth++;
+ nobj = 0;
+ binbuf_addv(newb,"ttffff;","#N","vpatcher", GETF(2), GETF(3), GETF(4), GETF(5));
+ }
+ }
+ if (!strcmp(first, "#X")) {
+ if (natom >= 5 && !strcmp(second, "restore") && (ISSYMBOL (&nextmess[4], "pd"))) {
+ binbuf_addv(newb,"tt;","#P","pop");
+ binbuf_addv(newb,"ttffffts;","#P","newobj", GETF(2), GETF(3), 50., 1.,
+ "patcher", atom_getsymbolarg(5, natom, nextmess));
+ if (stackdepth) stackdepth--;
+ nobj = stack[stackdepth];
+ nobj++;
+ } else if (!strcmp(second, "obj")) {
+ t_symbol *classname = atom_getsymbolarg(4, natom, nextmess);
+ if (classname == gensym("inlet")) binbuf_addv(newb,"ttfff;","#P","inlet", GETF(2), GETF(3), 15.);
+ else if (classname == gensym("inlet~")) binbuf_addv(newb,"ttffff;","#P","inlet", GETF(2), GETF(3), 15., 1.);
+ else if (classname == gensym("outlet")) binbuf_addv(newb,"ttfff;","#P","outlet", GETF(2), GETF(3), 15.);
+ else if (classname == gensym("outlet~")) binbuf_addv(newb,"ttffff;","#P","outlet", GETF(2), GETF(3), 15., 1.);
+ else if (classname == gensym("bng")) binbuf_addv(newb,"ttffff;","#P","button", GETF(2), GETF(3), GETF(5), 0.);
+ else if (classname == gensym("tgl")) binbuf_addv(newb,"ttffff;","#P","toggle", GETF(2), GETF(3), GETF(5), 0.);
+ else if (classname == gensym("vsl")) binbuf_addv(newb,"ttffffff;","#P","slider",
+ GETF(2), GETF(3), GETF(5), GETF(6), (GETF(8)-GETF(7)) / (GETF(6)==1?1:GETF(6)-1), GETF(7));
+ else {
+ binbuf_addv(newb,"ttffff","#P","newex", GETF(2), GETF(3), 50., 1.);
+ for (int i=4; i<natom; i++) outmess[i-4] = nextmess[i];
+ binbuf_add(newb, natom-4, outmess);
+ binbuf_addv(newb,";");
+ }
+ nobj++;
+ } else if (!strcmp(second, "msg") || !strcmp(second, "text")) {
+ binbuf_addv(newb,"ttffff","#P",strcmp(second, "msg") ? "comment" : "message",GETF(2),GETF(3),50.,1.);
+ for (int i=4; i<natom; i++) outmess[i-4] = nextmess[i];
+ binbuf_add(newb, natom-4, outmess);
+ binbuf_addv(newb,";");
+ nobj++;
+ } else if (!strcmp(second, "floatatom")) {
+ binbuf_addv(newb, "ttfff;", "#P", "flonum", GETF(2), GETF(3), 35);
+ nobj++;
+ } else if (!strcmp(second, "connect")) {
+ binbuf_addv(newb, "ttffff;", "#P", "connect", nobj-GETF(2)-1, GETF(3), nobj-GETF(4)-1, GETF(5));
+ }
+ }
+ }
+ nextindex = endmess + 1;
+ }
+ if (!maxtopd) binbuf_addv(newb, "tt;", "#P", "pop");
+#if 0
+ binbuf_write(newb, "import-result.pd", "/tmp", 0);
+#endif
+ return newb;
+}
+
+/* function to support searching */
+int binbuf_match(t_binbuf *inbuf, t_binbuf *searchbuf) {
+ for (size_t indexin = 0; indexin <= inbuf->n - searchbuf->n; indexin++) {
+ for (size_t nmatched = 0; nmatched < searchbuf->n; nmatched++) {
+ t_atom *a1 = &inbuf->v[indexin + nmatched], *a2 = &searchbuf->v[nmatched];
+ if (a1->a_type != a2->a_type ||
+ a1->a_type == A_SYMBOL && a1->a_symbol != a2->a_symbol ||
+ a1->a_type == A_FLOAT && a1->a_float != a2->a_float ||
+ a1->a_type == A_DOLLAR && a1->a_index != a2->a_index ||
+ a1->a_type == A_DOLLSYM && a1->a_symbol != a2->a_symbol) goto nomatch;
+ }
+ return 1;
+ nomatch: ;
+ }
+ return 0;
+}
+
+/* LATER figure out how to log errors */
+void binbuf_evalfile(t_symbol *name, t_symbol *dir) {
+ t_binbuf *b = binbuf_new();
+ int import = !strcmp(name->name + strlen(name->name) - 4, ".pat");
+ /* set filename so that new canvases can pick them up */
+ int dspstate = canvas_suspend_dsp();
+ glob_setfilename(0, name, dir);
+ if (import) {
+ if (binbuf_read(b, name->name, dir->name, 0)) {perror(name->name); goto bye;}
+ t_binbuf *newb = binbuf_convert(b, 1);
+ binbuf_free(b);
+ b = newb;
+ } else {
+ if (binbuf_read(b, name->name, dir->name, 2)) perror(name->name);
+ }
+bye:
+ glob_setfilename(0, &s_, &s_); /* bug fix by Krzysztof Czaja */
+ binbuf_free(b);
+ canvas_resume_dsp(dspstate);
+}
+
+void glob_evalfile(t_pd *ignore, t_symbol *name, t_symbol *dir) {
+ /* even though binbuf_evalfile appears to take care of dspstate, we have to do it again here, because
+ canvas_startdsp() assumes that all toplevel canvases are visible. LATER: check if this is still necessary (probably not) */
+ int dspstate = canvas_suspend_dsp();
+ binbuf_evalfile(name, dir);
+ t_pd *x = 0;
+ while ((x != s__X.thing) && (x = s__X.thing)) vmess(x, gensym("pop"), "i", 1);
+ if (lastpopped) pd_vmess(lastpopped, gensym("loadbang"), "");
+ lastpopped = 0;
+ canvas_resume_dsp(dspstate);
+}
+
+//copied from m_pd.h
+#define class_new2(NAME,NU,FREE,SIZE,FLAGS,SIG) class_new2(NAME,(t_newmethod)NU,(t_method)FREE,SIZE,FLAGS,SIG)
+
+extern "C" {
+void conf_init();
+void glob_init();
+void boxes_init();
+void garray_init();
+void pd_init() {
+ object_table = new t_hash<t_pd *,long>(127);
+ bindlist_class = class_new(gensym("bindlist"), 0, 0, sizeof(t_bindlist), CLASS_PD, 0);
+ class_addbang(bindlist_class, (t_method)bindlist_bang);
+ class_addfloat(bindlist_class, (t_method)bindlist_float);
+ class_addsymbol(bindlist_class, (t_method)bindlist_symbol);
+ class_addpointer(bindlist_class, (t_method)bindlist_pointer);
+ class_addlist(bindlist_class, (t_method)bindlist_list);
+ class_addanything(bindlist_class, (t_method)bindlist_anything);
+ binbuf_class = class_new2("__list", binbuf_new, binbuf_free2, sizeof(t_binbuf), CLASS_PD, "*");
+ wire_class = class_new2("__wire", wire_new, wire_free, sizeof(t_wire), CLASS_GOBJ, "*");
+ class_setsavefn(wire_class,(t_savefn)wire_save);
+ if (pd_objectmaker._class) bug("ARGH");
+ for (size_t i=0; i<sizeof(symlist)/sizeof(*symlist); i++) {
+ symlist[i]->n = strlen(symlist[i]->name);
+ dogensym(symlist[i]->name, symlist[i]->n, symlist[i]); /* why does this take three args? */
+ }
+ pd_objectmaker._class = class_new2("objectmaker", 0, 0, sizeof(t_pd), CLASS_DEFAULT, "");
+ pd_canvasmaker._class = class_new2("canvasmaker", 0, 0, sizeof(t_pd), CLASS_DEFAULT, "");
+ pd_bind(&pd_canvasmaker, &s__N);
+ class_addanything(pd_objectmaker._class, (t_method)new_anything);
+ obj_init();
+ conf_init();
+ glob_init();
+ boxes_init();
+ garray_init();
+}
+};
diff --git a/desiredata/src/locale/bokmal.tcl b/desiredata/src/locale/bokmal.tcl
new file mode 100644
index 00000000..8db87129
--- /dev/null
+++ b/desiredata/src/locale/bokmal.tcl
@@ -0,0 +1,453 @@
+#!/usr/bin/env tclsh
+# Norwegian (Norsk Bokml) translations for PureData
+# $Id: bokmal.tcl,v 1.1.2.5.2.2 2007-08-06 15:39:57 matju Exp $
+# by Gisle Frysland
+
+### Menus
+
+say file "Fil"
+ say new_file "Ny Fil"
+ say open_file "pne Fil..."
+ # say pdrc_editor ".pdrc Redigerer"
+ say server_prefs "Tjener Egenskaper..."
+ say client_prefs "Klient Egenskaper..."
+ say send_message "Send Melding..."
+ say paths "Stier..."
+ say close "Lukk"
+ say save "Lagre"
+ say save_as "Lagre Som..."
+ say print "Skriv Ut..."
+ say abort_server "Avbryt Tjener"
+ say quit "Avslutt"
+
+ say canvasnew_file "Ny Fil"
+ say canvasopen_file "pne Fil..."
+ say canvassave "Lagre"
+ say canvassave_as "Lagre Som..."
+ say clientpdrc_editor ".pdrc Redigering"
+ say clientddrc_editor ".ddrc Redigering"
+ say canvasclose "Lukk"
+ say canvasquit "Avslutt"
+
+say edit "Rediger"
+ say undo "Angre"
+ say redo "Gjr Om"
+ say cut "Klipp Ut"
+ say copy "Kopier"
+ say paste "Lim Inn"
+ say duplicate "Dupliser"
+ say select_all "Merk Alt"
+ say clear_selection "Fjern merking"
+ say text_editor "Tekst Redigerer..."
+ say font "Skrift"
+ say tidy_up "Rydd Opp"
+ say edit_mode "Redigeringsmodus"
+ say editmodeswitch "Rediger/Kjr modus"
+ say subpatcherize "Subpatcherize"
+
+ say canvascut "Klipp Ut"
+ say canvascopy "Kopier"
+ say canvasundo "Angre"
+ say canvasredo "Gjr Om"
+ say canvaspaste "Lim Inn"
+ say canvasduplicate "Dupliser"
+ say canvasselect_all "Merk Alt"
+ say canvaseditmodeswitch "Rediger/Kjr modus"
+
+say view "Vis"
+ say reload "Oppdater"
+ say redraw "Tegn P Nytt"
+
+ say canvasreload "Oppdater"
+ say canvasredraw "Tegn P Nytt"
+
+say find "Finn"
+ say find_again "Finn P Nytt"
+ say find_last_error "Finn Siste Feil"
+ say string "Finn Tekst"
+say canvasfind "Finn"
+ say canvasfind_again "Finn P Nytt"
+
+# contents of Put menu is Phase 5C
+say put "Sett Inn"
+ say Object "Objekt"
+ say Message "Melding"
+ say Number "Nummer"
+ say Symbol "Symbol"
+ say Comment "Kommentar"
+ say Graph "Graf"
+ say Array "Tabell"
+
+say media "Media"
+ say audio_on "Audio P"
+ say audio_off "Audio AV"
+ say test_audio_and_midi "Test Audio og MIDI"
+ say load_meter "Belastningsmler"
+
+ say canvasaudio_on "Audio P"
+ say canvasaudio_off "Audio AV"
+ say clienttest_audio_and_midi "Test Audio og MIDI"
+ say canvasload_meter "Belastningsmler"
+
+say window "Vindu"
+
+say help "Hjelp"
+ say about "Om..."
+ say documentation "Dokumentasjon..."
+ say class_browser "Klasseleser..."
+
+ say canvasabout "Om..."
+
+say properties "Egenskaper"
+say open "pne"
+
+### for key binding editor
+say general "Generelt"
+say audio_settings "Audio Innstillinger"
+say midi_settings "Midi Innstillinger"
+say latency_meter "Forsinkelsesmler"
+say Pdwindow "Pd vindu"
+
+say canvaspdwindow "Pd vindu"
+say canvaslatency_meter "Forsinkelsesmler"
+say clientaudio_settings "Audio Innstillinger"
+say clientmidi_settings "Midi Innstillinger"
+
+
+say_namespace summary {
+ say_category IEMGUI
+ say bng "Bang Boks"
+ say tgl "Av/P Boks"
+ say nbx "Nummer Boks (IEM)"
+ say hsl "Glidebryter (Horisontal"
+ say vsl "Glidebryter (Vertikal)"
+ say hradio "Velger Boks (Horisontal)"
+ say vradio "Velger Boks (Vertikal)"
+ say cnv "Bakgrunn (IEM)"
+ say vu "Vumler"
+ say dropper "Dra-og-Slipp Boks"
+
+ say_category LIM
+ say bang "send ut en bang melding"
+ say float "lagre og hente frem et tall"
+ say symbol "lagre og hente frem et symbol"
+ say int "lagre og hente frem et heltall"
+ say send "send en melding til et navngitt objekt"
+ say receive "ta i mot sendte meldinger"
+ say select "sjekk etter passende tall eller symboler"
+ say route "videresend meldinger i henhold til frste element"
+ say pack "lag sammensatte meldinger"
+ say unpack "hent elementer fra sammensatte meldinger"
+ say trigger "sekvenser og konverter meldinger"
+ say spigot "avbrytbar meldingsforbindelse"
+ say moses "bryt opp en numerisk strm"
+ say until "mekanisme for repetisjon"
+ say print "skriv ut meldinger"
+ say makefilename "formater et symbol med et variabelt felt"
+ say change "fjern repeterte tall fra en strm"
+ say swap "bytt om to tall"
+ say value "delt numerisk verdi"
+
+ say_category TID
+ say delay "send en melding etter en tidsforsinkelse"
+ say metro "send en melding periodisk"
+ say line "send en serie av linert stegvise tall"
+ say timer "ml tidsintervaller"
+ say cputime "ml CPU tid"
+ say realtime "ml sann tid"
+ say pipe "dynamisk skalerbar forsinkelsesk for tall"
+
+ say_category MATTEMATIKK
+ say + "legg til"
+ say - "trekk fra"
+ say * "multipliser"
+ say {/ div} "divider"
+ say {% mod} "delingsrestere"
+ say pow "eksponensiere"
+ say == "er lik?"
+ say != "er ikke lik?"
+
+
+ say > "strre enn?"
+ say < "mindre enn?"
+ say >= "ikke mindre enn?"
+ say <= "ikke strre enn?"
+ say & "bitvis konjunksjon (og)"
+ say | "bitvis atskillelse (eller)"
+ say && "logisk konjunksjon (og)"
+ say || "logisk atskillelse (eller)"
+ say mtof "MIDI til Hertz"
+ say ftom "Hertz til MIDI"
+ say powtodb "Watt til dB"
+ say dbtopow "dB til Watt"
+ say rmstodb "Volt til dB"
+ say dbtorms "dB til Volt"
+ say {sin cos tan atan atan2 sqrt} "trigonometri"
+ say log "Euler logaritme"
+ say exp "Euler eksponential"
+ say abs "absolutt verdi"
+ say random "tilfeldig"
+ say max "strste av to tall"
+ say min "minste av to tall"
+ say clip "tvinge et tall inn i et omrde"
+
+ say_category MIDI
+ say {notein ctlin pgmin bendin touchin polytouchin midiin sysexin} \
+ "MIDI inndata"
+ say {noteout ctlout pgmout bendout touchout polytouchout midiout} \
+ "MIDI utdata"
+ say makenote \
+ "sett inn en forsinket \"note off\" melding som korresponderer med en note-on"
+ say stripnote "fjern \"note off\" meldinger"
+
+ say_category TABELLER
+ say tabread "les et tall fra en tabell"
+ say tabread4 "les et tall fra en tabell, med 4 punkts interpolasjon"
+ say tabwrite "skriv et tall til en tabell"
+ say soundfiler "les og skriv tabeller til lydfiler"
+
+ say_category DIVERSE
+ say loadbang "bang ved lasting"
+ say serial "seriell enhetskontroll kun for NT"
+ say netsend "send meldinger over internettet"
+ say netreceive "motta dem"
+ say qlist "\"sequencer\" for meldinger"
+ say textfile "fil til melding konverterer"
+ say openpanel "\"pne\" dialog"
+ say savepanel "\"Lagre som\" dialog"
+ say bag "tallsett"
+ say poly "polyfonisk stemmeallokering"
+ say {key keyup} "numeriske noteverdier fra keyboard"
+ say keyname "symbolsk notenavn"
+ say_category "AUDIO MATTEMATIKK"
+ foreach word {+ - * /} {say $word~ "[say $word] (for signaler)"}
+ say max~ "supremum for signaler"
+ say min~ "infimum for signaler"
+ say clip~ "innskrenk signal til ligge mellom to grenseverdier"
+ say q8_rsqrt~ "billig resiprokal kvadratrot (obs -- 8 bits!)"
+ say q8_sqrt~ "billig kvadratrot (obs-- 8 bits!)"
+ say wrap~ "brett rundt (fractional part, sort of)"
+ say fft~ "kompleks forlengs diskr Fourier transform"
+ say ifft~ "kompleks invers diskr Fourier transform"
+ say rfft~ "sann forlengs diskr Fourier transform"
+ say rifft~ "sann invers diskr Fourier transform"
+ say framp~ "send ut en rampe for hver blokk"
+ foreach word {mtof ftom rmstodb dbtorms rmstopow powtorms} {
+ say $word~ "[say $word] (for signaler)"
+ }
+}
+
+# phase 4 (pdrc & ddrc)
+
+say section_audio "Audio"
+ say -r "sample rate"
+ say -audioindev "audio inn enheter"
+ say -audiooutdev "audio ut enheter"
+ say -inchannels "audio inndata kanaler (pr. enhet, som \"2\" el. \"16,8\")"
+ say -outchannels "antall audio ut kanaler (samme)"
+ say -audiobuf "spesifiser strrelse p audio buffer i ms"
+ say -blocksize "spesifiser audio I/U blokk strrelse i sample rammer"
+ say -sleepgrain "spesifiser antall millisekunder g i dvale nr inaktiv"
+ say -nodac "hindre audio utdata"
+ say -noadc "hindre audio inndata"
+ say audio_api_choice "Audio API"
+ say default "standard"
+ say -alsa "bruk ALSA audio API"
+ say -jack "bruk JACK audio API"
+ say -mmio "bruk MMIO audio API (standard for Windows)"
+ say -portaudio "bruk ASIO audio driver (via Portaudio)"
+ say -oss "bruk OSS audio API"
+ say -32bit "tillat 32 bit OSS audio (for RME Hammerfall)"
+ say {} "standard"
+
+say section_midi "MIDI"
+ say -nomidiin "hindre MIDI inndata"
+ say -nomidiout "hindre MIDI utdata"
+ say -midiindev "midi inn enhetsiste; d.v.s., \"1,3\" for frste og tredje"
+ say -midioutdev "midi ut enhetsliste, samme format"
+
+say section_externals "Eksterne"
+ say -path "fil skesti"
+ say -helppath "helpefil skesti"
+ say -lib "last objektbiblioteker"
+
+say section_gui "Gooey"
+ say -nogui "hindre oppstart av GUI (forsiktig)"
+ say -guicmd "bytt med annet GUI program (d.v.s., rsh)"
+ say -look "knappelinje ikoner"
+ say -font "spesifiser standard skriftstrrelse i punkter"
+
+say section_other "Annet"
+ say -open "pne fil(er) ved oppstart"
+ say -verbose "ekstra utprint ved oppstart og ved sking etter filer"
+ say -d "feilskingsniv"
+ say -noloadbang "sl av effekten av \[loadbang\]"
+ say -send "send en melding ved oppstart (etter patcher er lastet)"
+ say -listdev "vis audio og MIDI enheter ved oppstart"
+ say -realtime "bruk sanntids prioritet (trenger superbruker rettigheter)"
+
+say section_paths "Stier"
+
+# phase 4B: ddrc (keyword names not finalized!)
+say console "konsoll rullefelt linjer (0 = sl av konsoll)"
+say lang "Sprkvalg"
+say pointer_sense "Musepeker sensitivitet"
+say section_color "farger"
+ say canvas_color "lerret"
+ say canvasbgedit "lerretsbakgrunn (redigeringsmodus)"
+ say canvasbgrun "lerretsbakgrunn (kjremodus)"
+ say object_color "objekt"
+ say viewframe1 "objektboks farge"
+ say viewframe2 "objektboks farge"
+ say viewframe3 "objektboks farge"
+ say viewframe4 "objektboks framhevingsfarge"
+ say viewbg "objekt bakgrunn"
+ say viewfg "objekt forgrunn"
+ say commentbg "kommentar bakgrunn"
+ say commentfg "kommentar forgrunn"
+ say commentframe1 "kommentar ramme"
+ say commentframe2 "kommentar ramme"
+ say commentframe3 "kommentar ramme"
+ say viewselectframe "framhevingsboks"
+ say wire_color "trd"
+ say wirefg "trdfarge"
+ say wirefg2 "trd framhevingstone"
+ say wiredspfg "dsp trdfarge"
+ say futurewiredash "ny (streket) trd"
+ say others_color "andre"
+ say boxinletfg "inngangsfarge"
+ say boxoutletfg "utgangsfarge"
+ say selrectrect "markeringsboks"
+say keys "taster"
+say others "andre"
+say hairstate "Sl p siktekryss"
+say hairsnap "Siktekryss fest til objekt"
+say statusbar "Sl p statuslinje"
+say buttonbar "Sl p knappelinje"
+say menubar "Sl p menulinje"
+say scrollbar "Sl p auto rullefelt"
+say wirearrow "Trd Pil"
+say tooltip "VerktysTips"
+say insert_object "Sett Inn objekt"
+say chain_object "Kjedeobjekt"
+say clear_wires "Fjern trder"
+say auto_wire "Fjern objekt"
+say subpatcherize "Subpatcherize"
+say keynav "tastatur navigering"
+say key_nav_up "flytt opp"
+say key_nav_up_shift "pluss valg"
+say key_nav_down "flytt ned"
+say key_nav_down_shift "pluss valg"
+say key_nav_right "flytt hyre"
+say key_nav_right_shift "pluss valg"
+say key_nav_left "flytt venstre"
+say key_nav_left_shift "pluss valg"
+say key_nav_ioselect "velg inn/utganger"
+
+#phaze 5A
+say cannot "kan ikke"
+say cancel "Avbryt"
+say apply "Bruk"
+say ok "OK"
+say popup_open "pne"
+say popup_properties "Egenskaper"
+say popup_help "Hjelp"
+say filter "Filter: "
+say how_many_object_classes "%d av %d objektklasser"
+say do_what_i_mean "Gjr Det Jeg Mener"
+say save_changes? "Lagre endringer?"
+say reset "Nullstille"
+say Courier "Courier (monospaced)"
+say Helvetica "Helvetica (sansserif)"
+say Times "Times (serif)"
+say add "Legg til"
+say up "Opp"
+say down "Ned"
+say remove "Fjern"
+say lib_add "legg navnet du skrev til listen"
+say lib_up "bytt rekkeflge med forrige bibliotek"
+say lib_down "bytt rekkeflge med neste bibliotek"
+say lib_remove "fjern det valgte biblioteket"
+say dir_add "legg til en mappe ved bruke en filvelger"
+say dir_up "bytt rekkeflge med forrige mappe"
+say dir_down "bytt rekkeflge med neste mappe"
+say dir_remove "fjern den valgte mappen"
+say client_class_tree "Klient KlasseTre"
+say clipboard_view "Utklippstavlevisning"
+say history_view "Historievisning"
+
+### for Properties Dialog (phase 5B)
+say_category IEM
+say w "bredde(px)"
+say h "hyde(px)"
+say hold "ventetid(ms)"
+say break "pausetid(ms)"
+say min "minimumsverdi"
+say max "maksimumsverdi"
+say is_log "modus"
+say linear "liner"
+say logarithmic "logaritmisk"
+say isa "initiering"
+say n "antall valg"
+say steady "stdighet"
+say steady_no "hopp ved klikk"
+say steady_yes "stdig ved klikk"
+say snd "send-symbol"
+say rcv "motta-symbol"
+say lab "merkelapp"
+say ldx "merkelapp x forskyvning"
+say ldy "merkelapp y forskyvning"
+say fstyle "Skrift"
+say fs "skriftstrrelse"
+say bcol "bakgrunnsfarge"
+say fcol "forgrunnsfarge"
+say lcol "merkelappfarge"
+say yes "ja"
+say no "nei"
+say courier "courier (skrivemaskin)"
+say helvetica "helvetica (sansserif)"
+say times "times (serif)"
+say coords "graph on parent"
+
+say_category GAtomProperties
+say width "bredde"
+say lo "nedre grense"
+say hi "vre grense"
+say label "merkelapp"
+say wherelabel "vis merkelapp p"
+say symto "send symbol"
+say symfrom "motta symbol"
+
+say_category GraphProperties
+say x1 "x fra"
+say x2 "x til"
+say xpix "skjermbredde"
+say y2 "y fra"
+say y1 "y til"
+say ypix "skjermhyde"
+
+say_category CanvasProperties
+#say xscale "X enheter/px"
+#say yscale "Y enheter/px"
+say gop "Graph on Parent"
+say xmargin "X margin"
+say ymargin "Y margin"
+say height "hyde"
+
+say_category ArrayProperties
+say name "navn"
+say n "strrelse"
+say xfrom "x omrde fra"
+say xto "x omrde til"
+say yfrom "y omrde fra"
+say yto "y omrde til"
+
+say_category MainWindow
+say in "inn"
+say out "ut"
+say audio "Audio"
+say meters "Mlere"
+say io_errors "IU Feil"
+say tcl_console "Tcl Klient"
+say pd_console "Pd Tjener"
+
diff --git a/desiredata/src/locale/brasiliano.tcl b/desiredata/src/locale/brasiliano.tcl
new file mode 100644
index 00000000..34e5aaff
--- /dev/null
+++ b/desiredata/src/locale/brasiliano.tcl
@@ -0,0 +1,577 @@
+#!/usr/bin/env tclsh
+# Portuguese translations for DesireData
+# $Id: brasiliano.tcl,v 1.1.2.1 2007-10-05 23:15:45 matju Exp $
+# Author: chgp@riseup.net revision 0.4
+
+### Menus
+
+say file "Arquivo"
+ say new_file "Novo"
+ say open_file "Abrir..."
+ say server_prefs "Config. servidor..."
+ say client_prefs "Config. cliente..."
+ say send_message "Enviar mensagem..."
+ say paths "Caminhos..."
+ say close "Fechar Janela"
+ say save "Salvar"
+ say save_as "Salvar como..."
+ say print "Imprimir..."
+ say abort_server "Terminar o servidor"
+ say quit "Sair"
+
+ say canvasnew_file "Novo Arquivo"
+ say canvasopen_file "Abrir Arquivo..."
+ say canvassave "Salvar"
+ say canvassave_as "Salvar como..."
+ say clientpdrc_editor "Editor .pdrc"
+ say clientddrc_editor "Editor .ddrc"
+ say canvasclose "Fechar"
+ say canvasquit "Sair"
+
+say edit "Edição"
+ say undo "Desfazer"
+ say redo "Refazer"
+ say cut "Cortar"
+ say copy "Copiar"
+ say paste "Colar"
+ say duplicate "Duplicar"
+ say select_all "Selecionar tudo"
+ say clear_selection "Limpar seleção"
+ say text_editor "Editor de Texto..."
+ say font "Fonte"
+ say tidy_up "Tidy Up"
+ say edit_mode "Modo de edição"
+ say editmodeswitch "Modo de edição/execução"
+ say subpatcherize "Subpatcherizar :)"
+
+ say canvascut "Cortar"
+ say canvascopy "Copiar"
+ say canvasundo "Colar"
+ say canvasredo "Refazer"
+ say canvaspaste "Colar"
+ say canvasduplicate "Duplicar"
+ say canvasselect_all "Selecionar tudo"
+ say canvaseditmodeswitch "Modo de edição/execução"
+
+say view "Visualizar"
+ say reload "Recarregar"
+ say redraw "Redesenhar"
+
+ say canvasreload "Recarregar"
+ say canvasredraw "Redesenhar"
+say visual_diff "visual diff??"
+say get_elapsed "get elapsed??"
+
+say find "Procurar"
+ say find_again "Procura novamente"
+ say find_last_error "Encontrar o último erro"
+ say string "Procurar por sequência de caracteres"
+say canvasfind "Buscar"
+ say canvasfind_again "Busca novamente"
+
+# contents of Put menu is Phase 5C
+say put "Inserir"
+ say Object "Objeto"
+ say Message "Mensagem"
+ say Number "Número"
+ say Symbol "Símbolo"
+ say Comment "Comentário"
+ say Graph "Gráfico"
+ say Array "Tabela"
+
+say media "Mídia"
+ say audio_on "Ligar Áudio"
+ say audio_off "Desligar Áudio"
+ say test_audio_and_midi "Testar áudio e MIDI"
+ say load_meter "Carregar Meter"
+
+ say canvasaudio_on "Áudio Ligado"
+ say canvasaudio_off "Áudio Desligado"
+ say clienttest_audio_and_midi "Testar áudio e MIDI"
+ say canvasload_meter "Carregar Meter"
+
+say window "Janelas"
+
+say help "Ajuda"
+ say about "Sobre..."
+ say documentation "Documentação..."
+ say class_browser "Navegador..."
+
+ say canvasabout "Sobre..."
+
+say properties "Propriedades"
+say open "Abrir"
+
+### for key binding editor
+say general "Geral"
+say audio_settings "Configurações de Áudio"
+say midi_settings "Configurações Midi"
+say latency_meter "Medidor de latência"
+say Pdwindow "Janela do Pd"
+
+say canvaspdwindow "Janela do Pd"
+say canvaslatency_meter "Medidor de latência"
+say clientaudio_settings "Configurações de áudio"
+say clientmidi_settings "Configurações Midi"
+
+### for Properties Dialog (phase 5B)
+say_category IEM
+say w "largura(px)"
+say h "altura(px)"
+say hold "tempo de espera(ms)"
+say break "tempo de quebra(ms)"
+say min "valor mínimo"
+say max "valor máximo"
+say is_log "mode? (is_log)"
+say linear "linear"
+say logarithmic "logarítimico"
+say isa "início"
+say n "número de alternativas"
+say steady "steadiness?"
+say steady_no "pula no clique"
+say steady_yes "steady? no clique"
+say snd "envia-símbolo"
+say rcv "recebe-símbolo"
+say lab "etiqueta"
+say ldx "offset etiqueta x"
+say ldy "offset etiqueta y"
+say fstyle "Fonte tipo"
+say fs "tamanho da fonte"
+say bcol "cor de fundo"
+say fcol "cor da frente"
+say lcol "cor da etiqueta"
+say yes "sim"
+say no "não"
+say courier "courier (typewriter)"
+say helvetica "helvetica (sansserif)"
+say times "times (serif)"
+say coords "gráfico no pai"
+
+say_category GAtomProperties
+say width "largura"
+say lo "limite inferior"
+say hi "limite superior"
+say label "etiqueta"
+say wherelabel "exibe etiqueta"
+say symto "envia símbolo"
+say symfrom "recebe símbolo"
+
+say_category GraphProperties
+say x1 "de x"
+say x2 "para x"
+say xpix "largura da tela"
+say y2 "de y"
+say y1 "para y"
+say ypix "altura da tela"
+
+say_category CanvasProperties
+#say xscale "X units/px"
+#say yscale "Y units/px"
+say gop "gráfico no pai"
+say xmargin "margem x"
+say ymargin "margem y"
+say height "altura"
+say_category ArrayProperties
+say name "nome"
+say n "tamanho"
+say xfrom "escala x de?"
+say xto "escala x até"
+say yfrom "escala y de"
+say yto "escala y até"
+
+
+say_category MainWindow
+say in "entrada"
+say out "saída"
+say audio "Áudio"
+say meters "Medidores"
+say io_errors "Erros E/S"
+say tcl_console "Cliente Tcl"
+say pd_console "Servidor Pd"
+
+### phase 2
+
+say_category Other
+say_namespace summary {
+ say_category IEMGUI
+ say bng "Bang"
+ say tgl "Interruptor (Toggle)"
+ say nbx "Caixa numérica (IEM)"
+ say hsl "Slider (Horizontal)"
+ say vsl "Slider (Vertical)"
+ say hradio "Caixa de seleção (horizontal)"
+ say vradio "Caixa de seleção (Vertical)"
+ say cnv "Canvas (IEM)"
+ say dropper "Caixa arrasta-e-solta"
+ say vu "Medidor VU"
+
+ say_category GLUE
+ say bang "envia uma mensagem bang"
+ say float "armazena e acessa um número"
+ say symbol "armazena e acessa um símbolo"
+ say int "armazena e acessa um inteiro"
+ say send "armazena uma mensagem para um objeto rotulado"
+ say receive "rebe mensagens enviadas"
+ say select "testar por números ou símbolos coincidentes"
+ say route "refaz a rota das mensagens de acordo com o primeiro elemento"
+ say pack "\"empacotador\" de mensagens"
+ say unpack "\"desempacota\" mensagens compostas"
+ say trigger "sequencia e converte mensagens"
+ say spigot "interruptor de fluxo de mensagens"
+ say moses "part a numeric stream"
+ say until "mecanismo de loop"
+ say print "exibe mensagens"
+ say makefilename "formata um símbolo com um campo variável??"
+ say change "remover números repetidos de uma sequência"
+ say swap "troca dois números"
+ say value "compartilha valor numérico"
+
+ say_category TIME
+ say delay "envia uma mensagem após um intervalo de tempo"
+ say metro "Metrônomo - envia mensagens periodicamente"
+ say line "envia mensagem com números lineares"
+ say timer "mede intervalos de tempo"
+ say cputime "mede tempo de processamento"
+ say realtime "mede tempo real"
+ say pipe "linha de intervalo de tempo númerico que cresce dinamicamente"
+
+ say_category MATH
+ say + "adiciona"
+ say - "subtrai"
+ say * "multiplica"
+ say {/ div} "divisão"
+ say {% mod} "resto da divisão"
+ say pow "potência"
+ say == "igua a?"
+ say != "diferente de?"
+ say > "maior que?"
+ say < "menor que?"
+ say >= "menor ou igual a?"
+ say <= "maior ou igual a?"
+ say & "conjunção bitwise (e)"
+ say | "disjunção bitwise (ou)"
+ say && "conjunção lógica (e)"
+ say || "disjunção lógica (ou)"
+ say mtof "MIDI para Hertz"
+ say ftom "Hertz para MIDI"
+ say powtodb "Watts para dB"
+ say dbtopow "dB para Watts"
+ say rmstodb "Volts para dB"
+ say dbtorms "dB para Volts"
+ say {sin cos tan atan atan2 sqrt} "trigonometria"
+ say log "Logarítimo Euler"
+ say exp "Exponenciação Euler"
+ say abs "valor absoluto"
+ say random "randômico"
+ say max "máximo de dois números"
+ say min "mínimo de dois números"
+ say clip "forçar um número numa faixa"
+
+ say_category MIDI
+ say {notein ctlin pgmin bendin touchin polytouchin midiin sysexin} "entrada MIDI"
+ say {noteout ctlout pgmout bendout touchout polytouchout midiout} "saída MIDI"
+ say makenote "agenda uma mensagem \"note off\" correspondente a uma note-on"
+ say stripnote "separa mensagens \"note off\" "
+
+ say_category TABLES
+ say tabread "le um número de uma tabela"
+ say tabread4 "lê um número de uma tabela com 4 pontos de interpolação"
+ say tabwrite "escreve um número numa tabela"
+ say soundfiler "lê e escreve tabelas em arquivos de som"
+
+ say_category MISC
+ say loadbang "bang quando carregar patch"
+ say serial "controle de dispositivo para MS NT"
+ say netsend "envia mensagens através da internet"
+ say netreceive "recebe as mensagens através da internet"
+ say qlist "sequenciador de mensagens"
+ say textfile "conversor de arquivo para mensagens"
+ say openpanel "Diálogo \"Abrir\""
+ say savepanel "Diálogo \"Salvar como\" "
+ say bag "conjunto de números"
+ say poly "alocação de voz polifônica"
+ say {key keyup} "valor numéricos de teclas de teclado alfanumérico"
+ say keyname "nome simbólico da chave?"
+
+ say_category "Matemática com Áudio"
+ foreach word {+ - * /} {say $word~ "[say $word] (for signals)"}
+ say max~ "supremacia dos sinais"
+ say min~ "infinidade dos sinais"
+ say clip~ "constrict signal to lie between two bounds"
+ say q8_rsqrt~ "raiz quadrada reciproca barata (cuidado -- 8 bits!)"
+ say q8_sqrt~ "raiz quadrada barata (cuidado -- 8 bits!)"
+ say wrap~ "wraparound (tipo de parte fracionária)"
+ say fft~ "transformação discreta Fourier complex forward"
+ say ifft~ "transformação discreta Fourier complex inverse"
+ say rfft~ "transformação discreta Fourier real forward "
+ say rifft~ "transformação discreta Fourier real inverse "
+ say framp~ "dá saída numa rampa para cada bloco"
+ foreach word {mtof ftom rmstodb dbtorms rmstopow powtorms} {
+ say $word~ "[say $word] (para sinais)"
+ }
+}
+
+### phase 3
+
+say_namespace summary {
+ say_category "Cola de Áudio"
+ say dac~ "saída de áudio"
+ say adc~ "entrada de áudio"
+ say sig~ "converte números para sinais de áudio"
+ say line~ "gera rampas de áudio"
+ say vline~ "line~ de luxo"
+ say threshold~ "detecta sinal thresholds"
+ say snapshot~ "sample a signal (convert it back to a number)"
+ say vsnapshot~ "deluxe snapshot~"
+ say bang~ "send a bang message after each DSP block"
+ say samplerate~ "get the sample rate"
+ say send~ "nonlocal signal connection with fanout"
+ say receive~ "obtêm sinal do send~"
+ say throw~ "adiciona a um summing bus"
+ say catch~ "definir e ler um summing bus??"
+ say block~ "especificar tamanho do bloco e overlap"
+ say switch~ "liga e desliga computação DSP"
+ say readsf~ "le de arquivos de som no disco"
+ say writesf~ "grava arquivos de som no disco"
+
+ say_category "Osciladores de áudio e tabelas"
+ say phasor~ "oscilador dente de serra (sawtooth)"
+ say {cos~ osc~} "oscilador coseno"
+ say tabwrite~ "escrever em tabela"
+ say tabplay~ "tocar de uma tabela (sem transpor)"
+ say tabread~ "leitura de tabela não interpolada"
+ say tabread4~ "leitura de tabela com 4 ponto de interpolação"
+ say tabosc4~ "oscilador com tabela de ondas (wavetable)"
+ say tabsend~ "escreve um bloco continuamente em uma tabela"
+ say tabreceive~ "le um bloco continuamente de uma tabela"
+
+ say_category "Filtros de áudio"
+ say vcf~ "filtro controlador de voltagem"
+ say noise~ "gerador de ruido branco"
+ say env~ "envelope follower"
+ say hip~ "filtro passo alto"
+ say lop~ "filtro passo baixo"
+ say bp~ "filtro passo banda"
+ say biquad~ "filtro raw"
+ say samphold~ "unidade sample and hold"
+ say print~ "exibe um ou mais \"blocose \"blocks\""
+ say rpole~ "raw real-valued one-pole filter"
+ say rzero~ "raw real-valued one-zero filter"
+ say rzero_rev~ "[say rzero~] (tempo-revertido)"
+ say cpole~ "[say rpole~] (valor complexo)"
+ say czero~ "[say rzero~] (valor complexo)"
+ say czero_rev~ "[say rzero_rev~] (valor complexo)"
+
+ say_category "AUDIO DELAY"
+ say delwrite~ "escreve para uma linha de atraso(delay)"
+ say delread~ "ler de uma linha de atraso(delay)"
+ say vd~ "ler de uma linha de atraso num read from a delay line at a variable delay time"
+
+ say_category "Subjanelas"
+ say pd "define uma subjanela"
+ say table "array de números em uma subjanela"
+ say inlet "add an inlet to a pd"
+ say outlet "add an outlet to a pd"
+ say inlet~ "[say inlet] (for signal)"
+ say outlet~ "[say outlet] (for signal)"
+
+ say_category "Modelos de DADOS (templates)"
+ say struct "define uma estrutura de dados"
+ say {drawcurve filledcurve} "desenha uma curva"
+ say {drawpolygon filledpolygon} "desenha um polígono"
+ say plot "plotar um campo array"
+ say drawnumber "imprime um valor numérico"
+
+ say_category "Acessando DADOS"
+ say pointer "aponta para um objeto pertencente a um modelo"
+ say get "obtêm campos numéricos"
+ say set "altera campos numéricos"
+ say element "obtêm um elemento array"
+ say getsize "obtêm o tamanho do array"
+ say setsize "altera o tamanho de um array"
+ say append "adiciona um elemento a uma lista"
+ say sublist "obtêm um ponteiro em uma lista que é um elemento para uma outra escalar??"
+ say scalar "desenha uma escalar no pai"
+
+ say_category "OBSOLETE"
+ say scope~ "(usar tabwrite~ agora)"
+ say namecanvas "" ;# what was this anyway?
+ say template "(usar struct agora)"
+}
+
+# phase 4 (pdrc & ddrc)
+
+say section_audio "Áudio"
+ say -r "Frequência da amostra"
+ say -audioindev "dispositivos de entrada"
+ say -audiooutdev "dispositivos de saída"
+ say -inchannels "número de canais de entrada (por dispositivo, tipo \"2\" ou \"16,8\")"
+ say -outchannels "número de canais de saída (o mesmo)"
+ say -audiobuf "especificar tamanho do buffer de áudio em mseg."
+ say -blocksize "espcificar tamanho do bloco de E/S em quadros de amostras"
+ say -sleepgrain "especificar número para dormir quando inativa em milisegundos"
+ say -nodac "não processa áudio"
+ say -noadc "não processa(supress?) áudio"
+ say audio_api_choice "API de áudio"
+ say default "padrão"
+ say -alsa "usar API ALSA de áudio"
+ say -jack "usar API JACK de áudio"
+ say -mmio "usar API MMIO de áudio (padrão para windows)"
+ say -portaudio "usar driver de áudio ASIO (via Portaudio)"
+ say -oss "usar API OSS de áudio"
+ say -32bit "permitir acesso 32 bits a áudio OSS (para RME Hammerfall)"
+ say {} "padrão"
+
+say section_midi "MIDI"
+ say -nomidiin "não processa entrada MIDI"
+ say -nomidiout "não processa saída MIDI"
+ say -midiindev "dispositivos de entrada MIDI; ex, \"1,3\" para primeiro e terceiro"
+say -midioutdev "dispositivos de saída MIDI; lista de dispositivos de saída midi, mesmo formato"
+
+say section_externals "Externos"
+ say -path "caminho de procura por arquivos"
+ say -helppath "caminho de procura por arquivos de ajuda"
+ say -lib "carrega bibliotecas de objetos"
+
+say section_gui "Interface"
+ say -nogui "desabilita o início da interface gráfica (cuidado)"
+ say -guicmd "substitui outro programa de interface (ex., rsh)"
+ say -look "ícones da barra de butões"
+ say -font "especificar o padrão do tamanho da fonte em pontos"
+
+say section_other "Outros"
+ say -open "abrir arquivo(s) no início"
+ say -verbose "exibir mais detalhes no início e quando pesquisar por arquivos"
+ say -d "grau de depuração"
+ say -noloadbang "desabilita o efeito de \[loadbang\]"
+ say -send "envia uma mensagem no início (depois dos patches carregados)"
+ say -listdev "listar dispositivos de áudio e MIDI carga do logicial"
+ say -realtime "usar prioridade de tempo-real (necessita conta com privilégio especial ou root)"
+
+say section_paths "Caminhos"
+
+# phase 4B: ddrc (keyword names not finalized!)
+say console "linhas de rolamento da console (1 = desabilita console)"
+say lang "Linguagem"
+say pointer_sense "Sensibilidade do ponteiro do mouse"
+say section_color "Aparencia"
+ say canvas_color "canvas"
+ say canvasbgedit "fundo do canvas (modo edição)"
+ say canvasbgrun "canvas background (modo execução)"
+ say object_color "objeto"
+ say viewframe1 "cor da caixa de objeto"
+ say viewframe2 "cor da caixa de objeto"
+ say viewframe3 "cor da caixa de objeto"
+ say viewframe4 "cor de destaque da caixa de objeto"
+ say viewbg "fundo do objeto"
+ say viewfg "frente do objeto"
+ say commentbg "fundo do comentário"
+ say commentfg "frente do comentário"
+ say commentframe1 "quadro de comentário"
+ say commentframe2 "quadro de comentário"
+ say commentframe3 "quadro de comentário"
+ say viewselectframe "hilight box"
+ say wire_color "fio"
+ say wirefg "cor do fio"
+ say wirefg2 "destaque do fio"
+ say wiredspfg "cor do fio de áudio"
+ say futurewiredash "novo fio (esmagado?)"
+ say others_color "outras"
+ say boxinletfg "cor das entradas"
+ say boxoutletfg "cor das saídas"
+ say selrectrect "caixa de seleção"
+say keys "chaves"
+say others "outras"
+say hairstate "Ativa crosshair"
+say hairsnap "Crosshair gruda no objeto"
+say statusbar "Ativa barra de estado"
+say buttonbar "Ativa barra de butões"
+say menubar "Ativa barra de menus"
+say scrollbar "Ativa barra de rolagem automática"
+say wirearrow "Cabo com seta"
+say tooltip "Dica"
+say insert_object "Inserir objeto"
+say chain_object "Objeto corrente (Chain)"
+say clear_wires "Limpar cabos"
+say auto_wire "Remove objeto"
+say subpatcherize "Subpatcherizar :)"
+say keynav "navegação do teclado"
+say key_nav_up "move para cima"
+say key_nav_up_shift "selecione mais"
+say key_nav_down "mover para baixo"
+say key_nav_down_shift "selecione mais"
+say key_nav_right "move right"
+say key_nav_right_shift "selecione mais"
+say key_nav_left "mover para esquerda"
+say key_nav_left_shift "selecione mais"
+say key_nav_ioselect "seleciona entradas/saídas"
+# phase 5A
+
+say cannot "não consigo"
+say cancel "Cancelar"
+say apply "Aplicar"
+say ok "OK"
+say popup_open "Abrir"
+say popup_insert "Inserir"
+say popup_properties "Propriedades"
+say popup_clear_wires "Limpar conexões"
+say popup_remove_from_path "Remove objeto do caminho"
+say popup_delete_from_path "Apaga objeto do caminho"
+say popup_copy_id "copia identificação"
+say popup_help "Ajuda"
+say filter "Filtro: "
+say how_many_object_classes "%d de %d classes de objeto"
+say do_what_i_mean "Realize o que eu imagino!"
+say ask_cool "Este recurso quando estiver implementado vai ficar muito, foda."
+say save_changes? "Salvar as bobagens que você fez?"
+say reset "Reiniciar"
+say Courier "Courier (monospaced)"
+say Helvetica "Helvetica (sansserif)"
+say Times "Times (serif)"
+say add "Adiciona"
+say up "Acima"
+say down "Abaixo"
+say remove "Remove"
+say lib_add "adiciona o nome que você digitou na lista"
+say lib_up "altera ordem com biblioteca anterior"
+say lib_down "altera ordem com próxima biblioteca"
+say lib_remove "remove biblioteca selecionada na lista"
+say dir_add "adiciona um campo usando um diálogo de arquivo"
+say dir_up "troca ordem com campo anterior"
+say dir_down "troca ordem com próximo campo"
+say dir_remove "remove pasta selecionada na lista"
+say client_class_tree "Árvore de Classes pro freguês"
+say clipboard_view "Visão Clipboard"
+say command_history_view "Visão do histórico de comandos"
+say event_history_view "Ver histórico de eventos"
+
+# during/after piksel:
+
+say auto_apply "Auto-Aplicar"
+say font_preview "Prévia:"
+say font_preview_2 "ABCDEFGHIJKLMNOPQRSTUVWXYZ\nabcdefghijklmnopqrstuvwxyz\n0123456789"
+say font_style "Estilo:"
+say font_bold "Negrito"
+say font_italic "Itálico"
+say font_family "Nome:"
+say font_size "Tamanho:"
+say damn "Maldito!"
+say console_clear "Limpar Console"
+say horizontal "Horizontal"
+say vertical "Vertical"
+say language "Língua"
+
+# 2007:
+
+say no_matches "o padrão especificado não foi encontrado"
+say preset "modelo??"
+say canvasgrid "Cor da Grade"
+say grid_size "Tamanho da grade"
+say gridstate "Ativar grade de fundo"
+say snap_grid "Grudar na grade"
+say viewfont "fonte do objeto"
+say consolefont "fonte do console"
+say keyboarddialogfont "fonte do teclado virtual"
+say keyboard_view "Teclado Virtual"
+say log_height "Tamanho do Histórico"
+
diff --git a/desiredata/src/locale/catala.tcl b/desiredata/src/locale/catala.tcl
new file mode 100644
index 00000000..8f244256
--- /dev/null
+++ b/desiredata/src/locale/catala.tcl
@@ -0,0 +1,58 @@
+#!/usr/bin/env tclsh
+# Catalan (catal) translations for PureData
+# $Id: catala.tcl,v 1.1.2.5 2006-10-13 16:00:56 matju Exp $
+# by Nria Verges
+
+say file "Fitxer"
+ say new_file "Nou Fitxer"
+ say open_file "Obrir Fitxer..."
+ say pdrc_editor "Editor de .pdrc"
+ say send_message "Enviar Missatge..."
+ say paths "Camins..."
+ say close "Tancar"
+ say save "Desar"
+ say save_as "Guardar com a..."
+ say print "Imprimir..."
+ say quit "Sortir"
+
+say edit "Editar"
+ say undo "Desfer"
+ say redo "Refer"
+ say cut "Tallar"
+ say copy "Copiar"
+ say paste "Enganxar"
+ say duplicate "Duplicar"
+ say select_all "Seleccionar-ho tot"
+ say text_editor "Editor de text..."
+ say tidy_up "Netejar"
+ say edit_mode "Mode d'edici"
+
+say view "Veure"
+ say reload "Recarregar"
+ say redraw "Redissenyar"
+
+say find "Trobar"
+ say find_again "Trobar novament"
+ say find_last_error "Trobar l'ltima errada"
+
+say put "Posar"
+
+say media "Media"
+ say audio_on "Audio ON"
+ say audio_off "Audio OFF"
+
+say window "Finestra"
+
+say help "Ajuda"
+ say about "Sobre..."
+ say pure_documentation "Pure Documentaci..."
+ say class_browser "Cercador de Classes..."
+
+### Main Window
+
+say in "in"
+say out "out"
+say audio "Audio"
+say meters "Meters"
+say io_errors "Errades d'E/S"
+
diff --git a/desiredata/src/locale/chinese.tcl b/desiredata/src/locale/chinese.tcl
new file mode 100644
index 00000000..bdbd0a37
--- /dev/null
+++ b/desiredata/src/locale/chinese.tcl
@@ -0,0 +1,560 @@
+#!/usr/bin/env tclsh
+# English translations for PureData
+# $Id: chinese.tcl,v 1.1.2.3 2007-08-09 02:09:07 chunlee Exp $
+
+### Menus
+
+say file "案檔"
+ say new_file "新案檔"
+ say open_file "開啟舊檔..."
+ say server_prefs "伺服器設定..."
+ say client_prefs "客戶端設定..."
+ say send_message "傳送旨令..."
+ say paths "Paths..."
+ say close "關閉"
+ say save "存檔"
+ say save_as "另存新檔..."
+ say print "印出..."
+ say quit "結束"
+
+ say canvasnew_file "開啟新檔"
+ say canvasopen_file "開啟舊檔..."
+ say canvassave "存檔"
+ say canvassave_as "另存新檔..."
+ say clientpdrc_editor "遠端設定"
+ say clientddrc_editor "終端設定"
+ say canvasclose "關閉"
+ say canvasquit "結束"
+
+say edit "編輯"
+ say undo "回上一步"
+ say redo "回下一步"
+ say cut "剪下"
+ say copy "拷貝"
+ say paste "後貼"
+ say duplicate "復製"
+ say select_all "全選"
+ say text_editor "Text Editor..."
+ say font "字體"
+ say tidy_up "自動排列"
+ say edit_mode "編輯模式"
+ say editmodeswitch "編輯/執行 模式"
+
+ say canvascut "剪下"
+ say canvascopy "拷貝"
+ say canvasundo "回上一步"
+ say canvasredo "回下一步"
+ say canvaspaste "後貼"
+ say canvasduplicate "復製"
+ say canvasselect_all "全選"
+ say canvaseditmodeswitch "編輯/執行 模式"
+
+say view "顯示"
+ say reload "重新下載"
+ say redraw "重新畫製"
+
+ say canvasreload "重新下載"
+ say canvasredraw "重新畫製"
+
+say find "尋找"
+ say find_again "再次尋找"
+ say find_last_error "尋找上一錯誤"
+ say string "Find string"
+say canvasfind "尋找"
+ say canvasfind_again "再次尋找"
+
+# contents of Put menu is Phase 5C
+say put "放置"
+ say Object "物件"
+ say Message "信息"
+ say Number "數字"
+ say Symbol "符號"
+ say Comment "註譯"
+ say Graph "圖"
+ say Array "陣列"
+
+say media "Media"
+ say audio_on "聲頻開啟"
+ say audio_off "聲頻關閉"
+ say test_audio_and_midi "測試聲頻及MIDI"
+ say load_meter "負載錶"
+
+ say canvasaudio_on "聲頻開啟"
+ say canvasaudio_off "聲頻關閉"
+ say clienttest_audio_and_midi "測試聲頻及MIDI"
+ say canvasload_meter "負載錶"
+
+say window "視窗"
+
+say help "幫助"
+ say about "相關..."
+ say documentation "使用說明..."
+ say class_browser "物件瀏覽器..."
+
+ say canvasabout "相關..."
+
+say properties "內容"
+say open "開啟"
+
+### for key binding editor
+say general "一般"
+say audio_settings "聲頻設定"
+say midi_settings "Midi設定"
+say latency_meter "時延錶"
+say Pdwindow "Pd主視窗"
+
+say canvaspdwindow "Pd主視窗"
+say canvaslatency_meter "時延錶"
+say clientaudio_settings "聲頻設定"
+say clientmidi_settings "Midi設定"
+
+### for Properties Dialog (phase 5B)
+say_category IEM
+say w "寬(像素)"
+say h "高(像素)"
+say hold "有效顯示時限(毫秒)"
+say break "有效空閒時限(毫秒)"
+say min "最低數限"
+say max "最高數限"
+say is_log "模式"
+say linear "線性"
+say logarithmic "對數"
+say isa "起始"
+say n "選擇數量"
+say steady "穩定性"
+say steady_no "點選跳躍式"
+say steady_yes "點選持續式"
+say snd "傳送符號"
+say rcv "接收符號"
+say lab "標簽"
+say ldx "標簽橫落差"
+say ldy "標簽縱落差"
+say fstyle "字形"
+say fs "字體大小"
+say bcol "背景研色"
+say fcol "前景研色"
+say lcol "標簽研色"
+say yes "是"
+say no "否"
+say courier "courier (typewriter)"
+say helvetica "helvetica (sansserif)"
+say times "times (serif)"
+say coords "頂端顯示"
+
+say_category GAtomProperties
+say width "寬"
+say lo "最低數限"
+say hi "最高數限"
+say label "標簽"
+say wherelabel "標簽位置"
+say symto "傳送符號"
+say symfrom "接收符號"
+say pos "標簽位置"
+say_category GraphProperties
+say x1 "x from"
+say x2 "x to"
+say xpix "screen width"
+say y2 "y from"
+say y1 "y to"
+say ypix "screen height"
+
+say_category CanvasProperties
+#say xscale "X units/px"
+#say yscale "Y units/px"
+say gop "頂端顯示"
+say xmargin "橫軸邊緣限度"
+say ymargin "縱軸邊緣限度"
+say height "高"
+say_category ArrayProperties
+say name "名子"
+say n "大小"
+say xfrom "橫軸範圍啟"
+say xto "橫軸範圍使"
+say yfrom "縱軸範圍啟"
+say yto "縱軸範圍使"
+
+
+say_category MainWindow
+say in "進"
+say out "出"
+say audio "聲音"
+say meters "聲頻錶"
+say io_errors "聲頻錯誤"
+say console_clear "清空顯示"
+say tcl_console "TCL 旨令"
+say pd_console "Pd 旨令"
+### phase 2
+
+say_category Other
+say_namespace summary {
+ say_category IEMGUI
+ say bng "Bang Box"
+ say tgl "Toggle Box"
+ say nbx "Number Box (IEM)"
+ say hsl "Slider (Horizontal)"
+ say vsl "Slider (Vertical)"
+ say hradio "Choice Box (Horizontal)"
+ say vradio "Choice Box (Vertical)"
+ say cnv "Canvas (IEM)"
+ say dropper "Drag-and-Drop Box"
+ say vu "Vumeter"
+
+ say_category GLUE
+ say bang "output a bang message"
+ say float "store and recall a number"
+ say symbol "store and recall a symbol"
+ say int "store and recall an integer"
+ say send "send a message to a named object"
+ say receive "catch sent messages"
+ say select "test for matching numbers or symbols"
+ say route "route messages according to first element"
+ say pack "make compound messages"
+ say unpack "get elements of compound messages"
+ say trigger "sequence and convert messagess"
+ say spigot "interruptible message connection"
+ say moses "part a numeric stream"
+ say until "looping mechanism"
+ say print "print out messages"
+ say makefilename "format a symbol with a variable field"
+ say change "remove repeated numbers from a stream"
+ say swap "swap two numbers"
+ say value "shared numeric value"
+
+ say_category TIME
+ say delay "send a message after a time delay"
+ say metro "send a message periodically"
+ say line "send a series of linearly stepped numbers"
+ say timer "measure time intervals"
+ say cputime "measure CPU time"
+ say realtime "measure real time"
+ say pipe "dynamically growable delay line for numbers"
+
+ say_category MATH
+ say + "add"
+ say - "substract"
+ say * "multiply"
+ say {/ div} "divide"
+ say {% mod} "division remainder"
+ say pow "exponentiate"
+ say == "equal?"
+ say != "not equal?"
+ say > "more than?"
+ say < "less than?"
+ say >= "not less than?"
+ say <= "not more than?"
+ say & "bitwise conjunction (and)"
+ say | "bitwise disjunction (or)"
+ say && "logical conjunction (and)"
+ say || "logical disjunction (or)"
+ say mtof "MIDI to Hertz"
+ say ftom "Hertz to MIDI"
+ say powtodb "Watts to dB"
+ say dbtopow "dB to Watts"
+ say rmstodb "Volts to dB"
+ say dbtorms "dB to Volts"
+ say {sin cos tan atan atan2 sqrt} "trigonometry"
+ say log "Euler logarithm"
+ say exp "Euler exponential"
+ say abs "absolute value"
+ say random "random"
+ say max "greater of two numbers"
+ say min "lesser of two numbers"
+ say clip "force a number into a range"
+
+ say_category MIDI
+ say {notein ctlin pgmin bendin touchin polytouchin midiin sysexin} "MIDI input"
+ say {noteout ctlout pgmout bendout touchout polytouchout midiout} "MIDI output"
+ say makenote "schedule a delayed \"note off\" message corresponding to a note-on"
+ say stripnote "strip \"note off\" messages"
+
+ say_category TABLES
+ say tabread "read a number from a table"
+ say tabread4 "read a number from a table, with 4 point interpolation"
+ say tabwrite "write a number to a table"
+ say soundfiler "read and write tables to soundfiles"
+
+ say_category MISC
+ say loadbang "bang on load"
+ say serial "serial device control for NT only"
+ say netsend "send messages over the internet"
+ say netreceive "receive them"
+ say qlist "message sequencer"
+ say textfile "file to message converter"
+ say openpanel "\"Open\" dialog"
+ say savepanel "\"Save as\" dialog"
+ say bag "set of numbers"
+ say poly "polyphonic voice allocation"
+ say {key keyup} "numeric key values from keyboard"
+ say keyname "symbolic key name"
+
+ say_category "AUDIO MATH"
+ foreach word {+ - * /} {say $word~ "[say $word] (for signals)"}
+ say max~ "supremum of signals"
+ say min~ "infimum of signals"
+ say clip~ "constrict signal to lie between two bounds"
+ say q8_rsqrt~ "cheap reciprocal square root (beware -- 8 bits!)"
+ say q8_sqrt~ "cheap square root (beware -- 8 bits!)"
+ say wrap~ "wraparound (fractional part, sort of)"
+ say fft~ "complex forward discrete Fourier transform"
+ say ifft~ "complex inverse discrete Fourier transform"
+ say rfft~ "real forward discrete Fourier transform"
+ say rifft~ "real inverse discrete Fourier transform"
+ say framp~ "output a ramp for each block"
+ foreach word {mtof ftom rmstodb dbtorms rmstopow powtorms} {
+ say $word~ "[say $word] (for signals)"
+ }
+}
+
+### phase 3
+
+say_namespace summary {
+ say_category "AUDIO GLUE"
+ say dac~ "audio output"
+ say adc~ "audio input"
+ say sig~ "convert numbers to audio signals"
+ say line~ "generate audio ramps"
+ say vline~ "deluxe line~"
+ say threshold~ "detect signal thresholds"
+ say snapshot~ "sample a signal (convert it back to a number)"
+ say vsnapshot~ "deluxe snapshot~"
+ say bang~ "send a bang message after each DSP block"
+ say samplerate~ "get the sample rate"
+ say send~ "nonlocal signal connection with fanout"
+ say receive~ "get signal from send~"
+ say throw~ "add to a summing bus"
+ say catch~ "define and read a summing bus"
+ say block~ "specify block size and overlap"
+ say switch~ "switch DSP computation on and off"
+ say readsf~ "soundfile playback from disk"
+ say writesf~ "record sound to disk"
+
+ say_category "AUDIO OSCILLATORS AND TABLES"
+ say phasor~ "sawtooth oscillator"
+ say {cos~ osc~} "cosine oscillator"
+ say tabwrite~ "write to a table"
+ say tabplay~ "play back from a table (non-transposing)"
+ say tabread~ "non-interpolating table read"
+ say tabread4~ "four-point interpolating table read"
+ say tabosc4~ "wavetable oscillator"
+ say tabsend~ "write one block continuously to a table"
+ say tabreceive~ "read one block continuously from a table"
+
+ say_category "AUDIO FILTERS"
+ say vcf~ "voltage controlled filter"
+ say noise~ "white noise generator"
+ say env~ "envelope follower"
+ say hip~ "high pass filter"
+ say lop~ "low pass filter"
+ say bp~ "band pass filter"
+ say biquad~ "raw filter"
+ say samphold~ "sample and hold unit"
+ say print~ "print out one or more \"blocks\""
+ say rpole~ "raw real-valued one-pole filter"
+ say rzero~ "raw real-valued one-zero filter"
+ say rzero_rev~ "[say rzero~] (time-reversed)"
+ say cpole~ "[say rpole~] (complex-valued)"
+ say czero~ "[say rzero~] (complex-valued)"
+ say czero_rev~ "[say rzero_rev~] (complex-valued)"
+
+ say_category "AUDIO DELAY"
+ say delwrite~ "write to a delay line"
+ say delread~ "read from a delay line"
+ say vd~ "read from a delay line at a variable delay time"
+
+ say_category "SUBWINDOWS"
+ say pd "define a subwindow"
+ say table "array of numbers in a subwindow"
+ say inlet "add an inlet to a pd"
+ say outlet "add an outlet to a pd"
+ say inlet~ "[say inlet] (for signal)"
+ say outlet~ "[say outlet] (for signal)"
+
+ say_category "DATA TEMPLATES"
+ say struct "define a data structure"
+ say {drawcurve filledcurve} "draw a curve"
+ say {drawpolygon filledpolygon} "draw a polygon"
+ say plot "plot an array field"
+ say drawnumber "print a numeric value"
+
+ say_category "ACCESSING DATA"
+ say pointer "point to an object belonging to a template"
+ say get "get numeric fields"
+ say set "change numeric fields"
+ say element "get an array element"
+ say getsize "get the size of an array"
+ say setsize "change the size of an array"
+ say append "add an element to a list"
+ say sublist "get a pointer into a list which is an element of another scalar"
+ say scalar "draw a scalar on parent"
+
+ say_category "OBSOLETE"
+ say scope~ "(use tabwrite~ now)"
+ say namecanvas "" ;# what was this anyway?
+ say template "(use struct now)"
+}
+
+# phase 4 (pdrc & ddrc)
+
+say section_audio "聲頻"
+ say -r "取樣率"
+ say -audioindev "輸入裝置"
+ say -audiooutdev "輸出裝置"
+ say -inchannels "輸入音軌"
+ say -outchannels "輸出音軌"
+ say -audiobuf "聲頻緩衝器大小(毫秒)"
+ say -blocksize "聲頻輸出/入區塊大小(樣框數目)"
+ say -sleepgrain "空閒至睡眠時間(毫秒)"
+ say -nodac "停用聲頻輸出"
+ say -noadc "停用聲頻輸入"
+ say audio_api_choice "聲頻介面"
+ say default "內定值"
+ say -alsa "使用ALSA"
+ say -jack "使用JACK"
+ say -mmio "使用MMIO(Windows內定值)"
+ say -portaudio "使用ASIO(透過Portaudio)"
+ say -oss "使用OSS"
+ say -32bit "允許32位元OSS(for RME Hammerfall)"
+ say {} "內定值"
+
+say section_midi "MIDI"
+ say -nomidiin "停用MIDI輸入"
+ say -nomidiout "停用MIDI輸出"
+ say -midiindev "Midi輸入裝置名單"
+ say -midioutdev "Midi輸出裝置名單"
+
+say section_externals "外加功能"
+ say -path "尋找路徑"
+ say -helppath "說明文件路徑"
+ say -lib "加載功能組"
+
+say section_gui "使用者介面"
+ say -nogui "suppress starting the GUI (caution)"
+ say -guicmd "substitute another GUI program (e.g., rsh)"
+ say -console "console scrollback lines (0 = disable console)"
+ say -look "buttonbar icons"
+ say -statusbar "enable statusbar"
+ say -font "specify default font size in points"
+
+say section_other "其它"
+ say -open "自動開啟檔案"
+ say -verbose "詳係回報"
+ say -d "除錯階級"
+ say -noloadbang "停用 \[loadbang\]"
+ say -send "啟動後傳送旨令"
+ say -listdev "程式開啟時列出聲頻及MIDI裝置名單"
+ say -realtime "使用即時配給 (須要根權)"
+
+say section_paths "路徑"
+
+# phase 4B: ddrc (keyword names not finalized!)
+
+say section_color "色彩"
+ say canvas_color "畫布"
+ say canvasbgedit "畫布背景 (編輯模式)"
+ say canvasbgrun "畫布背景 (執行模式)"
+ say object_color "物件"
+ say viewframe1 "物件外框"
+ say viewframe2 "物件外框"
+ say viewframe3 "物件外框"
+ say viewframe4 "物件反白"
+ say viewbg "物件背景"
+ say viewfg "物件前景"
+ say commentbg "註譯背景"
+ say commentfg "註譯前景"
+ say commentframe1 "註譯外框"
+ say commentframe2 "註譯背景"
+ say commentframe3 "註譯背景"
+ say viewselectframe "物件反白外框"
+ say wire_color "通路"
+ say wirefg "通路研色"
+ say wirefg2 "通路反白"
+ say wiredspfg "聲頻通路"
+ say futurewiredash "未接通路"
+ say others_color "其它"
+ say boxinletfg "輸入點研色"
+ say boxoutletfg "輸出點研色"
+ say selrectrect "多選框"
+say keys "快速鍵"
+say others "其它"
+say hairstate "顯示十字器"
+say hairsnap "十字器停留物件左上角"
+say statusbar "顯示目前狀態"
+say buttonbar "顯示按鈕排"
+say menubar "顯示清單"
+say scrollbar "自動拉霸顯示"
+say wirearrow "通路箭頭"
+say tooltip "提示"
+say insert_object "嵌入物件"
+say chain_object "自動連結新物件"
+say clear_wires "清除通路"
+say auto_wire "移除物件"
+say subpatcherize "自動封裝"
+say keynav "鍵盤導覽"
+say key_nav_up "上移"
+say key_nav_up_shift "加入選區"
+say key_nav_down "下移"
+say key_nav_down_shift "加入選區"
+say key_nav_right "右移"
+say key_nav_right_shift "加入選區"
+say key_nav_left "左移"
+say key_nav_left_shift "加入選區"
+say key_nav_ioselect "選擇輸出/入點"
+
+# phase 5A
+
+say cannot "不能"
+say cancel "取消"
+say apply "使用"
+say ok "好"
+say popup_open "打開"
+say popup_insert "嵌入物件"
+say popup_properties "內容"
+say popup_clear_wires "清除通路"
+say popup_auto_wire "移除物件"
+say popup_help "輔助"
+say filter "過濾: "
+say how_many_object_classes "%d of %d object classes"
+say do_what_i_mean "照我意思做"
+say save_changes? "確定存檔?"
+say reset "重新設定"
+say Courier "Courier (monospaced)"
+say Helvetica "Helvetica (sansserif)"
+say Times "Times (serif)"
+say add "加入"
+say up "上移"
+say down "下移"
+say remove "移除"
+say lib_add "add the name you typed to the list"
+say lib_up "swap order with previous library"
+say lib_down "swap order with next library"
+say lib_remove "remove library selected in the list"
+say dir_add "add a folder using a file dialog"
+say dir_up "swap order with previous folder"
+say dir_down "swap order with next folder"
+say dir_remove "remove folder selected in the list"
+say client_class_tree "客戶端類別樹"
+say clipboard_view "閱覽筆記板"
+say command_history_view "閱覽旨令歷史記錄"
+say event_history_view "閱覽事件歷史記錄"
+say keyboard_view "顯示鍵盤"
+say abort_server "強迫中止伺服器"
+# during/after piksel:
+
+say auto_apply "自動更新"
+say font_preview "預覽:"
+say font_preview_2 "ABCDEFGHIJKLMNOPQRSTUVWXYZ\nabcdefghijklmnopqrstuvwxyz\n0123456789"
+say font_style "形態:"
+say font_bold "粗體"
+say font_italic "斜體"
+say font_family "字體名:"
+say font_size "大小:"
+say damn "可惡!"
+say preset "預設"
+say console "儲存旨令行數"
+say language "語言"
+say pointer_sense "滑鼠游標敏感度"
+say clear_selection "全部反選"
+say popup_remove_from_path "移除通路中物件"
+say popup_delete_from_path "刪除通路中物件"
+say popup_copy_id "考背愛低"
+
diff --git a/desiredata/src/locale/dansk.tcl b/desiredata/src/locale/dansk.tcl
new file mode 100644
index 00000000..4c789f15
--- /dev/null
+++ b/desiredata/src/locale/dansk.tcl
@@ -0,0 +1,564 @@
+#!/usr/bin/env tclsh
+# $Id: dansk.tcl,v 1.1.2.2 2007-08-18 18:01:10 matju Exp $
+# Danish translations for PureData
+# by Steffen Leve Poulsen
+
+### Menus
+
+say file "Fil"
+ say new_file "Ny fil"
+ say open_file "bn fil..."
+ say server_prefs "Server Preferenser..."
+ say client_prefs "Klient Preferenser..."
+ say send_message "Send besked..."
+ say paths "Stier..."
+ say close "Luk"
+ say save "Gem"
+ say save_as "Gem som..."
+ say print "Udskriv..."
+ say abort_server "Stop server"
+ say quit "Afslut"
+
+ say canvasnew_file "Ny Fil"
+ say canvasopen_file "bn Fil..."
+ say canvassave "Gem"
+ say canvassave_as "Gem som..."
+ say clientpdrc_editor ".pdrc reidgering"
+ say clientddrc_editor ".ddrc redigering"
+ say canvasclose "Luk"
+ say canvasquit "Afslut"
+
+say edit "Rediger"
+ say undo "Fortryd"
+ say redo "Genskab"
+ say cut "Klip"
+ say copy "Kopier"
+ say paste "St ind"
+ say duplicate "Dubler"
+ say select_all "Vlg alt"
+ say clear_selection "Afvlg"
+ say text_editor "Tekstredigering..."
+ say font "Font"
+ say tidy_up "Ordn"
+ say edit_mode "Rediger"
+ say editmodeswitch "Rediger/Kr tilstand"
+ say subpatcherize "Gr til underlap"
+
+ say canvascut "Klip"
+ say canvascopy "Kopier"
+ say canvasundo "Fortryd"
+ say canvasredo "Genskab"
+ say canvaspaste "St ind"
+ say canvasduplicate "Dubler"
+ say canvasselect_all "Vlg alt"
+ say canvaseditmodeswitch "Rediger/Kr tilstand"
+
+say view "Se"
+ say reload "bn igen"
+ say redraw "Gentegn"
+
+ say canvasreload "bn igen"
+ say canvasredraw "Gentegn"
+
+say find "Sg"
+ say find_again "Sg igen"
+ say find_last_error "Find sidste fejl"
+ say string "Find streng"
+say canvasfind "Sg"
+ say canvasfind_again "Sg igen"
+
+# contents of Put menu is Phase 5C
+say put "Indst"
+ say Object "Objekt"
+ say Message "Besked"
+ say Number "Tal"
+ say Symbol "Symbol"
+ say Comment "Kommentar"
+ say Graph "Graf"
+ say Array "Tabel"
+
+say media "Medier"
+ say audio_on "Start lyd"
+ say audio_off "Stop lyd"
+ say test_audio_and_midi "Test lyd og MIDI"
+ say load_meter "Belastning"
+
+ say canvasaudio_on "Start lyd"
+ say canvasaudio_off "Stop lyd"
+ say clienttest_audio_and_midi "Test lyd og MIDI"
+ say canvasload_meter "Belastning"
+
+say window "Vindue"
+
+say help "Hjlp"
+ say about "Om..."
+ say documentation "Dokumentation..."
+ say class_browser "Se klasser..."
+
+ say canvasabout "Om..."
+
+say properties "Egenskaber"
+say open "bn"
+
+### for key binding editor
+say general "Generelt"
+say audio_settings "Lyd indstillinger"
+say midi_settings "MIDI indstillinger"
+say latency_meter "Forsinkelse"
+say Pdwindow "Pd vindue"
+
+say canvaspdwindow "Pd vindue"
+say canvaslatency_meter "Forsinkelse"
+say clientaudio_settings "Lyd indstillinger"
+say clientmidi_settings "MIDI indstillinger"
+
+### for Properties Dialog (phase 5B)
+say_category IEM
+say w "bredde(px)"
+say h "hjde(px)"
+say hold "vis (ms)"
+say break "afbryd (ms)"
+say min "minimum vrdi"
+say max "maximum vrdi"
+say is_log "modus"
+say linear "liner"
+say logarithmic "logaritmisk"
+say isa "startvrdi"
+say n "antal valg"
+say steady "reaktion"
+say steady_no "Hop ved klik"
+say steady_yes "Bliv ved klik"
+say snd "sende-navn"
+say rcv "modtage-navn"
+say lab "etiket"
+say ldx "etiket x afst"
+say ldy "etiket y afst"
+say fstyle "Udseende"
+say fs "font strrelse"
+say bcol "baggrundsfarve"
+say fcol "forgrundsfarve"
+say lcol "farve etiket"
+say yes "ja"
+say no "nej"
+say courier "courier (typewriter)"
+say helvetica "helvetica (sansserif)"
+say times "times (serif)"
+say coords "vis p forldre"
+
+say_category GAtomProperties
+say width "bredde"
+say lo "nedre grnse"
+say hi "vre grnse"
+say label "etiket"
+say wherelabel "vis label"
+say symto "sende-navn"
+say symfrom "modtage-navn"
+
+say_category GraphProperties
+say x1 "x fra"
+say x2 "x til"
+say xpix "bredde"
+say y2 "y fra"
+say y1 "y til"
+say ypix "hjde"
+
+say_category CanvasProperties
+#say xscale "X enheder/px"
+#say yscale "Y enheder/px"
+say gop "vis p forlder"
+say xmargin "x margen"
+say ymargin "y margen"
+say height "hjde"
+say_category ArrayProperties
+say name "navn"
+say n "strrelse"
+say xfrom "x fra"
+say xto "x til"
+say yfrom "y fra"
+say yto "y til"
+
+
+say_category MainWindow
+say in "ind"
+say out "ud"
+say audio "Lyd"
+say meters "Meter"
+say io_errors "IO fejl"
+say tcl_console "Tcl Klient"
+say pd_console "Pd Server"
+
+### phase 2
+
+say_category Other
+say_namespace summary {
+ say_category IEMGUI
+ say bng "Bang Boks"
+ say tgl "Toggle Boks"
+ say nbx "Tal Boks (IEM)"
+ say hsl "Fader (vandret)"
+ say vsl "Fader (lodret)"
+ say hradio "Valgboks (vandret)"
+ say vradio "Valgbox (lodret)"
+ say cnv "Lrred (IEM)"
+ say dropper "Trk og slip box"
+ say vu "Vumeter"
+
+ say_category GLUE
+ say bang "send et bang"
+ say float "gem og genkald decimaltal"
+ say symbol "gem og genkald symbol"
+ say int "gem og genkald heltal"
+ say send "send besked til objekt med navn"
+ say receive "modtag sendte beskeder"
+ say select "vlg symbol eller tal"
+ say route "rute efter frste element"
+ say pack "pak elementer"
+ say unpack "pak elementer ud"
+ say trigger "rkkeflge og omdannelse"
+ say spigot "afbryder"
+ say moses "del talstrm"
+ say until "gentagne bangs"
+ say print "skriv til promt"
+ say makefilename "formater navn med variabel"
+ say change "fjern gentagelser"
+ say swap "ombyt to tal"
+ say value "global variabel"
+
+ say_category TIME
+ say delay "forsink bang"
+ say metro "metronom"
+ say line "skridtvis liner interpolation"
+ say timer "ml tid mellem beskeder"
+ say cputime "ml CPU tid"
+ say realtime "ml reel tid"
+ say pipe "dynamisk voksende forsinkelse af tal"
+
+ say_category MATH
+ say + "adder"
+ say - "subtraher"
+ say * "multiplicer"
+ say {/ div} "divider"
+ say {% mod} "heltal modulus"
+ say pow "eksponent"
+ say == "ens?"
+ say != "forskellig?"
+ say > "strrer end?"
+ say < "mindre end?"
+ say >= "strrer eller lig med?"
+ say <= "mindre eller lig med?"
+ say & "bitmssig (og)"
+ say | "bitmssig (eller)"
+ say && "boelsk (og)"
+ say || "boelsk (eller)"
+ say mtof "MIDI til Hertz"
+ say ftom "Hertz til MIDI"
+ say powtodb "W til dB"
+ say dbtopow "dB til W"
+ say rmstodb "Volt til dB"
+ say dbtorms "dB til Volt"
+ say {sin cos tan atan atan2 sqrt} "trigonometri"
+ say log "Euler logaritme"
+ say exp "Euler exponentiale"
+ say abs "absolutte vrdi"
+ say random "tilfldigt heltal"
+ say max "strst af to tal"
+ say min "mindst af to tal"
+ say clip "klip tal hvis udenfor grnser"
+
+ say_category MIDI
+ say {notein ctlin pgmin bendin touchin polytouchin midiin sysexin} "MIDI ind"
+ say {noteout ctlout pgmout bendout touchout polytouchout midiout} "MIDI ud"
+ say makenote "formater miditone"
+ say stripnote "fjern \"note off\" beskeder"
+
+ say_category TABLES
+ say tabread "ls tal fra tabel"
+ say tabread4 "ls tal fra tabel, med kubisk interpolation"
+ say tabwrite "skriv tal ind i tabel"
+ say soundfiler "ls og skriv tabeller"
+
+ say_category MISC
+ say loadbang "bang ved start"
+ say serial "serielport (kun NT)"
+ say netsend "send bekeder via netvrk"
+ say netreceive "modtag beskeder fra netvrk"
+ say qlist "besked sequencer"
+ say textfile "fil til besked konverter"
+ say openpanel "\"bn\" dialog"
+ say savepanel "\"Gem som\" dialog"
+ say bag "talst"
+ say poly "polyfonisk stemmekontrol"
+ say {key keyup} "tastaturvrdier"
+ say keyname "tastnavn"
+
+ say_category "Signal matematik"
+ foreach word {+ - * /} {say $word~ "[say $word] (for signals)"}
+ say max~ "strst af to signaler"
+ say min~ "mindst af to signaler"
+ say clip~ "begrns signal"
+ say q8_rsqrt~ "billig omvendt kvadratrod (8 bit!)"
+ say q8_sqrt~ "billig kvadratrod (8 bit!)"
+ say wrap~ "decimaldel af signal"
+ say fft~ "compleks diskret Fourier transformation"
+ say ifft~ "omvendt compleks diskret Fourier transformation"
+ say rfft~ "reel diskret Fourier transformation"
+ say rifft~ "omvendt reel diskret Fourier transformation"
+ say framp~ "rampe per blok"
+ foreach word {mtof ftom rmstodb dbtorms rmstopow powtorms} {
+ say $word~ "[say $word] (for signals)"
+ }
+}
+
+### phase 3
+
+say_namespace summary {
+ say_category "LYD LIM"
+ say dac~ "lyd ud"
+ say adc~ "lyd ind"
+ say sig~ "konverter tal til signal"
+ say line~ "signal rampe"
+ say vline~ "deluxe line~"
+ say threshold~ "find signalgrnse"
+ say snapshot~ "konverter signal til tal"
+ say vsnapshot~ "deluxe snapshot~"
+ say bang~ "bang efter hver blok"
+ say samplerate~ "hent samplefrekvens"
+ say send~ "send et signal til mange modtagere"
+ say receive~ "modtag fra send~"
+ say throw~ "mange signalafsendere til en modtager"
+ say catch~ "modtag fra throw~"
+ say block~ "st blokstrrelse og overlap"
+ say switch~ "tnd/sluk DSP lokalt"
+ say readsf~ "afspil lydfil fra hrdskive"
+ say writesf~ "optag lyd p hrdskive"
+
+ say_category "signal oscillatorer og tabeller"
+ say phasor~ "savtak-generator"
+ say {cos~ osc~} "cubisk interpoleret cosinus tabelopslag"
+ say tabwrite~ "skriv signal til tabel"
+ say tabplay~ "afspil tabel (uden transponering)"
+ say tabread~ "ikke interpoleret tabelafspilning"
+ say tabread4~ "kubisk interpoleret tabelafspilning"
+ say tabosc4~ "tabel oscillator"
+ say tabsend~ "skriv en blok kontinuerligt til tabel"
+ say tabreceive~ "ls en blok kontinuerligt fra tabel"
+
+ say_category "Signal filtre"
+ say vcf~ "volt controlleret filter"
+ say noise~ "hvid stj"
+ say env~ "flg signal"
+ say hip~ "hjpas filter"
+ say lop~ "lavpas filter"
+ say bp~ "bndpas filter"
+ say biquad~ "2-pol-2-nul-filter"
+ say samphold~ "sample og frys dims"
+ say print~ "skriv en eller flere \"blocks\" ud"
+ say rpole~ "en pol reel filter"
+ say rzero~ "et nul reel filter"
+ say rzero_rev~ "[say rzero~] (baglns)"
+ say cpole~ "[say rpole~] (kompleks)"
+ say czero~ "[say rzero~] (kompleks)"
+ say czero_rev~ "[say rzero_rev~] (kompleks)"
+
+ say_category "AUDIO DELAY"
+ say delwrite~ "forsink"
+ say delread~ "ls efter forsinkelse"
+ say vd~ "ls efter varieret forsinkelse"
+
+ say_category "SUBWINDOWS"
+ say pd "definer undervindue"
+ say table "tabel i undervindue"
+ say inlet "tilfj indgang til et vindue"
+ say outlet "tilfj udgang fra et vindue"
+ say inlet~ "[say inlet] (signal)"
+ say outlet~ "[say outlet] (signal)"
+
+ say_category "DATA skabeloner"
+ say struct "definer en data struktur"
+ say {drawcurve filledcurve} "tegn en kurve"
+ say {drawpolygon filledpolygon} "tegn en polygon"
+ say plot "tegn en tabel"
+ say drawnumber "skriv et tal"
+
+ say_category "ACCESSING DATA"
+ say pointer "peg p et objekt der hrer til en skabelon"
+ say get "hent numeriske felt"
+ say set "skift numerisk felt"
+ say element "hent element fra tabel"
+ say getsize "hent strrelse p tabel"
+ say setsize "st lngde p tabel"
+ say append "tilfj element til liste"
+ say sublist "peger p start af undertabel"
+ say scalar "tegn skalar p forlder"
+
+ say_category "FOORLDET"
+ say scope~ "(brug tabwrite~ nu)"
+ say namecanvas "" ;# what was this anyway?
+ say template "(brug struct)"
+}
+
+# phase 4 (pdrc & ddrc)
+
+say section_audio "Lyd"
+ say -r "sample rate"
+ say -audioindev "LYD-ind enheder"
+ say -audiooutdev "LYD-ud enheder"
+ say -inchannels "antal lydkanaler ind (per enhed, som \"2\" or \"16,8\")"
+ say -outchannels "antal lydkanaler ud (samme)"
+ say -audiobuf "Lydbuffer i millisekunder"
+ say -blocksize "specificer lyd I/O blok i samples"
+ say -sleepgrain "specificer pause i millisekunder ved ledighed"
+ say -nodac "ingen lyd ud"
+ say -noadc "ingen lyd ind"
+ say audio_api_choice "Audio API"
+ say default "forudindstillet"
+ say -alsa "brug ALSA lyd API"
+ say -jack "brug JACK lyd API"
+ say -mmio "brug MMIO lyd API (forudindstillet til Windows)"
+ say -portaudio "brug ASIO lyd (via Portaudio)"
+ say -oss "brug OSS lyd API"
+ say -32bit "tillad 32 bit OSS lyd (til RME Hammerfall)"
+ say {} "forudindstillet"
+
+say section_midi "MIDI"
+ say -nomidiin "ingen MIDI ind"
+ say -nomidiout "ingen MIDI ud"
+ say -midiindev "midi ind enhedsliste; e.g., \"1,3\" frste og tredje"
+ say -midioutdev "midi ud enhedsliste (samme format)"
+
+say section_externals "Eksterne biblioteker"
+ say -path "fil sgesti"
+ say -helppath "hjlpefil sgesti"
+ say -lib "bn biblioteker"
+
+say section_gui "Gooey"
+ say -nogui "ingen grafisk brugerflade (pas p)"
+ say -guicmd "brug anden grafisk brugerflade (e.g., rsh)"
+ say -look "knap ikoner"
+ say -font "st forudindstillet fontstrrelse i points"
+
+say section_other "Andet"
+ say -open "bn fil(er) ved start"
+ say -verbose "ekstra beskeder ved opstart og filsgning"
+ say -d "fejlsgning"
+ say -noloadbang "ingen \[loadbang\]"
+ say -send "send besked ved start (efter alt er bent)"
+ say -listdev "list lyd og MIDI enheder ved start"
+ say -realtime "brug real-time priority (behver root privilege)"
+
+say section_paths "Stier"
+
+# phase 4B: ddrc (keyword names not finalized!)
+say console "spol antal linier tilbage i konsollen (0 = skriv ikke til konsol)"
+say lang "Sprog"
+say pointer_sense "Musens flsomhed"
+say section_color "farver"
+ say canvas_color "lrred"
+ say canvasbgedit "farve p lrred ved redigering"
+ say canvasbgrun "farve p lrred ved Kr"
+ say object_color "objekt"
+ say viewframe1 "farve p objektboks"
+ say viewframe2 "farve p objektboks"
+ say viewframe3 "farve p objektboks"
+ say viewframe4 "farve p valgt objektboks"
+ say viewbg "baggrundsfarve p objektboks"
+ say viewfg "forgrundsfarve p objektboks"
+ say commentbg "baggrundsfarve p kommentar"
+ say commentfg "forgrundsfarve p kommentar"
+ say commentframe1 "ramme p kommentar"
+ say commentframe2 "ramme p kommentar"
+ say commentframe3 "ramme p kommentar"
+ say viewselectframe "valgt boks"
+ say wire_color "trd"
+ say wirefg "trd farve"
+ say wirefg2 "valgt trd"
+ say wiredspfg "signaltrd"
+ say futurewiredash "ny (stiplet) trd"
+ say others_color "andet"
+ say boxinletfg "farve p indgang"
+ say boxoutletfg "farve p udgang"
+ say selrectrect "valgt omrde"
+say keys "taster"
+say others "andet"
+say hairstate "aktiver kors"
+say hairsnap "snap kors til objekt"
+say statusbar "Aktiver statusvisning"
+say buttonbar "Aktiver objekt knapper"
+say menubar "Aktiver menubar"
+say scrollbar "Aktiver autospoleknap"
+say wirearrow "trd pil"
+say tooltip "Vrktjstip"
+say insert_object "Indst objekt"
+say chain_object "Forbind objekt(er)"
+say clear_wires "Fjern trde"
+say auto_wire "Fjern objekt"
+say subpatcherize "Subpatcherize"
+say keynav "tastatur navigation"
+say key_nav_up "flyt op"
+say key_nav_up_shift "plus select"
+say key_nav_down "flyt ned"
+say key_nav_down_shift "plus select"
+say key_nav_right "flyt til hjre"
+say key_nav_right_shift "plus select"
+say key_nav_left "flyt til venstre"
+say key_nav_left_shift "plus select"
+say key_nav_ioselect "vlg ind/udgang"
+# phase 5A
+
+say cannot "Kan ikke"
+say cancel "fortryd"
+say apply "Gr det"
+say ok "OK"
+say popup_open "bn"
+say popup_insert "St ind"
+say popup_properties "Egenskaber"
+say popup_clear_wires "Slet trde"
+say popup_remove_from_path "Fjern objekt fra sti"
+say popup_delete_from_path "Slet objekt fra sti"
+say popup_help "Hjlp"
+say filter "Filter: "
+say how_many_object_classes "%d af %d objektklasser"
+say do_what_i_mean "Gr hvad jeg mener"
+say ask_cool "Det ville have vret fedt at kunne gre, ikk?"
+say save_changes? "Gem ndringer?"
+say reset "Nulstil"
+say Courier "Courier (monospaced)"
+say Helvetica "Helvetica (sansserif)"
+say Times "Times (serif)"
+say add "Tilfj"
+say up "Op"
+say down "Ned"
+say remove "Fjern"
+say lib_add "tilfj bibliotek til listen"
+say lib_up "byt med forrige bibliotek"
+say lib_down "byt med nste bibliotek"
+say lib_remove "fjern valgte fra listen"
+say dir_add "tilfj mappe vha. dialog"
+say dir_up "byt med forrige mappe"
+say dir_down "byt med nste mappe"
+say dir_remove "fjern valgt mappe fra listen"
+say client_class_tree "Klient klasse tr"
+say clipboard_view "Se klipbord"
+say command_history_view "se kommando historie"
+say event_history_view "se handlings historie"
+
+# during/after piksel:
+
+say auto_apply "Automatisk"
+say font_preview "Se:"
+say font_preview_2 "ABCDEFGHIJKLMNOPQRSTUVWXYZ\nabcdefghijklmnopqrstuvwxyz\n0123456789"
+say font_style "Stil:"
+say font_bold "Fremhvet"
+say font_italic "Skr"
+say font_family "Navn:"
+say font_size "Strrelse:"
+say damn "Pokkers!"
+say console_clear "Slet indholdet i konsollen"
+say horizontal "Vandret"
+say vertical "Lodret"
+say language "Sprog"
+
+# 2007:
+
+say no_matches "(ingen svarer til)"
+say preset "forudsat"
diff --git a/desiredata/src/locale/deutsch.tcl b/desiredata/src/locale/deutsch.tcl
new file mode 100644
index 00000000..439e672b
--- /dev/null
+++ b/desiredata/src/locale/deutsch.tcl
@@ -0,0 +1,280 @@
+#!/usr/bin/env tclsh
+# German translations for PureData
+# $Id: deutsch.tcl,v 1.1.2.13 2006-11-25 01:45:05 matju Exp $
+# by Max Neupert, Georg Holzmann, Thomas Grill
+
+say file "Datei"
+ say new_file "Neu"
+ say open_file "ffnen..."
+ say pdrc_editor ".pdrc Editor"
+ say send_message "Sende Nachricht..." ;# georg&foo say "Message"
+ say paths "Pfade..."
+ say close "Schlieen"
+ say save "Speichern"
+ say save_as "Speichern Unter..."
+ say print "Drucken..."
+ say quit "Beenden"
+
+say edit "Bearbeiten"
+ say undo "Rckgngig"
+ say redo "Wiederherstellen"
+ say cut "Ausschneiden"
+ say copy "Kopieren"
+ say paste "Einfgen"
+ say duplicate "Duplizieren"
+ say select_all "Alles auswhlen"
+ say text_editor "Texteditor..."
+ say tidy_up "Aufrumen"
+ say edit_mode "Editiermodus" ;# georg says "Edit Modus"
+
+say view "Ansicht"
+ say reload "Neu Laden"
+ say redraw "Neu Zeichnen"
+
+say find "Suchen"
+ say find_again "Weitersuchen" ;# georg: "Suche Nochmal"
+ say find_last_error "Finde letzten Fehler" ;# georg: "Finde Letzten Error"
+
+say put "Erstelle"
+
+say media "Media"
+ say audio_on "Audio AN"
+ say audio_off "Audio AUS"
+
+say window "Fenster"
+
+say help "Hilfe"
+ say about "ber..."
+ say pure_documentation "Pure Documentation..."
+ say class_browser "Class Browser..."
+
+
+
+### Main Window
+
+say in "Eingang"
+say out "Ausgang"
+say audio "Audio"
+say meters "Pegel"
+say io_errors "IO Fehler"
+
+
+say_namespace summary {
+ say_category "IEMGUI"
+ say bng "Bang-Feld"
+ say tgl "Schalter"
+ say nbx "Zahlenfeld (IEM)"
+ say hsl "Schieberegler (Horizontal)"
+ say vsl "Schieberegler (Vertical)"
+ say hradio "Radioknopf (Horizontal)"
+ say vradio "Radioknopf (Vertical)"
+ say cnv "Hintergrund (IEM)"
+ say vu "VU-Pegel"
+ say dropper "\"Drag-and-Drop\" Box"
+
+ say_category "GLUE"
+ say bang "Bang-Nachricht ausgeben"
+ say float "Zahl speichern und abrufen"
+ say symbol "Symbol speichern und abrufen"
+ say int "Ganzzahl speichern und abrufen"
+ say send "Nachricht an benanntes Objekt schicken"
+ say receive "Nachrichten empfangen"
+ say select "auf bereinstimmende Symbole oder Zahlen prfen"
+ say route "Nachrichten gem ihrem ersten Element umleiten"
+ say pack "Nachrichten packen"
+ say unpack "gepackte Nachrichten auflsen"
+ say trigger "Nachrichten auslsen und umwandeln"
+ say spigot "eine steuerbare Nachrichtenverbindung"
+ say moses "einen Zahlenstrom aufteilen"
+ say until "Schleife"
+ say print "Ausgabe in Konsole umleiten"
+ say makefilename "Symbol mit Variable formatieren"
+ say change "entfernt wiederholte Nachrichten"
+ say swap "zwei Zahlen austauschen"
+ say value "gemeinsamer Zahlenspeicher"
+
+ say_category "TIME"
+ say delay "verzgert Nachrichten"
+ say metro "sendet Nachrichten im Takt"
+ say line "interpoliert zwischen zwei Zahlen"
+ say timer "misst Zeitabstnde"
+ say cputime "Prozessorzeit-Messung"
+ say realtime "Echtzeit-Messung"
+ say pipe "dynamisch verlngerbare Verzgerungsstrecke"
+
+ say_category "MATH"
+ say + "addieren"
+ say - "subtrahieren"
+ say * "multiplizieren"
+ say {/ div} "dividieren"
+ say {% mod} "Divisionsrest"
+ say pow "potenzieren"
+ say == "gleich?"
+ say != "ungleich?"
+ say > "grer als?"
+ say < "kleiner als?"
+ say >= "grer gleich?"
+ say <= "kleiner gleich?"
+ say & "bitweise UND-Funktion"
+ say | "bitweise ODER-Funktion"
+ say && "logische UND-Funktion "
+ say || "logische ODER-Funktion"
+ say mtof "MIDI zu Hertz Umrechnung"
+ say ftom "Hertz zu MIDI Umrechnung"
+ say powtodb "Watt zu dB Umrechnung"
+ say dbtopow "dB zu Watt Umrechnung"
+ say rmstodb "Volt zu dB Umrechnung"
+ say dbtorms "dB zu Volt Umrechnung"
+ say {sin cos tan atan atan2 sqrt} "Trigonometrie"
+ say log "natrlicher Logarithmus"
+ say exp "Exponentialfunktion"
+ say abs "absoluter Wert"
+ say random "Zufallszahl"
+ say max "grere zweier Zahlen"
+ say min "kleinere zweier Zahlen"
+ say clip "Begrenzung einer Zahlenreihe"
+
+ say_category "MIDI"
+ say {notein ctlin pgmin bendin touchin polytouchin midiin sysexin} \
+"MIDI Eingang"
+ say {noteout ctlout pgmout bendout touchout polytouchout midiout} \
+"MIDI Ausgang"
+ say makenote \
+ "eine verzgerte \"note off\" Nachricht nach einer \"noteon\"-Nachricht einplanen"
+ say stripnote "entferne \"note off\" Nachrichten"
+
+ say_category "TABLES"
+ say tabread "liest Zahl aus einer Tabelle"
+ say tabread4 "liest Zahl aus einer Tabelle, mit 4-Punkt-Interpolation"
+ say tabwrite "schreibt Zahl in eine Tabelle"
+ say soundfiler "schreibt und liest Samples in/aus einer Tabelle"
+
+ say_category "MISC"
+ say loadbang "Bang beim ffnen der Datei"
+ say serial "Serielle Schnittstelle, nur NT"
+ say netsend "sendet Nachrichten ber das Netzwerk"
+ say netreceive "empfngt Nachrichten ber das Netzwerk"
+ say qlist "Nachrichten-Sequenzer"
+ say textfile "Datei zu Nachricht bersetzung"
+ say openpanel "\"ffnen...\" Dialog"
+ say savepanel "\"Speichern unter...\" Dialog"
+ say bag "Zahlenpaar"
+ say poly "Polyphone Stimmenbelegung"
+ say {key keyup} "Numerische Tastenwerte der Tastatur"
+ say keyname "Symbolischer Tastenname"
+
+ say_category "AUDIO MATH"
+ foreach word {+ - * /} {say $word~ "[say $word] (fr Audiosignale)"}
+ say max~ "Maximum eines Audiosignals"
+ say min~ "Minimum eines Audiosignals"
+ say clip~ "begrenzt ein Audiosignal von unten und oben"
+ say q8_rsqrt~ "schnelle reziproke Quadratwurzel (Achtung! - 8 Bit)"
+ say q8_sqrt~ "schnelle Quadratwurzel (Achtung! - 8 Bit)"
+ say wrap~ "wraparound (fractional part, sort of)"
+ say fft~ "komplexe Fouriertransformation vorwrts"
+ say ifft~ "komplexe inverse Fast-Fouriertransformation"
+ say rfft~ "reelle Fouriertransformation vorwrts"
+ say rifft~ "reelle inverse Fast-Fouriertransformation"
+ say framp~ "erzeugt eine Rampe fr jeden Block"
+ foreach word {mtof ftom rmstodb dbtorms rmstopow powtorms} {
+ say $word~ "[say $word] (fr Audiosignale)"
+ }
+}
+
+### phase 3
+
+say_namespace summary {
+ say_category "AUDIO GLUE"
+ say dac~ "Audio Ausgabe"
+ say adc~ "Audio Eingabe"
+ say sig~ "wandelt Zahlen in Audiosignal um"
+ say line~ "generiert Audio Rampen"
+ say vline~ "deluxe line~"
+ say threshold~ "erkennt Schwellenwerte des Audiosignals"
+ say snapshot~ "tastet ein Audiosignal ab (konvertiert es zu Zahlen)"
+ say vsnapshot~ "deluxe snapshot~"
+ say bang~ "sendet Bang nach jedem DSP-Block"
+ say samplerate~ "gibt die Abtastrate aus"
+ say send~ "nonlocal signal connection with fanout"
+ say receive~ "empfngt Audiosignal von send~"
+ say throw~ "fgt Audiosignal zu einem sich summierenden Bus zu"
+ say catch~ "definiert und liest einen Bus"
+ say block~ "legt Block-Gre und berlappung fest"
+ say switch~ "schaltet DSP-Berechnung an/aus"
+ say readsf~ "spielt Audiodateien von Festplatte ab"
+ say writesf~ "nimmt Audio auf Festplatte auf"
+
+ say_category "AUDIO-OSZILLATOREN AND TABELLEN"
+ say phasor~ "Sgezahn-Oszillator"
+ say {cos~ osc~} "Cosinus-Oszillator"
+ say tabwrite~ "in eine Tabelle schreiben"
+ say tabplay~ "aus einer Tabelle abspielen (nicht-transponierend)"
+ say tabread~ "Tabelle auslesen (ohne Interpolation)"
+ say tabread4~ "Tabelle auslesen (mit Vier-Punkt Interpolation)"
+ say tabosc4~ "wavetable Oszillator"
+ say tabsend~ "einen Block kontinuierlich in eine Tabelle schreiben"
+ say tabreceive~ "einen Block kontinuierlich aus einer Tabelle lesen"
+
+ say_category "AUDIO FILTER"
+ say vcf~ "Spannungsgesteuerter Filter"
+ say noise~ "generiert weies Rauschen"
+ say env~ "Hllkurven-Abtaster"
+ say hip~ "Hochpassfilter"
+ say lop~ "Tiefpassfilter"
+ say bp~ "Bandpassfilter"
+ say biquad~ "grober Filter"
+ say samphold~ "sample and hold unit"
+ say print~ "print out one or more \"blocks\""
+ say rpole~ "raw real-valued one-pole filter"
+ say rzero~ "raw real-valued one-zero filter"
+ say rzero_rev~ "[say rzero~] (time-reversed)"
+ say cpole~ "[say rpole~] (complex-valued)"
+ say czero~ "[say rzero~] (complex-valued)"
+ say czero_rev~ "[say rzero_rev~] (complex-valued)"
+
+ say_category "AUDIO VERZGERUNG"
+ say delwrite~ "in eine Verzgerungsstrecke schreiben"
+ say delread~ "von einer Verzgerungsstrecke lesen"
+ say vd~ "von einer Verzgerungsstrecke in variabler Verzgerungszeit lesen"
+
+ say_category "UNTERFENSTER"
+ say pd "definiere ein Unterfenster"
+ say table "Zahlentabelle in einem Unterfenster"
+ say inlet "Eingang hinzufgen"
+ say outlet "Ausgang hinzufgen"
+ say inlet~ "[say inlet] (fr Audiosignale)"
+ say outlet~ "[say outlet] (fr Audiosignale)"
+
+ say_category "DATA TEMPLATES"
+ say struct "define a data structure"
+ say {drawcurve filledcurve} "zeichnet eine Kurve"
+ say {drawpolygon filledpolygon} "zeichnet ein Polygon"
+ say plot "plot an array field"
+ say drawnumber "einen Zahlenwert ausgeben"
+
+ say_category "DATENZUGRIFF"
+ say pointer "point to an object belonging to a template"
+ say get "get numeric fields"
+ say set "legt Wert in Zahlenfeldern fest"
+ say element "get an array element"
+ say getsize "Gre eines Arrays feststellen"
+ say setsize "Gre eines Arrays bestimmen"
+ say append "Element an eine Liste anfgen"
+ say sublist "get a pointer into a list which is an element of another \
+scalar"
+ say scalar "draw a scalar on parent"
+
+ say_category "BERHOLT"
+ say scope~ "(benutze tabwrite~ anstatt)"
+ say namecanvas "" ;# what was this anyway?
+ say template "(benutze struct anstatt)"
+}
+
+say cannot "kann nicht"
+
+say filter "Filter" ;# sorry
+say how_many_object_classes "%d/%d"
+
+say save_changes? "nderungen speichern?"
+
+
diff --git a/desiredata/src/locale/english.tcl b/desiredata/src/locale/english.tcl
new file mode 100644
index 00000000..f4de0445
--- /dev/null
+++ b/desiredata/src/locale/english.tcl
@@ -0,0 +1,573 @@
+#!/usr/bin/env tclsh
+# English translations for PureData
+# $Id: english.tcl,v 1.1.2.34.2.22 2007-09-04 11:24:02 chunlee Exp $
+
+### Menus
+
+say file "File"
+ say new_file "New File"
+ say open_file "Open File..."
+ say server_prefs "Server Preferences..."
+ say client_prefs "Client Preferences..."
+ say send_message "Send Message..."
+ say paths "Paths..."
+ say close "Close"
+ say save "Save"
+ say save_as "Save As..."
+ say print "Print..."
+ say abort_server "Abort Server"
+ say quit "Quit"
+
+ say canvasnew_file "New File"
+ say canvasopen_file "Open File..."
+ say canvassave "Save"
+ say canvassave_as "Save As..."
+ say clientpdrc_editor ".pdrc Editor"
+ say clientddrc_editor ".ddrc Editor"
+ say canvasclose "Close"
+ say canvasquit "Quit"
+
+say edit "Edit"
+ say undo "Undo"
+ say redo "Redo"
+ say cut "Cut"
+ say copy "Copy"
+ say paste "Paste"
+ say duplicate "Duplicate"
+ say select_all "Select All"
+ say clear_selection "Deselect selection"
+ say text_editor "Text Editor..."
+ say font "Font"
+ say tidy_up "Tidy Up"
+ say edit_mode "Edit Mode"
+ say editmodeswitch "Edit/Run mode"
+ say subpatcherize "Subpatcherize"
+
+ say canvascut "Cut"
+ say canvascopy "Copy"
+ say canvasundo "Undo"
+ say canvasredo "Redo"
+ say canvaspaste "Paste"
+ say canvasduplicate "Duplicate"
+ say canvasselect_all "Select All"
+ say canvaseditmodeswitch "Edit/Run mode"
+
+say view "View"
+ say reload "Reload"
+ say redraw "Redraw"
+
+ say canvasreload "Reload"
+ say canvasredraw "Redraw"
+
+say find "Find"
+ say find_again "Find Again"
+ say find_last_error "Find Last Error"
+ say string "Find string"
+say canvasfind "Find"
+ say canvasfind_again "Find Again"
+
+# contents of Put menu is Phase 5C
+say put "Put"
+ say Object "Object"
+ say Message "Message"
+ say Number "Number"
+ say Symbol "Symbol"
+ say Comment "Comment"
+ say Graph "Graph"
+ say Array "Array"
+
+say media "Media"
+ say audio_on "Audio ON"
+ say audio_off "Audio OFF"
+ say test_audio_and_midi "Test Audio and MIDI"
+ say load_meter "Load Meter"
+
+ say canvasaudio_on "Audio ON"
+ say canvasaudio_off "Audio OFF"
+ say clienttest_audio_and_midi "Test Audio and MIDI"
+ say canvasload_meter "Load Meter"
+
+say window "Window"
+
+say help "Help"
+ say about "About..."
+ say documentation "Documentation..."
+ say class_browser "Class Browser..."
+
+ say canvasabout "About..."
+
+say properties "Properties"
+say open "Open"
+
+### for key binding editor
+say general "General"
+say audio_settings "Audio Settings"
+say midi_settings "Midi Settings"
+say latency_meter "Latency Meter"
+say Pdwindow "Pd window"
+
+say canvaspdwindow "Pd window"
+say canvaslatency_meter "Latency Meter"
+say clientaudio_settings "Audio Settings"
+say clientmidi_settings "Midi Settings"
+
+### for Properties Dialog (phase 5B)
+say_category IEM
+say w "width(px)"
+say h "height(px)"
+say hold "hold time(ms)"
+say break "break time(ms)"
+say min "minimum value"
+say max "maximum value"
+say is_log "mode"
+say linear "linear"
+say logarithmic "logarithmic"
+say isa "init"
+say n "number of choices"
+say steady "steadiness"
+say steady_no "jump on click"
+say steady_yes "steady on click"
+say snd "send-symbol"
+say rcv "receive-symbol"
+say lab "label"
+say ldx "label x offset"
+say ldy "label y offset"
+say fstyle "Typeface"
+say fs "font size"
+say bcol "background color"
+say fcol "forground color"
+say lcol "label color"
+say yes "yes"
+say no "no"
+say courier "courier (typewriter)"
+say helvetica "helvetica (sansserif)"
+say times "times (serif)"
+say coords "graph on parent"
+
+say_category GAtomProperties
+say width "width"
+say lo "lower limit"
+say hi "upper limit"
+say label "label"
+say wherelabel "show label on"
+say symto "send symbol"
+say symfrom "receive symbol"
+
+say_category GraphProperties
+say x1 "x from"
+say x2 "x to"
+say xpix "screen width"
+say y2 "y from"
+say y1 "y to"
+say ypix "screen height"
+
+say_category CanvasProperties
+#say xscale "X units/px"
+#say yscale "Y units/px"
+say gop "graph on parent"
+say xmargin "xmargin"
+say ymargin "ymargin"
+say height "height"
+say_category ArrayProperties
+say name "name"
+say n "size"
+say xfrom "x range from"
+say xto "x range to"
+say yfrom "y range from"
+say yto "y range to"
+
+
+say_category MainWindow
+say in "in"
+say out "out"
+say audio "Audio"
+say meters "Meters"
+say io_errors "IO Errors"
+say tcl_console "Tcl Client"
+say pd_console "Pd Server"
+
+### phase 2
+
+say_category Other
+say_namespace summary {
+ say_category IEMGUI
+ say bng "Bang Box"
+ say tgl "Toggle Box"
+ say nbx "Number Box (IEM)"
+ say hsl "Slider (Horizontal)"
+ say vsl "Slider (Vertical)"
+ say hradio "Choice Box (Horizontal)"
+ say vradio "Choice Box (Vertical)"
+ say cnv "Canvas (IEM)"
+ say dropper "Drag-and-Drop Box"
+ say vu "Vumeter"
+
+ say_category GLUE
+ say bang "output a bang message"
+ say float "store and recall a number"
+ say symbol "store and recall a symbol"
+ say int "store and recall an integer"
+ say send "send a message to a named object"
+ say receive "catch sent messages"
+ say select "test for matching numbers or symbols"
+ say route "route messages according to first element"
+ say pack "make compound messages"
+ say unpack "get elements of compound messages"
+ say trigger "sequence and convert messagess"
+ say spigot "interruptible message connection"
+ say moses "part a numeric stream"
+ say until "looping mechanism"
+ say print "print out messages"
+ say makefilename "format a symbol with a variable field"
+ say change "remove repeated numbers from a stream"
+ say swap "swap two numbers"
+ say value "shared numeric value"
+
+ say_category TIME
+ say delay "send a message after a time delay"
+ say metro "send a message periodically"
+ say line "send a series of linearly stepped numbers"
+ say timer "measure time intervals"
+ say cputime "measure CPU time"
+ say realtime "measure real time"
+ say pipe "dynamically growable delay line for numbers"
+
+ say_category MATH
+ say + "add"
+ say - "substract"
+ say * "multiply"
+ say {/ div} "divide"
+ say {% mod} "division remainder"
+ say pow "exponentiate"
+ say == "equal?"
+ say != "not equal?"
+ say > "more than?"
+ say < "less than?"
+ say >= "not less than?"
+ say <= "not more than?"
+ say & "bitwise conjunction (and)"
+ say | "bitwise disjunction (or)"
+ say && "logical conjunction (and)"
+ say || "logical disjunction (or)"
+ say mtof "MIDI to Hertz"
+ say ftom "Hertz to MIDI"
+ say powtodb "Watts to dB"
+ say dbtopow "dB to Watts"
+ say rmstodb "Volts to dB"
+ say dbtorms "dB to Volts"
+ say {sin cos tan atan atan2 sqrt} "trigonometry"
+ say log "Euler logarithm"
+ say exp "Euler exponential"
+ say abs "absolute value"
+ say random "random"
+ say max "greater of two numbers"
+ say min "lesser of two numbers"
+ say clip "force a number into a range"
+
+ say_category MIDI
+ say {notein ctlin pgmin bendin touchin polytouchin midiin sysexin} "MIDI input"
+ say {noteout ctlout pgmout bendout touchout polytouchout midiout} "MIDI output"
+ say makenote "schedule a delayed \"note off\" message corresponding to a note-on"
+ say stripnote "strip \"note off\" messages"
+
+ say_category TABLES
+ say tabread "read a number from a table"
+ say tabread4 "read a number from a table, with 4 point interpolation"
+ say tabwrite "write a number to a table"
+ say soundfiler "read and write tables to soundfiles"
+
+ say_category MISC
+ say loadbang "bang on load"
+ say serial "serial device control for NT only"
+ say netsend "send messages over the internet"
+ say netreceive "receive them"
+ say qlist "message sequencer"
+ say textfile "file to message converter"
+ say openpanel "\"Open\" dialog"
+ say savepanel "\"Save as\" dialog"
+ say bag "set of numbers"
+ say poly "polyphonic voice allocation"
+ say {key keyup} "numeric key values from keyboard"
+ say keyname "symbolic key name"
+
+ say_category "AUDIO MATH"
+ foreach word {+ - * /} {say $word~ "[say $word] (for signals)"}
+ say max~ "supremum of signals"
+ say min~ "infimum of signals"
+ say clip~ "constrict signal to lie between two bounds"
+ say q8_rsqrt~ "cheap reciprocal square root (beware -- 8 bits!)"
+ say q8_sqrt~ "cheap square root (beware -- 8 bits!)"
+ say wrap~ "wraparound (fractional part, sort of)"
+ say fft~ "complex forward discrete Fourier transform"
+ say ifft~ "complex inverse discrete Fourier transform"
+ say rfft~ "real forward discrete Fourier transform"
+ say rifft~ "real inverse discrete Fourier transform"
+ say framp~ "output a ramp for each block"
+ foreach word {mtof ftom rmstodb dbtorms rmstopow powtorms} {
+ say $word~ "[say $word] (for signals)"
+ }
+}
+
+### phase 3
+
+say_namespace summary {
+ say_category "AUDIO GLUE"
+ say dac~ "audio output"
+ say adc~ "audio input"
+ say sig~ "convert numbers to audio signals"
+ say line~ "generate audio ramps"
+ say vline~ "deluxe line~"
+ say threshold~ "detect signal thresholds"
+ say snapshot~ "sample a signal (convert it back to a number)"
+ say vsnapshot~ "deluxe snapshot~"
+ say bang~ "send a bang message after each DSP block"
+ say samplerate~ "get the sample rate"
+ say send~ "nonlocal signal connection with fanout"
+ say receive~ "get signal from send~"
+ say throw~ "add to a summing bus"
+ say catch~ "define and read a summing bus"
+ say block~ "specify block size and overlap"
+ say switch~ "switch DSP computation on and off"
+ say readsf~ "soundfile playback from disk"
+ say writesf~ "record sound to disk"
+
+ say_category "AUDIO OSCILLATORS AND TABLES"
+ say phasor~ "sawtooth oscillator"
+ say {cos~ osc~} "cosine oscillator"
+ say tabwrite~ "write to a table"
+ say tabplay~ "play back from a table (non-transposing)"
+ say tabread~ "non-interpolating table read"
+ say tabread4~ "four-point interpolating table read"
+ say tabosc4~ "wavetable oscillator"
+ say tabsend~ "write one block continuously to a table"
+ say tabreceive~ "read one block continuously from a table"
+
+ say_category "AUDIO FILTERS"
+ say vcf~ "voltage controlled filter"
+ say noise~ "white noise generator"
+ say env~ "envelope follower"
+ say hip~ "high pass filter"
+ say lop~ "low pass filter"
+ say bp~ "band pass filter"
+ say biquad~ "raw filter"
+ say samphold~ "sample and hold unit"
+ say print~ "print out one or more \"blocks\""
+ say rpole~ "raw real-valued one-pole filter"
+ say rzero~ "raw real-valued one-zero filter"
+ say rzero_rev~ "[say rzero~] (time-reversed)"
+ say cpole~ "[say rpole~] (complex-valued)"
+ say czero~ "[say rzero~] (complex-valued)"
+ say czero_rev~ "[say rzero_rev~] (complex-valued)"
+
+ say_category "AUDIO DELAY"
+ say delwrite~ "write to a delay line"
+ say delread~ "read from a delay line"
+ say vd~ "read from a delay line at a variable delay time"
+
+ say_category "SUBWINDOWS"
+ say pd "define a subwindow"
+ say table "array of numbers in a subwindow"
+ say inlet "add an inlet to a pd"
+ say outlet "add an outlet to a pd"
+ say inlet~ "[say inlet] (for signal)"
+ say outlet~ "[say outlet] (for signal)"
+
+ say_category "DATA TEMPLATES"
+ say struct "define a data structure"
+ say {drawcurve filledcurve} "draw a curve"
+ say {drawpolygon filledpolygon} "draw a polygon"
+ say plot "plot an array field"
+ say drawnumber "print a numeric value"
+
+ say_category "ACCESSING DATA"
+ say pointer "point to an object belonging to a template"
+ say get "get numeric fields"
+ say set "change numeric fields"
+ say element "get an array element"
+ say getsize "get the size of an array"
+ say setsize "change the size of an array"
+ say append "add an element to a list"
+ say sublist "get a pointer into a list which is an element of another scalar"
+ say scalar "draw a scalar on parent"
+
+ say_category "OBSOLETE"
+ say scope~ "(use tabwrite~ now)"
+ say namecanvas "" ;# what was this anyway?
+ say template "(use struct now)"
+}
+
+# phase 4 (pdrc & ddrc)
+
+say section_audio "Audio"
+ say -r "sample rate"
+ say -audioindev "audio in devices"
+ say -audiooutdev "audio out devices"
+ say -inchannels "audio input channels (by device, like \"2\" or \"16,8\")"
+ say -outchannels "number of audio out channels (same)"
+ say -audiobuf "specify size of audio buffer in msec"
+ say -blocksize "specify audio I/O block size in sample frames"
+ say -sleepgrain "specify number of milliseconds to sleep when idle"
+ say -nodac "suppress audio output"
+ say -noadc "suppress audio input"
+ say audio_api_choice "Audio API"
+ say default "default"
+ say -alsa "use ALSA audio API"
+ say -jack "use JACK audio API"
+ say -mmio "use MMIO audio API (default for Windows)"
+ say -portaudio "use ASIO audio driver (via Portaudio)"
+ say -oss "use OSS audio API"
+ say -32bit "allow 32 bit OSS audio (for RME Hammerfall)"
+ say {} "default"
+
+say section_midi "MIDI"
+ say -nomidiin "suppress MIDI input"
+ say -nomidiout "suppress MIDI output"
+ say -midiindev "midi in device list; e.g., \"1,3\" for first and third"
+ say -midioutdev "midi out device list, same format"
+
+say section_externals "Externals"
+ say -path "file search path"
+ say -helppath "help file search path"
+ say -lib "load object libraries"
+
+say section_gui "Gooey"
+ say -nogui "suppress starting the GUI (caution)"
+ say -guicmd "substitute another GUI program (e.g., rsh)"
+ say -look "buttonbar icons"
+ say -font "specify default font size in points"
+
+say section_other "Other"
+ say -open "open file(s) on startup"
+ say -verbose "extra printout on startup and when searching for files"
+ say -d "debug level"
+ say -noloadbang "disable the effect of \[loadbang\]"
+ say -send "send a message at startup (after patches are loaded)"
+ say -listdev "list audio and MIDI devices upon startup"
+ say -realtime "use real-time priority (needs root privilege)"
+
+say section_paths "Paths"
+
+# phase 4B: ddrc (keyword names not finalized!)
+say console "console scrollback lines (0 = disable console)"
+say lang "Language to use"
+say pointer_sense "Mouse pointer sensitivity"
+say section_color "Appearance"
+ say canvas_color "canvas"
+ say canvasbgedit "canvas background (edit mode)"
+ say canvasbgrun "canvas background (run mode)"
+ say object_color "object"
+ say viewframe1 "objectbox color"
+ say viewframe2 "objectbox color"
+ say viewframe3 "objectbox color"
+ say viewframe4 "objectbox highlight color"
+ say viewbg "object background"
+ say viewfg "object foreground"
+ say commentbg "comment background"
+ say commentfg "comment forground"
+ say commentframe1 "comment frame"
+ say commentframe2 "comment frame"
+ say commentframe3 "comment frame"
+ say viewselectframe "hilight box"
+ say wire_color "wire"
+ say wirefg "wire color"
+ say wirefg2 "wire highlight"
+ say wiredspfg "dsp wire color"
+ say futurewiredash "new (dashed) wire"
+ say others_color "others"
+ say boxinletfg "inlet color"
+ say boxoutletfg "outlet color"
+ say selrectrect "selection box"
+say keys "keys"
+say others "others"
+say hairstate "Activate crosshair"
+say hairsnap "Crosshair snap to object"
+say statusbar "Activate statusbar"
+say buttonbar "Activate buttonbar"
+say menubar "Activate menubar"
+say scrollbar "Active auto scrollbar"
+say wirearrow "Wire Arrow"
+say tooltip "ToolTip"
+say insert_object "Insert object"
+say chain_object "Chain object"
+say clear_wires "Clear wires"
+say auto_wire "Remove object"
+say subpatcherize "Subpatcherize"
+say keynav "keyboard navigation"
+say key_nav_up "move up"
+say key_nav_up_shift "plus select"
+say key_nav_down "move down"
+say key_nav_down_shift "plus select"
+say key_nav_right "move right"
+say key_nav_right_shift "plus select"
+say key_nav_left "move left"
+say key_nav_left_shift "plus select"
+say key_nav_ioselect "select in/outlets"
+# phase 5A
+
+say cannot "can't"
+say cancel "Cancel"
+say apply "Apply"
+say ok "OK"
+say popup_open "Open"
+say popup_insert "Insert"
+say popup_properties "Properties"
+say popup_clear_wires "Clear wires"
+say popup_remove_from_path "Remove object from path"
+say popup_delete_from_path "Delete object from path"
+say popup_help "Help"
+say filter "Filter: "
+say how_many_object_classes "%d of %d object classes"
+say do_what_i_mean "Do What I Mean"
+say ask_cool "This would be a cool feature, eh?"
+say save_changes? "Save changes?"
+say reset "Reset"
+say Courier "Courier (monospaced)"
+say Helvetica "Helvetica (sansserif)"
+say Times "Times (serif)"
+say add "Add"
+say up "Up"
+say down "Down"
+say remove "Remove"
+say lib_add "add the name you typed to the list"
+say lib_up "swap order with previous library"
+say lib_down "swap order with next library"
+say lib_remove "remove library selected in the list"
+say dir_add "add a folder using a file dialog"
+say dir_up "swap order with previous folder"
+say dir_down "swap order with next folder"
+say dir_remove "remove folder selected in the list"
+say client_class_tree "Client Class Tree"
+say clipboard_view "Clipboard View"
+say command_history_view "Command History View"
+say event_history_view "Event History View"
+
+# during/after piksel:
+
+say auto_apply "Auto-Apply"
+say font_preview "Preview:"
+say font_preview_2 "ABCDEFGHIJKLMNOPQRSTUVWXYZ\nabcdefghijklmnopqrstuvwxyz\n0123456789"
+say font_style "Style:"
+say font_bold "Bold"
+say font_italic "Italic"
+say font_family "Name:"
+say font_size "Size:"
+say damn "Damn!"
+say console_clear "Clear Console"
+say horizontal "Horizontal"
+say vertical "Vertical"
+say language "Language"
+
+# 2007:
+
+say no_matches "(no matches)"
+say preset "preset"
+say canvasgrid "Grid color"
+say grid_size "Grid size"
+say gridstate "Activate background grid"
+say snap_grid "Snap to grid"
+say viewfont "object font"
+say consolefont "console font"
+say keyboarddialogfont "virtual keyboard font"
+say keyboard_view "Virtual keyboard"
+say log_height "Log Height"
+
diff --git a/desiredata/src/locale/espanol.tcl b/desiredata/src/locale/espanol.tcl
new file mode 100644
index 00000000..32a46202
--- /dev/null
+++ b/desiredata/src/locale/espanol.tcl
@@ -0,0 +1,526 @@
+#!/usr/bin/env tclsh
+# Español translations for PureData
+# $Id: espanol.tcl,v 1.1.2.3.2.1 2006-12-05 04:51:47 matju Exp $
+# translated by Mario Mora (makro) & Ramiro Cosentino (rama)
+
+### Menus
+
+say file "Archivo"
+ say new_file "Nuevo Archivo"
+ say open_file "Abrir Archivo..."
+ say pdrc_editor "Editor .pdrc"
+ say send_message "Enviar Mensaje..."
+ say paths "Rutas..."
+ say close "Cerrar"
+ say save "Guardar"
+ say save_as "Guardar Como..."
+ say print "Imprimir..."
+ say quit "Salir"
+
+ say canvasnew_file "Archivo Nuevo"
+ say canvasopen_file "Abrir Archivo..."
+ say canvassave "Guardar"
+ say canvassave_as "Guardar como..."
+ say clientpdrc_editor "Editor .pdrc "
+ say clientddrc_editor "Editor .ddrc "
+ say canvasclose "Cerrar"
+ say canvasquit "Salir"
+
+say edit "Edición"
+ say undo "Deshacer"
+ say redo "Rehacer"
+ say cut "Cortar"
+ say copy "Copiar"
+ say paste "Pegar"
+ say duplicate "Duplicar"
+ say select_all "Seleccionar Todo"
+ say text_editor "Editor de Texto..."
+ say tidy_up "Ordenar"
+ say edit_mode "Modo Edición"
+ say editmodeswitch "Modo edicion/ejecucion"
+
+ say canvascut "Cortar"
+ say canvascopy "Copiar"
+ say canvasundo "Deshacer"
+ say canvasredo "Rehacer"
+ say canvaspaste "Pegar"
+ say canvasselect_all "Seleccionar todo"
+ say canvaseditmodeswitch "Modo edicion/ejecucion"
+
+say view "Ver"
+ say reload "Recargar"
+ say redraw "Refrescar"
+
+ say canvasreload "Recargar"
+ say canvasredraw "Refrescar"
+
+say find "Buscar"
+ say find_again "Buscar Nuevamente"
+ say find_last_error "Buscar Ultimo Error"
+
+say canvasfind "Buscar"
+ say canvasfind_again "Buscar Nuevamente"
+
+# contents of Put menu is Phase 5C
+say put "Poner"
+ say Object "Objeto"
+ say Message "Mensaje"
+ say Number "Numero"
+ say Symbol "Simbolo"
+ say Comment "Comentario"
+ say Canvas "Canvas";#
+ say Array "Deposito";#array as "desposito"?
+
+ say canvasobject "Objeto"
+ say canvasmessage "Mensaje"
+ say canvasnumber "Numero"
+ say canvassymbol "Simbolo"
+ say canvascomment "Comentario"
+ say canvasbang "Bang";#
+ say canvastoggle "Interruptor";# toggle as "interruptor"?
+ say canvasnumber2 "Numero2"
+ say canvasvslider "Deslizador Vertical";#slider as "deslizador"??
+ say canvashslider "Deslizador Horizontal"
+ say canvasvradio "Rango Vertical";#radio as "Rango"??
+ say canvashradio "Rango Horizontal";#
+ say canvascanvas "Canvas";#
+ say canvasarray "Array";#
+
+say media "Media"
+ say audio_on "Audio ON"
+ say audio_off "Audio OFF"
+ say test_audio_and_midi "Probar Audio y MIDI"
+ say load_meter "Medidor de Carga"
+
+ say canvasaudio_on "Audio ON"
+ say canvasaudio_off "Audio OFF"
+ say clienttest_audio_and_midi "Probar Audio y MIDI"
+ say canvasload_meter "Medidor de Carga"
+
+say window "Ventana"
+
+say help "Ayuda"
+ say about "Acerca de..."
+ say pure_documentation "Pura Documentacion..."
+ say class_browser "Navegador de Clases..."
+ say canvasabout "Acerca de..."
+
+say properties "Propiedades"
+say open "Abrir"
+
+### for key binding editor
+say general "General"
+say audio_settings "Configuracion Audio "
+say midi_settings "Configuracion Midi "
+say latency_meter "Medidor de Latencia"
+say Pdwindow "Ventana Pd "
+
+say canvaspdwindow "Ventana Pd"
+say canvaslatency_meter "Medidor de Latencia"
+say clientaudio_settings "Configuracion Audio"
+say clientmidi_settings "Configuracion Midi"
+
+### for Properties Dialog (phase 5B)
+say_category IEM
+say w "ancho(px)"
+say h "alto(px)"
+say hold "tiempo de mantencion(ms)"
+say break "tiempo de quiebre(ms)"
+say min "valor minimo"
+say max "valor maximo"
+say is_log "modo"
+say linear "linear"
+say logarithmic "logaritmico"
+say isa "inicio"
+say n "numero de posibilidades"
+say steady "regularidad"
+say steady_no "saltar en click";#
+say steady_yes "estabilizar en click";#
+say snd "enviar-simbolo"
+say rcv "recibir-simbolo"
+say lab "etiqueta"
+say ldx "etiqueta compensacion x";#
+say ldy "etiqueta compensacion y";#
+say fstyle "Tipografia"
+say fs "Tamaño de fuente"
+say bcol "Color Fondo"
+say fcol "color primer plano"
+say lcol "color etiqueta"
+say yes "si"
+say no "no"
+say courier "courier (typewriter)"
+say helvetica "helvetica (sansserif)"
+say times "times (serif)"
+say coords "grafico en pariente" ;# parent?? as "pariente"??
+
+say_category GAtomProperties
+say width "ancho"
+say lo "limite bajo"
+say hi "limite alto"
+say label "etiquetal"
+say wherelabel "mostrar etiqueta on"
+say symto "enviar simbolo"
+say symfrom "recibir simbolo"
+
+say_category GraphProperties
+say x1 "desde x"
+say x2 "hacia x"
+say xpix "ancho pantalla"
+say y2 "desde y"
+say y1 "hacia y"
+say ypix "altura pantalla"
+
+say_category CanvasProperties
+#say xscale "X units/px"
+#say yscale "Y units/px"
+
+say_category ArrayProperties
+say name "nombre"
+say n "Tamaño"
+
+### Main Window
+say_category MainWindow
+say in "in"
+say out "out"
+say audio "Audio"
+say meters "Medidores"
+say io_errors "Errores de E/S"
+
+### phase 2
+
+say_category Other
+say_namespace summary {
+ say_category IEMGUI
+ say bng "Bang Box";# Caja de bang?
+# say Bang "Bang"
+# say Toggle "Interruptor";# toggle as "interruptor"?
+ say tgl "Toggle Box";#Caja palanca? caja interruptora?
+ say nbx "Number Box (IEM)";#Caja de numeros?
+# say Number2 "Numero2"
+ say hsl "deslizador (Horizontal)";#
+ say vsl "Deslizador (Vertical)";#
+ say hradio "Choice Box (Horizontal)";# Caja seleccionadora?
+ say vradio "Choice Box (Vertical)";#
+# say Vradio "Rango Vertical";#radio as "rango"?
+# say Hradio "Rango Horizontal";#
+ say cnv "Canvas (IEM)"
+ say dropper "Drag-and-Drop Box";#Caja agarrar y soltar?
+ say vu "Vumeter";# medidor VU?
+
+ say_category GLUE
+ say bang "envia un mensaje de bang"
+ say float "guarda y recuerda un numero"
+ say symbol "guarda y recuerda un simbolo"
+ say int "guarda y recuerda un entero"
+ say send "envia un mensaje a un objeto nombrado"
+ say receive "catch sent messages"
+ say select "test para numeros o simbolos coincidentes"
+ say route "rutea mensajes de acuerdo al primer elemento"
+ say pack "genera mensajes compuestos"
+ say unpack "obtiene elementos de mensajes compuestos"
+ say trigger "ordena y convierte mensajes"
+ say spigot "conexion mensajes interrumpible"
+ say moses "divide un flujo de numeros"
+ say until "mecanismo de loop"
+ say print "imprime mensajes"
+ say makefilename "formatea un simbolo con un campo variable";#
+ say change "remover numeros repetidos de un flujo de datos";#
+ say swap "intercambiar dos numeros";#
+ say value "compartir valor numerico"
+
+ say_category TIME
+ say delay "envia un mensaje despues de un retraso de tiempo"
+ say metro "envia un mensaje periodicamente"
+ say line "envia una serie de numeros encaminados linearmente"
+ say timer "medicion de intervalos de tiempo"
+ say cputime "medicion tiempo CPU"
+ say realtime "medicion tiempo real"
+ say pipe "linea de retraso dinamicamente creciente para numeros"
+
+ say_category MATH
+ say + "sumar"
+ say - "sustraer"
+ say * "multiplicar"
+ say {/ div} "dividir"
+ say {% mod} "resto de la division"
+ say pow "exponencial"
+ say == "igual?"
+ say != "no igual?"
+ say > "mas que?"
+ say < "menos que?"
+ say >= "no menos que?"
+ say <= "no mas que?"
+ say & "bitwise conjunction (and)";#bitwise? conjuncion (y)
+ say | "bitwise disjunction (or)";#bitwise? conjuncion (o)
+ say && "conjuncion logica (y)"
+ say || "separacion logica (o)"
+ say mtof "MIDI a Hertz"
+ say ftom "Hertz a MIDI"
+ say powtodb "Watts a dB"
+ say dbtopow "dB a Watts"
+ say rmstodb "Volts a dB"
+ say dbtorms "dB a Volts"
+ say {sin cos tan atan atan2 sqrt} "trigonometria"
+ say log "logaritmo Euler"
+ say exp "exponencial Euler"
+ say abs "valor absoluto"
+ say random "aleatorio"
+ say max "mayor de dos numeros"
+ say min "menor de dos numeros"
+ say clip "fuerza un numero en un rango"
+
+ say_category MIDI
+ say {notein ctlin pgmin bendin touchin polytouchin midiin sysexin} "entrada MIDI"
+ say {noteout ctlout pgmout bendout touchout polytouchout midiout} "salida MIDI"
+ say makenote "programa un retrasado \"note off\" mensaje correspondiente a un note-on";#
+ say stripnote "tira \"note off\" mensajes";#
+
+ say_category TABLES
+ say tabread "lee un numero desde una tabla"
+ say tabread4 "lee un numero desde una tabla, con 4 puntos de interpolacion"
+ say tabwrite "escribe un numero a una tabla"
+ say soundfiler "lee y escribe tablas a archivos de audio"
+
+ say_category MISC
+ say loadbang "bang en carga"
+ say serial "control recurso serial for NT only"
+ say netsend "envia mensajes sobre internet"
+ say netreceive "recibirlos"
+ say qlist "secuencia mensajes"
+ say textfile "convertidor de archivo a mensaje"
+ say openpanel "\"Abrir\" dialogo"
+ say savepanel "\"Guardar como\" dialogo"
+ say bag "sistema de numeros"
+ say poly "asignacion de voz polifonica"
+ say {key keyup} "valores numericos de teclas del teclado"
+ say keyname "simbolo de la tecla";#
+
+ say_category "AUDIO MATH"
+ foreach word {+ - * /} {say $word~ "[say $word] (for signals)"};#this has to be translated too?
+ say max~ "supremo de señales"
+ say min~ "infimo de señales"
+ say clip~ "fuerza la señal a permanecer entre dos limites"
+ say q8_rsqrt~ "raiz cuadrada reciproca economica (cuidado -- 8 bits!)";#
+ say q8_sqrt~ "raiz cuadrada economica (cuidado -- 8 bits!)";#
+ say wrap~ "abrigo alrededor (parte fraccional, tipo de)";#wrap? as abrigo?? around as "alrededor"??
+ say fft~ "transformada fourier discreta compleja delantero";#
+ say ifft~ "transformada fourier discreta compleja inversa";#
+ say rfft~ "transformada fourier discreta real delantero";#
+ say rifft~ "transformada fourier discreta real delantero";#
+ say framp~ "arroja una rampa para cada bloque"
+ foreach word {mtof ftom rmstodb dbtorms rmstopow powtorms} {
+ say $word~ "[say $word] (para señales)";#
+ }
+}
+
+### phase 3
+
+say_namespace summary {
+ say_category "UTILIDADES AUDIO"
+ say dac~ "salida audio"
+ say adc~ "entrada audio"
+ say sig~ "convierte numeros a señales de audio"
+ say line~ "genera rampas de audio"
+ say vline~ "line~ delujo"
+ say threshold~ "detectar umbrales de la señal"
+ say snapshot~ "toma muestras de una señal (reconvierte a numeros)"
+ say vsnapshot~ "snapshot~ delujo";#
+ say bang~ "envia un mensaje bang despues de cada block DSP"
+ say samplerate~ "obtener rango de muestreo"
+ say send~ "conexion señal no local con fanout";# fanout??
+ say receive~ "obtener señal desde send~"
+ say throw~ "agrega a un bus sumador";#
+ say catch~ "define y lee bus sumador";#
+ say block~ "especifica tamaño del bloque y overlap"
+ say switch~ "selecciona computacion DSP on y off";#
+ say readsf~ "reproduce archivo de audio desde disco"
+ say writesf~ "graba sonido a disco"
+
+ say_category "OSCILADORES DE AUDIO Y TABLAS"
+ say phasor~ "oscilador diente de sierra"
+ say {cos~ osc~} "oscilador coseno"
+ say tabwrite~ "escribe a una tabla"
+ say tabplay~ "reproduce desde una tabla (sin transponer)"
+ say tabread~ "lee tabla sin interpolacion"
+ say tabread4~ "lee tabla con 4 puntos de interpolacion"
+ say tabosc4~ "oscilador de tabla de ondas"
+ say tabsend~ "escribe un bloque continuamente a una tabla"
+ say tabreceive~ "lee un bloque continuamente desde una tabla"
+
+ say_category "FILTROS AUDIO"
+ say vcf~ "filtro controlado por voltaje"
+ say noise~ "generador ruido blanco"
+ say env~ "lector envolvente"
+ say hip~ "filtro pasa agudos"
+ say lop~ "filtro pasa bajos"
+ say bp~ "filtro pasa banda"
+ say biquad~ "filtro crudo"
+ say samphold~ "unidad muestra y mantener";# sample as "muestra"
+ say print~ "imprimir uno o mas \"bloques\""
+ say rpole~ "filtro crudo valor real de un polo"
+ say rzero~ "fitro crudo valor real de un cero"
+ say rzero_rev~ "[say rzero~] (tiempo-invertido)"
+ say cpole~ "[say rpole~] (complejo-valorado)"
+ say czero~ "[say rzero~] (complejo-valorado)"
+ say czero_rev~ "[say rzero_rev~] (complejo-valorado)"
+
+ say_category "AUDIO DELAY"
+ say delwrite~ "escribir a una linea de retraso"
+ say delread~ "leer desde una linea de retraso"
+ say vd~ "leer desde una linea de retraso a un tiempo de retraso variable"
+
+ say_category "SUBVENTANAS"
+ say pd "define una subventana"
+ say table "arsenal de numeros en una subventana"
+ say inlet "agrega una entrada a pd"
+ say outlet "agrega una salida a pd"
+ say inlet~ "[say entrada] (para señal)";#
+ say outlet~ "[say salida] (para señal)";#
+
+ say_category "PLANTILLAS DE DATOS"
+ say struct "define una estructura de datos"
+ say {drawcurve filledcurve} "dibuja una curva"
+ say {drawpolygon filledpolygon} "dibuja un poligono"
+ say plot "trace un campo del arsenal";#
+ say drawnumber "imprime un valor numerico"
+
+ say_category "ACCEDIENDO A DATOS"
+ say pointer "señale a un objeto que pertenece a una plantilla"
+ say get "obtener campos numericos"
+ say set "cambiar campos numericos"
+ say element "obtener un elemento del deposito";#array as "deposito"
+ say getsize "obtener el tamaño del deposito"
+ say setsize "cambiar el tamaño del deposito"
+ say append "agregar un elemento a una lista"
+ say sublist "obtenga un indicador en una lista que sea un elemento de otro escalar";# scalar as escalar?? some maths expert should give his opinion
+ say scalar "dibuje un escalar en pariente";#same
+
+ say_category "OBSOLETE"
+ say scope~ "(use tabwrite~ ahora)"
+ say namecanvas "" ;# what was this anyway?
+ say template "(use struct ahora)"
+}
+
+# phase 4 (pdrc & ddrc)
+
+say section_audio "Audio"
+ say -r "rango de muestreo"
+ say -audioindev "dispositivos entrada de audio"
+ say -audiooutdev "dispositivos salida de audio"
+ say -inchannels "canales entrada audio (por dispositivo, como \"2\" or \"16,8\")"
+ say -outchannels "numero de canales salida audio (igual)"
+ say -audiobuf "especificar tamaño de almacenador de audio en mseg"
+ say -blocksize "especificar tamaño block E/S audio en muestras por cuadro"
+ say -sleepgrain "especificar numero de milisegundos para suspension cuando este inactivo";#
+ say -nodac "suprimir salida de audio"
+ say -noadc "suprimir entrada de audio"
+ say audio_api_choice "Audio API"
+ say default "defecto"
+ say -alsa "usar ALSA audio API"
+ say -jack "usar JACK audio API"
+ say -mmio "usar MMIO audio API (por defecto para Windows)"
+ say -portaudio "usar ASIO audio driver (via Portaudio)"
+ say -oss "usar OSS audio API"
+ say -32bit "permitir 32 bit OSS audio (para RME Hammerfall)"
+ say {} "defecto"
+
+say section_midi "MIDI"
+ say -nomidiin "suprime entrada MIDI"
+ say -nomidiout "suprime salida MIDI"
+ say -midiindev "lista dispositivos midi in; e.g., \"1,3\" para primero y tercero"
+ say -midioutdev "lista dispositivos midi out, mismo formato"
+
+say section_externals "Externals"
+ say -path "ruta busqueda de archivo"
+ say -helppath "ruta busqueda archivo de ayuda"
+ say -lib "cargar librerias de objeto"
+
+say section_gui "Gooey";# what??
+ say -nogui "suprime inicio de gui (precaucion)"
+ say -guicmd "substituye por otro programa GUI (e.g., rsh)"
+ say -console "lineas retroceso consola (0 = desactivar consola)"
+ say -look "iconos barra de botones"
+ say -statusbar "activar barra de status"
+ say -font "especificar tamaño de fuente por defecto en puntos"
+
+say section_other "Otro"
+ say -open "abrir archivo(s) en inicio"
+ say -verbose "impresion extra en inicio y al buscar archivos";#
+ say -d "nivel chequeo errores";#
+ say -noloadbang "desactivar el efecto de \[loadbang\]"
+ say -send "enviar un mensaje al inicio (despues patches estan cargados)"
+ say -listdev "lista dispositivos audio y MIDI al inicio"
+ say -realtime "usar prioridad tiempo-real (necesita privilegios de administrador)"
+
+say section_paths "Rutas"
+
+# ddrc
+
+say section_color "colores"
+ say canvas_color "canvas";#
+ say canvasbgedit "canvas fondo (modo edicion)"
+ say canvasbgrun "canvas fondo (modo ejecucion)"
+ say object_color "objeto"
+ say viewframe1 "color objeto";# objetbox as "objeto"
+ say viewframe2 "color objeto";#
+ say viewframe3 "color objeto";#
+ say viewframe4 "color resaltado objeto";#
+ say viewbg "objeto fondo"
+ say viewfg "objeto primer plano"
+ say commentbg "comentario fondo"
+ say commentfg "comentario primer plano"
+ say commentframe1 "comentario cuadro";#frame as "cuadro"
+ say commentframe2 "comentario cuadro"
+ say commentframe3 "comentario cuadro"
+ say viewselectframe "caja resaltada";#
+ say wire_color "cable";# wire as "cable"
+ say wirefg "color cable"
+ say wirefg2 "cable resaltado"
+ say wiredash "cable rociado"
+ say others_color "otros"
+ say inletfg "color entrada"
+ say outletfg "color salida"
+ say selrect "caja de seleccion";# selection box
+say keys "teclas"
+say others "otros"
+say canvashairstate "Activar malla";# crosshair como "malla"
+say canvashairsnap "Malla ajustada a objeto"
+say canvasstatusbar "Activar barra de estatus"
+say canvasbuttonbar "Activar barra de botones"
+
+
+# phase 5A
+
+say cannot "no puedo"
+say cancel "Cancelar"
+say apply "Aplicar"
+say ok "OK"
+say popup_open "Abrir"
+say popup_properties "Propiedades"
+say popup_help "Ayuda"
+say filter "Filtro: "
+say how_many_object_classes "%d of %d object classes";# this has to be translated?
+say do_what_i_mean "haga lo que quiero decir"
+say save_changes? "Guardar cambios?"
+say reset "Reiniciar"
+say Courier "Courier (monospaced)"
+say Helvetica "Helvetica (sansserif)"
+say Times "Times (serif)"
+say add "Agregar"
+say up "Arriba"
+say down "Abajo"
+say remove "Remover"
+say lib_add "agrega el nombre tipeado en la lista"
+say lib_up "intercambiar orden con libreria previa"
+say lib_down "intercambiar orden con libreria proxima"
+say lib_remove "remover libreria seleccionada en la lista"
+say dir_add "agregar una carpeta usando un cuadro de dialogo"
+say dir_up "intercambiar orden con carpeta previa"
+say dir_down "intercambiar orden con carpeta proxima"
+say dir_remove "remover carpeta seleccionada en la lista"
+
+
+### Other
+
+
+
diff --git a/desiredata/src/locale/euskara.tcl b/desiredata/src/locale/euskara.tcl
new file mode 100644
index 00000000..9a27d1f5
--- /dev/null
+++ b/desiredata/src/locale/euskara.tcl
@@ -0,0 +1,554 @@
+#!/usr/bin/env tclsh
+# Basque translations for PureData
+# translated by Ibon Rodriguez Garcia
+### Menus
+
+say file "Fitxategia"
+ say new_file "Berria"
+ say open_file "Ireki..."
+ say server_prefs "Zerbitzari Hobespenak..."
+ say client_prefs "Bezero Hobespenak..."
+ say send_message "Mezua Bidali..."
+ say paths "Bide Izena..."
+ say close "Itxi"
+ say save "Gorde"
+ say save_as "Gorde Honela..."
+ say print "Inprimatu..."
+ say quit "Irten"
+
+ say canvasnew_file "Berria"
+ say canvasopen_file "Ireki..."
+ say canvassave "Gorde"
+ say canvassave_as "Gorde Honela..."
+ say clientpdrc_editor ".pdrc Editorea"
+ say clientddrc_editor ".ddrc Editorea"
+ say canvasclose "Itxi"
+ say canvasquit "Irten"
+
+say edit "Editatu"
+ say undo "Desegin"
+ say redo "Berregin"
+ say cut "Ebaki"
+ say copy "Kopiatu"
+ say paste "Itsatsi"
+ say duplicate "Bikoiztu"
+ say select_all "Hautatu Dena"
+ say text_editor "Testu Editorea..."
+ say font "Letra Tipoa"
+ say tidy_up "Doitu"
+ say edit_mode "Edizio Modua"
+ say editmodeswitch "Edizio/Exekuzio modua"
+
+ say canvascut "Ebaki"
+ say canvascopy "Kopiatu"
+ say canvasundo "Desegin"
+ say canvasredo "Berregin"
+ say canvaspaste "Itsatsi"
+ say canvasduplicate "Bikoiztu"
+ say canvasselect_all "Hautatu Dena"
+ say canvaseditmodeswitch "Edizio/Rxekuzio Modua"
+
+say view "Ikusi"
+ say reload "Berriz Kargatu"
+ say redraw "Eguneratu"
+
+ say canvasreload "Berriz Kargatu"
+ say canvasredraw "Eguneratu"
+
+say find "Bilatu"
+ say find_again "Bilatu Berriro"
+ say find_last_error "Bilatu Azken Errorea"
+ say string "Bilatu Katea"
+say canvasfind "Bilatu"
+ say canvasfind_again "Bilatu Berriro"
+
+# contents of Put menu is Phase 5C
+say put "Jarri"
+ say Object "Objektua"
+ say Message "Mezua"
+ say Number "Zenbakia"
+ say Symbol "Ikurra"
+ say Comment "Iruzkina"
+ say Bang "Bang"
+ say Toggle "Konmutagailua"
+ say Number2 "2 Zenbakia"
+ say Vslider "Graduatzaile Bertikala"
+ say Hslider "Graduatzaile Horizontala"
+ say Vradio "Maila Bertikala"
+ say Hradio "Maila Horizontala"
+ say Canvas "Canvas"
+ say Array "Taula"
+
+ say canvasobject "Objektua"
+ say canvasmessage "Mezua"
+ say canvasnumber "Zenbakia"
+ say canvassymbol "Ikurra"
+ say canvascomment "Iruzkina"
+ say canvasbang "Bang"
+ say canvastoggle "Konmutagailua"
+ say canvasnumber2 "2 Zenbakia"
+ say canvasvslider "Graduatzaile Bertikala"
+ say canvashslider "Graduatzaile Horizontala"
+ say canvasvradio "Maila Bertikala"
+ say canvashradio "Maila Horizontala"
+ say canvascanvas "Canvas"
+ say canvasarray "Taula"
+
+say media "Media"
+ say audio_on "Audio ON"
+ say audio_off "Audio OFF"
+ say test_audio_and_midi "Probatu Audio eta MIDI"
+ say load_meter "Kargatu Neurgailua"
+
+ say canvasaudio_on "Audio ON"
+ say canvasaudio_off "Audio OFF"
+ say clienttest_audio_and_midi "Probatu Audio eta MIDI"
+ say canvasload_meter "Kargatu Neurgailua"
+
+say window "Leihoa"
+
+say help "Laguntza"
+ say about "...(r)i buruz"
+ say pure_documentation "Dokumentazio Hutsa..."
+ say class_browser "Klase Arakatzailea..."
+
+ say canvasabout "...(r)i buruz"
+
+say properties "Propietateak"
+say open "Ireki"
+
+### for key binding editor
+say general "Nagusia"
+say audio_settings "Audio Ezarpenak"
+say midi_settings "Midi Ezarpenak"
+say latency_meter "Latentzia Neurgailua"
+say Pdwindow "Pd Leihoa"
+
+say canvaspdwindow "Pd Leihoa"
+say canvaslatency_meter "Latentzia Neurgailua"
+say clientaudio_settings "Audio Ezarpenak"
+say clientmidi_settings "Midi Ezarpenak"
+
+### for Properties Dialog (phase 5B)
+say_category IEM
+say w "Zabalera(px)"
+say h "Garaiera(px)"
+say hold "Euste Denbora(ms)"
+say break "Eten Denbora(ms)"
+say min "Gutxienezko Balioa"
+say max "Gehienezko Balioa"
+say is_log "Modua"
+say linear "Lineala"
+say logarithmic "Logaritmikoa"
+say isa "Hasi"
+say n "Aukera Kopurua"
+say steady "Erregulartasuna"
+say steady_no "Klik egitean jauzi"
+say steady_yes "Klik Egitean Finkatu"
+say snd "Bidaltze Ikurra"
+say rcv "Jasotze Ikurra"
+say lab "Etiketa"
+say ldx "Desplazatu x Etiketa"
+say ldy "Desplazatu y Etiketa"
+say fstyle "Letra Tipoa"
+say fs "Letra Tamaina"
+say bcol "Atzeko Planoaren Kolorea"
+say fcol "Aurreko Planoaren Kolorea"
+say lcol "Etiketaren Kolorea"
+say yes "Bai"
+say no "Ez"
+say courier "Courier (idazmakina)"
+say helvetica "Helvetica (sansserif)"
+say times "Times (serif)"
+say coords "Grafikoa Nagusian"
+
+say_category GAtomProperties
+say width "Zabalera"
+say lo "Beheko Muga"
+say hi "Goiko Muga"
+say label "Etiketa"
+say wherelabel "Erakutsi On Etiketa"
+say symto "Bidali Ikurra"
+say symfrom "Jaso Ikurra"
+
+say_category GraphProperties
+say x1 "x(e)tik"
+say x2 "x(e)ra"
+say xpix "Pantailaren Zabalera"
+say y2 "y(e)tik"
+say y1 "y(e)ra"
+say ypix "Pantailaren Garaiera"
+
+say_category CanvasProperties
+#say xscale "X Unitate/px"
+#say yscale "Y Unitate/px"
+say gop "Grafikoa Nagusian"
+say xmargin "xmarjina"
+say ymargin "ymarjina"
+say height "Garaiera"
+say_category ArrayProperties
+say name "Izena"
+say n "Tamaina"
+say xfrom "x(e)tiko tartea"
+say xto "x(e)rako tartea"
+say yfrom "y(e)tiko tartea"
+say yto "y(e)rako tartea"
+
+
+say_category MainWindow
+say in "in"
+say out "out"
+say audio "Audio"
+say meters "Neurgailuak"
+say io_errors "IO Akatsak"
+
+### phase 2
+
+say_category Other
+say_namespace summary {
+ say_category IEMGUI
+ say bng "Bang Kutxa"
+ say tgl "Toggle Kutxa"
+ say nbx "Zenbaki Kutxa (IEM)"
+ say hsl "Graduatzailea (Horizontala)"
+ say vsl "Graduatzailea (Bertikala)"
+ say hradio "Aukera Kutxa (Horizontala)"
+ say vradio "Aukera Kutxa (Bertikala)"
+ say cnv "Canvas (IEM)"
+ say dropper "Arrastatu eta Jaregin Kutxa"
+ say vu "Vumeter"
+
+ say_category GLUE
+ say bang "Bang Mezua Erakutsi"
+ say float "Zenbaki Bat Gorde eta Gogoratu"
+ say symbol "Ikur Bat Gorde eta Gogoratu"
+ say int "Osoko Bat Gorde eta Gogoratu"
+ say send "Mezu Bat Bidali Objektu Izendun Bati"
+ say receive "Bidalitako Mezuak Jaso"
+ say select "Pareko Zenbaki edo Ikurrak Aztertu"
+ say route "Lehenengo Elementuarekin Bat Datozen Mezuak Bideratu"
+ say pack "Mezu Konposatuak Egin"
+ say unpack "MEzu Konposatuetako Elementuak Jaso"
+ say trigger "Mezuak Sekuentziatu eta Bihurtu"
+ say spigot "Mezuen Konexio Etengarria"
+ say moses "Zenbakizko Transmisioa Zatitu"
+ say until "Begiztatze Mekanismoa"
+ say print "Inprimatu Mezuak"
+ say makefilename "Ikur Bat Formateatu Eremu Aldakor Batekin"
+ say change "Ezabatu Transmisio Batetik Errepikatutako Zenbakiak"
+ say swap "Trukatu Bi Zenbaki"
+ say value "Zenbakizko Balioa Partekatu"
+
+ say_category TIME
+ say delay "Bidali Mezua Atzerapen Denbora eta Gero"
+ say metro "Bidali Mezua Aldizka"
+ say line "Bidali Linealki Mailakatutako Zenbaki Saila"
+ say timer "Neurtu Denbora Tartea"
+ say cputime "Neurtu CPU Denbora"
+ say realtime "Neurtu Denbora Erreala"
+ say pipe "Zenbakientzako Dinamikoki Hazkorra Den Atzerapen Linea"
+
+ say_category MATH
+ say + "Gehitu"
+ say - "Kendu"
+ say * "Biderkatu"
+ say {/ div} "Zatitu"
+ say {% mod} "Zatiketaren Hondarra"
+ say pow "exponentziala"
+ say == "Berdin?"
+ say != "Ezberdin?"
+ say > "baino Gehiago?"
+ say < "baino Gutxiago?"
+ say >= "baino Gutxiago Ez?"
+ say <= "baino Gehiago Ez?"
+ say & "bitwise konjuntzioa (eta)"
+ say | "bitwise disjuntzioa (edo)"
+ say && "konjuntzio logikoa (eta)"
+ say || "disjuntzio logikoa (edo)"
+ say mtof "MIDItik Hertzetara"
+ say ftom "Hertzetatik MIDIra"
+ say powtodb "Wattetatik dBtara"
+ say dbtopow "dBtatik to Wattetara"
+ say rmstodb "Voltetatik dBetara"
+ say dbtorms "dBetatik Voltetara"
+ say {sin cos tan atan atan2 sqrt} "trigonometria"
+ say log "Euler logaritmoa"
+ say exp "Euler exponentziala"
+ say abs "balio absolutua"
+ say random "ausaz"
+ say max "Bi zenbakitan handiena"
+ say min "Bi zenbakitan handiena"
+ say clip "Behartu Zenbaki Bat Bitarte Batera"
+
+ say_category MIDI
+ say {notein ctlin pgmin bendin touchin polytouchin midiin sysexin} "MIDI sarrera"
+ say {noteout ctlout pgmout bendout touchout polytouchout midiout} "MIDI irteera"
+ say makenote "antolatu note-on bati dagokion \"note off\" mezu atzeratu bat"
+ say stripnote "Kendu \"note off\" mezuak"
+
+ say_category TABLES
+ say tabread "Irakurri zenbaki bat taula batetik"
+ say tabread4 "Irakurri zenbaki bat taula batetik, 4 interpolazio-punturekin"
+ say tabwrite "Idatzi Zenbaki Bat Taula Batean"
+ say soundfiler "Irakurri eta Idatzi Taulak Soinu Fitxategiei"
+
+ say_category MISC
+ say loadbang "Bang Kargatu"
+ say serial "Serieko Atakaren Kontrolatzailea, NTrako soilik"
+ say netsend "Bidali Mezuak Interneten Gainetik"
+ say netreceive "Jaso Mezuak Interneten Gainetik"
+ say qlist "Mezu Sekuentziadorea"
+ say textfile "Bihurtu fitxategia mezu"
+ say openpanel "\"zabaldu\" Elkarrizketa"
+ say savepanel "\"Gorde Honela\" Elkarrizketa"
+ say bag "Zenbaki Multzoa"
+ say poly "Ahots Polifonikoaren Esleipena"
+ say {key keyup} "Teklaturako Zenbakizko Teklen Balioak"
+ say keyname "Tekla Izen Sinbolikoa"
+
+ say_category "AUDIO MATH"
+ foreach word {+ - * /} {say $word~ "[say $word] (for signals)"}
+ say max~ "Seinalearen Gehienezko Balioa"
+ say min~ "Seinalearen Gutxienezko Balioa"
+ say clip~ "Behartu Seinalea Bi Mugen Artean Egotera"
+ say q8_rsqrt~ "Elkarrekiko Erro Karratu Ekonomikoa (Kontuz -- 8 bit!)"
+ say q8_sqrt~ "Erro Karratu Ekonomikoa (Kontuz -- 8 bit!)"
+ say wrap~ "Wraparound (Alde Zatikiar Mota)"
+ say fft~ "Aurreko Fourier-en transformatu Diskretu Konplexua"
+ say ifft~ "Alderantzizko Fourier-en transformatu Diskretu Konplexua"
+ say rfft~ "Aurreko Fourier-en transformatu Diskretu Erreala"
+ say rifft~ "Alderantzizko Fourier-en transformatu Diskretu Erreala"
+ say framp~ "Atera arrapala bat bloke bakoitzarentzat"
+ foreach word {mtof ftom rmstodb dbtorms rmstopow powtorms} {
+ say $word~ "[say $word] (Seinalearentzat)"
+ }
+}
+
+### phase 3
+
+say_namespace summary {
+ say_category "AUDIO GLUE"
+ say dac~ "audio irteera"
+ say adc~ "audio sarrera"
+ say sig~ "Bihurtu Zenbakiak Audio Seinale"
+ say line~ "Sortu Audio Arrapalak"
+ say vline~ "Luxuzko linea~"
+ say threshold~ "Antzeman Seinalearen Atalaseak"
+ say snapshot~ "Lagindu seinale bat (Bihurtu Zenbaki)"
+ say vsnapshot~ "Luxuzko Argazkia~"
+ say bang~ "Badili Bang Mezu Bat DSP block Bakoitzaren Ostean"
+ say samplerate~ "Lortu Laginaren Maiztasuna"
+ say send~ "Konektatu Seinale Ez-Lokal Bat Banagune Batekin"
+ say receive~ "Lortu Seinatea send~etik"
+ say throw~ "Gehitu Summing Bus Batera"
+ say catch~ "Definitu eta Irakurri Summing Bus Bat"
+ say block~ "Zehaztu Blokearen Tamaina eta Teilakapena"
+ say switch~ "Piztu eta Itzali DSP kalkulagailua"
+ say readsf~ "Erreproduzitu Soinu Fitxategia Diskotik"
+ say writesf~ "Grabatu Soinua Diskoan"
+
+ say_category "AUDIO OSZILADOREAK ETA TAULAK"
+ say phasor~ "Zerra Hortz Motako Osziladorea"
+ say {cos~ osc~} "Kosinu Osziladorea"
+ say tabwrite~ "Idatzi Taula Batean"
+ say tabplay~ "Erreproduzitu Taula Batetik (transposiziorik gabe)"
+ say tabread~ "Irakurri Interpolazio Gabeko Taula"
+ say tabread4~ "Irakurri 4 Interpolazio Puntuko Taula"
+ say tabosc4~ "Uhin Taulako Osziladorea"
+ say tabsend~ "Idatzi Bloke Bat Taula Batera Etengabe"
+ say tabreceive~ "Irakurri Bloke Bat Taula Batetik Etengabe"
+
+ say_category "AUDIO IRAGAZKIAK"
+ say vcf~ "Tentsio Kontrolatuko Iragazkia"
+ say noise~ "Zarata Zuri Sortzailea"
+ say env~ "Inguratze Jarraitzailea"
+ say hip~ "Goi Paseko Iragazkia"
+ say lop~ "Behe Paseko Iragazkia"
+ say bp~ "Banda Paseko Iragazkia"
+ say biquad~ "Iragazki Gordina"
+ say samphold~ "Lagindu eta blokeatu Unitatea"
+ say print~ "Inprimatu \"Blocks\" Bat Edo Gehiago"
+ say rpole~ "Polo Bakarreko Balio Errealeko Iragazki Gordina"
+ say rzero~ "Zero-Bat Balio Errealeko Iragazki Gordina"
+ say rzero_rev~ "[say rzero~] (Denbora Alderantzizkatua)"
+ say cpole~ "[say rpole~] (Konplexua-Zenbatetsia)"
+ say czero~ "[say rzero~] (Konplexua-Zenbatetsia)"
+ say czero_rev~ "[say rzero_rev~] (Konplexua-Zenbatetsia)"
+
+ say_category "AUDIO ATZERAPENA"
+ say delwrite~ "Idatzi Atzerapen Lerro Batean"
+ say delread~ "Irakurri Atzerapen Lerro Batetik"
+ say vd~ "Irakurri Atzerapen Lerro Batetik Atzerapen Lerro Aldakor Batean"
+
+ say_category "AZPILEIHOAK"
+ say pd "Azpileiho Bat Definitu"
+ say table "Zenbaki Taula Azpileiho Batean"
+ say inlet "Gehitu Sarrera Bat PD Batean"
+ say outlet "Gehitu Irteera Bat PD Batean"
+ say inlet~ "[say inlet] (seinalearentzat)"
+ say outlet~ "[say outlet] (seinalearentzat)"
+
+ say_category "DATU TXANTILIOIAK"
+ say struct "Definitu Datu Egitura Bat"
+ say {drawcurve filledcurve} "Marraztu Kurba Bat"
+ say {drawpolygon filledpolygon} "Marraztu Poligono Bat"
+ say plot "Trazatu Taula Bateko Eremu Bat"
+ say drawnumber "Inprimatu Zenbakizko Balio Bat"
+
+ say_category "DATUETARAKO SARBIDEA"
+ say pointer "Seinalatu Txantilioi Batekoa Den Elementu Bat"
+ say get "Lortu Zenbakizko Eremuak"
+ say set "Zenbakizko Eremuak Aldatu"
+ say element "Lortu Taula Bateko Elementu Bat"
+ say getsize "Lortu Taula Baten Tamaina"
+ say setsize "Aldatu Taula Baten Tamaina"
+ say append "Gehitu Elementu Bat Zerrenda Batera"
+ say sublist "Lortu Erakusle Bat Beste Eskalar Bateko Elementua Den Zerrenda Batean"
+ say scalar "Marraztu Eskalar Bat Nagusian"
+
+ say_category "ZAHARKITUA"
+ say scope~ "(Erabili tabwrite~ Orain)"
+ say namecanvas "" ;# what was this anyway?
+ say template "(Erabili struct now)"
+}
+
+# phase 4 (pdrc & ddrc)
+
+say section_audio "Audio"
+ say -r "LAgin-Maiztasuna"
+ say -audioindev "Audio Sarrerako Gailuak"
+ say -audiooutdev "Audio Irteerako Gailuak"
+ say -inchannels "Audio Sarrerako Kanalak (Gailuko, adib. \"2\" edo \"16,8\")"
+ say -outchannels "Audio Irteerako Kanalen Kopurua (Berbera)"
+ say -audiobuf "Zehaztu Audio Bufferraren Tamaina Milisegundotan"
+ say -blocksize "Zehaztu S/I Audio Blokeak Lagin Markoetan"
+ say -sleepgrain "Zehaztu Lotarako Milisegundo Kopurua Inaktibo Dagoenean"
+ say -nodac "Ezabatu Audio Irteera"
+ say -noadc "Ezabatu Audio Sarrera"
+ say audio_api_choice "Audio API"
+ say default "Lehenetsia"
+ say -alsa "Erabili ALSA audio API"
+ say -jack "Erabili JACK audio API"
+ say -mmio "Erabili MMIO audio API (Windowserako Lehenetsia)"
+ say -portaudio "Erabili ASIO audio driver (Portaudio bidez)"
+ say -oss "Erabili OSS audio API"
+ say -32bit "Baimendu 32 bit OSS audio (RME Hammerfallerako)"
+ say {} "Lehenetsia"
+
+say section_midi "MIDI"
+ say -nomidiin "MIDI Sarrera Kendu"
+ say -nomidiout "MIDI Irteera Kendu"
+ say -midiindev "midi in Gailuen Zerrenda; adib., \"1,3\" lehenengo eta hirugarrenerako"
+ say -midioutdev "midi out Gailuen Zerrenda, Formatu Berbera"
+
+say section_externals "Kanpokoak"
+ say -path "Fitxategiak Topatzeko Bidea"
+ say -helppath "Laguntza Fitxategiak Topatzeko Bidea"
+ say -lib "Kargatu Objektuen Liburutegiak"
+
+say section_gui "Gooey"
+ say -nogui "Desgaitu GUI Hastea (Kontuz)"
+ say -guicmd "Ordeztu Beste GUI Programa (adib., rsh)"
+ say -console "Kontsolaren Atzerapen Lineak (0 = Desgaitu Kontsola)"
+ say -look "Botoi Barraren Ikonoak"
+ say -statusbar "Gaitu Egoera Barra"
+ say -font "Zehaztu LEtra Mota Lehenetsia Puntutan"
+
+say section_other "Bestelakoak"
+ say -open "Ireki Fitxategia(k) Hasieran"
+ say -verbose "Inprimatze Gehigarria Hasieran eta Fitxategiak Bilatzean"
+ say -d "Arazte Maila"
+ say -noloadbang "Desgaitu \[loadbang\] Efektua"
+ say -send "Bidali Mezu Bat Hasieran (Adabakiak Kargatu Eta Gero)"
+ say -listdev "Zerrendatu Audio eta MIDI Gailuak Hasieraren Gainetik"
+ say -realtime "Erabili Denbora Errealeko Lehenespena (sustrai-pribilegioa behar du)"
+
+say section_paths "Ibilbideak"
+
+# phase 4B: ddrc (keyword names not finalized!)
+
+say section_color "Koloreak"
+ say canvas_color "canvas"
+ say canvasbgedit "canvas Atzeko Planoa (edizio-modua)"
+ say canvasbgrun "canvas Atzeko Planoa (exekutatze-modua)"
+ say object_color "objektua"
+ say viewframe1 "Objektu Kutxaren Kolorea"
+ say viewframe2 "Objektu Kutxaren Kolorea"
+ say viewframe3 "Objektu Kutxaren Kolorea"
+ say viewframe4 "Objektu Kutxa Nabarmentzeko Kolorea"
+ say viewbg "Objektuaren Atzeko Planoa"
+ say viewfg "Objektuaren Aurreko Planoa"
+ say commentbg "Iruzkinaren Atzeko Planoa"
+ say commentfg "Iruzkinaren Aurreko Planoa"
+ say commentframe1 "Iruzkin Markoa"
+ say commentframe2 "Iruzkin Markoa"
+ say commentframe3 "Iruzkin Markoa"
+ say viewselectframe "Nabarmendu Kutxa"
+ say wire_color "Haria"
+ say wirefg "Hariaren Kolorea"
+ say wirefg2 "Nabarmendu Haria"
+ say wiredspfg "dsp Hari Kolorea"
+ say futurewiredash "Hari (Marratu) Berria"
+ say others_color "Bestelakoak"
+ say boxinletfg "Sarrera Kolorea"
+ say boxoutletfg "Irteera Kolorea"
+ say selrectrect "Hautapen Kutxa"
+say keys "Teklak"
+say others "Bestelakoak"
+say canvashairstate "Gaitu Amarauna"
+say canvashairsnap "Doitu Amarauna Objektuari"
+say canvasstatusbar "Gaitu Egoera Barra"
+say canvasbuttonbar "Gaitu Botoi Barra"
+say wirewirearrow "Gezia Lotu"
+say viewtooltip "Argibidea"
+say canvasinsert_object "Txertatu Objektua"
+say canvaschain_object "Kateatu Objektua"
+say canvasclear_wires "Garbitu Hariak"
+say canvasauto_wire "Ezabatu Objektua"
+# phase 5A
+
+say cannot "Ezin"
+say cancel "Ezeztatu"
+say apply "Aplikatu"
+say ok "Ados"
+say popup_open "Ireki"
+say popup_insert "Txertatu"
+say popup_properties "Propietateak"
+say popup_clear_wires "Garbitu Hariak"
+say popup_auto_wire "Ezabatu Objektua"
+say popup_help "Laguntza"
+say filter "Iragazkia : "
+say how_many_object_classes "Objektu Klaseen %d(r)en %d"
+say do_what_i_mean "Egin Esan Nahi Dudana"
+say save_changes? "Aldaketak Gorde?"
+say reset "Garbitu"
+say Courier "Courier (monospaced)"
+say Helvetica "Helvetica (sansserif)"
+say Times "Times (serif)"
+say add "Gehitu"
+say up "Gora"
+say down "Behera"
+say remove "Ezabatu"
+say lib_add "Gehitu Idatzitako Izena Zerrendara"
+say lib_up "Trukatu Agindua Aurreko Liburutegiarekin"
+say lib_down "Trukatu Agindua Hurrengo Liburutegiarekin"
+say lib_remove "Ezabatu Zerrendan Aurkeratutako Liburutegia"
+say dir_add "Gehitu Karpeta Bat Elkarrizketa Fitxategia Erabiliz"
+say dir_up "Trukatu Agindua Aurreko Karpetarekin"
+say dir_down "Trukatu Agindua Hurrengo Karpetarekin"
+say dir_remove "Ezabatu Zerrendan Aukeratutako Karpeta"
+say client_class_tree "Bezero Klaseen Zuhaitza"
+say clipboard_view "Ikusi Arbela"
+say history_view "Ikusi Historia"
+
+# during/after piksel:
+
+say auto_apply "Auto-Aplikatu"
+say font_preview "Aurrebista:"
+say font_preview_2 "ABCDEFGHIJKLMNOPQRSTUVWXYZ\nabcdefghijklmnopqrstuvwxyz\n0123456789"
+say font_style "Estiloa:"
+say font_bold "Lodia"
+say font_italic "Etzana"
+say font_family "Izena:"
+say font_size "Tamaina:"
+say damn "Arraioa!"
diff --git a/desiredata/src/locale/francais.tcl b/desiredata/src/locale/francais.tcl
new file mode 100644
index 00000000..1101bff9
--- /dev/null
+++ b/desiredata/src/locale/francais.tcl
@@ -0,0 +1,539 @@
+#!/usr/bin/env tclsh
+# French (franais) translations for PureData
+# $Id: francais.tcl,v 1.1.2.5.2.8 2007-07-11 19:21:32 matju Exp $
+# by Patrice Colet
+
+say file "Fichier"
+ say new_file "Nouveau Fichier"
+ say open_file "Ouvrir Fichier..."
+ say server_prefs "Prfrences serveur..."
+ say client_prefs "Prfrences client..."
+ say send_message "Envoyer Message..."
+ say paths "Chemins..."
+ say close "Fermer"
+ say save "Sauvegarder"
+ say save_as "Sauvegarder Sous..."
+ say print "Imprimer..."
+ say quit "Quitter"
+
+ say canvasnew_file "Nouveau Fichier"
+ say canvasopen_file "Ouvrir Fichier..."
+ say canvassave "Sauver"
+ say canvassave_as "Sauver sous..."
+ #say clientpdrc_editor "diteur de .pdrc"
+ #say clientddrc_editor "diteur de .ddrc"
+ say canvasclose "Fermer"
+ say canvasquit "Quitter"
+
+say edit "dition"
+ say undo "Dfaire"
+ say redo "Refaire"
+ say cut "Couper"
+ say copy "Copier"
+ say paste "Coller"
+ say duplicate "Dupliquer"
+ say select_all "Slectionner tout"
+ say text_editor "diteur de texte..."
+ say font "Police"
+ say tidy_up "Aligner"
+ say edit_mode "Mode d'dition"
+ say editmodeswitch "Mode dition/execution"
+
+ say canvascut "Couper"
+ say canvascopy "Copier"
+ say canvasundo "Annuler"
+ say canvasredo "Rtablir"
+ say canvaspaste "Coller"
+ say canvasduplicate "Dupliquer"
+ say canvasselect_all "Slectionner Tout"
+ say canvaseditmodeswitch "Mode dition/execution"
+
+say view "Vue"
+ say reload "Recharger"
+ say redraw "Redessiner"
+
+ say canvasreload "Recharger"
+ say canvasredraw "Redessiner"
+
+ say find "Trouver"
+ say find_again "Trouver encore"
+ say find_last_error "Trouver la dernire erreur"
+ say string "Trouver chane de charactres"
+ say canvasfind "Trouver"
+ say canvasfind_again "Trouver encore"
+
+say put "Mettre"
+ say Object "Objet"
+ say Message "Message"
+ say Number "Nombre"
+ say Symbol "Symbole"
+ say Comment "Commentaire"
+ say Array "Tableau"
+
+say media "Mdia"
+ say audio_on "Audio ON"
+ say audio_off "Audio OFF"
+ say test_audio_and_midi "Tester l'audio et le MIDI"
+ say load_meter "CPU-mtre"
+
+ say canvasaudio_on "Audio ON"
+ say canvasaudio_off "Audio OFF"
+ say clienttest_audio_and_midi "Tester l'audio et le MIDI"
+ say canvasload_meter "CPU-mtre"
+
+say window "Fentre"
+
+say help "Aide"
+ say about " propos de..."
+ say pure_documentation "Pure Documentation..."
+ say class_browser "Explorateur de classes..."
+
+ say canvasabout " propos de..."
+
+ say properties "Proprits"
+say open "Ouvrir"
+
+### for key binding editor
+say general "Gnerale"
+say audio_settings "Paramtres audio"
+say midi_settings "Paramtres MIDI"
+say latency_meter "Latence-mtre"
+say Pdwindow "Console PD"
+
+say canvaspdwindow "Console PD"
+say canvaslatency_meter "Latence-mtre"
+say clientaudio_settings "Paramtres audio"
+say clientmidi_settings "Paramtres audio"
+
+### for Properties Dialog (phase 5B)
+say_category IEM
+say w "Largeur(px)"
+say h "Hauteur(px)"
+say hold "Temps de maintien(ms)"
+say break "temps d'arrt(ms)"
+say min "Valeur minimum"
+say max "Valeur maximum"
+say is_log "Mode"
+say linear "Lineaire"
+say logarithmic "Logarithmique"
+say isa "Initialisation"
+say n "Nombre de choix"
+say steady "Rgularit"
+say steady_no "Caler sur le click"
+say steady_yes "Suivre le click"
+say snd "symbole d'envoie"
+say rcv "symbole de reception"
+say lab "label"
+say ldx "Dcalage x du label"
+say ldy "Dcalage du label"
+say fstyle "Style de police"
+say fs "Taille de la police"
+say bcol "Couleur d'arrire plan"
+say fcol "Couleur du premier plan"
+say lcol "couleur du label"
+say yes "Oui"
+say no "Non"
+say courier "courrier (typewriter)"
+say helvetica "helvetique (sansserif)"
+say times "times (serif)"
+say coords "Afficher sur le parent"
+
+say_category "Proprits du Gatom"
+say width "Largeur"
+say lo "Plus Petite Limite"
+say hi "Plus Grande Limite"
+say label "Label"
+say wherelabel "Montrer le label allum"
+say symto "Symbole d'envoie"
+say symfrom "Symbole de reception"
+
+say_category "Proprits du graph"
+say x1 "Depuis x"
+say x2 "Vers x"
+say xpix "Largeur d'cran"
+say y2 "Depuis y"
+say y1 "Vers y"
+say ypix "Hauteur d'cran"
+
+say_category "Proprits du canevas"
+#say xscale "X units/px"
+#say yscale "Y units/px"
+say gop "Afficher sur le parent"
+say xmargin "Marge x"
+say ymargin "Marge y"
+say height "Hauteur"
+say_category MainWindow
+say name "Nom"
+say n "Taille"
+say xfrom "tendue sur x depuis"
+say xto "tendue sur x jusque"
+say yfrom "tendue sur y depuis"
+say yto "tendue sur x jusque"
+
+
+### Main Window
+
+say in "entre"
+say out "sortie"
+say audio "Audio"
+say meters "Niveaux"
+say io_errors "Erreurs d'E/S"
+say cannot "ne peut"
+
+say_category Autre
+say_namespace summary {
+ say_category IEMGUI
+# say bng "Dclencheur"
+ say bng "Bang"
+ say tgl "Interrupteur"
+ say nbx "Boite de Nombre (IEM)"
+# say Number2 "Nombre2"
+ say hsl "Glissire (Horizontale)"
+ say vsl "Glissire (Verticale)"
+# say hsl "Slecteur (Horizontal)"
+ say hradio "Bote De Selection (Horizontale)"
+ say vradio "Bote De Selection (Verticale)"
+# say cnv "Illustration (IEM)"
+ say cnv "Canevas (IEM)"
+ say dropper "Boite Pour Glisser-Dposer"
+ say vu "Vu-mtre"
+
+ say_category GLUE
+ say bang "Envoyer un Dclenchement"
+ say float "Stocker et rapeller un nombre flottant"
+ say symbol "Stocker et rapeller un symbole"
+ say int "Stocker et rapeller un nombre entier"
+ say send "Envoyer un message vers un objet dfini"
+ say receive "Recevoir un message envoy"
+ say select "Tester la reception d'un chiffre ou d'un symbole"
+ say route "Diriger un message en fonction du premier lement"
+ say pack "Empaqueter un message"
+ say unpack "Dsempaqueter un message"
+ say trigger "Mettre en squence un message"
+ say spigot "Interrupteur de message"
+ say moses "partitionner un flot numrique en deux (mose)"
+ say until "Mchanisme de bouclage"
+ say print "Afficher un message dans la console"
+ say makefilename "Formater un symbole avec un champ variable"
+ say change "Supprimer les rpetitions d'un flot"
+ say swap "Permuter deux chiffres"
+ say value "Partager une valeur numrique"
+
+ say_category TEMPS
+ say delay "Envoyer un dclenchement aprs un dlai"
+ say metro "Envoyer un dclenchement priodiquement"
+ say line "Envoyer linairement une serie de nombres "
+ say timer "Mesurer l'intervalle de temps"
+ say cputime "Mesurer le temps de calcul"
+ say realtime "Mesurer le temps rel"
+ say pipe "Dlai dynamique pour les nombres"
+
+ say_category MATH
+ say + "Ajouter"
+ say - "Soustraire"
+ say * "Multiplier"
+ say {/ div} "Diviser"
+ say {% mod} "Retenue d'une Division"
+ say pow "Exponentiel"
+ say == "gal?"
+ say != "Different?"
+ say > "Plus Grand Que?"
+ say < "Plus Petit Que?"
+ say >= "Plus Grand ou gal ?"
+ say <= "Plus Petit ou gal ?"
+ say & "et logique (and)"
+ say | "ou logique (or)"
+ say && "et logique (and)"
+ say || "ou logique (or)"
+ say mtof "MIDI vers Hertz"
+ say ftom "Hertz vers MIDI"
+ say powtodb "Watts vers dB"
+ say dbtopow "dB vers Watts"
+ say rmstodb "Volts vers dB"
+ say dbtorms "dB vers Volts"
+ say {sin cos tan atan atan2 sqrt} "Trigonometrie"
+ say log "Logarithme d'Euler"
+ say exp "Exponentiel d'Euler"
+ say abs "Valeur absolue"
+ say random "Alatoire"
+ say max "Le plus grand des deux nombres"
+ say min "Le plus petit des deux nombres"
+ say clip "Forcer un nombre entre deux valeurs"
+
+ say_category MIDI
+ say {notein ctlin pgmin bendin touchin polytouchin midiin sysexin} "Entre MIDI"
+ say {noteout ctlout pgmout bendout touchout polytouchout midiout} "Sortie MIDI"
+ say makenote "Programmer un message dcal \"note off\" correspondant un note-on"
+ say stripnote "ignorer les messages \"note off\" "
+
+ say_category TABLEAUX
+ say tabread "Lire Un Nombre Depuis Une Tableau"
+ say tabread4 "Lire Un Nombre Depuis Une Tableau, avec 4 points d'interpolation"
+ say tabwrite "Ecrire un nombre dans une tableau"
+ say soundfiler "Lire et crire un tableau vers un fichier"
+
+ say_category MISC
+ say loadbang "Dclencher au lancement"
+ say serial "Contrle du port serie pour NT seulement"
+ say netsend "Envoyer messages travers internet"
+ say netreceive "Recevoir messages travers internet"
+ say qlist "Squenceur de messages"
+ say textfile "Convertisseur de fichier vers messages"
+ say openpanel "dialogue \"Ouvrir\" "
+ say savepanel " dialogue \"Sauver sous\""
+ say bag "Srie de nombres"
+ say poly "Allocation de voix polyphoniques"
+ say {key keyup} "Valeurs Numriques Du Clavier"
+ say keyname "Nom symbolique d'une touche de clavier"
+
+ say_category "AUDIO MATH"
+ foreach word {+ - * /} {say $word~ "[say $word] (for signals)"}
+ say max~ "Valeur maximale de signaux"
+ say min~ "Valeur minimale de signaux"
+ say clip~ "Contraint le signal rester entre deux valeurs"
+ say q8_rsqrt~ "Racine carre rciproque (attention -- 8 bits!)"
+ say q8_sqrt~ "Racine carre (attention -- 8 bits!)"
+ say wrap~ "Envelopper autour (Genre De partie fractionnelle)"
+ say fft~ "Transformation discrte de Fourier"
+ say ifft~ "Partie complexe de la transforme de fourier"
+ say rfft~ "Partie relle de la transforme de fourier"
+ say rifft~ "Inverse de la Partie relle de la transforme de fourier"
+ say framp~ "Donne la rampe pour chaque block"
+ foreach word {mtof ftom rmstodb dbtorms rmstopow powtorms} {
+ say $word~ "[say $word] (pour les signaux)"
+ }
+}
+
+### phase 3
+
+say_namespace summary {
+ say_category "AUDIO GLUE"
+ say dac~ "Sortie audio"
+ say adc~ "Entre audio"
+ say sig~ "Conversion d'un nombre vers un signal"
+ say line~ "Gnre une rampe audio"
+ say vline~ "line~ de luxe"
+ say threshold~ "Dtecte les seuils d'un signal"
+ say snapshot~ "chantillonne un signal (converti en nombres)"
+ say vsnapshot~ "snapshot~ de luxe"
+ say bang~ "Envoie un signal de dclenchement aprs chaque block DSP"
+ say samplerate~ "Obtient la frquence d'chantillonnage"
+ say send~ "Connection d'un signal non-local avec un transcepteur" #fanout=transceiver=transcepteur
+ say receive~ "Reoit le signal venant de send~"
+ say throw~ "Additionne le Signal un bus"
+ say catch~ "Dfinit et lit la somme des signaux dans un bus"
+ say block~ "spcifie la taille et la convergence d'un block"
+ say switch~ "Permutation marche/arrt du calcul DSP"
+ say readsf~ "Lit un fichier audio depuis le disque"
+ say writesf~ "Enregistre un fichier audio sur le disque"
+
+ say_category "OSCILLATEURS AUDIO ET TABLEAUX"
+ say phasor~ "Oscillateur en Dent De Scie"
+ say {cos~ osc~} "oscillateur cosinusodal"
+ say tabwrite~ "crit dans un tableau"
+ say tabplay~ "Lecture d'un tableau (non-transpositeur)"
+ say tabread~ "Lecture non-interpolatrice d'un tableau"
+ say tabread4~ "Lecture d'un tableau avec quatre points d'interpolation"
+ say tabosc4~ "Oscillateur table d'onde"
+ say tabsend~ "crit continuellement un block dans un tableau"
+ say tabreceive~ "Lit continuellement un block dans un tableau"
+
+ say_category "FILTRES AUDIO"
+ say vcf~ "filtre contrl par un signal (voltage)"
+ say noise~ "gnrateur de bruit blanc"
+ say env~ "suiveur d'enveloppe"
+ say hip~ "filtre passe haut"
+ say lop~ "filtre passe bas"
+ say bp~ "filtre passe bande"
+ say biquad~ "filtre brut"
+ say samphold~ "chantillonneur bloqueur"
+ say print~ "imprime un ou plusieurs \"blocks\""
+ say rpole~ "filtre valeurs relles brut un-ple"
+ say rzero~ "filtre valeurs relles brut zro-ple"
+ say rzero_rev~ "[say rzero~] (temps-invers)"
+ say cpole~ "[say rpole~] (valeurs-complexes)"
+ say czero~ "[say rzero~] (valeurs-complexes)"
+ say czero_rev~ "[say rzero_rev~] (valeurs-complexes)"
+
+ say_category "DELAI AUDIO"
+ say delwrite~ "crit dans une ligne de delai"
+ say delread~ "lit depuis une ligne de delai"
+ say vd~ "lit depuis une ligne de delai un temps de delai variable"
+
+ say_category "SUBWINDOWS"
+ say pd "Definie un subwindow"
+ say table "Tableau de nombres dans un subwindow"
+ say inlet "Ajouter une entre un pd" ###LOL
+ say outlet "Ajouter une sortie un pd" ###LOL
+ say inlet~ "[say inlet] (pour un signal)"
+ say outlet~ "[say outlet] (pour un signal)"
+
+ say_category "CALIBRAGE DE DONNEES"
+ say struct "dfinit une structure de donnes"
+ say {drawcurve filledcurve} "Dessine une courbe"
+ say {drawpolygon filledpolygon} "Dessine un polygone"
+ say plot "parcelle le champ d'un tableau"
+ say drawnumber "Imprime une valeur numrique"
+
+ say_category "ACCEDER AUX DONNEES"
+ say pointer "Pointe vers un objet appartenant un calibrage"
+ say get "Obtient des champs numriques"
+ say set "Change des champs numriques"
+ say element "Obtient l'lment d'un tableau"
+ say getsize "Obtient la taille d'un tableau"
+ say setsize "Change la taille d'un tableau"
+ say append "Ajoute un lment la liste"
+ say sublist "Obtient un pointeur dans la liste qui est l'lment d'un autre scalaire"
+ say scalar "Dessine un scalaire sur le parent"
+
+ say_category "OBSOLETE"
+ say scope~ "(utiliser tabwrite~)"
+ say namecanvas "Renomme un patch" ;# what was this anyway?
+ say template "(utiliser struct)"
+}
+
+# phase 4 (pdrc & ddrc)
+
+say section_audio "Audio"
+ say -r "Frquence d'chantillonage"
+ say -audioindev "Appareils audio en entre"
+ say -audiooutdev "Appareils audio en sortie"
+ say -inchannels "Nombre de canaux d'entre audio(par appareil, comme \"2\" ou \"16,8\")"
+ say -outchannels "Nombre de canaux de sortie audio (pareil)"
+ say -audiobuf "specifie la taille de la mmoire tampon en msec"
+ say -blocksize "specifie la taille du block audio I/O en nombre d'chantillons"
+ say -sleepgrain "specify number of milliseconds to sleep when idle"
+ say -nodac "Supprime la sortie audio"
+ say -noadc "Supprime l'entre audio"
+ say audio_api_choice "Audio API"
+ say default "default"
+ say -alsa "use ALSA audio API"
+ say -jack "use JACK audio API"
+ say -mmio "use MMIO audio API (default for Windows)"
+ say -portaudio "use ASIO audio driver (via Portaudio)"
+ say -oss "use OSS audio API"
+ say -32bit "allow 32 bit OSS audio (for RME Hammerfall)"
+ say {} "default"
+
+say section_midi "MIDI"
+ say -nomidiin "Supprime l'entre MIDI"
+ say -nomidiout "Supprime la sortie MIDI"
+ say -midiindev "Liste des appareils MIDI en entre; e.g., \"1,3\" pour le premier, et le troisime"
+ say -midioutdev "Liste des appareils MIDI en sortie, mme format"
+
+say section_externals "Externals"
+ say -path "Chemin de recherche de fichiers"
+ say -helppath "Chemin de recherche des fichiers d'aides"
+ say -lib "Charge une librairie d'objets"
+
+say section_gui "Gooey"
+ say -nogui "supprime le dmarrage du GUI (attention)"
+ say -guicmd "substitue le GUI un autre programme (e.g., rsh)"
+ say -console "console scrollback lines (0 = disable console)"
+ say -look "icne de la barre des boutons"
+ say -statusbar "active la barre de status"
+ say -font "Specifie la taille par dfaut de la police"
+
+say section_other "Autre"
+ say -open "ouvrir un ou plusieurs fichier(s) au dmarrage"
+ say -verbose "extra printout on startup and when searching for files"
+ say -d "debug level"
+ say -noloadbang "disable the effect of \[loadbang\]"
+ say -send "envoie un message au dmarrage (aprs que les patches soient chargs)"
+ say -listdev "list audio and MIDI devices upon startup"
+ say -realtime "use real-time priority (needs root privilege)"
+
+say section_paths "Paths"
+
+# phase 4B: ddrc (keyword names not finalized!)
+
+say section_color "couleurs"
+ say canvas_color "canevas"
+ say canvasbgedit "arrire plan d'un canevas (edit mode)"
+ say canvasbgrun "arrire plan d'un canevas (run mode)"
+ say object_color "objet"
+ say viewframe1 "couleur de la boite d'objet"
+ say viewframe2 "couleur de la boite d'objet"
+ say viewframe3 "couleur de la boite d'objet"
+ say viewframe4 "couleur du point culminant de la boite d'objet"
+ say viewbg "arrire plan d'un objet"
+ say viewfg "arrire plan d'un objet"
+ say commentbg "arrire plan d'un commentaire"
+ say commentfg "premier plan d'un commentaire"
+ say commentframe1 "comment frame"
+ say commentframe2 "comment frame"
+ say commentframe3 "comment frame"
+ say viewselectframe "boite selectionne"
+ say wire_color "cordon"
+ say wirefg "couleur d'un cordon"
+ say wirefg2 "couleur du point culminant d'un cordon"
+ say wiredspfg "couleur d'un cordon DSP"
+ say futurewiredash "nouveau cordon (en pointillets)"
+ say others_color "couleur des autres"
+ say boxinletfg "couleur de l'entre"
+ say boxoutletfg "couleur de la sortie"
+ say selrectrect "boite de selection"
+say keys "touches"
+say others "autres"
+say canvashairstate "Activer le rticule"
+say canvashairsnap "Crosshair snap to object"
+say canvasstatusbar "Activer la barre du status"
+say canvasbuttonbar "Activer la barre des boutons"
+say wirewirearrow "Flche blanche"
+say viewtooltip "ToolTip"
+say canvasinsert_object "Inserer un objet"
+say canvaschain_object "Enchanner un objet"
+say canvasclear_wires "Supprimer les cordons"
+say canvasauto_wire "Supprimer un objet"
+# phase 5A
+
+say cannot "ne peut"
+say cancel "Annuler"
+say apply "Appliquer"
+say ok "OK"
+say popup_open "Ouvrir"
+say popup_insert "Insrer"
+say popup_properties "Proprits"
+say popup_clear_wires "Supprimer les cordons"
+say popup_auto_wire "Supprimer l'objet"
+say popup_help "Aide"
+say filter "Filtre: "
+say how_many_object_classes "%d of %d classes d'objet"
+say do_what_i_mean "Fais ce que je te dis"
+say ask_cool "a serait cool, hein?"
+say save_changes? "Sauvergarder les changements?"
+say reset "Remise zero"
+say Courier "Courier (monospaced)"
+say Helvetica "Helvetica (sansserif)"
+say Times "Times (serif)"
+say add "Ajouter"
+say up "Vers le haut"
+say down "Vers le haut"
+say remove "Supprimer"
+say lib_add "Ajouter le nom ajout la liste"
+say lib_up "Inverser l'ordre avec la lbrairie prcdente"
+say lib_down "Inverser l'ordre avec la lbrairie suivante"
+say lib_remove "Supprimer la librairie selectionne dans la liste"
+say dir_add "Ajouter un dossier avec la boite de dialogue"
+say dir_up "Inverser l'ordre avec le dossier prcdent"
+say dir_down "Inverser l'ordre avec le dossier suivant"
+say dir_remove "Supprimer le dossier selectionn dans la liste"
+say client_class_tree "Client Class Tree"
+say clipboard_view "Vue du presse-papier"
+say command_history_view "Vue de l'historique de commandes"
+say event_history_view "Vue de l'historique d'vnements"
+
+# during/after piksel:
+
+say auto_apply "Appliquer automatiquement"
+say font_preview "Aperu"
+say font_preview_2 "ABCDEFGHIJKLMNOPQRSTUVWXYZ\nabcdefghijklmnopqrstuvwxyz\n0123456789"
+say font_style "Style:"
+say font_bold "Gras"
+say font_italic "Italique"
+say font_family "Nom:"
+say font_size "Taille:"
+say damn "Zut alors!"
+say console_clear "Effacer la console"
+say horizontal "Horizontal"
+say vertical "Vertical"
diff --git a/desiredata/src/locale/index.tcl b/desiredata/src/locale/index.tcl
new file mode 100644
index 00000000..c35c2156
--- /dev/null
+++ b/desiredata/src/locale/index.tcl
@@ -0,0 +1,21 @@
+say english "English"
+say francais "Franais"
+say espanol "Espaol"
+say deutsch "Deutsch"
+say bokmal "Norsk Bokml"
+say italiano "Italiano"
+say portugues "Portugus"
+say catala "Catal"
+say euskara "Euskara"
+say polski "Polski"
+say dansk "Dansk"
+say nederlands "Nederlands"
+say turkce "Trke"
+say brasiliano "Brasiliano"
+
+# those were made using:
+# iconv -f utf-8 -t ucs-2 | od -tx2 -An | sed 's/ /\\u/g'
+
+say chinese "\u4e2d\u6587"
+say nihongo "\u65e5\u672c\u8a9e"
+say russkij "\u0420\u0443\u0441\u0441\u043a\u0438\u0439"
diff --git a/desiredata/src/locale/italiano.tcl b/desiredata/src/locale/italiano.tcl
new file mode 100644
index 00000000..8513e4b9
--- /dev/null
+++ b/desiredata/src/locale/italiano.tcl
@@ -0,0 +1,544 @@
+#!/usr/bin/env tclsh
+# English translations for PureData
+# $Id: italiano.tcl,v 1.1.2.5.2.1 2006-12-05 04:51:47 matju Exp $
+# by Davide Morelli and Federico Ferri
+
+### Menus
+
+say file "File"
+ say new_file "Nuovo File"
+ say open_file "Apri File..."
+ say pdrc_editor "Editor di .pdrc"
+ say ddrc_editor "Editor di .ddrc"
+ say send_message "Invia un Messaggio..."
+ say paths "Percorsi..."
+ say close "Chiudi"
+ say save "Salva"
+ say save_as "Salva con nome..."
+ say print "Stampa..."
+ say quit "Esci"
+
+ say canvasnew_file "Nuovo File"
+ say canvasopen_file "Apri File..."
+ say canvassave "Salva"
+ say canvassave_as "Salva con nome..."
+ say clientpdrc_editor ".pdrc Editor"
+ say clientddrc_editor ".ddrc Editor"
+ say canvasclose "Chiudi"
+ say canvasquit "Esci"
+
+say edit "Modifica"
+ say undo "Annulla"
+ say redo "Ripristina"
+ say cut "Taglia"
+ say copy "Copia"
+ say paste "Incolla"
+ say duplicate "Duplica"
+ say select_all "Seleziona tutto"
+ say text_editor "Editor di Testi..."
+ say font "Font"
+ say tidy_up "Tidy Up"
+ say edit_mode "Modalit modifica"
+ say editmodeswitch "Modalit modifica/esegui"
+
+ say canvascut "Taglia"
+ say canvascopy "Copia"
+ say canvasundo "Annulla"
+ say canvasredo "Ripristina"
+ say canvaspaste "Incolla"
+ say canvasduplicate "Duplica"
+ say canvasselect_all "Seleziona tutto"
+ say canvaseditmodeswitch "Modalit modifica/esegui"
+
+say view "Visualizza"
+ say reload "Ricarica"
+ say redraw "Ridisegna"
+
+ say canvasreload "Ricarica"
+ say canvasredraw "Ridisegna"
+
+say find "Trova"
+ say find_again "Cerca Ancora"
+ say find_last_error "Cerca l'ultimo errore"
+ say string "Cerca stringa"
+say canvasfind "Trova"
+ say canvasfind_again "Cerca Ancora"
+
+# ???
+say put "Inserisci"
+ say Object "Oggetto"
+ say Message "Messaggio"
+ say Number "Numero"
+ say Symbol "Simbolo"
+ say Comment "Commento"
+ say Array "Array"
+ say Graph "Grafico"
+ say VU "Misuratore VU"
+
+say media "Media"
+ say audio_on "Audio ON"
+ say audio_off "Audio OFF"
+ say test_audio_and_midi "Test Audio e MIDI"
+ say load_meter "Misura carico cpu"
+
+ say canvasaudio_on "Audio ON"
+ say canvasaudio_off "Audio OFF"
+ say clienttest_audio_and_midi "Test Audio e MIDI"
+ say canvasload_meter "Misura carico cpu"
+
+say window "Finestra"
+
+say help "Aiuto"
+ say about "Informazioni su..."
+ say pure_documentation "Guida..."
+ say class_browser "Elenco delle classi..."
+
+ say canvasabout "Informazioni su..."
+
+say properties "Propriet"
+say open "Apri"
+
+### for key binding editor
+say general "Generali"
+say audio_settings "Impostazioni audio"
+say midi_settings "Impostazioni MIDI"
+say latency_meter "Misura latenza"
+say Pdwindow "Pd window"
+
+say canvaspdwindow "Pd window"
+say canvaslatency_meter "Misura latenza"
+say clientaudio_settings "Impostazioni audio"
+say clientmidi_settings "Impostazioni MIDI"
+
+### for Properties Dialog (phase 5B)
+say_category IEM
+say w "larghezza(px)"
+say h "altezza(px)"
+say hold "hold time(ms)"
+say break "break time(ms)"
+say min "minimo"
+say max "massimo"
+say is_log "modo"
+say linear "lineare"
+say logarithmic "logaritmico"
+say isa "val. iniziale"
+say n "numero di scelte"
+say steady "comportamento"
+say steady_no "salta"
+say steady_yes "stabile"
+say snd "send-symbol"
+say rcv "receive-symbol"
+say lab "etichetta"
+say ldx "etichetta offset-x"
+say ldy "etichetta offset-y"
+say fstyle "font"
+say fs "dim. font"
+say bcol "Colore sfondo"
+say fcol "Colore primo piano"
+say lcol "Colore etichetta"
+say yes "si"
+say no "no"
+say courier "courier (typewriter)"
+say helvetica "helvetica (sansserif)"
+say times "times (serif)"
+say coords "grafico su parent"
+
+say_category GAtomProperties
+say width "larghezza"
+say lo "limite inferiore"
+say hi "limite superiore"
+say label "etichetta"
+say wherelabel "mostra etichetta"
+say symto "send symbol"
+say symfrom "receive symbol"
+
+say_category GraphProperties
+say x1 "x da"
+say x2 "x a"
+say xpix "larghezza schermo"
+say y2 "y da"
+say y1 "y a"
+say ypix "altezza schermo"
+
+say_category CanvasProperties
+#say xscale "X units/px"
+#say yscale "Y units/px"
+say gop "graph on parent"
+say xmargin "margine-x"
+say ymargin "margine-y"
+say height "altezza"
+say_category ArrayProperties
+say name "nome"
+say n "dimensione"
+say xfrom "x range da"
+say xto "x range a"
+say yfrom "y range da"
+say yto "y range a"
+
+
+say_category MainWindow
+say in "in"
+say out "out"
+say audio "Audio"
+say meters "Livelli"
+say io_errors "Errori IO"
+
+### phase 2
+
+say_category Other
+say_namespace summary {
+ say_category IEMGUI
+ say bng "Bang Box"
+# say Bang "Bang"
+# say Toggle "Toggle"
+ say tgl "Toggle Box"
+ say nbx "Number Box (IEM)"
+# say Number2 "Number2"
+ say hsl "Slider (Orizzontale)"
+ say vsl "Slider (Verticale)"
+ say hradio "Choice Box (Orizzontale)"
+ say vradio "Choice Box (Verticale)"
+# say Vradio "Radio verticale"
+# say Hradio "Radio orizzontale"
+ say cnv "Canvas (IEM)"
+# say Canvas "Canvas"
+ say vu "Vumeter"
+ say dropper "Drag-and-Drop Box"
+
+ say_category GLUE
+ say bang "invia un bang"
+ say float "salva e richiama un numero in virgola mobile"
+ say symbol "salva e richiama un simbolo"
+ say int "salva e richiama un numero intero"
+ say send "invia un messaggio ad un oggetto con nome"
+ say receive "cattura i messaggi inviati"
+ say select "invia un bang quando i numeri o i simboli combaciano"
+ say route "instrada i messaggi in base al primo elemento della lista"
+ say pack "impacchetta i valori in un messaggio"
+ say unpack "ricava gli elementi di un pacchetto"
+ say trigger "converte i messaggi ed esegue in sequenza"
+ say spigot "connessione interrompibile"
+ say moses "divide un flusso numerico"
+ say until "meccanismo per creare un ciclo"
+ say print "stampa messaggi in console"
+ say makefilename "formatta un simbolo con argomenti"
+ say change "rimuove le ripetizioni numeriche da un flusso"
+ say swap "scambia tra loro due numeri"
+ say value "valore numerico condiviso"
+
+ say_category TIME
+ say delay "invia un messaggio dopo un ritardo temporale"
+ say metro "invia un messaggio periodicamente"
+ say line "invia una serie di numeri interpolati linearmente"
+ say timer "misura intervalli di tempo"
+ say cputime "misura l'utilizzo della CPU"
+ say realtime "misura il tempo reale"
+ say pipe "linea di ritardo dinamicamente dimensionabile per numeri"
+
+ say_category MATH
+ say + "somma"
+ say - "sottrai"
+ say * "moltiplica"
+ say {/ div} "dividi"
+ say {% mod} "resto delal divisione intera"
+ say pow "esponenziale"
+ say == "uguale?"
+ say != "non uguale?"
+ say > "maggiore?"
+ say < "minore?"
+ say >= "non maggiore?"
+ say <= "non minore?"
+ say & "congiunzione binaria (and)"
+ say | "disgiunzione binaria (or)"
+ say && "congiunzione logica (and)"
+ say || "disgiunzione logica (or)"
+ say mtof "da MIDI a Hertz"
+ say mtof "da Hertz a MIDI"
+ say powtodb "da Watts a dB"
+ say dbtopow "da dB a Watts"
+ say rmstodb "da Volts a dB"
+ say dbtorms "da dB a Volts"
+ say {sin cos tan atan atan2 sqrt} "trigonometria"
+ say log "logaritmo di Eulero"
+ say exp "esponenziale di Eulero"
+ say abs "valore assoluto"
+ say random "valore casuale"
+ say max "il maggiore tra due numeri"
+ say min "il minore tra due numeri"
+ say clip "forza un numero dentro un intervallo"
+
+ say_category MIDI
+ say {notein ctlin pgmin bendin touchin polytouchin midiin sysexin} \
+ "MIDI input"
+ say {noteout ctlout pgmout bendout touchout polytouchout midiout} \
+ "MIDI output"
+ say makenote \
+ "crea e metti in coda un messaggio \"note off\" corrispondente a questo note-on"
+ say stripnote "togli i messaggi di \"note off\""
+
+ say_category TABLES
+ say tabread "leggi un valore da una tabella"
+ say tabread4 "leggi un valore da una tabella con interpolazione su 4 punti"
+ say tabwrite "scrivi un valore in una tabella"
+ say soundfiler "leggi e scrivi tabelle in file audio"
+
+ say_category MISC
+ say loadbang "bang al caricamento"
+ say serial "controllo per la porta seriale (solo per NT)"
+ say netsend "manda messaggi su internet"
+ say netreceive "riceve messaggi da internet"
+ say qlist "sequencer di messaggi"
+ say textfile "convertitore di file in messaggi"
+ say openpanel "\"Apri\" dialog"
+ say savepanel "\"salva con nome\" dialog"
+ say bag "insieme di numeri"
+ say poly "allocazione polifonica di voci"
+ say {key keyup} "valori numerici da tastiera"
+ say keyname "valori in simboli da tastiera"
+
+ say_category "AUDIO MATH"
+ foreach word {+ - * /} {say $word~ "[say $word] (per segnali)"}
+ say max~ "il valore massimo"
+ say min~ "il valore minimo"
+ say clip~ "costringe il segnale all'interno di un intervallo"
+ say q8_rsqrt~ "radice quadrata reciproca veloce (attenzione -- 8 bits!)"
+ say q8_sqrt~ "radice quadrata veloce (attenzione -- 8 bits!)"
+ say wrap~ "wraparound (fractional part, sort of)"
+ say fft~ "Trasformata di Fourier complessa discreta"
+ say ifft~ "Trasformata di Fourier complessa discreta inversa"
+ say rfft~ "Trasformata di Fourier reale discreta"
+ say rifft~ "Trasformata di Fourier reale discreta inversa"
+ say framp~ "output a ramp for each block"
+ foreach word {mtof ftom rmstodb dbtorms rmstopow powtorms} {
+ say $word~ "[say $word] (per segnali)"
+ }
+}
+
+
+ ### phase 3
+
+say_namespace summary {
+ say_category "AUDIO GLUE"
+ say dac~ "audio output"
+ say adc~ "audio input"
+ say sig~ "converte numeri in segnali audio"
+ say line~ "genera una rampa sui segnali"
+ say vline~ "line~ con maggiore precisione"
+ say threshold~ "avverte il superamento di una soglia"
+ say snapshot~ "converte un segnale in numero"
+ say vsnapshot~ "snapshot~ con maggiore precisione"
+ say bang~ "invia un bang dopo ogni blicco DSP"
+ say samplerate~ "invia la frequenza di campionamento"
+ say send~ "invia segnali"
+ say receive~ "riceve segnali da send~"
+ say throw~ "aggiunge il segnale ad un bus"
+ say catch~ "legge il segnale da un bus"
+ say block~ "specifica la dimensione del blocco DSP"
+ say switch~ "attiva o disattiva la computazione DSP in questa finestra"
+ say readsf~ "riproduzione di un file audio"
+ say writesf~ "registrazione di un file audio"
+
+ say_category "AUDIO OSCILLATORS AND TABLES"
+ say phasor~ "oscillatore a onda triangolare"
+ say {cos~ osc~} "oscillatore a onda sinusoidale"
+ say tabwrite~ "scrive il segnale in una tabella"
+ say tabplay~ "riproduce il segnale registrato in una tabella (senza trasportare)"
+ say tabread~ "legge il segnale da una tabella senza interpolazione"
+ say tabread4~ "legge il segnale da una tabella con interpolazione su 4 punti"
+ say tabosc4~ "oscillatore wavetable"
+ say tabsend~ "scrive continuamente un blocco su una tabella"
+ say tabreceive~ "legge continuamente un blocco da una tabella"
+
+ say_category "AUDIO FILTERS"
+ say vcf~ "filtro a voltaggio controllato"
+ say noise~ "rumore bianco"
+ say env~ "indicatore di inviluppo"
+ say hip~ "filtro passa alto"
+ say lop~ "filtro passa basso"
+ say bp~ "filtro a banda passante"
+ say biquad~ "filtro biquadratico"
+ say samphold~ "campiona e trattiene un segnale"
+ say print~ "scrive uno o pi blocchi sulla console"
+ say rpole~ "raw real-valued one-pole filter"
+ say rzero~ "raw real-valued one-zero filter"
+ say rzero_rev~ "[say rzero~] (time-reversed)"
+ say cpole~ "[say rpole~] (complex-valued)"
+ say czero~ "[say rzero~] (complex-valued)"
+ say czero_rev~ "[say rzero_rev~] (complex-valued)"
+
+ say_category "AUDIO DELAY"
+ say delwrite~ "scrive una linea di ritardo"
+ say delread~ "legge una linea di ritardo"
+ say vd~ "legge una linea di ritardo con tempo variabile"
+
+ say_category "SUBWINDOWS"
+ say pd "definisce una sottofinestra"
+ say table "un vettore di numeri in una sottofinestra"
+ say inlet "aggiunge un inlet"
+ say outlet "aggiunge un outlet"
+ say inlet~ "[say inlet] (per segnali)"
+ say outlet~ "[say outlet] (per segnali)"
+
+ say_category "DATA TEMPLATES"
+ say struct "definisce una struttura dati"
+ say {drawcurve filledcurve} "disegna una curva"
+ say {drawpolygon filledpolygon} "disegna un poligono"
+ say plot "disegna un vettore"
+ say drawnumber "stampa un valore numerico"
+
+ say_category "ACCESSING DATA"
+ say pointer "puntatore ad un oggetto che appartiene ad un template"
+ say get "ottiene una propriet numerica"
+ say set "imposta una propriet numerica"
+ say element "ottiene una propriet vettore"
+ say getsize "imposta una propriet vettore"
+ say setsize "cambia le dimensioni di un vettore"
+ say append "aggiunge un elemento ad una lista"
+ say sublist "ottiene un puntatore da una lista che un elemento di un'altro scalare"
+ say scalar "disegna uno scalare sulla finestra"
+
+ say_category "OBSOLETE"
+ say scope~ "(usa tabwrite~)"
+ say namecanvas "" ;# what was this anyway?
+ say template "(usa struct)"
+}
+
+# phase 4 (pdrc & ddrc)
+
+say section_audio "Audio"
+ say -r "frequenza di campionamento"
+ say -audioindev "periferiche audio in"
+ say -audiooutdev "periferiche audio out"
+ say -inchannels "canali audio input (per periferica, es.: \"2\" o \"16,8\")"
+ say -outchannels "numero di canali audio out (come sopra)"
+ say -audiobuf "dimensione del buffer audio in msec"
+ say -blocksize "dimensione del blocco I/O block in campioni"
+ say -sleepgrain "numero di millisecondi di attesa quando idle"
+ say -nodac "senza audio output"
+ say -noadc "senza audio input"
+ say audio_api_choice "Audio API"
+ say default "default"
+ say -alsa "usa ALSA audio API"
+ say -jack "usa JACK audio API"
+ say -mmio "usa MMIO audio API (default for Windows)"
+ say -portaudio "usa ASIO audio driver (via Portaudio)"
+ say -oss "usa OSS audio API"
+ say -32bit "permetti audio OSS a 32 bit (per RME Hammerfall)"
+ say {} "default"
+
+say section_midi "MIDI"
+ say -nomidiin "senza MIDI input"
+ say -nomidiout "senza MIDI output"
+ say -midiindev "lista periferiche midi in; es.: \"1,3\" per la prima e la terza"
+ say -midioutdev "lista periferiche midi out; come sopra"
+
+say section_externals "Externals"
+ say -path "percorso di ricerca files"
+ say -helppath "percorso di ricerca help"
+ say -lib "carica le seguenti librerie"
+
+say section_gui "Gooey"
+ say -nogui "senza avviare la GUI (attenzione)"
+ say -guicmd "programma GUI alternativo (es.: rsh)"
+ say -console "n. linee scrollback console (0 = disabilita la console)"
+ say -look "icone pulsantiera"
+ say -statusbar "abilita barra di stato"
+ say -font "dimensione di default per i font (in punti)"
+
+say section_other "Other"
+ say -open "apri file(s) all'avvio"
+ say -verbose "stampa messaggi extra all'avvio e durante la ricerca di files"
+ say -d "levello di debug"
+ say -noloadbang "disabilita l'effetto di \[loadbang\]"
+ say -send "manda un messaggio all'avvio (dopo il caricamento delle patch)"
+ say -listdev "elenca le periferiche audio e MIDI all'avvio"
+ say -realtime "usa real-time priority (necessita privilegi root)"
+
+say section_paths "Paths"
+
+# phase 4B: ddrc (keyword names not finalized!)
+
+say section_color "colors"
+ say canvas_color "canvas"
+ say canvasbgedit "sfondo canvas (modalit edit)"
+ say canvasbgrun "sfondo canvas (modalit run)"
+ say object_color "oggetto"
+ say viewframe1 "colore objectbox"
+ say viewframe2 "colore objectbox"
+ say viewframe3 "colore objectbox"
+ say viewframe4 "colore objectbox selezionato"
+ say viewbg "sfondo oggetto"
+ say viewfg "primo piano oggetto"
+ say commentbg "sfondo commento"
+ say commentfg "testo del commento"
+ say commentframe1 "cornice commento"
+ say commentframe2 "cornice commento"
+ say commentframe3 "cornice commento"
+ say viewselectframe "box selezione (viewselectframe)"
+ say wire_color "cavo"
+ say wirefg "colore cavo"
+ say wirefg2 "colore cavo selezionato"
+ say wiredspfg "colore cavo audio"
+ say futurewiredash "nuovo cavo (tratteggiato)"
+ say others_color "altro"
+ say boxinletfg "colore inlet color"
+ say boxoutletfg "colore outlet color"
+ say selrectrect "box selezione (selrectrect)"
+say keys "tasti"
+say others "altro"
+say canvashairstate "Attiva cursore di precisione"
+say canvashairsnap "Cursore \"magnetico\""
+say canvasstatusbar "Attiva barra di stato"
+say canvasbuttonbar "Attiva pulsantiera"
+say wirewirearrow "Wire Arrow"
+say viewtooltip "Suggerimenti"
+say canvasinsert_object "Inserisci oggetto"
+say canvaschain_object "Cascata oggetto"
+say canvasclear_wires "Elimina connessioni"
+say canvasauto_wire "Rimuovi oggetto"
+# phase 5A
+
+say cannot "non posso"
+say cancel "Annulla"
+say apply "Applica"
+say ok "OK"
+say popup_open "Apri"
+say popup_insert "Inserisci"
+say popup_properties "Propriet"
+say popup_clear_wires "Elimina connessioni"
+say popup_auto_wire "Rimuovi connessioni"
+say popup_help "Aiuto"
+say filter "Filtra: "
+say how_many_object_classes "%d su %d oggetti"
+say do_what_i_mean "Do What I Mean"
+say save_changes? "Salvare le modifiche?"
+say reset "Reset"
+say Courier "Courier (monospaced)"
+say Helvetica "Helvetica (sansserif)"
+say Times "Times (serif)"
+say add "Aggiungi"
+say up "Spusta su"
+say down "Sposta gi"
+say remove "Rimuovi"
+say lib_add "aggiungi il nome che hai scritto alla lista"
+say lib_up "inverti di ordine con la libreria precedente"
+say lib_down "inverti di ordine con la libreria successiva"
+say lib_remove "rimuove la libreria selezionata dalla lista"
+say dir_add "aggiunge una directory"
+say dir_up "inverti di ordine con la directory precedente"
+say dir_down "inverti di ordine con la directory successiva"
+say dir_remove "rimuove la directory selezionata dalla lista"
+say client_class_tree "Albero delle Classi"
+say clipboard_view "Appunti"
+say history_view "Storia"
+
+# during/after piksel:
+
+say auto_apply "Auto-Applica"
+say font_preview "Anteprima:"
+say font_preview_2 "ABCDEFGHIJKLMNOPQRSTUVWXYZ\nabcdefghijklmnopqrstuvwxyz\n0123456789"
+say font_style "Stile:"
+say font_bold "Grassetto"
+say font_italic "Corsivo"
+say font_family "Nome:"
+say font_size "Dimensione font"
diff --git a/desiredata/src/locale/localeutils.tcl b/desiredata/src/locale/localeutils.tcl
new file mode 100755
index 00000000..f53c5b66
--- /dev/null
+++ b/desiredata/src/locale/localeutils.tcl
@@ -0,0 +1,109 @@
+#!/usr/bin/env tclsh
+# to check the difference between locale files
+# arguments:
+# -list view the list of supported locales
+# -lang <locale> compare <locale> to english
+# no option: summary of all locales
+
+proc lwithout {a b} {
+ set r {}
+ foreach x $b {set c($x) {}}
+ foreach x $a {if {![info exists c($x)]} {lappend r $x}}
+ return $r
+}
+
+proc lintersection {a b} {
+ set r {}
+ foreach x $b {set c($x) {}}
+ foreach x $a {if {[info exists c($x)]} {lappend r $x}}
+ return $r
+}
+
+proc say {k args} {
+ global text
+ if {[llength $args]} {
+ set ${::name}($k) [lindex $args 0]
+ } else {
+ if {[info exist text($k)]} {
+ puts "------------"
+ return $text($k)
+ } else {return "{{$k}}"}
+ }
+}
+
+proc say_namespace {k code} {uplevel 1 $code}
+proc say_category {text} {}
+
+set ::name ::index
+array set ::index {}
+source index.tcl
+
+foreach lang [array names ::index] {
+ set ::name ::$lang
+ source $lang.tcl
+}
+
+proc summary {} {
+ foreach lang [lsort [lwithout [array names ::index] english]] {
+ puts "#-----------------------------8<-----CUT------8<-----------------------------#"
+ key_compare $lang; value_compare $lang
+ }
+}
+
+proc compare {lang} {
+ key_compare $lang
+ value_compare $lang
+}
+
+proc value_compare {lang} {
+ puts "\nFollowing entries have the same value as English:"
+ set values {}
+ set english2 [array names ::english]
+ set locale [array names ::$lang]
+ set intersect [lintersection $english2 $locale]
+ foreach item [lsort $intersect] {
+ set val1 $::english($item)
+ set val2 [set ::${lang}($item)]
+ if {$val1 == $val2} {
+ lappend values $item
+ }
+ }
+ foreach item $values {puts "\t $item"}
+}
+
+
+proc key_compare {lang} {
+ set english2 [array names ::english]
+ set locale [array names ::$lang]
+ set diff_missing [lwithout $english2 $locale]
+ set diff_extra [lwithout $locale $english2]
+ set percent_missing [expr int(([llength $diff_missing] / [llength $english2].0)*100)]
+ set percent_extra [expr int(([llength $diff_extra] / [llength $english2].0)*100)]
+ puts "\ncompare $lang to english --> ${percent_missing}% difference"
+ foreach item [lsort $diff_missing] {
+ puts " - $item"
+ }
+ puts "\ncompare english to $lang --> ${percent_extra}% difference"
+ foreach item [lsort $diff_extra] {
+ puts " + $item"
+ }
+}
+
+
+if {![llength $argv]} {
+ summary
+} else {
+ switch -regexp -- [lindex $argv 0] {
+ ^-list\$ {puts [lwithout [array names ::index] english]}
+ ^-lang\$ {
+ set lang [lindex $argv 1]
+ if {[lsearch [array names ::index] $lang] > 0} {compare $lang} {puts "Unknown locale '$lang'"}
+ }
+ ^-h\$ {
+ puts "-list view the list of supported locales"
+ puts "-lang <locale> only report about <locale> instead of about all locales"
+ }
+ default {puts "Unknown option '[lindex $argv 0]'. try -h for help"}
+ }
+}
+
diff --git a/desiredata/src/locale/nederlands.tcl b/desiredata/src/locale/nederlands.tcl
new file mode 100644
index 00000000..bb910dc7
--- /dev/null
+++ b/desiredata/src/locale/nederlands.tcl
@@ -0,0 +1,599 @@
+#!/usr/bin/env tclsh
+# English translations for PureData
+# $Id: nederlands.tcl,v 1.1.2.1 2007-10-05 23:14:58 matju Exp $
+
+### Menus
+
+say file "Bestand"
+ say new_file "Nieuw Bestand"
+ say open_file "Open Bestand"
+ say server_prefs "Server Voorkeuren..."
+ say client_prefs "Client Voorkeuren..."
+ say pdrc_editor ".pdrc Bewerken"
+ say ddrc_editor ".ddrc Bewerken"
+ say send_message "Zend Boodschap..."
+ say paths "Paden..."
+ say close "Sluiten"
+ say save "Opslaan"
+ say save_as "Opslaan Als..."
+ say print "Afdrukken..."
+ say abort_server "Server Afsluiten"
+ say quit "Sluiten"
+
+ say canvasnew_file "Nieuw Bestand"
+ say canvasopen_file "Open Bestand..."
+ say canvassave "Opslaan"
+ say canvassave_as "Opslaan Als..."
+ say clientpdrc_editor ".pdrc Editor"
+ say clientddrc_editor ".ddrc Editor"
+ say canvasclose "Venster Sluiten"
+ say canvasquit "Sluiten"
+
+say edit "Bewerken"
+ say undo "Ongedaan Maken"
+ say redo "Bewerking Herdoen"
+ say cut "Knippen"
+ say copy "Kopieren"
+ say paste "Plakken"
+ say duplicate "Dupliceren"
+ say select_all "Alles Selecteren"
+ say text_editor "Text Editor..."
+ say font "Lettertype"
+ say tidy_up "Opkuisen"
+ say edit_mode "Edit modus"
+ say editmodeswitch "Edit/Run modus"
+
+ say canvascut "Knip"
+ say canvascopy "Kopiëer"
+ say canvasundo "Maak Ongedaan"
+ say canvasredo "Bewerking Opnieuw"
+ say canvaspaste "Plak"
+ say canvasduplicate "Dupliceer"
+ say canvasselect_all "Selecteer Alles"
+ say canvaseditmodeswitch "Edit/Run modus"
+
+say view "Beeld"
+ say reload "Herlaad"
+ say redraw "Herteken"
+
+ say canvasreload "Herlaad"
+ say canvasredraw "Herteken"
+
+say find "Zoek"
+ say find_again "Zoek Opnieuw"
+ say find_last_error "Zoek Laatste Fout"
+ say string "Zoek String"
+say canvasfind "Zoek"
+ say canvasfind_again "Zoek Opnieuw"
+
+# contents of Put menu is Phase 5C
+say put "Plaats"
+ say Object "Object"
+ say Message "Boodschap"
+ say Number "Nummer"
+ say Symbol "Symbool"
+ say Comment "Commentaar"
+ say Graph "Graph"
+ say Bang "Bang"
+ say Toggle "Toggle"
+ say Number2 "Nummer2"
+ say Vslider "Verticale Schuifregelaar"
+ say Hslider "Horizontale Schuifregelaar"
+ say Vradio "Verticale Radio"
+ say Hradio "Horizontale Radio"
+ say Canvas "Canvas"
+ say Array "Array"
+
+ say canvasobject "Object"
+ say canvasmessage "Boodschap"
+ say canvasnumber "Nummer"
+ say canvassymbol "Symbool"
+ say canvascomment "Commentaar"
+ say canvasbang "Bang"
+ say canvastoggle "Toggle"
+ say canvasnumber2 "Nummer2"
+ say canvasvslider "Verticale Schuifregelaar"
+ say canvashslider "Horizontale Schuifregelaar"
+ say canvasvradio "Verticale Radio"
+ say canvashradio "Horizontale Radio"
+ say canvascanvas "Canvas"
+ say canvasarray "Array"
+
+say media "Media"
+ say audio_on "Audio AAN"
+ say audio_off "Audio UIT"
+ say test_audio_and_midi "Test Audio en MIDI"
+ say load_meter "Belasting Meter"
+
+ say canvasaudio_on "Audio AAN"
+ say canvasaudio_off "Audio UIT"
+ say clienttest_audio_and_midi "Test Audio en MIDI"
+ say canvasload_meter "Belasting Meter"
+
+say window "Venster"
+
+say help "Hulp"
+ say about "Over..."
+ say pure_documentation "Pure Documentatie..."
+ say class_browser "Class Browser..."
+
+ say canvasabout "Over..."
+
+say properties "Eigenschappen"
+say open "Open"
+say documentation "Documentatie..."
+
+### for key binding editor
+say general "Algemeen"
+say audio_Instellingen "Audio Instellingen"
+say midi_Instellingen "Midi Instellingen"
+say latency_meter "Vertraging Meter"
+say Pdwindow "Pd venster"
+
+say canvaspdwindow "Pd venster"
+say canvaslatency_meter "Vertraging Meter"
+say clientaudio_Instellingen "Audio Istellingen"
+say clientmidi_Instellingen "Midi Instellingen"
+
+### for Properties Dialog (phase 5B)
+say_category IEM
+say w "breedte(px)"
+say h "hoogte(px)"
+say hold "houd tijd(ms)"
+say break "breek tijd(ms)"
+say min "minimum waarde"
+say max "maximum waarde"
+say is_log "modus"
+say linear "lineair"
+say logarithmic "logarithmisch"
+say isa "init"
+say n "aantal keuzen"
+say steady "gelijkmatigheid"
+say steady_no "verspring bij klik"
+say steady_yes "blijf staan bij klik"
+say snd "zend-symbool"
+say rcv "ontvang-symbool"
+say lab "etiket"
+say ldx "etiket x afstand"
+say ldy "etiket y afstand"
+say fstyle "Lettertype"
+say fs "letter grootte"
+say bcol "achtergrond kleur"
+say fcol "voorgrond kleur"
+say lcol "etiket kleur"
+say yes "ja"
+say no "nee"
+say courier "courier (typewriter)"
+say helvetica "helvetica (sansserif)"
+say times "times (serif)"
+say coords "graph on parent"
+
+say_category GAtomProperties
+say width "breedte"
+say lo "ondergrens"
+say hi "bovengrens"
+say label "etiket"
+say wherelabel "toon etiket aan"
+say symto "zend symbool"
+say symfrom "ontvang symbool"
+
+say_category GraphProperties
+say x1 "x van"
+say x2 "x tot"
+say xpix "scherm breedte"
+say y2 "y van"
+say y1 "y tot"
+say ypix "scherm hoogte"
+
+say_category CanvasProperties
+#say xscale "X units/px"
+#say yscale "Y units/px"
+say gop "graph on parent"
+say xmargin "xmarge"
+say ymargin "ymarge"
+say height "hoogte"
+say_category ArrayProperties
+say name "naam"
+say n "grootte"
+say xfrom "x omvang van"
+say xto "x omvang tot"
+say yfrom "y omvang van"
+say yto "y omvang tot"
+
+
+say_category MainWindow
+say in "in"
+say out "uit"
+say audio "Audio"
+say meters "Meters"
+say io_errors "IO Foutmeldingen"
+
+### phase 2
+
+say_category Other
+say_namespace summary {
+ say_category IEMGUI
+ say bng "Bang Box"
+ say tgl "Toggle Box"
+ say nbx "Nummer Box (IEM)"
+ say hsl "Schuifregelaar (Horizontaal)"
+ say vsl "Schuifregelaar (Verticaal)"
+ say hradio "Keuze Box (Horizontaal)"
+ say vradio "Keuze Box (Verticaal)"
+ say cnv "Canvas (IEM)"
+ say dropper "Drag-and-Drop Box"
+ say vu "Vumeter"
+
+ say_category GLUE
+ say bang "stuur een bang boodschap uit"
+ say float "een nummer opslaan en opvragen"
+ say symbol "een symbool opslaan en opvragen"
+ say int "een geheel getal opslaan en opvragen"
+ say send "stuur een boodschap naar benoemd object"
+ say receive "ontvang verzonden boodschappen"
+ say select "geef bang bij overeenkomstige nummers of symbolen"
+ say route "leid boodschappen om volgens eerste element"
+ say pack "maak samengestelde boodschappen"
+ say unpack "splits samengestelde boodschappen"
+ say trigger "sequentie en conversie van boodschappen"
+ say spigot "onderbreekbare verbinding"
+ say moses "een nummer-stroom splitsen"
+ say until "lus mechanisme"
+ say print "druk boodschap af"
+ say makefilename "maak een symbool met een variabel teken"
+ say change "verwijder herhalingen uit een nummer-stroom"
+ say swap "twee nummers omwisselen"
+ say value "gedeelde waarde"
+
+ say_category TIME
+ say delay "stuur een boodschap na een vertraging"
+ say metro "stuur een periodieke bang"
+ say line "stuur een reeks lineair gerangschikte nummers"
+ say timer "meet tijdsintervallen"
+ say cputime "meet CPU tijd"
+ say realtime "meet echte tijd"
+ say pipe "dynamisch aanpasbare vertraging"
+
+ say_category MATH
+ say + "plus"
+ say - "min"
+ say * "vermenigvuldig"
+ say {/ div} "delen"
+ say {% mod} "rest na deling"
+ say pow "machtsverheffing"
+ say == "is gelijk aan?"
+ say != "verschillend van?"
+ say > "is groter dan?"
+ say < "is kleiner dan?"
+ say >= "is groter dan of gelijk aan?"
+ say <= "is kleiner dan of gelijk aan?"
+ say & "bitsgewijze conjunctie (and)"
+ say | "bitsgewijze disjunctie (or)"
+ say && "logische conjunctie (and)"
+ say || "logische disjunctie (or)"
+ say mtof "MIDI naar Hertz"
+ say ftom "Hertz naar MIDI"
+ say powtodb "Watt naar dB"
+ say dbtopow "dB naar Watt"
+ say rmstodb "Volt naar dB"
+ say dbtorms "dB naar Volt"
+ say {sin cos tan atan atan2 sqrt} "driehoeksmeting"
+ say log "Euler logaritme"
+ say exp "Euler exponentieel"
+ say abs "absolute waarde"
+ say random "toeval"
+ say max "bovengrens waarde"
+ say min "ondergrens waarde"
+ say clip "houd een getal binnen een bereik"
+
+ say_category MIDI
+ say {notein ctlin pgmin bendin touchin polytouchin midiin sysexin} "MIDI ingang"
+ say {noteout ctlout pgmout bendout touchout polytouchout midiout} "MIDI uitgang"
+ say makenote "plan een uitgestelde \"note off\" boodschap voor elke note-on"
+ say stripnote "verwijder \"note off\" boodschappen"
+
+ say_category TABLES
+ say tabread "lees een nummer uit een tabel"
+ say tabread4 "lees een nummer uit een tabel, met 4 punts interpolatie"
+ say tabwrite "schrijf een nummer in een tabel"
+ say soundfiler "lees en schrijf tabellen van en naar bestanden"
+
+ say_category MISC
+ say loadbang "bang bij laden"
+ say serial "seriele apparaatcontrole enkel voor NT"
+ say netsend "stuur boodschappen over het internet"
+ say netreceive "ontvang boodschappen over het internet"
+ say qlist "boodschap sequencer"
+ say textfile "bestand naar boodschap omzetter"
+ say openpanel "\"Open\" dialoogvenster"
+ say savepanel "\"Save as\" dialoogvenster"
+ say bag "verzameling nummers"
+ say poly "polyphonische stemtoewijzing"
+ say {key keyup} "numerieke waarden van toetsen"
+ say keyname "symbolische naam van toetsen"
+
+ say_category "AUDIO WISKUNDE"
+ foreach word {+ - * /} {say $word~ "[say $word] (for signals)"}
+ say max~ "supremum van signalen"
+ say min~ "infimum van signalen"
+ say clip~ "beperk signaal tussen twee begrensingen"
+ say q8_rsqrt~ "goedkope reciprocal vierkantswortel (let op -- 8 bits!)"
+ say q8_sqrt~ "goedkope vierkantswortel (let op -- 8 bits!)"
+ say wrap~ "wraparound (fractional part, sort of)"
+ say fft~ "complex forward discrete Fourier transform"
+ say ifft~ "complex inverse discrete Fourier transform"
+ say rfft~ "real forward discrete Fourier transform"
+ say rifft~ "real inverse discrete Fourier transform"
+ say framp~ "output a ramp for each block"
+ foreach word {mtof ftom rmstodb dbtorms rmstopow powtorms} {
+ say $word~ "[say $word] (for signals)"
+ }
+}
+
+### phase 3
+
+say_namespace summary {
+ say_category "AUDIO LIJM"
+ say dac~ "audio uitgang"
+ say adc~ "audio ingang"
+ say sig~ "zet nummers om naar audiosignaal"
+ say line~ "genereer audio helling"
+ say vline~ "deluxe line~"
+ say threshold~ "detecteer audio grens"
+ say snapshot~ "neem staal van signaal (converteer terug naar nummer)"
+ say vsnapshot~ "deluxe snapshot~"
+ say bang~ "stuur een bang boodschap na elke DSP blok"
+ say samplerate~ "geef de sample rate"
+ say send~ "niet-locale signaal verbinding met uitwaaiering"
+ say receive~ "ontvang signaal van send~"
+ say throw~ "voeg toe aan een summing bus"
+ say catch~ "definieer en lees van een summing bus"
+ say block~ "specifieer blok grootte en overlapping"
+ say switch~ "schakel DSP berekeningen aan een uit"
+ say readsf~ "speel een geluidsbestand af van schijf"
+ say writesf~ "neem geluid op naar schijf"
+
+ say_category "AUDIO OSCILLATOREN AND TABELLEN"
+ say phasor~ "zaagtand oscillator"
+ say {cos~ osc~} "cosinus oscillator"
+ say tabwrite~ "schrijf naar een tabel"
+ say tabplay~ "speel af van een tabel (niet-transponerend)"
+ say tabread~ "niet-interpolerend lezen van tabel"
+ say tabread4~ "4 punts interpolerend lezen van tabel"
+ say tabosc4~ "golfvormtabel oscillator"
+ say tabsend~ "schijf een blok continu naar een tabel"
+ say tabreceive~ "lees een blok continu van een tabel"
+
+ say_category "AUDIO FILTERS"
+ say vcf~ "voltage controlled filter"
+ say noise~ "witte ruis generator"
+ say env~ "envelope follower"
+ say hip~ "hoog doorlaat filter"
+ say lop~ "laag doorlaat filter"
+ say bp~ "band doorlaat filter"
+ say biquad~ "rauwe filter"
+ say samphold~ "sample and hold eenheid"
+ say print~ "druk een of meer \"blokken\" af"
+ say rpole~ "raw real-valued one-pole filter"
+ say rzero~ "raw real-valued one-zero filter"
+ say rzero_rev~ "[say rzero~] (time-reversed)"
+ say cpole~ "[say rpole~] (complex-valued)"
+ say czero~ "[say rzero~] (complex-valued)"
+ say czero_rev~ "[say rzero_rev~] (complex-valued)"
+
+ say_category "AUDIO VERTRAGING"
+ say delwrite~ "schrijf naar vertragingslijn"
+ say delread~ "lees van vertragingslijn"
+ say vd~ "lees van een vertragingslijn met een variabele tijd"
+
+ say_category "SUBVENSTERS"
+ say pd "definieer een subvenster"
+ say table "reeks nummers in een subvenster"
+ say inlet "voeg een ingang toe aan een subvenster"
+ say outlet "voeg een uitgang toe aan een subvenster"
+ say inlet~ "[say inlet] (voor signaal)"
+ say outlet~ "[say outlet] (voor signaal)"
+
+ say_category "DATA TEMPLATES"
+ say struct "definieer een datastructuur"
+ say {drawcurve filledcurve} "teken een curve"
+ say {drawpolygon filledpolygon} "teken een veelhoek"
+ say plot "teken een array veld"
+ say drawnumber "druk een numerieke waarde af"
+
+ say_category "DATA BEREIKEN"
+ say pointer "wijs naar een object dat bij een template hoort"
+ say get "numerieke velden lezen"
+ say set "numerieke velden schrijven"
+ say element "een array element lezen"
+ say getsize "de grootte van een array opvragen"
+ say setsize "de grootte van een array wijzigen"
+ say append "een element aan een lijst toevoegen"
+ say sublist "een pointer in een lijst krijgen die een element is van een andere scalar"
+ say scalar "teken een scalar op parent"
+
+ say_category "OBSOLETE"
+ say scope~ "(use tabwrite~ now)"
+ say namecanvas "" ;# what was this anyway?
+ say template "(use struct now)"
+}
+
+# phase 4 (pdrc & ddrc)
+
+say section_audio "Audio"
+ say -r "sample rate"
+ say -audioindev "audio in apparaten"
+ say -audiooutdev "audio out apparaten"
+ say -inchannels "aantal audio-in kanalen (per apparaat, bijvoorbeeld \"2\" of \"16,8\")"
+ say -outchannels "aantal audio-uit kanalen (idem)"
+ say -audiobuf "specifieer grootte van audio buffer in msec"
+ say -blocksize "specifieer audio IN/UIT blok grootte in sample frames"
+ say -sleepgrain "specifieer het aantal milliseconden slaap wanneer inactief"
+ say -nodac "onderdruk audio uitgang"
+ say -noadc "onderdruk audio ingang"
+ say audio_api_choice "Audio API"
+ say default "default"
+ say -alsa "gebruik ALSA audio API"
+ say -jack "gebruik JACK audio API"
+ say -mmio "gebruik MMIO audio API (default voor Windows)"
+ say -portaudio "gebruik ASIO audio stuurprogramma (via Portaudio)"
+ say -oss "gebruik OSS audio API"
+ say -32bit "sta 32 bit OSS audio toe (voor RME Hammerfall)"
+ say {} "default"
+
+say section_midi "MIDI"
+ say -nomidiin "onderdruk MIDI ingang"
+ say -nomidiout "onderdruk MIDI uitgang"
+ say -midiindev "midi in apparatenlijst; bijvb., \"1,3\" voor eerste en derde"
+ say -midioutdev "midi uit apparatenlijst, (idem)"
+
+say section_externals "Externals"
+ say -path "zoek-pad voor bestanden"
+ say -helppath "zoek-pad voor help bestanden"
+ say -lib "laad objecten bibliotheek"
+
+say section_gui "Goe-wie"
+ say -nogui "start zonder grafische interface (opgelet)"
+ say -guicmd "gebruik een andere grafische interface (bijvb., rsh)"
+ say -console "console terug scroll lijnen (0 = schakel console uit)"
+ say -look "ikonen knoppenbalk"
+ say -statusbar "activeer statusbalk"
+ say -font "specifieer lettertekengrootte"
+
+say section_other "Andere"
+ say -open "open bestand bij opstarten"
+ say -verbose "extra informatie afdrukken vij opstarten en het zoeken naar bestanden"
+ say -d "debug niveau"
+ say -noloadbang "desactiveer \[loadbang\]"
+ say -send "stuur een boodschap (nadat de patches geladen zijn)"
+ say -listdev "geef lijst weer van audio en midi apparaten bij opstarten"
+ say -realtime "gebruik realtime prioriteit (vereist root-privileges)"
+
+say section_paths "Paden"
+
+# phase 4B: ddrc (keyword names not finalized!)
+
+say section_color "kleuren"
+ say canvas_color "canvas"
+ say canvasbgedit "canvas achtergrond (edit modus)"
+ say canvasbgrun "canvas achtergrond (run modus)"
+ say object_color "object"
+ say viewframe1 "objectbox kleur"
+ say viewframe2 "objectbox kleur"
+ say viewframe3 "objectbox kleur"
+ say viewframe4 "objectbox geselecteerd kleur"
+ say viewbg "object achtergrond"
+ say viewfg "object voorgrond"
+ say commentbg "comment achtergrond"
+ say commentfg "comment voorgrond"
+ say commentframe1 "commentaar frame"
+ say commentframe2 "commentaar frame"
+ say commentframe3 "commentaar frame"
+ say viewselectframe "geselecteerde box"
+ say wire_color "draad"
+ say wirefg "draad kleur"
+ say wirefg2 "draad geselecteerd"
+ say wiredspfg "dsp draad kleur"
+ say futurewiredash "nieuwe (stippelijn) draad"
+ say others_color "andere"
+ say boxinletfg "inlet kleur"
+ say boxoutletfg "outlet kleur"
+ say selrectrect "selectie box"
+say keys "toetsen"
+say others "andere"
+say canvashairstate "Activeer crosshair"
+say canvashairsnap "Crosshair spring naar object"
+say canvasstatusbar "Activeer statusbalk"
+say canvasbuttonbar "Activeer knoppenbalk"
+say wirewirearrow "Draad Pijl"
+say viewtooltip "ToolTip"
+say canvasinsert_object "Voeg object in"
+say canvaschain_object "Ketting object"
+say canvasclear_wires "Wis draden"
+say canvasauto_wire "Verwijder object"
+say subpatcherize "Subpatcherizeer"
+say keynav "toetsenbord navigatie"
+say key_nav_up "omhoog"
+say key_nav_up_shift "voeg toe aan selectie"
+say key_nav_down "omlaag"
+say key_nav_down_shift "voeg toe aan selectie"
+say key_nav_right "rechts"
+say key_nav_right_shift "voeg toe aan selectie"
+say key_nav_left "links"
+say key_nav_left_shift "voeg toe aan selectie"
+say key_nav_ioselect "selecteer in/outlets"
+
+# phase 5A
+
+say cannot "Kan niet"
+say cancel "Annuleer"
+say apply "Pas Toe"
+say ok "Akkoord"
+say popup_open "Open"
+say popup_insert "Invoegen"
+say popup_properties "Eigenschappen"
+say popup_clear_wires "Wis draden"
+say popup_auto_wire "Verwijder object (autowire)"
+say popup_help "Help"
+say popup_remove_from_path "Verwijder object uit pad"
+say popup_delete_from_path "Wis object uit pad"
+say popup_help "Hulp"
+say filter "Filter: "
+say do_what_i_mean "Do What I Mean"
+say ask_cool "Dit zou een leuke functie zijn he ?"
+say reset "Reset"
+say filter "Filter: "
+say how_many_object_classes "%d of %d object classes"
+say do_what_i_mean "Doe wat ik bedoel"
+say save_changes? "Wijzigingen opslaan?"
+say reset "Herstel"
+say Courier "Courier (monospaced)"
+say Helvetica "Helvetica (sansserif)"
+say Times "Times (serif)"
+say add "Voeg toe"
+say up "Opwaards"
+say down "Neerwaards"
+say remove "Verwijder"
+say lib_add "Voeg de naam die u ingaf toe aan de lijst"
+say lib_up "Verwissel volgorde met vorige bibliotheek"
+say lib_down "Verwissel volgorde met volgende bibliotheek"
+say lib_remove "verwijder bibliotheek geselecteerd in de lijst"
+say dir_add "voeg een map toe door middel van een dialoogvenster"
+say dir_up "verwissel volgorde met vorige map"
+say dir_down "verwissel volgorde met volgende map"
+say dir_remove "verwijder map geselecteerd in de lijst"
+say client_class_tree "Client Class Tree"
+say clipboard_view "Kladblok Weergave"
+say history_view "Geschiedenis Weergave"
+say command_history_view "Geschiedenis Commando's"
+say event_history_view "Geschiedenis Gebeurtenissen"
+
+# during/after piksel:
+
+say auto_apply "Automatisch-Toepassen"
+say font_preview "Voorsmaak:"
+say font_preview_2 "ABCDEFGHIJKLMNOPQRSTUVWXYZ\nabcdefghijklmnopqrstuvwxyz\n0123456789"
+say font_style "Stijl:"
+say font_bold "Vet"
+say font_italic "Scontchuingedrukt"
+say font_family "Naam:"
+say font_size "Lettertekengrootte"
+say damn "Miljaar!"
+say console_clear "Console Leegmaken"
+say horizontal "Horizontaal"
+say vertical "Verticaal"
+say language "Taal"
+
+# 2007:
+
+say no_matches "(geen overeenkomsten)"
+say preset "preset"
+say canvasgrid "Grid kleur"
+say grid_size "Grid grootte"
+say gridstate "Activateer achtergrond grid"
+say snap_grid "Verspring volgens grid eenheden"
+say viewfont "lettertype voor objecten"
+say consolefont "lettertype voor console"
+say keyboarddialogfont "lettertype voor virtueel toetsenbord"
+say keyboard_view "Virtueel toetsenbord"
+say log_height "Log Hoogte"
diff --git a/desiredata/src/locale/nihongo.tcl b/desiredata/src/locale/nihongo.tcl
new file mode 100644
index 00000000..ecedbf44
--- /dev/null
+++ b/desiredata/src/locale/nihongo.tcl
@@ -0,0 +1,574 @@
+#!/usr/bin/env tclsh
+# Japanese translations for PureData
+# $Id: nihongo.tcl,v 1.1.2.1 2007-08-12 05:56:49 matju Exp $
+# by Kentaro Fukuchi and friends
+
+### Menus
+say file "ファイル"
+ say new_file "新規作成"
+ say open_file "ファイルを開く..."
+ say server_prefs "サーバー設定..."
+ say client_prefs "クライアント設定..."
+ say send_message "メッセージ送信..."
+ say paths "パス..."
+ say close "閉じる"
+ say save "保存"
+ say save_as "名前を付けて保存..."
+ say print "印刷..."
+ say abort_server "サーバー停止"
+ say quit "終了"
+
+ say canvasnew_file "新規作成"
+ say canvasopen_file "ファイルを開く..."
+ say canvassave "保存"
+ say canvassave_as "名前を付けて保存..."
+ say clientpdrc_editor ".pdrc エディター"
+ say clientddrc_editor ".ddrc エディター"
+ say canvasclose "閉じる"
+ say canvasquit "終了"
+
+say edit "編集"
+ say undo "元に戻す"
+ say redo "やり直し"
+ say cut "カット"
+ say copy "コピー"
+ say paste "ペースト"
+ say duplicate "複製"
+ say select_all "すべてを選択"
+ say clear_selection "選択を解除"
+ say text_editor "テキストエディタ..."
+ say font "フォント"
+ say tidy_up "整列";## tidy up これでよいか?
+ say edit_mode "編集モード"
+ say editmodeswitch "編集/実行モード切替"
+ say subpatcherize "サブパッチ化";## Subpacherizer これでよいか?
+
+ say canvascut "カット"
+ say canvascopy "コピー"
+ say canvasundo "元に戻す"
+ say canvasredo "やり直し"
+ say canvaspaste "ペースト"
+ say canvasduplicate "複製"
+ say canvasselect_all "すべてを選択"
+ say canvaseditmodeswitch "編集/実行モード切替"
+
+say view "表示"
+ say reload "再読込み"
+ say redraw "再描画"
+
+ say canvasreload "再読込み"
+ say canvasredraw "再描画"
+
+say find "検索"
+ say find_again "再検索"
+ say find_last_error "最後のエラーを検索"
+ say string "文字列の検索"
+say canvasfind "Find"
+ say canvasfind_again "再検索"
+
+# contents of Put menu is Phase 5C
+say put "挿入";## オブジェクトの挿入というニュアンスでよいか?
+ say Object "オブジェクト"
+ say Message "メッセージ"
+ say Number "ナンバー"
+ say Symbol "シンボル"
+ say Comment "コメント"
+ say Graph "グラフ"
+ say Array "配列"
+
+say media "メディア"
+ say audio_on "オーディオON"
+ say audio_off "オーディオOFF"
+ say test_audio_and_midi "オーディオとMIDIのテスト"
+ say load_meter "負荷メーター"
+
+ say canvasaudio_on "オーディオON"
+ say canvasaudio_off "オーディオOFF"
+ say clienttest_audio_and_midi "オーディオとMIDIのテスト"
+ say canvasload_meter "負荷メーター"
+
+say window "ウィンドウ"
+
+say help "ヘルプ"
+ say about "Desire Dataについて..."
+ say documentation "ドキュメント..."
+ say class_browser "クラス・ブラウザー..."
+
+ say canvasabout "Desire Dataについて..."
+
+say properties "プロパティ"
+say open "開く"
+
+### for key binding editor
+say general "一般"
+say audio_settings "オーディオの設定"
+say midi_settings "MIDIの設定"
+say latency_meter "レイテンシ・メーター"
+say Pdwindow "Pdウィンドウ"
+
+say canvaspdwindow "Pdウィンドウ"
+say canvaslatency_meter "レイテンシ・メーター"
+say clientaudio_settings "オーディオの設定"
+say clientmidi_settings "MIDIの設定"
+
+### for Properties Dialog (phase 5B)
+say_category IEM
+say w "幅(px)"
+say h "高さ(px)"
+say hold "ホールド(ms)"
+say break "break time(ms)";## すみません、ニュアンスわかりません
+say min "最小値"
+say max "最大値"
+say is_log "モード"
+say linear "線型"
+say logarithmic "対数"
+say isa "初期化"
+say n "number of choices"
+say steady "クリック時動作";##Steadiness 意訳でよいか?
+say steady_no "ジャンプ"
+say steady_yes "ジャンプ無";##steady on clickこれでよいか?
+say snd "送信先シンボル"
+say rcv "受信元シンボル"
+say lab "ラベル"
+say ldx "ラベル x方向オフセット"
+say ldy "ラベル y方向オフセット"
+say fstyle "フォント"
+say fs "サイズ"
+say bcol "背景カラー";##「背景色」も検討したが「ラベル色」としないよう統一
+say fcol "前景カラー"
+say lcol "ラベルカラー"
+say yes "はい"
+say no "いいえ"
+say courier "courier (typewriter)";##フォント名のためママでよいか?
+say helvetica "helvetica (sansserif)"
+say times "times (serif)"
+say coords "描画";##Graph on parent 意訳でよいか?
+
+say_category GAtomProperties
+say width "幅"
+say lo "最小値"
+say hi "最大値"
+say label "ラベル"
+say wherelabel "ラベル表示位置";##おそらく未使用
+say symto "送信先シンボル"
+say symfrom "受信元シンボル"
+
+say_category GraphProperties
+say x1 "x 開始値"
+say x2 "x 終了値"
+say xpix "幅"
+say y2 "y 開始値"
+say y1 "y 終了値"
+say ypix "高さ"
+
+say_category CanvasProperties
+#say xscale "X ピクセル毎単位";##unitx/px この訳でよいか
+#say yscale "Y ピクセル毎単位"
+say gop "描画";##この訳でよいか?
+say xmargin "xマージン"
+say ymargin "yマージン"
+say height "高さ"
+say_category ArrayProperties
+say name "名前"
+say n "サイズ"
+say xfrom "x 開始値"
+say xto "x 終了値"
+say yfrom "y 開始値"
+say yto "y 終了値"
+
+
+say_category MainWindow
+say in "in"
+say out "out"
+say audio "オーディオ"
+say meters "メーター"
+say io_errors "I/Oエラー"
+say tcl_console "Tclクライアント"
+say pd_console "Pdサーバー"
+
+### phase 2
+
+say_category Other
+say_namespace summary {
+ say_category IEMGUI
+ say bng "Bangボックス"
+ say tgl "トグル・ボックス"
+ say nbx "ナンバー・ボックス(IEM)"
+ say hsl "スライダー(水平)"
+ say vsl "スライダー(垂直)"
+ say hradio "選択ボックス(水平)"
+ say vradio "選択ボックス(垂直)"
+ say cnv "キャンバス(IEM)"
+ say dropper "ドラッグ&ドロップ・ボックス"
+ say vu "VUメーター"
+
+ say_category GLUE
+ say bang "Bangを送信"
+ say float "数値の保存/読出し"
+ say symbol "シンボルの保存/読出し"
+ say int "整数の保存/読出し"
+ say send "オブジェクトへメッセージを送信"
+ say receive "送信されたメッセージの受信"
+ say select "数値またはシンボルの一致を検査する"
+ say route "先頭の要素を評価し、ルートを分岐する"
+ say pack "メッセージを結合する"
+ say unpack "結合されたメッセージを分離する"
+ say trigger "任意の形式に変換したメッセージを、任意の順で送信"
+ say spigot "メッセージをフィルタ"
+ say moses "連続する数値を、指定した値を境に分岐して出力"
+ say until "ループ機能"
+ say print "メッセージを表示"
+ say makefilename "変数を含むシンボルをファイル名の形式に変換"
+ say change "連続する数値のうち、重複するものをフィルタ"
+ say swap "二つの値を入れ替える"
+ say value "グローバル変数の保存/読出し"
+
+ say_category TIME
+ say delay "メッセージを遅延させる"
+ say metro "定期的にメッセージを送信"
+ say line "直線的に変化する連続した数値を送信"
+ say timer "経過時間を計測"
+ say cputime "CPU時間を計測"
+ say realtime "実時間を計測"
+ say pipe "数値送信に用いる、可変長のディレイラインを作成"
+
+ say_category MATH
+ say + "加算"
+ say - "減算"
+ say * "乗算"
+ say {/ div} "除算"
+ say {% mod} "余り"
+ say pow "対数"
+ say == "等号"
+ say != "不等号"
+ say > "大なり"
+ say < "小なり"
+ say >= "大なりイコール"
+ say <= "小なりイコール"
+ say & "ビット演算 (and)"
+ say | "ビット演算 (or)"
+ say && "論理積 (and)"
+ say || "論理和 (or)"
+ say mtof "MIDIノー・トナンバーを周波数に変換"
+ say ftom "周波数をMIDIノート・ナンバーに変換"
+ say powtodb "ワット数をdBに変換"
+ say dbtopow "dBをワット数に変換"
+ say rmstodb "電圧をdBに変換"
+ say dbtorms "dBを電圧に変換"
+ say {sin cos tan atan atan2 sqrt} "三角関数"
+ say log "自然対数"
+ say exp "指数関数"
+ say abs "絶対値"
+ say random "乱数"
+ say max "二項のうち、より大きい数"
+ say min "二項のうち、より小さい数"
+ say clip "数値をしきい値内におさめる"
+
+ say_category MIDI
+ say {notein ctlin pgmin bendin touchin polytouchin midiin sysexin} "MIDI入力"
+ say {noteout ctlout pgmout bendout touchout polytouchout midiout} "MIDI出力"
+ say makenote "ノートオンを送信し、指定した時間経過後にノート・オフを送信"
+ say stripnote "連続するノート・オフをフィルター"
+
+ say_category TABLES
+ say tabread "テーブルから数値読出し"
+ say tabread4 "4点による擬似補間を用いて、テーブルから数値を読出し"
+ say tabwrite "テーブルに数値を書込み"
+ say soundfiler "テーブルからファイルへ、相互に読出し/書込み"
+
+ say_category MISC
+ say loadbang "読込時にBangを送信"
+ say serial "シリアル・デバイス・コントロール(NTのみ)"
+ say netsend "インターネットを介してメッセージ送信"
+ say netreceive "インターネットを介してメッセージ受信"
+ say qlist "メッセージ・シーケンサー"
+ say textfile "ファイルを読み込みメッセージを生成"
+ say openpanel "「ファイルを開く」ダイアログを表示"
+ say savepanel "「ファイルを保存」ダイアログを表示"
+ say bag "数値の集合を保持"
+ say poly "ポリフォニックの入力信号を管理"
+ say {key keyup} "キーボード入力のアスキー・コードを送信"
+ say keyname "キーボード入力文字を送信"
+
+ say_category "AUDIO MATH"
+ foreach word {+ - * /} {say $word~ "[say $word] (シグナル用)"}
+ say max~ "シグナルの最大値"
+ say min~ "シグナルの最小値"
+ say clip~ "シグナルの値をしきい値内に強制変換"
+ say q8_rsqrt~ "簡易版平方根の逆数 (注意:8ビット)"
+ say q8_sqrt~ "簡易版平方根 (注意:8ビット)"
+ say wrap~ "入力値にもっとも近い整数との差 (入力が正の場合は小数部)"
+ say fft~ "複素離散フーリエ変換"
+ say ifft~ "複素逆離散フーリエ変換"
+ say rfft~ "実離散フーリエ変換"
+ say rifft~ "逆離散フーリエ変換"
+ say framp~ "output a ramp for each block"
+ foreach word {mtof ftom rmstodb dbtorms rmstopow powtorms} {
+ say $word~ "[say $word] (シグナル用)"
+ }
+}
+
+### phase 3
+
+say_namespace summary {
+ say_category "音声結線"
+ say dac~ "音声出力"
+ say adc~ "音声入力"
+ say sig~ "数値を音声信号に変換"
+ say line~ "音声に時間変化の勾配を付加"
+ say vline~ "line~の機能拡張版"
+ say threshold~ "信号からしきい値を検出"
+ say snapshot~ "信号をサンプリング(数値に書き戻す)"
+ say vsnapshot~ "snapshot~の機能拡張版"
+ say bang~ "BANGメッセージを以降の全てのDSPブロックに出力"
+
+ say samplerate~ "サンプリング周波数を取得"
+
+ say send~ "複数の出力を備えた遠隔接続"
+ say receive~ "send~より信号を受け取る"
+ say throw~ "加算バス(ミキサ)に追加する"
+ say catch~ "加算バス(ミキサ)の内容を読み出す"
+ say block~ "ブロックの大きさとオーバーラップを指定"
+ say switch~ "DSP処理をオン/オフ"
+ say readsf~ "ディスク上の音声ファイルを再生"
+ say writesf~ "音声をディスクに記録"
+
+ say_category "オシレータとテーブル"
+ say phasor~ "鋸状波オシレータ"
+ say {cos~ osc~} "サイン波オシレータ"
+ say tabwrite~ "テーブルへ書き込む"
+ say tabplay~ "テーブルから再生(移調は伴わない)"
+ say tabread~ "補間を行わずにテーブルから読み込む"
+ say tabread4~ "四点多項式による補間を行いながらテーブルから読み込む"
+ say tabosc4~ "ウェーブテーブルオシレータ"
+ say tabsend~ "テーブルへ1ブロックを連続的に書き込む"
+ say tabreceive~ "テーブルから1ブロックを連続的に読み出す"
+
+ say_category "フィルタ"
+ say vcf~ "電圧制御式バンドパスフィルタ"
+ say noise~ "ホワイトノイズ発生器"
+ say env~ "エンヴェロープフォロワ "
+ say hip~ "ハイパスフィルタ"
+ say lop~ "ローパスフィルタ"
+ say bp~ "バンドパスフィルタ"
+ say biquad~ "引数により様々な設計ができるフィルタ"
+ say samphold~ "サンプルアンドホールド"
+ say print~ "ひとつまたは複数のブロックの音声信号をコンソールに表示"
+ say rpole~ "単極(再帰)フィルタ"
+ say rzero~ "1ゼロ点(非再帰)フィルタ"
+ say rzero_rev~ "反転1ゼロ点(非再帰)フィルタ"
+ say cpole~ "複素単極(再帰)フィルタ"
+ say czero~ "複素1ゼロ点(非再帰)フィルタ"
+ say czero_rev~ "複素反転1ゼロ点(非再帰)フィルタ"
+
+ say_category "ディレイ"
+ say delwrite~ "ディレイラインに書き込み"
+ say delread~ "ディレイラインから読み出す"
+ say vd~ "ディレイラインから任意のタイミングで読み出す"
+
+ say_category "サブウインドウ"
+ say pd "サブウインドウを定義"
+ say table "サブウインドウ内で数値を配列"
+ say inlet "サブウインドウ内へ結線"
+ say outlet "サブウインドウ外へ結線"
+ say inlet~ "サブウインドウ内へ結線(音声信号用)"
+ say outlet~ "サブウインドウ外へ結線(音声信号用)"
+
+ say_category "データテンプレート"
+ say struct "データの構造を定義"
+ say {drawcurve filledcurve} "曲線を描く"
+ say {drawpolygon filledpolygon} "多角形を描く"
+ say plot "配列を描画"
+ say drawnumber "数値を表示"
+
+ say_category "データアクセス"
+ say pointer "テンプレートに属するオブジェクトを指定"
+ say get "数値データを取得"
+ say set "数値データを任意の値に書き換え"
+ say element "配列の要素を取得"
+ say getsize "配列の大きさを取得"
+ say setsize "配列の大きさを変更"
+ say append "リストに要素を付加"
+ say sublist "リストからポインタを取得(これは他のスケーラの一要素です)"
+ say scalar "スケーラを親ウインドウに表示"
+
+ say_category "もう使う必要のないもの"
+ say scope~ "(tabwrite~に統合されました)"
+ say namecanvas "" ;# what was this anyway? 正直、これってなんだっけ?
+ say template "(structに統合されました)"
+}
+
+# phase 4 (pdrc & ddrc)
+
+say section_audio "オーディオ"
+ say -r "サンプリング周波数"
+ say -audioindev "音声入力デバイス"
+ say -audiooutdev "音声出力デバイス"
+ say -inchannels "音声入力チャンネル(デバイスによる。例えば“2”や“16,8”のように。)"
+ say -outchannels "音声出力チャンネル(入力に同じ)"
+ say -audiobuf "音声バッファの大きさをミリ秒で定義"
+ say -blocksize "音声入力/出力のブロックの大きさをサンプルフレーム数で定義"
+ say -sleepgrain "ミリ秒で定義される値をアイドル時にスリープさせる"
+ say -nodac "音声出力を停止"
+ say -noadc "音声入力を停止"
+ say audio_api_choice "オーディオAPI"
+ say default "デフォルト"
+ say -alsa "オーディオAPIとしてALSAを使う"
+ say -jack "オーディオAPIとしてJACKを使う"
+ say -mmio "オーディオAPIとしてMMIOを使う(Windows標準)"
+ say -portaudio "ASIOドライバを使う(Portaudioを通じて)"
+ say -oss "オーディオAPIとしてOSSを使う"
+ say -32bit "32ビットのOSSオーディオを許可する(RME Hammerfallのみ)"
+ say {} "デフォルト"
+
+say section_midi "MIDI"
+ say -nomidiin "MIDI入力を停止"
+ say -nomidiout "MIDI出力を停止"
+ say -midiindev "MIDIインデバイスのリスト(用例:“1,3”で1番目と3番目)"
+ say -midioutdev "MIDIアウトデバイスのリスト(用例:“1,3”で1番目と3番目)"
+
+say section_externals "エクスターナル"
+ say -path "ファイルの検索パス"
+ say -helppath "ヘルプファイルの検索パス"
+ say -lib "オブジェクトのライブラリをロード"
+
+say section_gui "GUI"
+ say -nogui "GUIなしで起動する(危険です)"
+ say -guicmd "他のGUIプログラムと置き換える(例えばrshのような)"
+ say -look "ボタンバーのアイコン"
+ say -font "起動時のフォントのサイズをpointで定義"
+
+say section_other "その他"
+ say -open "起動時にファイルを開く"
+ say -verbose "起動時とファイル検索時のコンソールへの表示を詳細化"
+ say -d "デバッグレベル"
+ say -noloadbang "“loadbang”を無効にする"
+ say -send "起動時にメッセージを送信する(全てのパッチが読み込まれた直後に)"
+ say -listdev "オーディオデバイスとMIDIデバイスのリストを起動時に表示する"
+ say -realtime "優先度を最優先にする(管理者権限が必要)"
+
+say section_paths "パス"
+
+# phase 4B: ddrc (keyword names not finalized!)
+say console "コンソールウインドウの表示行数 (0 = コンソールを停止)"
+say lang "使用言語"
+say pointer_sense "マウス感度"
+say section_color "アピアランス"
+ say canvas_color "カンバス"
+ say canvasbgedit "カンバス背景(エディットモード時)"
+ say canvasbgrun "カンバス背景(実行モード時)"
+ say object_color "オブジェクト"
+ say viewframe1 "オブジェクトボックスの色"
+ say viewframe2 "オブジェクトボックスの色"
+ say viewframe3 "オブジェクトボックスの色"
+ say viewframe4 "オブジェクトボックス選択時の色"
+ say viewbg "オブジェクト背景"
+ say viewfg "オブジェクト前景"
+ say commentbg "コメント背景"
+ say commentfg "コメント前景"
+ say commentframe1 "コメントフレーム"
+ say commentframe2 "コメントフレーム"
+ say commentframe3 "コメントフレーム"
+ say viewselectframe "選択されたボックス"
+ say wire_color "結線"
+ say wirefg "結線色"
+ say wirefg2 "選択された結線"
+ say wiredspfg "音声信号用結線の色"
+ say futurewiredash "新規結線"
+ say others_color "その他"
+ say boxinletfg "インレットの色"
+ say boxoutletfg "アウトレットの色"
+ say selrectrect "セレクションボックス"
+say keys "キー"
+say others "その他"
+say hairstate "十字型カーソルを表示"
+say hairsnap "十字型カーソルをオブジェクトにスナップ"
+say statusbar "ステータスバーを表示"
+say buttonbar "ボタンバーを表示"
+say menubar "メニューバーを表示"
+say scrollbar "オートスクロールバーを表示"
+say wirearrow "結線端の信号の方向を示す矢印"
+say tooltip "ツールチップ"
+say insert_object "オブジェクトを挿入"
+say chain_object "オブジェクトを繋ぐ"
+say clear_wires "結線を全て外す"
+say auto_wire "オブジェクトを消去"
+say subpatcherize "サブパッチとして独立させる"
+say keynav "キーボードナビゲーション"
+say key_nav_up "上へ移動"
+say key_nav_up_shift "上へ移動して選択"
+say key_nav_down "下へ移動"
+say key_nav_down_shift "下へ移動して選択"
+say key_nav_right "右へ移動"
+say key_nav_right_shift "右へ移動して選択"
+say key_nav_left "左へ移動"
+say key_nav_left_shift "左へ移動して選択"
+say key_nav_ioselect "インレット/アウトレットを選択"
+
+# phase 5A
+
+say cannot "不可能です"
+say cancel "キャンセル"
+say apply "適用する"
+say ok "OK"
+say popup_open "開く"
+say popup_insert "挿入する"
+say popup_properties "プロパティ"
+say popup_clear_wires "結線を全て外す"
+say popup_remove_from_path "パスからオブジェクトを外す"
+say popup_delete_from_path "パスからオブジェクトを消去する"
+say popup_help "ヘルプ"
+say filter "フィルタ: "
+say how_many_object_classes "%2\$d 中 %1\$d 個のオブジェクトクラス"
+say do_what_i_mean "言ったとおりにやってよね"
+say ask_cool "これってイカス機能だよね〜"
+say save_changes? "変更を保存しますか?"
+say reset "リセット"
+say Courier "Courier (monospaced)"
+say Helvetica "Helvetica (sansserif)"
+say Times "Times (serif)"
+say add "追加"
+say up "上へ"
+say down "下へ"
+say remove "消去"
+say lib_add "リストに書いた名前を加える"
+say lib_up "前のライブラリと順番を入れ替える"
+say lib_down "次のライブラリと順番を入れ替える"
+say lib_remove "リスト中の選択されたライブラリを外す"
+say dir_add "ダイアログを使ってフォルダを加える"
+say dir_up "前のフォルダと順番を入れ替える"
+say dir_down "次のフォルダと順番を入れ替える"
+say dir_remove "リスト中の選択されたフォルダを外す"
+say client_class_tree "クライアント構成"
+say clipboard_view "クリップボードを表示"
+say command_history_view "操作履歴を表示"
+say event_history_view "イベント履歴を表示"
+
+# during/after piksel:
+
+say auto_apply "自動的に適用する"
+say font_preview "プレビュー:"
+say font_preview_2 "ABCDEFGHIJKLMNOPQRSTUVWXYZ\nabcdefghijklmnopqrstuvwxyz\n0123456789"
+say font_style "スタイル:"
+say font_bold "太字"
+say font_italic "斜体"
+say font_family "名前:"
+say font_size "大きさ:"
+say damn "最低!"
+say console_clear "コンソールをクリア"
+say horizontal "水平方向"
+say vertical "鉛直方向"
+say language "言語"
+
+# 2007:
+
+say no_matches "(適合するものなし)"
+say preset "プリセット"
+say canvasgrid "グリッドの色"
+say grid_size "グリッドの大きさ"
+say gridstate "背景にグリッドを表示"
+say snap_grid "グリッドにスナップ"
+say viewfont "オブジェクトのフォント"
+say consolefont "コンソールのフォント"
+say keyboarddialogfont "仮想キーボードのフォント"
+say keyboard_view "仮想キーボード"
diff --git a/desiredata/src/locale/polski.tcl b/desiredata/src/locale/polski.tcl
new file mode 100644
index 00000000..5be7cd48
--- /dev/null
+++ b/desiredata/src/locale/polski.tcl
@@ -0,0 +1,557 @@
+#!/usr/bin/env tclsh
+# Polish (polski) translations for PureData
+# $Id: polski.tcl,v 1.1.2.2 2007-08-01 04:24:43 matju Exp $
+# by Michal Seta, mis@artengine.ca
+
+say file "Plik"
+ say new_file "Nowy Plik"
+ say open_file "Otwórz Plik..."
+ say server_prefs "Preferencje servera..."
+ say client_prefs "Preferencje klienta..."
+ say send_message "Wysłać Wiadomość..."
+ say paths "Ścieżki..."
+ say close "Zamknąć"
+ say save "Zapisz"
+ say save_as "Zapisz Jako..."
+ say print "Wydrukuj..."
+ say quit "Zakończ"
+
+ say canvasnew_file "Nowy Plik"
+ say canvasopen_file "Otwórz Plik..."
+ say canvassave "Zapisz"
+ say canvassave_as "Zapisz Jako..."
+ say clientpdrc_editor "Edycja .pdrc"
+ say clientddrc_editor "Edycja .ddrc"
+ say canvasclose "Zamknij"
+ say canvasquit "Zakończ"
+
+say edit "Edycja"
+ say undo "Cofnij"
+ say redo "Ponów"
+ say cut "Wytnij"
+ say copy "Skopiuj"
+ say paste "Wklei"
+ say duplicate "Powiel"
+ say select_all "Zaznacz wszystko"
+ say text_editor "Edytor tekstu..."
+ say font "Czcionka"
+ say tidy_up "Wyrównać"
+ say edit_mode "Tryb edycji"
+ say editmodeswitch "Tryb edycji/pracy"
+
+ say canvascut "Wytnij"
+ say canvascopy "Skopiuj"
+ say canvasundo "Anuluj"
+ say canvasredo "Ponów"
+ say canvaspaste "Wklei"
+ say canvasduplicate "Powiel"
+ say canvasselect_all "Zaznacz wszystko"
+ say canvaseditmodeswitch "Tryb edycji/pracy"
+
+say view "Widok"
+ say reload "Załaduj ponownie"
+ say redraw "Odśwież"
+
+ say canvasreload "Załaduj ponownie"
+ say canvasredraw "Odśwież"
+
+ say find "Szukaj"
+ say find_again "Szukaj ponownie"
+ say find_last_error "Znajdź ostatni błąd"
+ say string "Znajdź ciąg znaków"
+ say canvasfind "Szukaj"
+ say canvasfind_again "Szukaj ponownie"
+
+say put "Połóż"
+ say Object "Objekt"
+ say Message "Komunikat"
+ say Number "Liczba"
+ say Symbol "Znak"
+ say Comment "Komentarz"
+ say Array "Tabela"
+
+say media "Media"
+ say audio_on "Włącz dźwięk"
+ say audio_off "Wyłącz dźwięk"
+ say test_audio_and_midi "Próba dżwięku i MIDI"
+ say load_meter "Miernik procesora"
+
+ say canvasaudio_on "Włącz dźwięk"
+ say canvasaudio_off "Wyłącz dźwięk"
+ say clienttest_audio_and_midi "Próba dżwięku i MIDI"
+ say canvasload_meter "Miernik procesora"
+
+say window "Okno"
+
+say help "Pomoc"
+ say about "Na temat..."
+ say pure_documentation "Dokumentacja..."
+ say class_browser "Przeglądarka klas..."
+
+ say canvasabout "Na temat..."
+
+ say properties "Właściwości"
+say open "Otwórz"
+
+### for key binding editor
+say general "Ogólne"
+say audio_settings "Ustawienia dżwięku"
+say midi_settings "Ustawienia MIDI"
+say latency_meter "Miernik opóźnienia"
+say Pdwindow "Okno PD"
+
+say canvaspdwindow "Konsola PD"
+say canvaslatency_meter "Miernik opóźnienia"
+say clientaudio_settings "Ustawienia dżwięku"
+say clientmidi_settings "Ustawienia MIDI"
+
+### for Properties Dialog (phase 5B)
+say_category IEM
+say w "Szerokość(px)"
+say h "Wysokość(px)"
+say hold "Czas utrzymania(ms)"
+say break "Czas zatrzymania(ms)"
+say min "Zmienna minimalna"
+say max "Zmienna maxymalna"
+say is_log "Tryb"
+say linear "Liniowy"
+say logarithmic "Logarytmiczny"
+say isa "Uruchomienie"
+say n "Ilość wyboru"
+say steady "Równomierny"
+say steady_no "Skok po kliknięciu"
+say steady_yes "Stały po kliknięciu"
+say snd "oznakowanie wysłania"
+say rcv "oznakowanie pobrania"
+say lab "etykieta"
+say ldx "przesunięcie etykiety po x"
+say ldy "przesunięcie etykiety po y"
+say fstyle "Czcionka"
+say fs "Rozmiar czcionki"
+say bcol "Kolor tła"
+say fcol "Kolor przedni"
+say lcol "Kolor etykiety"
+say yes "Tak"
+say no "Nie"
+say courier "courrier (typewriter)"
+say helvetica "helvetique (sansserif)"
+say times "times (serif)"
+say coords "grafika na nadrzędnym"
+
+say_category GAtomProperties
+say width "szerokość"
+say lo "ograniczenie niskie"
+say hi "ograniczenie wysole"
+say label "etykieta"
+say wherelabel "wyświetlić etykietę"
+say symto "wyślij znak"
+say symfrom "pobierz znak"
+
+say_category GraphProperties
+say x1 "x od"
+say x2 "x do"
+say xpix "szerokość ekranu"
+say y2 "y od"
+say y1 "y do"
+say ypix "wysokość ekranu"
+
+say_category CanvasProperties
+#say xscale "X units/px"
+#say yscale "Y units/px"
+say gop "grafika na nadrzędnym"
+say xmargin "margines x"
+say ymargin "margines y"
+say height "wysokość"
+say_category ArrayProperties
+say name "nazwa"
+say n "rozmiar"
+say xfrom "zakres x od"
+say xto "zakres x do"
+say yfrom "zakres y od"
+say yto "zakres y do"
+
+
+say_category MainWindow
+say in "wejście"
+say out "wyjście"
+say audio "Dźwięk"
+say meters "Pomiary"
+say io_errors "Błędy I/O"
+say tcl_console "Klient Tcl"
+say pd_console "Server pd"
+
+### phase 2
+
+say_category Other
+say_namespace summary {
+ say_category IEMGUI
+ say bng "Bang"
+ say tgl "Przerzutnik"
+ say nbx "Liczba"
+ say hsl "Suwak (poziomy)"
+ say vsl "Suwak (Pionowy)"
+ say hradio "Pole wyboru (poziome)"
+ say vradio "Pole wyboru (pionowe)"
+ say cnv "Płótno"
+ say dropper "Drag-and-Drop Box"
+ say vu "Miernik VU"
+
+ say_category GLUE
+ say bang "output a bang message"
+ say float "store and recall a number"
+ say symbol "store and recall a symbol"
+ say int "store and recall an integer"
+ say send "send a message to a named object"
+ say receive "catch sent messages"
+ say select "test for matching numbers or symbols"
+ say route "route messages according to first element"
+ say pack "make compound messages"
+ say unpack "get elements of compound messages"
+ say trigger "sequence and convert messagess"
+ say spigot "interruptible message connection"
+ say moses "part a numeric stream"
+ say until "looping mechanism"
+ say print "print out messages"
+ say makefilename "format a symbol with a variable field"
+ say change "remove repeated numbers from a stream"
+ say swap "swap two numbers"
+ say value "shared numeric value"
+
+ say_category TIME
+ say delay "send a message after a time delay"
+ say metro "send a message periodically"
+ say line "send a series of linearly stepped numbers"
+ say timer "measure time intervals"
+ say cputime "measure CPU time"
+ say realtime "measure real time"
+ say pipe "dynamically growable delay line for numbers"
+
+ say_category MATH
+ say + "add"
+ say - "substract"
+ say * "multiply"
+ say {/ div} "divide"
+ say {% mod} "division remainder"
+ say pow "exponentiate"
+ say == "equal?"
+ say != "not equal?"
+ say > "more than?"
+ say < "less than?"
+ say >= "not less than?"
+ say <= "not more than?"
+ say & "bitwise conjunction (and)"
+ say | "bitwise disjunction (or)"
+ say && "logical conjunction (and)"
+ say || "logical disjunction (or)"
+ say mtof "MIDI to Hertz"
+ say ftom "Hertz to MIDI"
+ say powtodb "Watts to dB"
+ say dbtopow "dB to Watts"
+ say rmstodb "Volts to dB"
+ say dbtorms "dB to Volts"
+ say {sin cos tan atan atan2 sqrt} "trigonometry"
+ say log "Euler logarithm"
+ say exp "Euler exponential"
+ say abs "absolute value"
+ say random "random"
+ say max "greater of two numbers"
+ say min "lesser of two numbers"
+ say clip "force a number into a range"
+
+ say_category MIDI
+ say {notein ctlin pgmin bendin touchin polytouchin midiin sysexin} "MIDI input"
+ say {noteout ctlout pgmout bendout touchout polytouchout midiout} "MIDI output"
+ say makenote "schedule a delayed \"note off\" message corresponding to a note-on"
+ say stripnote "strip \"note off\" messages"
+
+ say_category TABLES
+ say tabread "read a number from a table"
+ say tabread4 "read a number from a table, with 4 point interpolation"
+ say tabwrite "write a number to a table"
+ say soundfiler "read and write tables to soundfiles"
+
+ say_category MISC
+ say loadbang "bang on load"
+ say serial "serial device control for NT only"
+ say netsend "send messages over the internet"
+ say netreceive "receive them"
+ say qlist "message sequencer"
+ say textfile "file to message converter"
+ say openpanel "\"Open\" dialog"
+ say savepanel "\"Save as\" dialog"
+ say bag "set of numbers"
+ say poly "polyphonic voice allocation"
+ say {key keyup} "numeric key values from keyboard"
+ say keyname "symbolic key name"
+
+ say_category "AUDIO MATH"
+ foreach word {+ - * /} {say $word~ "[say $word] (for signals)"}
+ say max~ "supremum of signals"
+ say min~ "infimum of signals"
+ say clip~ "constrict signal to lie between two bounds"
+ say q8_rsqrt~ "cheap reciprocal square root (beware -- 8 bits!)"
+ say q8_sqrt~ "cheap square root (beware -- 8 bits!)"
+ say wrap~ "wraparound (fractional part, sort of)"
+ say fft~ "complex forward discrete Fourier transform"
+ say ifft~ "complex inverse discrete Fourier transform"
+ say rfft~ "real forward discrete Fourier transform"
+ say rifft~ "real inverse discrete Fourier transform"
+ say framp~ "output a ramp for each block"
+ foreach word {mtof ftom rmstodb dbtorms rmstopow powtorms} {
+ say $word~ "[say $word] (for signals)"
+ }
+}
+
+### phase 3
+
+say_namespace summary {
+ say_category "AUDIO GLUE"
+ say dac~ "audio output"
+ say adc~ "audio input"
+ say sig~ "convert numbers to audio signals"
+ say line~ "generate audio ramps"
+ say vline~ "deluxe line~"
+ say threshold~ "detect signal thresholds"
+ say snapshot~ "sample a signal (convert it back to a number)"
+ say vsnapshot~ "deluxe snapshot~"
+ say bang~ "send a bang message after each DSP block"
+ say samplerate~ "get the sample rate"
+ say send~ "nonlocal signal connection with fanout"
+ say receive~ "get signal from send~"
+ say throw~ "add to a summing bus"
+ say catch~ "define and read a summing bus"
+ say block~ "specify block size and overlap"
+ say switch~ "switch DSP computation on and off"
+ say readsf~ "soundfile playback from disk"
+ say writesf~ "record sound to disk"
+
+ say_category "AUDIO OSCILLATORS AND TABLES"
+ say phasor~ "sawtooth oscillator"
+ say {cos~ osc~} "cosine oscillator"
+ say tabwrite~ "write to a table"
+ say tabplay~ "play back from a table (non-transposing)"
+ say tabread~ "non-interpolating table read"
+ say tabread4~ "four-point interpolating table read"
+ say tabosc4~ "wavetable oscillator"
+ say tabsend~ "write one block continuously to a table"
+ say tabreceive~ "read one block continuously from a table"
+
+ say_category "AUDIO FILTERS"
+ say vcf~ "voltage controlled filter"
+ say noise~ "white noise generator"
+ say env~ "envelope follower"
+ say hip~ "high pass filter"
+ say lop~ "low pass filter"
+ say bp~ "band pass filter"
+ say biquad~ "raw filter"
+ say samphold~ "sample and hold unit"
+ say print~ "print out one or more \"blocks\""
+ say rpole~ "raw real-valued one-pole filter"
+ say rzero~ "raw real-valued one-zero filter"
+ say rzero_rev~ "[say rzero~] (time-reversed)"
+ say cpole~ "[say rpole~] (complex-valued)"
+ say czero~ "[say rzero~] (complex-valued)"
+ say czero_rev~ "[say rzero_rev~] (complex-valued)"
+
+ say_category "AUDIO DELAY"
+ say delwrite~ "write to a delay line"
+ say delread~ "read from a delay line"
+ say vd~ "read from a delay line at a variable delay time"
+
+ say_category "SUBWINDOWS"
+ say pd "define a subwindow"
+ say table "array of numbers in a subwindow"
+ say inlet "add an inlet to a pd"
+ say outlet "add an outlet to a pd"
+ say inlet~ "[say inlet] (for signal)"
+ say outlet~ "[say outlet] (for signal)"
+
+ say_category "DATA TEMPLATES"
+ say struct "define a data structure"
+ say {drawcurve filledcurve} "draw a curve"
+ say {drawpolygon filledpolygon} "draw a polygon"
+ say plot "plot an array field"
+ say drawnumber "print a numeric value"
+
+ say_category "ACCESSING DATA"
+ say pointer "point to an object belonging to a template"
+ say get "get numeric fields"
+ say set "change numeric fields"
+ say element "get an array element"
+ say getsize "get the size of an array"
+ say setsize "change the size of an array"
+ say append "add an element to a list"
+ say sublist "get a pointer into a list which is an element of another scalar"
+ say scalar "draw a scalar on parent"
+
+ say_category "OBSOLETE"
+ say scope~ "(use tabwrite~ now)"
+ say namecanvas "" ;# what was this anyway?
+ say template "(use struct now)"
+}
+
+# phase 4 (pdrc & ddrc)
+
+say section_audio "Audio"
+ say -r "sample rate"
+ say -audioindev "audio in devices"
+ say -audiooutdev "audio out devices"
+ say -inchannels "audio input channels (by device, like \"2\" or \"16,8\")"
+ say -outchannels "number of audio out channels (same)"
+ say -audiobuf "specify size of audio buffer in msec"
+ say -blocksize "specify audio I/O block size in sample frames"
+ say -sleepgrain "specify number of milliseconds to sleep when idle"
+ say -nodac "suppress audio output"
+ say -noadc "suppress audio input"
+ say audio_api_choice "Audio API"
+ say default "default"
+ say -alsa "use ALSA audio API"
+ say -jack "use JACK audio API"
+ say -mmio "use MMIO audio API (default for Windows)"
+ say -portaudio "use ASIO audio driver (via Portaudio)"
+ say -oss "use OSS audio API"
+ say -32bit "allow 32 bit OSS audio (for RME Hammerfall)"
+ say {} "default"
+
+say section_midi "MIDI"
+ say -nomidiin "suppress MIDI input"
+ say -nomidiout "suppress MIDI output"
+ say -midiindev "midi in device list; e.g., \"1,3\" for first and third"
+ say -midioutdev "midi out device list, same format"
+
+say section_externals "Externals"
+ say -path "file search path"
+ say -helppath "help file search path"
+ say -lib "load object libraries"
+
+say section_gui "Gooey"
+ say -nogui "suppress starting the GUI (caution)"
+ say -guicmd "substitute another GUI program (e.g., rsh)"
+ say -look "buttonbar icons"
+ say -font "specify default font size in points"
+
+say section_other "Other"
+ say -open "open file(s) on startup"
+ say -verbose "extra printout on startup and when searching for files"
+ say -d "debug level"
+ say -noloadbang "disable the effect of \[loadbang\]"
+ say -send "send a message at startup (after patches are loaded)"
+ say -listdev "list audio and MIDI devices upon startup"
+ say -realtime "use real-time priority (needs root privilege)"
+
+say section_paths "Paths"
+
+# phase 4B: ddrc (keyword names not finalized!)
+say console "console scrollback lines (0 = disable console)"
+say lang "Language to use"
+say pointer_sense "Mouse pointer sensitivity"
+say section_color "colors"
+ say canvas_color "canvas"
+ say canvasbgedit "canvas background (edit mode)"
+ say canvasbgrun "canvas background (run mode)"
+ say object_color "object"
+ say viewframe1 "objectbox color"
+ say viewframe2 "objectbox color"
+ say viewframe3 "objectbox color"
+ say viewframe4 "objectbox highlight color"
+ say viewbg "object background"
+ say viewfg "object foreground"
+ say commentbg "comment background"
+ say commentfg "comment forground"
+ say commentframe1 "comment frame"
+ say commentframe2 "comment frame"
+ say commentframe3 "comment frame"
+ say viewselectframe "hilight box"
+ say wire_color "wire"
+ say wirefg "wire color"
+ say wirefg2 "wire highlight"
+ say wiredspfg "dsp wire color"
+ say futurewiredash "new (dashed) wire"
+ say others_color "others"
+ say boxinletfg "inlet color"
+ say boxoutletfg "outlet color"
+ say selrectrect "selection box"
+say keys "keys"
+say others "others"
+say hairstate "Activate crosshair"
+say hairsnap "Crosshair snap to object"
+say statusbar "Activate statusbar"
+say buttonbar "Activate buttonbar"
+say menubar "Activate menubar"
+say scrollbar "Active auto scrollbar"
+say wirearrow "Wire Arrow"
+say tooltip "ToolTip"
+say insert_object "Insert object"
+say chain_object "Chain object"
+say clear_wires "Clear wires"
+say auto_wire "Remove object"
+say subpatcherize "Subpatcherize"
+say keynav "keyboard navigation"
+say key_nav_up "move up"
+say key_nav_up_shift "plus select"
+say key_nav_down "move down"
+say key_nav_down_shift "plus select"
+say key_nav_right "move right"
+say key_nav_right_shift "plus select"
+say key_nav_left "move left"
+say key_nav_left_shift "plus select"
+say key_nav_ioselect "select in/outlets"
+# phase 5A
+
+say cannot "can't"
+say cancel "Cancel"
+say apply "Apply"
+say ok "OK"
+say popup_open "Open"
+say popup_insert "Insert"
+say popup_properties "Properties"
+say popup_clear_wires "Clear wires"
+say popup_remove_from_path "Remove object from path"
+say popup_delete_from_path "Delete object from path"
+say popup_help "Help"
+say filter "Filter: "
+say how_many_object_classes "%d of %d object classes"
+say do_what_i_mean "Do What I Mean"
+say ask_cool "This would be a cool feature, eh?"
+say save_changes? "Save changes?"
+say reset "Reset"
+say Courier "Courier (monospaced)"
+say Helvetica "Helvetica (sansserif)"
+say Times "Times (serif)"
+say add "Add"
+say up "Up"
+say down "Down"
+say remove "Remove"
+say lib_add "add the name you typed to the list"
+say lib_up "swap order with previous library"
+say lib_down "swap order with next library"
+say lib_remove "remove library selected in the list"
+say dir_add "add a folder using a file dialog"
+say dir_up "swap order with previous folder"
+say dir_down "swap order with next folder"
+say dir_remove "remove folder selected in the list"
+say client_class_tree "Client Class Tree"
+say clipboard_view "Clipboard View"
+say command_history_view "Command History View"
+say event_history_view "Event History View"
+
+# during/after piksel:
+
+say auto_apply "Auto-Apply"
+say font_preview "Preview:"
+say font_preview_2 "ABCDEFGHIJKLMNOPQRSTUVWXYZ\nabcdefghijklmnopqrstuvwxyz\n0123456789"
+say font_style "Style:"
+say font_bold "Bold"
+say font_italic "Italic"
+say font_family "Name:"
+say font_size "Size:"
+say damn "Damn!"
+say console_clear "Clear Console"
+say horizontal "Horizontal"
+say vertical "Vertical"
+say language "Language"
+
+# 2007:
+
+say no_matches "(no matches)"
+say preset "preset"
diff --git a/desiredata/src/locale/portugues.tcl b/desiredata/src/locale/portugues.tcl
new file mode 100644
index 00000000..64385356
--- /dev/null
+++ b/desiredata/src/locale/portugues.tcl
@@ -0,0 +1,119 @@
+#!/usr/bin/env tclsh
+# Portuguese (Portugus) translations for PureData
+# $Id: portugues.tcl,v 1.1.2.5 2006-10-13 16:00:56 matju Exp $
+# by Nuno Godinho
+
+# (waiting for a version that has 8859-1 accents)
+
+### Menus
+
+say file "Ficheiro"
+ say new_file "Novo Ficheiro"
+ say open_file "Abrir Ficheiro..."
+ say pdrc_editor "Editor .pdrc"
+ say send_message "Enviar Mensagem..."
+ say paths "Caminhos..."
+ say close "Fechar"
+ say save "Gravar"
+ say save_as "Gravar Como..."
+ say print "Imprimir..."
+ say quit "Sair"
+
+say edit "Editar"
+ say undo "Desfazer"
+ say redo "Refazer"
+ say cut "Cortar"
+ say copy "Copiar"
+ say paste "Colar"
+ say duplicate "Duplicar"
+ say select_all "Seleccionar Tudo"
+ say text_editor "Editor de Texto..."
+ say tidy_up "Arranjar"
+ say edit_mode "Modo Editar"
+
+say view "Vista"
+ say reload "Recarregar"
+ say redraw "Redesenhar"
+
+say find "Procurar"
+ say find_again "Procurar Novamente"
+ say find_last_error "Encontrar Ultimo Erro"
+
+say put "Colocar"
+
+say media "Media"
+ say audio_on "Audio ON"
+ say audio_off "Audio OFF"
+ say test_audio_and_midi "Testar Audio e MIDI"
+ say load_meter "Medidor de Carga"
+
+say window "Janela"
+
+say help "Ajuda"
+ say about "Acerca..."
+ say pure_documentation "Documentao do Pure..."
+ say class_browser "Listar Classes..."
+
+
+### Main Window
+
+say in "entrada"
+say out "saida"
+say audio "Audio"
+say meters "Medidores"
+say io_errors "Erros de IO"
+
+### Other
+
+say cannot "impossivel"
+
+### phase 4
+
+say section_audio "udio"
+ say -r "frequncia de amostragem"
+ say -audioindev "dispositivos de entradaa udio"
+ say -audiooutdev "dispositivos de sada udio"
+ say -inchannels "canais de entrada udio (por dispositivo, como \"2\" ou \"16,8\")"
+ say -outchannels "nmero de canais de sada udio (igual)"
+ say -audiobuf "especificar tamanho do buffer de udio em ms"
+ say -blocksize "especificar tamanho do bloco I/O udio em nmero de amostras"
+ say -sleepgrain "especificar nmero de milisegundos que dorme quando inactivo"
+ say -nodac "inibir sada de udio"
+ say -noadc "inibir entrada de udio"
+ say audio_api_choice "udio API"
+ say default "defeito"
+ say -alsa "usar ALSA audio API"
+ say -jack "usar JACK audio API"
+ say -mmio "usar MMIO audio API (por defeito para Windows)"
+ say -portaudio "usar ASIO audio driver (via Portaudio)"
+ say -oss "usar OSS audio API"
+ say -32bit "permitir OSS udio a 32 bit (para RME Hammerfall)"
+
+say section_midi "MIDI"
+ say -nomidiin "inibir entrada MIDI"
+ say -nomidiout "inibir sada MIDI"
+ say -midiindev "lista de dispositivos de entrada midi; ex., \"1,3\" para primeiro e terceiro"
+ say -midioutdev "lista de dispositivos de sada midi, mesmo formato"
+
+say section_externals "Externals"
+ say -path "adicionar a caminho de pesquisa de ficheiros"
+ say -helppath "adicionar a caminho de pesquisa de ficheiros de ajuda"
+ say -lib "carregar biblioteca(s) de objectos"
+
+say section_gui "Gooey"
+ say -nogui "inibir inicializao de GUI (cuidado)"
+ say -guicmd "substituir programa de GUI (ex., rsh)"
+ say -console "linhas armazenadas na consola (0 = inibir consola)"
+ say -look "pasta contendo icons para barra de botes"
+ say -statusbar "inibir barra de status"
+ say -font "especificar tamanho da fonte por defeito em pontos"
+
+say section_other "Outros"
+ say -open "abrir ficheiro(s) na inicializao"
+ say -verbose "impresses extra na inicializao e durante pesquisa de ficheiros"
+ say -d "nvel de depurao"
+ say -noloadbang "inibir efeito de \[loadbang\]"
+ say -send "enviar mensagem na inicializao (depois dos patches carregados)"
+ say -listdev "listar dispositivos udio e MIDI aps inicializao"
+ say -realtime "usar prioridade de tempo-real (necessrios privilgios de root)"
+
diff --git a/desiredata/src/locale/russkij.tcl b/desiredata/src/locale/russkij.tcl
new file mode 100644
index 00000000..448c4bf5
--- /dev/null
+++ b/desiredata/src/locale/russkij.tcl
@@ -0,0 +1,574 @@
+#!/usr/bin/env tclsh
+# русский перевод PureData (пьюр дата - англ., "чисто данные")
+# by Ilya Dmitrichenko, 'errordeveloper"^at^"gmail"^dot^"com'
+# $Id: russkij.tcl,v 1.1.2.1 2007-10-26 20:17:14 matju Exp $
+
+### Menus
+
+say file "Файл"
+ say new_file "Новый файл"
+ say open_file "Открыть файл..."
+ say server_prefs "Настройки сервера..."
+ say client_prefs "Настройки клиента..."
+ say send_message "Послать сообщение..."
+ say paths "Расположение расширений..."
+ say close "Закрыть"
+ say save "Сохранить"
+ say save_as "Сохранить с именем..."
+ say print "Распечатать..."
+ say abort_server "О сервере"
+ say quit "Покинуть программу"
+
+ say canvasnew_file "Новый файл"
+ say canvasopen_file "Отрыть файл..."
+ say canvassave "Сохранить"
+ say canvassave_as "Сохранить как..."
+ say clientpdrc_editor "отредактировать .pdrc"
+ say clientddrc_editor "отредактировать .ddrc"
+ say canvasclose "Закрыть"
+ say canvasquit "Выход"
+
+say edit "Правка"
+ say undo "Шаг назад"
+ say redo "Шаг вперёд"
+ say cut "Вырезать"
+ say copy "Копировать"
+ say paste "Вставить"
+ say duplicate "Дублировать"
+ say select_all "Выбрать всё"
+ say clear_selection "Отменить выбор"
+ say text_editor "Текстовый редактор..."
+ say font "Шрифт"
+ say tidy_up "Упорядочить"
+ say edit_mode "Режим редактирования"
+ say editmodeswitch "Режим исполнения/редактирования"
+ say subpatcherize "Превратить в суб-патч"
+
+ say canvascut "Вырезать"
+ say canvascopy "Копировать"
+ say canvasundo "Шаг назад"
+ say canvasredo "Шаг вперёд"
+ say canvaspaste "Вставить"
+ say canvasduplicate "Дублировать"
+ say canvasselect_all "Выбрать всё"
+ say canvaseditmodeswitch "Режим исполнения/редактирования"
+
+say view "Вид"
+ say reload "Перезагрузить"
+ say redraw "Обновить"
+
+ say canvasreload "Перезагрузить"
+ say canvasredraw "Обновить"
+
+say find "Поиск"
+ say find_again "Найти ещё"
+ say find_last_error "Найти последнею ошибку"
+ say string "Искать текст"
+say canvasfind "Найти"
+ say canvasfind_again "Найти ещё"
+
+# contents of Put menu is Phase 5C
+say put "Положить"
+ say Object "Обьект"
+ say Message "Сообщение"
+ say Number "Номер"
+ say Symbol "Символ"
+ say Comment "Комментарий"
+ say Graph "Пустая графа"
+ say Array "Графа с данными"
+
+say media "Мотор"
+ say audio_on "ВКЛ звук"
+ say audio_off "ВЫКЛ звук"
+ say test_audio_and_midi "Проверка аудио и MIDI"
+ say load_meter "Измеритель загруженности"
+
+ say canvasaudio_on "ВКЛ звук"
+ say canvasaudio_off "ВЫКЛ звук"
+ say clienttest_audio_and_midi "Проверка звука и MIDI"
+ say canvasload_meter "загруз. метр"
+
+say window "Окна"
+
+say help "Помощь"
+ say about "О программе..."
+ say documentation "Документация..."
+ say class_browser "Браузер классов..."
+
+ say canvasabout "О программе..."
+
+say properties "Свойства"
+say open "Открыть"
+
+### for key binding editor
+say general "Общее"
+say audio_settings "Настройки звука"
+say midi_settings "Настройки MIDI"
+say latency_meter "Измеритель опозданий"
+say Pdwindow "Основное окно"
+
+say canvaspdwindow "Основное окно"
+say canvaslatency_meter "Измеритель задержек"
+say clientaudio_settings "Настройки аудио"
+say clientmidi_settings "Настройки MIDI"
+
+### for Properties Dialog (phase 5B)
+say_category IEM
+say w "ширина, px"
+say h "высота, px"
+say hold "время удержки, мс"
+say break "break time, мс"
+say min "наименьшее значение"
+say max "наибольшее значение"
+say is_log "режим"
+say linear "линейный"
+say logarithmic "логорифмичекий"
+say isa "init"
+say n "колличество вариантов"
+say steady "стойкость"
+say steady_no "сдвиг при клике"
+say steady_yes "стойкий при клике"
+say snd "отправлять с символом"
+say rcv "получать по сиволу"
+say lab "название"
+say ldx "смещение названия Х"
+say ldy "смещение названия У"
+say fstyle "шрифт"
+say fs "размер шрифта"
+say bcol "цвет фона"
+say fcol "основной цвет"
+say lcol "цвет названия"
+say yes "да"
+say no "нет"
+say courier "courier (typewriter)"
+say helvetica "helvetica (sansserif)"
+say times "times (serif)"
+say coords "graph on parent"
+
+say_category GAtomProperties
+say width "ширина"
+say lo "нижний предел"
+say hi "верхний предел"
+say label "обозначение"
+say wherelabel "отображать"
+say symto "отправлять с символом"
+say symfrom "получать по сиволу"
+
+say_category GraphProperties
+say x1 "значения x с"
+say x2 "x до"
+say xpix "ширина"
+say y2 "значения y с"
+say y1 "y до"
+say ypix "высота"
+
+say_category CanvasProperties
+#say xscale "X units/px"
+#say yscale "Y units/px"
+say gop "graph on parent"
+say xmargin "предел по оси X"
+say ymargin "предел по оси Y"
+say height "высота"
+say_category ArrayProperties
+say name "название"
+say n "размер"
+say xfrom "значения x с"
+say xto "значения x до"
+say yfrom "значения у с"
+say yto "значения у до"
+
+
+say_category MainWindow
+say in "вход"
+say out "выход"
+say audio "Аудио"
+say meters "Уровни"
+say io_errors "Ошибки на входе и выходе"
+say tcl_console "клиент Tcl"
+say pd_console "pd сервер"
+
+### phase 2
+
+say_category Other
+say_namespace summary {
+ say_category IEMGUI
+ say bng "Bang Box"
+ say tgl "Toggle Box"
+ say nbx "Number Box (IEM)"
+ say hsl "Slider (Горизонтальный)"
+ say vsl "Slider (Вертикальный)"
+ say hradio "Choice Box (Горизонтальный)"
+ say vradio "Choice Box (Вертикальный)"
+ say cnv "Полотно (IEM)"
+ say dropper "Drag-and-Drop Box"
+ say vu "Уровень громкости (VU-meter)"
+
+ say_category GLUE
+ say bang "выдать 'bang'"
+ say float "store and recall a number"
+ say symbol "store and recall a symbol"
+ say int "сохранить число"
+ say send "отсылка сообсчений с символы"
+ say receive "приём отосланных сообсчений по символу"
+ say select "test for matching numbers or symbols"
+ say route "route messages according to first element"
+ say pack "make compound messages"
+ say unpack "get elements of compound messages"
+ say trigger "sequence and convert messagess"
+ say spigot "прерываемый поток сообщений"
+ say moses "разбить поток чисел"
+ say until "механизм кругового действия"
+ say print "текстовый вывод"
+ say makefilename "создать текст с переменными полями"
+ say change "убрать повторяющееся число из потока"
+ say swap "поменять два числа местами"
+ say value "сохранить обсщедоступную переменную с заданным именем"
+
+ say_category TIME
+ say delay "выдавать соовщение с заданной задержкой"
+ say metro "выдавать переодическое соовщение с заданным интервалом"
+ say line "выдать линейную прогрессию"
+ say timer "отмерить временной промеуток"
+ say cputime "отмерить промежуток по процесорному времени"
+ say realtime "отмерить реальный временной промежуток"
+ say pipe "динамически нарастающий накопитель чисел с задержкой вывода"
+
+ say_category MATH
+ say + "сумма"
+ say - "разность"
+ say * "произведение"
+ say {/ div} "частное"
+ say {% mod} "деление с остатком"
+ say pow "возвести в стапань"
+ say == "равно?"
+ say != "не равно?"
+ say > "больше?"
+ say < "меньше?"
+ say >= "не меньше?"
+ say <= "не больше?"
+ say & "bitwise conjunction (and)"
+ say | "bitwise disjunction (or)"
+ say && "logical conjunction (and)"
+ say || "logical disjunction (or)"
+ say mtof "MIDI > Герцы"
+ say ftom "Герцы > MIDI"
+ say powtodb "Ватты > dB"
+ say dbtopow "dB > Ватты"
+ say rmstodb "Вольты > dB"
+ say dbtorms "dB > Вольты"
+ say {sin cos tan atan atan2 sqrt} "Тригонометрические функции"
+ say log "Натуральный логоритм"
+ say exp "Экспонента Эвлера"
+ say abs "Значение по модулю"
+ say random "Случайное число"
+ say max "Наибольшее из двух"
+ say min "Наименьшее из дцух"
+ say clip "Ограничить значения в потоке чисел"
+
+ say_category MIDI
+ say {notein ctlin pgmin bendin touchin polytouchin midiin sysexin} "MIDI вход"
+ say {noteout ctlout pgmout bendout touchout polytouchout midiout} "MIDI выход"
+ say makenote "schedule a delayed \"note off\" message corresponding to a note-on"
+ say stripnote "strip \"note off\" messages"
+
+ say_category TABLES
+ say tabread "получить значение из таблицы (по индексу)"
+ say tabread4 "read a number from a table, with 4 point interpolation"
+ say tabwrite "вписать значение в таблицу"
+ say soundfiler "считывать аудио-файл в/из таблиц"
+
+ say_category MISC
+ say loadbang "выдать 'bang' при загрузке"
+ say serial "доступ к серийному порту (только в NT)"
+ say netsend "посылать сообщения по сети (по TCP или UDP)"
+ say netreceive "получать сообщения из сети (по TCP или UDP)"
+ say qlist "message sequencer"
+ say textfile "file to message converter"
+ say openpanel "диалоговое окно \"Открыть\""
+ say savepanel "диалоговое окно \"Save as\""
+ say bag "набор чисел"
+ say poly "полифонизатор"
+ say {key keyup} "числовые значения клавиш клавиатуры"
+ say keyname "именные значения клавиш"
+
+ say_category "AUDIO MATH"
+ foreach word {+ - * /} {say $word~ "[say $word] (для сигналов)"}
+ say max~ "supremum of signals"
+ say min~ "infimum of signals"
+ say clip~ "ограничить амплитуду сигнала"
+ say q8_rsqrt~ "упрощенный алгоритм (8 бит) обратного квадратного корня"
+ say q8_sqrt~ "упрощенный алгоритм (8 бит) квадратного корня"
+ say wrap~ "wraparound (fractional part, sort of)"
+ say fft~ "complex forward discrete Fourier transform"
+ say ifft~ "complex inverse discrete Fourier transform"
+ say rfft~ "real forward discrete Fourier transform"
+ say rifft~ "вещественный обратный inverse discrete Fourier transform"
+ say framp~ "output a ramp for each block"
+ foreach word {mtof ftom rmstodb dbtorms rmstopow powtorms} {
+ say $word~ "[say $word] (for signals)"
+ }
+}
+
+### phase 3
+
+say_namespace summary {
+ say_category GLUE
+ say dac~ "аудио выход"
+ say adc~ "аудио вход"
+ say sig~ "превратить число в сигнал"
+ say line~ "generate audio ramps"
+ say vline~ "улучшенный line~"
+ say threshold~ "detect signal thresholds"
+ say snapshot~ "семплироавть сигнал (представить в виде числа)"
+ say vsnapshot~ "улучшенный snapshot~"
+ say bang~ "посылать 'bang' с каждым аудио-блоком"
+ say samplerate~ "узнать частоту дискретизации"
+ say send~ "отослать сигнал для удалённого приёма"
+ say receive~ "получить отосланный сигнал"
+ say throw~ "отослать сигнал в суммарный канал"
+ say catch~ "считывать с суммарного канала"
+ say block~ "размер аудио-блока и нахлестки"
+ say switch~ "switch DSP computation on and off"
+ say readsf~ "чтение с диска"
+ say writesf~ "запись на диск"
+
+ say_category "AUDIO OSCILLATORS AND TABLES"
+ say phasor~ "генератор пилообразного сигнала"
+ say {cos~ osc~} "генератор синусодального сигнала"
+ say tabwrite~ "писать сигнал в таблицу"
+ say tabplay~ "play back from a table (non-transposing)"
+ say tabread~ "non-interpolating table read"
+ say tabread4~ "four-point interpolating table read"
+ say tabosc4~ "табличный вибратор"
+ say tabsend~ "постоянно вписывать блок в таблицу"
+ say tabreceive~ "постоянно считывать блок из таблицы"
+
+ say_category "AUDIO FILTERS"
+ say vcf~ "фильтр контролирумый напряжением"
+ say noise~ "генератор \"белого\" шума"
+ say env~ "envelope follower"
+ say hip~ "high pass filter"
+ say lop~ "low pass filter"
+ say bp~ "band pass filter"
+ say biquad~ "raw filter"
+ say samphold~ "sample and hold unit"
+ say print~ "print out one or more \"blocks\""
+ say rpole~ "raw real-valued one-pole filter"
+ say rzero~ "raw real-valued one-zero filter"
+ say rzero_rev~ "[say rzero~] (time-reversed)"
+ say cpole~ "[say rpole~] (комплексный)"
+ say czero~ "[say rzero~] (комплексный)"
+ say czero_rev~ "[say rzero_rev~] (комплексный)"
+
+ say_category "AUDIO DELAY"
+ say delwrite~ "write to a delay line"
+ say delread~ "read from a delay line"
+ say vd~ "read from a delay line at a variable delay time"
+
+ say_category "SUBWINDOWS"
+ say pd "новое окно"
+ say table "таблица в новом окне"
+ say inlet "добавляет впуск"
+ say outlet "добавляет выпуск"
+ say inlet~ "[say inlet] (для сигналов)"
+ say outlet~ "[say outlet] (для сигналов)"
+
+ say_category "DATA TEMPLATES"
+ say struct "define a data structure"
+ say {drawcurve filledcurve} "начертить кривую"
+ say {drawpolygon filledpolygon} "начертить многоугольник"
+ say plot "plot an array field"
+ say drawnumber "print a numeric value"
+
+ say_category "Доступ к данным"
+ say pointer "указать на объект в шаблоне"
+ say get "получить численное значение"
+ say set "изменить численное значение"
+ say element "получить значение из таблицы"
+ say getsize "получить размер таблицы"
+ say setsize "изменить размер таблицы"
+ say append "добавить к списку"
+ say sublist "get a pointer into a list which is an element of another scalar"
+ say scalar "draw a scalar on parent"
+
+ say_category "Ныне отсутсвующее"
+ say scope~ "(теперь используется tabwrite~)"
+ say namecanvas "именовать полотно" ;# what was this anyway?
+ say template "(теперь используется struct)"
+}
+
+# phase 4 (pdrc & ddrc)
+
+say section_audio "Audio"
+ say -r "частота дискретизации"
+ say -audioindev "аудио вход"
+ say -audiooutdev "аудио выход"
+ say -inchannels "кол-во входных каналов (в соответствии с устройствами, на пример: \"2\" или \"16,8\")"
+ say -outchannels "кол-во выходных каналов"
+ say -audiobuf "размер сигнального буфера (милисек)"
+ say -blocksize "указать размер аудио-блока в сэмпл-фреймах"
+ say -sleepgrain "указать время (милисек) для перехода в режим сна когда неактивен"
+ say -nodac "предотвратить звук на входе (при запуске)"
+ say -noadc "предотвратить звук на выходе (при запуске)"
+ say audio_api_choice "Выбор аудио API"
+ say default "по умолчанию"
+ say -alsa "использовать ALSA аудио API"
+ say -jack "использовать JACK аудио API"
+ say -mmio "использовать MMIO API (в Windows, по-умолчанию)"
+ say -portaudio "использовать дарйвера ASIO (при помощи Portaudio)"
+ say -oss "использовать OSS аудио API"
+ say -32bit "включить 32-битный режим аудио (OSS, для карт RME Hammerfall)"
+ say {} "по умолчанию"
+
+say section_midi "MIDI"
+ say -nomidiin "предотвратить MIDI вход"
+ say -nomidiout "предотвратить MIDI выход"
+ say -midiindev "midi in device list; e.g., \"1,3\" for first and third"
+ say -midioutdev "midi out device list, same format"
+
+say section_externals "Расширения"
+ say -path "путь поиска файлов"
+ say -helppath "путь поиска вспомогательных примеров"
+ say -lib "загрузить библиотеку (по имени)"
+
+say section_gui "Графический интерфейс"
+ say -nogui "отключит графический интерфейс"
+ say -guicmd "запуск с использованием иной программы (например: rsh или ssh)"
+ say -look "иконки на панельке"
+ say -font "размер шрифта в точках"
+
+say section_other "Остальное"
+ say -open "открыть файл(ы) при запуске"
+ say -verbose "вывод дополнительной информации"
+ say -d "уровень debug"
+ say -noloadbang "отключить действие \[loadbang\]"
+ say -send "послать сообсчение при запуске (как только все патчи загружены)"
+ say -listdev "вывод доступных аудио и MIDI устройств"
+ say -realtime "исполнение в \"реальном времени\" (требует привелегий спец-пользователя)"
+
+say section_paths "Путь"
+
+# phase 4B: ddrc (keyword names not finalized!)
+say console "колличество полос памяти на консоли (0 = отключить консоль)"
+say lang "язык"
+say pointer_sense "чувствительность курсора"
+say section_color "вид"
+ say canvas_color "полотно"
+ say canvasbgedit "цвет фона в режиме редактора"
+ say canvasbgrun "цвет фона в режиме исполнения"
+ say object_color "объект"
+ say viewframe1 "цвет рамки"
+ say viewframe2 "цвет рамки"
+ say viewframe3 "цвет рамки"
+ say viewframe4 "цвет выделенной рамки"
+ say viewbg "цвет фона объекта"
+ say viewfg "основной цвет объекта"
+ say commentbg "фон комментария"
+ say commentfg "цвет текста комментария"
+ say commentframe1 "рамка комментария"
+ say commentframe2 "рамка комментария"
+ say commentframe3 "рамка комментария"
+ say viewselectframe "выделенная рамка"
+ say wire_color "провод"
+ say wirefg "цвет провода"
+ say wirefg2 "выделенный провод"
+ say wiredspfg "цвет провода несущего сигнал"
+ say futurewiredash "новый провод (пунктиром)"
+ say others_color "другое"
+ say boxinletfg "цвет inlet"
+ say boxoutletfg "цвет outlet"
+ say selrectrect "выделение"
+say keys "клавиши"
+say others "другие"
+say hairstate "включить крестик (crosshair)"
+say hairsnap "crosshair snap to object"
+say statusbar "включить строку статуса"
+say buttonbar "включить панельку кнопок"
+say menubar "включить менюшку"
+say scrollbar "включить автопромотку"
+say wirearrow "wire стрелка"
+say tooltip "подсказки"
+say insert_object "Вставить объект"
+say chain_object "Цепочка оьектов"
+say clear_wires "Прибрать провода"
+say auto_wire "Удалить объект"
+say subpatcherize "Превратить в суб-патч"
+say keynav "Навигация припомощи клавиатуры"
+say key_nav_up "вверх"
+say key_nav_up_shift "выделение с добавкой"
+say key_nav_down "вниз"
+say key_nav_down_shift "выделение с добавкой"
+say key_nav_right "направо"
+say key_nav_right_shift "выделение с добавкой"
+say key_nav_left "налево"
+say key_nav_left_shift "выделение с добавкой"
+say key_nav_ioselect "select in/outlets"
+# phase 5A
+
+say cannot "Не получается .."
+say cancel "Сброс"
+say apply "Применить"
+say ok "Окей"
+say popup_open "Открыть"
+say popup_insert "Вставить"
+say popup_properties "Свойства"
+say popup_clear_wires "Прибрать провода"
+say popup_remove_from_path "Remove object from path"
+say popup_delete_from_path "Delete object from path"
+say popup_help "Помощь"
+say filter "Фильтровать: "
+say how_many_object_classes "%d из %d классов объектов"
+say do_what_i_mean "Сделай всё!"
+say ask_cool "Было бы круто добавить такой наворот! Не так ли?"
+say save_changes? "Сохранить?"
+say reset "Сброс"
+say Courier "Courier (monospaced)"
+say Helvetica "Helvetica (sansserif)"
+say Times "Times (serif)"
+say add "Добавить"
+say up "Вверх"
+say down "Вниз"
+say remove "Удалить"
+say lib_add "добавить к списку"
+say lib_up "поменять местами с предыдущей библиотекой"
+say lib_down "поменять местами со следующей библиотекой"
+say lib_remove "удалить выбранную библиотеку"
+say dir_add "указать местонахождения"
+say dir_up "поменять местами с предыдущей папкой"
+say dir_down "поменять местами со следующей папкой"
+say dir_remove "удалить из списка"
+say client_class_tree "Дерево классов"
+say clipboard_view "Clipboard View"
+say command_history_view "Просмотр истории команд"
+say event_history_view "Просмотр истории событий"
+
+# during/after piksel:
+
+say auto_apply "Автопримение"
+say font_preview "Просмотр:"
+say font_preview_2 "ABCDEFGHIJKLMNOPQRSTUVWXYZ\nabcdefghijklmnopqrstuvwxyz\n0123456789"
+say font_style "Стиль:"
+say font_bold "Жирный"
+say font_italic "Курсивом"
+say font_family "Название:"
+say font_size "Размер:"
+say damn "Эх!"
+# say damn "Нах!"
+# say damn "Тьфу! Да ну тебя!"
+say console_clear "Очистить консоль"
+say horizontal "Горизонталь"
+say vertical "Вертикаль"
+say language "Язык"
+
+# 2007:
+
+say no_matches "(совпадений нет)"
+say preset "preset"
+say canvasgrid "цвет клеток"
+say grid_size "размер клеточки"
+say gridstate "показать клеточки"
+say snap_grid "подгонка под клетки"
+say viewfont "шрифт имён объектов"
+say consolefont "консольный шрифт"
+say keyboarddialogfont "шрифт разметки виртуальной клавиатуры"
+say keyboard_view "Виртуальные клавиши"
diff --git a/desiredata/src/locale/turkce.tcl b/desiredata/src/locale/turkce.tcl
new file mode 100644
index 00000000..e33cb235
--- /dev/null
+++ b/desiredata/src/locale/turkce.tcl
@@ -0,0 +1,572 @@
+#!/usr/bin/env tclsh
+# Turkish translations for PureData
+# $Id: turkce.tcl,v 1.1.2.1 2007-10-05 23:14:23 matju Exp $
+# by Koray Tahiroglu
+
+### Menus
+
+say file "Dosya"
+ say new_file "Yeni"
+ say open_file "Aç..."
+ say server_prefs "Sunucu Tercihleri..."
+ say client_prefs "Kullanıcı Tercihleri..."
+ say send_message "Mesajı Gönder..."
+ say paths "Yollar..."
+ say close "Kapat"
+ say save "Kaydet"
+ say save_as "Farklı Kaydet..."
+ say print "Yazdır..."
+ say abort_server "Sunucuyu Durdur"
+ say quit "Çıkış"
+
+ say canvasnew_file "Yeni"
+ say canvasopen_file "Aç..."
+ say canvassave "Kaydet"
+ say canvassave_as "Farklı Kaydet..."
+ say clientpdrc_editor ".pdrc Düzenleyicisi"
+ say clientddrc_editor ".ddrc Düzenleyicisi"
+ say canvasclose "Kapat"
+ say canvasquit "Çıkış"
+
+say edit "Düzen"
+ say undo "Geri Al"
+ say redo "Yeniden Yap"
+ say cut "Kes"
+ say copy "Kopyala"
+ say paste "Yapıştır"
+ say duplicate "Çoğalt"
+ say select_all "Tümünü Seç"
+ say clear_selection "Seçimi Kaldır"
+ say text_editor "Not Defteri..."
+ say font "Yazı Tipi"
+ say tidy_up "Derle Toparla"
+ say edit_mode "Düzenleme Durumu"
+ say editmodeswitch "Düzenleme/Çalıştırma Durumu"
+ say subpatcherize "Alt-Bağlantı"
+
+ say canvascut "Kes"
+ say canvascopy "Kopyala"
+ say canvasundo "Geri Al"
+ say canvasredo "Yeniden Yap"
+ say canvaspaste "Yapıştır"
+ say canvasduplicate "Çoğalt"
+ say canvasselect_all "Tümünü Seç"
+ say canvaseditmodeswitch "Düzenleme/Çalıştırma Durumu"
+
+say view "Görünüm"
+ say reload "Yeniden Yükle"
+ say redraw "Yeniden Çiz"
+
+ say canvasreload "Yeniden Yükle"
+ say canvasredraw "Yeniden Çiz"
+
+say find "Bul"
+ say find_again "Sonrakini Bul"
+ say find_last_error "En Son Hatayı Bul"
+ say string "Diziyi Bul"
+say canvasfind "Bul"
+ say canvasfind_again "Sonrakini Bul"
+
+# contents of Put menu is Phase 5C
+say put "Yerleştir"
+ say Object "Nesne"
+ say Message "Mesaj"
+ say Number "Sayı"
+ say Symbol "Simge"
+ say Comment "Not"
+ say Graph "Grafik"
+ say Array "Dizilim"
+
+say media "Ortam"
+ say audio_on "Ses Aç"
+ say audio_off "Ses Kapat"
+ say test_audio_and_midi "Ses ve MIDI Testi"
+ say load_meter "Ölçeri Yükle"
+
+ say canvasaudio_on "Ses Aç"
+ say canvasaudio_off "Ses Kapat"
+ say clienttest_audio_and_midi "Ses ve MIDI Testi"
+ say canvasload_meter "Ölçeri Yükle"
+
+say window "Pencere"
+
+say help "Yardım"
+ say about "Hakkında..."
+ say documentation "Belgeleme..."
+ say class_browser "Sınıf Gözatıcısı..."
+
+ say canvasabout "Hakkında..."
+
+say properties "Özellikler"
+say open "Aç"
+
+### for key binding editor
+say general "Genel"
+say audio_settings "Ses Ayarları"
+say midi_settings "Midi Ayarları"
+say latency_meter "Gecikme Ölçeri"
+say Pdwindow "Pd penceresi"
+
+say canvaspdwindow "Pd penceresi"
+say canvaslatency_meter "Gecikme Ölçeri"
+say clientaudio_settings "Ses Ayarları"
+say clientmidi_settings "Midi Ayarları"
+
+### for Properties Dialog (phase 5B)
+say_category IEM
+say w "genişlik(px)"
+say h "yükseklik(px)"
+say hold "tutma zamanı(ms)"
+say break "kesme zamanı(ms)"
+say min "en az değer"
+say max "en fazla değer"
+say is_log "durum"
+say linear "doğrusal"
+say logarithmic "logaritmik"
+say isa "init"
+say n "seçenek sayısı"
+say steady "kararlı"
+say steady_no "tıklama ile sıçra"
+say steady_yes "tıklama ile kararli ol"
+say snd "simge-gönder"
+say rcv "simge-al"
+say lab "Etiket"
+say ldx "Etiket x kaydır"
+say ldy "Etiket y kaydır"
+say fstyle "Yazı Biçimi"
+say fs "Yazitippi boyutu"
+say bcol "arkaplan rengi"
+say fcol "önalan rengi"
+say lcol "Etiket rengi"
+say yes "evet"
+say no "hayır"
+say courier "courier (typewriter)"
+say helvetica "helvetica (sansserif)"
+say times "times (serif)"
+say coords "üstteki grafik"
+
+say_category GAtomÖzellikleri
+say width "genişlik"
+say lo "alt sınır"
+say hi "üst sınır"
+say label "etiket"
+say wherelabel "etiket göster"
+say symto "simge gönder"
+say symfrom "simge al"
+
+say_category GrafikÖzellikleri
+say x1 "x'den"
+say x2 "x'e"
+say xpix "görüntü alanı genişliği"
+say y2 "y'den"
+say y1 "y'e"
+say ypix "görüntü alanı yükselkiği"
+
+say_category KanavaÖzellikleri
+#say xscale "X birim/px"
+#say yscale "Y birim/px"
+say gop "üstteki grafik"
+say xmargin "x-kenar boşluğu"
+say ymargin "y-kenar boşluğu"
+say height "yükseklik"
+say_category DizilimÖzellikleri
+say name "adı"
+say n "boyutu"
+say xfrom "x aralığından"
+say xto "x aralığına"
+say yfrom "y aralığından"
+say yto "y aralığına"
+
+
+say_category AnaPencere
+say in "giriş"
+say out "çıkış"
+say audio "Ses"
+say meters "Ölçerler"
+say io_errors "IO Hataları"
+say tcl_console "Tcl Kullanıcısi"
+say pd_console "Pd Sunucusu"
+
+### phase 2
+
+say_category Diğer
+say_namespace özet {
+ say_category IEMGUI
+ say bng "Patlama Kutusu"
+ say tgl "Düğme Kutusu"
+ say nbx "Sayı Kutusu (IEM)"
+ say hsl "Kaydırıcı (yatay)"
+ say vsl "Kaydırıcı (düşey)"
+ say hradio "Seçme Kutusu (yatay)"
+ say vradio "Seçme Kutusu (düşey)"
+ say cnv "Kanava (IEM)"
+ say dropper "Taşı-ve-Bırak Kutusu"
+ say vu "Vumeter"
+
+ say_category GLUE
+ say bang "patlama mesajı ver"
+ say float "sayıyı sakla ve yeniden çağır"
+ say symbol "simgeyi sakla ve yeniden çağır"
+ say int "tamsayıyı sakla ve yeniden çağır"
+ say send "isimlendirilmiş bir nesneye mesaj gönder"
+ say receive "gönderilen mesajları al"
+ say select "eşleşen sayı ve simgeler için test"
+ say route "ilk öğelerine göre mesajları yönlendir"
+ say pack "make bileşik mesajlar oluştur"
+ say unpack "get elements of compound messages"
+ say trigger "mesajları sırala ve dönüştür"
+ say spigot "kesilebilir mesaj bağlantısı"
+ say moses "sayısal akımı ayır"
+ say until "döngü meaknizması"
+ say print "mesajları yazdır"
+ say makefilename "simgeyi bir değişken alanı ile biçimlendir"
+ say change "tekrar edilen sayıları akımdan ayır"
+ say swap "iki sayıyı takas et"
+ say value "paylaşılan sayısal değer"
+
+ say_category ZAMAN
+ say delay "zaman geciktirmesi sonunda mesaj gönder"
+ say metro "belirli aralıklarla mesaj gönder"
+ say line "send a series of linearly stepped numbers"
+ say timer "zaman aralıklarını hesapla"
+ say cputime "CPU zamanını hesapla"
+ say realtime "gerçek zamanı hesapla"
+ say pipe "sayılar için dinamik olarak büyüyen gecikme hattı"
+
+ say_category MATEMATİK
+ say + "topla"
+ say - "çıkart"
+ say * "çarp"
+ say {/ div} "böl"
+ say {% mod} "bölümden kalan"
+ say pow "üs al"
+ say == "eşit?"
+ say != "eşit değil?"
+ say > "büyük?"
+ say < "küçük?"
+ say >= "küçük değil?"
+ say <= "büyük değil?"
+ say & "bit olarak birleşme (and)"
+ say | "bit olarak ayırtım (or)"
+ say && "mantıksal birleşme (and)"
+ say || "mantıksal ayırtım (or)"
+ say mtof "MIDI'den Hertz'e"
+ say ftom "Hertz'den MIDI'ye"
+ say powtodb "Watts'dan dB'e"
+ say dbtopow "dB'den Watts'a"
+ say rmstodb "Gerilimden dB'e"
+ say dbtorms "dB'den Gerilime"
+ say {sin cos tan atan atan2 sqrt} "trigonometri"
+ say log "Euler logaritma"
+ say exp "Euler Üssel"
+ say abs "mutlak değer"
+ say random "rasgele"
+ say max "iki sayının en büyüğü"
+ say min "iki sayının en küçüğü"
+ say clip "sayıyı belirli bir değer aralığına indirge"
+
+ say_category MIDI
+ say {notein ctlin pgmin bendin touchin polytouchin midiin sysexin} "MIDI giriş"
+ say {noteout ctlout pgmout bendout touchout polytouchout midiout} "MIDI çıkış"
+ say makenote " note-on a uygun olarak gecikmeli bir \"note off\" mesajı düzenle"
+ say stripnote "strip \"note off\" mesajı"
+
+ say_category TABLOLAR
+ say tabread "tablodan bir sayı oku"
+ say tabread4 "tablodan 4 noktalı aradeğerleme ile sayı oku"
+ say tabwrite "tabloya bir sayı yaz"
+ say soundfiler "tabloları ses dosyalarına yaz ve oku"
+
+ say_category MISC
+ say loadbang "yüklendiği zaman patlama gönder"
+ say serial "yalnızca NT için dizisel aygıt kontrolü"
+ say netsend "internet üzerinden mesaj gönder"
+ say netreceive "internet üzerinden mesaj al"
+ say qlist "mesaj ardıştırıcısı"
+ say textfile "dosyayı mesaja çevirici"
+ say openpanel "\"Aç\" diyalog"
+ say savepanel "\"Farklı Kaydet\" diyalog"
+ say bag "sayılar kümesi"
+ say poly "çoksesli ses ayırması"
+ say {key keyup} "klavyeden sayısal tuş değerleri"
+ say keyname "simgelsel tuş ismi"
+
+ say_category "Ses Matematiği"
+ foreach word {+ - * /} {say $word~ "[say $word] (sinyaller için)"}
+ say max~ "sinyallerin enyükseği"
+ say min~ "sinyallerin en düşüğü"
+ say clip~ "sinyalin iki sınır arasında yer almasının sağlanması"
+ say q8_rsqrt~ "indirimli ters karekökü (dikkat -- 8 bits!)"
+ say q8_sqrt~ "ndirimli karekök (dikkat -- 8 bits!)"
+ say wrap~ "wraparound (fractional part, sort of)"
+ say fft~ "complex forward discrete Fourier transform"
+ say ifft~ "complex inverse discrete Fourier transform"
+ say rfft~ "real forward discrete Fourier transform"
+ say rifft~ "real inverse discrete Fourier transform"
+ say framp~ "output a ramp for each block"
+ foreach word {mtof ftom rmstodb dbtorms rmstopow powtorms} {
+ say $word~ "[say $word] (for signals)"
+ }
+}
+
+### phase 3
+
+say_namespace summary {
+ say_category "AUDIO GLUE"
+ say dac~ "audio output"
+ say adc~ "audio input"
+ say sig~ "convert numbers to audio signals"
+ say line~ "generate audio ramps"
+ say vline~ "deluxe line~"
+ say threshold~ "detect signal thresholds"
+ say snapshot~ "sample a signal (convert it back to a number)"
+ say vsnapshot~ "deluxe snapshot~"
+ say bang~ "send a bang message after each DSP block"
+ say samplerate~ "get the sample rate"
+ say send~ "nonlocal signal connection with fanout"
+ say receive~ "get signal from send~"
+ say throw~ "add to a summing bus"
+ say catch~ "define and read a summing bus"
+ say block~ "specify block size and overlap"
+ say switch~ "switch DSP computation on and off"
+ say readsf~ "soundfile playback from disk"
+ say writesf~ "record sound to disk"
+
+ say_category "AUDIO OSCILLATORS AND TABLES"
+ say phasor~ "sawtooth oscillator"
+ say {cos~ osc~} "cosine oscillator"
+ say tabwrite~ "write to a table"
+ say tabplay~ "play back from a table (non-transposing)"
+ say tabread~ "non-interpolating table read"
+ say tabread4~ "four-point interpolating table read"
+ say tabosc4~ "wavetable oscillator"
+ say tabsend~ "write one block continuously to a table"
+ say tabreceive~ "read one block continuously from a table"
+
+ say_category "AUDIO FILTERS"
+ say vcf~ "voltage controlled filter"
+ say noise~ "white noise generator"
+ say env~ "envelope follower"
+ say hip~ "high pass filter"
+ say lop~ "low pass filter"
+ say bp~ "band pass filter"
+ say biquad~ "raw filter"
+ say samphold~ "sample and hold unit"
+ say print~ "print out one or more \"blocks\""
+ say rpole~ "raw real-valued one-pole filter"
+ say rzero~ "raw real-valued one-zero filter"
+ say rzero_rev~ "[say rzero~] (time-reversed)"
+ say cpole~ "[say rpole~] (complex-valued)"
+ say czero~ "[say rzero~] (complex-valued)"
+ say czero_rev~ "[say rzero_rev~] (complex-valued)"
+
+ say_category "AUDIO DELAY"
+ say delwrite~ "write to a delay line"
+ say delread~ "read from a delay line"
+ say vd~ "read from a delay line at a variable delay time"
+
+ say_category "SUBWINDOWS"
+ say pd "define a subwindow"
+ say table "array of numbers in a subwindow"
+ say inlet "add an inlet to a pd"
+ say outlet "add an outlet to a pd"
+ say inlet~ "[say inlet] (for signal)"
+ say outlet~ "[say outlet] (for signal)"
+
+ say_category "DATA TEMPLATES"
+ say struct "define a data structure"
+ say {drawcurve filledcurve} "draw a curve"
+ say {drawpolygon filledpolygon} "draw a polygon"
+ say plot "plot an array field"
+ say drawnumber "print a numeric value"
+
+ say_category "ACCESSING DATA"
+ say pointer "point to an object belonging to a template"
+ say get "get numeric fields"
+ say set "change numeric fields"
+ say element "get an array element"
+ say getsize "get the size of an array"
+ say setsize "change the size of an array"
+ say append "add an element to a list"
+ say sublist "get a pointer into a list which is an element of another scalar"
+ say scalar "draw a scalar on parent"
+
+ say_category "OBSOLETE"
+ say scope~ "(use tabwrite~ now)"
+ say namecanvas "" ;# what was this anyway?
+ say template "(use struct now)"
+}
+
+# phase 4 (pdrc & ddrc)
+
+say section_audio "Audio"
+ say -r "sample rate"
+ say -audioindev "audio in devices"
+ say -audiooutdev "audio out devices"
+ say -inchannels "audio input channels (by device, like \"2\" or \"16,8\")"
+ say -outchannels "number of audio out channels (same)"
+ say -audiobuf "specify size of audio buffer in msec"
+ say -blocksize "specify audio I/O block size in sample frames"
+ say -sleepgrain "specify number of milliseconds to sleep when idle"
+ say -nodac "suppress audio output"
+ say -noadc "suppress audio input"
+ say audio_api_choice "Audio API"
+ say default "default"
+ say -alsa "use ALSA audio API"
+ say -jack "use JACK audio API"
+ say -mmio "use MMIO audio API (default for Windows)"
+ say -portaudio "use ASIO audio driver (via Portaudio)"
+ say -oss "use OSS audio API"
+ say -32bit "allow 32 bit OSS audio (for RME Hammerfall)"
+ say {} "default"
+
+say section_midi "MIDI"
+ say -nomidiin "suppress MIDI input"
+ say -nomidiout "suppress MIDI output"
+ say -midiindev "midi in device list; e.g., \"1,3\" for first and third"
+ say -midioutdev "midi out device list, same format"
+
+say section_externals "Externals"
+ say -path "file search path"
+ say -helppath "help file search path"
+ say -lib "load object libraries"
+
+say section_gui "Gooey"
+ say -nogui "suppress starting the GUI (caution)"
+ say -guicmd "substitute another GUI program (e.g., rsh)"
+ say -look "buttonbar icons"
+ say -font "specify default font size in points"
+
+say section_other "Other"
+ say -open "open file(s) on startup"
+ say -verbose "extra printout on startup and when searching for files"
+ say -d "debug level"
+ say -noloadbang "disable the effect of \[loadbang\]"
+ say -send "send a message at startup (after patches are loaded)"
+ say -listdev "list audio and MIDI devices upon startup"
+ say -realtime "use real-time priority (needs root privilege)"
+
+say section_paths "Paths"
+
+# phase 4B: ddrc (keyword names not finalized!)
+say console "console scrollback lines (0 = disable console)"
+say lang "Language to use"
+say pointer_sense "Mouse pointer sensitivity"
+say section_color "Apparences"
+ say canvas_color "canvas"
+ say canvasbgedit "canvas background (edit mode)"
+ say canvasbgrun "canvas background (run mode)"
+ say object_color "object"
+ say viewframe1 "objectbox color"
+ say viewframe2 "objectbox color"
+ say viewframe3 "objectbox color"
+ say viewframe4 "objectbox highlight color"
+ say viewbg "object background"
+ say viewfg "object foreground"
+ say commentbg "comment background"
+ say commentfg "comment forground"
+ say commentframe1 "comment frame"
+ say commentframe2 "comment frame"
+ say commentframe3 "comment frame"
+ say viewselectframe "hilight box"
+ say wire_color "wire"
+ say wirefg "wire color"
+ say wirefg2 "wire highlight"
+ say wiredspfg "dsp wire color"
+ say futurewiredash "new (dashed) wire"
+ say others_color "others"
+ say boxinletfg "inlet color"
+ say boxoutletfg "outlet color"
+ say selrectrect "selection box"
+say keys "keys"
+say others "others"
+say hairstate "Activate crosshair"
+say hairsnap "Crosshair snap to object"
+say statusbar "Activate statusbar"
+say buttonbar "Activate buttonbar"
+say menubar "Activate menubar"
+say scrollbar "Active auto scrollbar"
+say wirearrow "Wire Arrow"
+say tooltip "ToolTip"
+say insert_object "Insert object"
+say chain_object "Chain object"
+say clear_wires "Clear wires"
+say auto_wire "Remove object"
+say subpatcherize "Subpatcherize"
+say keynav "keyboard navigation"
+say key_nav_up "move up"
+say key_nav_up_shift "plus select"
+say key_nav_down "move down"
+say key_nav_down_shift "plus select"
+say key_nav_right "move right"
+say key_nav_right_shift "plus select"
+say key_nav_left "move left"
+say key_nav_left_shift "plus select"
+say key_nav_ioselect "select in/outlets"
+# phase 5A
+
+say cannot "can't"
+say cancel "Cancel"
+say apply "Apply"
+say ok "OK"
+say popup_open "Open"
+say popup_insert "Insert"
+say popup_properties "Properties"
+say popup_clear_wires "Clear wires"
+say popup_remove_from_path "Remove object from path"
+say popup_delete_from_path "Delete object from path"
+say popup_help "Help"
+say filter "Filter: "
+say how_many_object_classes "%d of %d object classes"
+say do_what_i_mean "Do What I Mean"
+say ask_cool "This would be a cool feature, eh?"
+say save_changes? "Save changes?"
+say reset "Reset"
+say Courier "Courier (monospaced)"
+say Helvetica "Helvetica (sansserif)"
+say Times "Times (serif)"
+say add "Add"
+say up "Up"
+say down "Down"
+say remove "Remove"
+say lib_add "add the name you typed to the list"
+say lib_up "swap order with previous library"
+say lib_down "swap order with next library"
+say lib_remove "remove library selected in the list"
+say dir_add "add a folder using a file dialog"
+say dir_up "swap order with previous folder"
+say dir_down "swap order with next folder"
+say dir_remove "remove folder selected in the list"
+say client_class_tree "Client Class Tree"
+say clipboard_view "Clipboard View"
+say command_history_view "Command History View"
+say event_history_view "Event History View"
+
+# during/after piksel:
+
+say auto_apply "Auto-Apply"
+say font_preview "Preview:"
+say font_preview_2 "ABCDEFGHIJKLMNOPQRSTUVWXYZ\nabcdefghijklmnopqrstuvwxyz\n0123456789"
+say font_style "Style:"
+say font_bold "Bold"
+say font_italic "Italic"
+say font_family "Name:"
+say font_size "Size:"
+say damn "Damn!"
+say console_clear "Clear Console"
+say horizontal "Horizontal"
+say vertical "Vertical"
+say language "Language"
+
+# 2007:
+
+say no_matches "(no matches)"
+say preset "preset"
+say canvasgrid "Grid color"
+say grid_size "Grid size"
+say gridstate "Activate background grid"
+say snap_grid "Snap to grid"
+say viewfont "object font"
+say consolefont "console font"
+say keyboarddialogfont "virtual keyboard font"
+say keyboard_view "Virtual keyboard" \ No newline at end of file
diff --git a/desiredata/src/m_atomic.h b/desiredata/src/m_atomic.h
new file mode 100644
index 00000000..f7314d11
--- /dev/null
+++ b/desiredata/src/m_atomic.h
@@ -0,0 +1,55 @@
+/* Copyright (c) 2005, Tim Blechmann
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt" in this distribution. */
+
+
+#if defined(__GNUC__) && (defined(_X86_) || defined(__i386__) || defined(__i586__) || defined(__i686__))
+
+/* gcc, x86 */
+#define ATOMIC_INC(X) \
+ asm __volatile__("lock incl (%0) \n" \
+ : :"r"(X) :"memory")
+
+
+#define ATOMIC_DEC(X) \
+ asm __volatile__("lock decl (%0) \n" \
+ : :"r"(X) :"memory")
+
+
+
+#elif defined(NT) && defined(_MSC_VER)
+
+/* msvc */
+#include <windows.h>
+#define ATOMIC_INC(X) InterlockedIncrement(X)
+#define ATOMIC_DEC(X) InterlockedDecrement(X)
+
+
+#elif defined(__GNUC__) && defined(__POWERPC__)
+
+/* ppc */
+#define ATOMIC_INC(X) { \
+int X##_i; \
+asm __volatile__( \
+ "1: \n" \
+ "lwarx %0, 0, %2 \n" \
+ "addic %0, %0, 1 \n" \
+ "stwcx. %0, 0, %2 \n" \
+ "bne- 1b \n" \
+ :"=&r"(X##_i), "=m"(X) \
+ : "r" (&X), "m"(X) \
+ : "cc"); }
+
+
+#define ATOMIC_DEC(X) { \
+int X##_i; \
+asm __volatile__( \
+ "1: \n" \
+ "lwarx %0, 0, %2 \n" \
+ "addic %0, %0, -1 \n" \
+ "stwcx. %0, 0, %2 \n" \
+ "bne- 1b \n" \
+ :"=&r"(X##_i), "=m"(X) \
+ : "r" (&X), "m"(X) \
+ : "cc"); }
+#endif
diff --git a/desiredata/src/m_fifo.c b/desiredata/src/m_fifo.c
new file mode 100644
index 00000000..34d19d1b
--- /dev/null
+++ b/desiredata/src/m_fifo.c
@@ -0,0 +1,443 @@
+/* Copyright (c) 2004, Tim Blechmann
+ * supported by vibrez.net
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt" in this distribution. */
+
+
+#include <stddef.h>
+#include <stdlib.h>
+#include "m_pd.h"
+
+#ifndef LOCKFREE
+
+/* we always have the implementation for posix systems with threadlocks */
+
+#include "pthread.h"
+#include "errno.h"
+
+typedef struct _fifocell
+{
+ struct _fifocell* next;
+ void* data; /* pointer to our data */
+} t_fifocell;
+
+struct _fifo {
+ t_fifocell * head;
+ t_fifocell * tail;
+ pthread_mutex_t mutex;
+};
+
+t_fifo *fifo_init(void) {
+ t_fifo* ret = (t_fifo*)malloc(sizeof(t_fifo));
+ t_fifocell * fifo_begin = (t_fifocell*)malloc(sizeof(t_fifocell));
+ fifo_begin->data = 0;
+ fifo_begin->next = 0;
+ ret->head = fifo_begin;
+ ret->tail = fifo_begin;
+ pthread_mutex_init(&ret->mutex, 0);
+ pthread_mutex_unlock(&ret->mutex);
+ return ret;
+}
+
+void fifo_destroy(t_fifo* fifo) {
+ void *data;
+ do data = fifo_get(fifo); while (data);
+ pthread_mutex_lock(&fifo->mutex);
+ pthread_mutex_destroy(&fifo->mutex);
+ free(fifo);
+ return;
+}
+
+/* fifo_put and fifo_get are the only threadsafe functions!!! */
+void fifo_put(t_fifo* fifo, void* data) {
+ if (data) {
+ t_fifocell * cell = (t_fifocell*)malloc(sizeof(t_fifocell));
+ cell->data = data;
+ cell->next = 0;
+ pthread_mutex_lock(&fifo->mutex);
+ fifo->tail->next = cell;
+ fifo->tail = cell;
+ pthread_mutex_unlock(&fifo->mutex);
+ }
+ return;
+}
+
+/* this fifo_get returns 0 if the fifo is empty or locked by another thread */
+void* fifo_get(t_fifo* fifo) {
+ t_fifocell * cell;
+ void *data;
+ if(pthread_mutex_trylock(&fifo->mutex) != EBUSY) {
+ cell = fifo->head->next;
+ if (cell) {
+ fifo->head->next = cell->next;
+ if(cell == fifo->tail)
+ fifo->tail = fifo->head;
+ data = cell->data;
+ free(cell);
+ } else data = 0;
+ pthread_mutex_unlock(&fifo->mutex);
+ } else data = 0;
+ return data;
+}
+
+#else /* LOCKFREE */
+
+/*
+ lockfree fifo adapted from the midishare: Copyright � Grame 1999
+ Grame Research Laboratory, 9, rue du Garet 69001 Lyon - France
+ grame@rd.grame.fr
+*/
+
+typedef struct _fifocell {
+ struct _fifocell *next;
+ void *data; /* pointer to our data */
+} t_fifocell;
+
+typedef struct _lifo {
+ unsigned long ic; /* operation counter */
+ t_fifocell* top; /* stack pointer */
+ unsigned long oc; /* operation counter */
+#ifdef __POWERPC__
+ long unused [5]; /* lifo size must be at least 32 bytes */
+ /* to avoid livelock in multiprocessor */
+#endif
+} t_lifo;
+
+struct _fifo {
+ t_lifo in;
+ t_lifo out;
+};
+
+/* platform dependent code */
+
+#ifdef __SMP__
+#define LOCK lock ;
+#else
+#define LOCK
+#endif
+
+#if defined(__GNUC__) && (defined(__POWERPC__) || defined(__PPC__))
+
+static void* lifo_pop(t_lifo* lifo) {
+ register void * data;
+ register volatile long a, b;
+ register long c=0;
+ asm volatile (
+ "# LFPOP \n"
+ "0: \n"
+ " lwarx %4, %1, %2 \n" /* creates a reservation on lf */
+ " cmpwi %4, 0 \n" /* test if the lifo is empty */
+ " beq- 1f \n"
+ " lwz %5, 0(%4) \n" /* next cell in b */
+ " sync \n" /* synchronize instructions */
+ " stwcx. %5, %1, %2 \n" /* if the reservation is not altered */
+ /* modify lifo top */
+ " bne- 0b \n" /* otherwise: loop and try again */
+ "0: \n"
+ " lwarx %5, %1, %3 \n" /* creates a reservation on lf->count */
+ " addi %5, %5, -1 \n" /* dec count */
+ " sync \n" /* synchronize instructions */
+ " stwcx. %5, %1, %3 \n" /* conditionnal store */
+ " bne- 0b \n"
+ "1: \n"
+ " mr %0, %4 \n"
+ :"=r" (data), "=r" (c)
+ : "r" (&lifo->top), "r" (&lifo->oc), "r" (a), "r" (b), "1" (c)
+ : "r0" /* prevents using r0 because of the ambiguity of 'addi' coding: */
+ /* gcc version 2.95.3 20010315 (release - Linux-Mandrake 8.0 for PPC) */
+ /* compiles the instruction "addi 0, 0, n" as li 0, n */
+ );
+ return data;
+}
+
+static void* lifo_push(register t_lifo *lifo, register void *data) {
+ register volatile long t1;
+ register long t2=0;
+ asm volatile (
+ "# LFPUSH \n"
+ "0: \n"
+ " lwarx %0, %3, %1 \n"
+ " stw %0, 0(%2) \n"
+ " sync \n"
+ " stwcx. %2, %3, %1 \n"
+ " bne- 0b \n"
+ "0: \n"
+ " lwarx %0, %3, %4 \n"
+ " addi %0, %0, 1 \n"
+ " sync \n"
+ " stwcx. %0, %3, %4 \n"
+ " bne- 0b \n"
+ : "=r" (t1)
+ : "r" (&lifo->top), "r" (data), "r" (t2), "r" (&lifo->oc), "0" (t1)
+ : "r0" /* prevents using r0 because of the ambiguity of 'addi' coding: */
+ /* gcc version 2.95.3 20010315 (release - Linux-Mandrake 8.0 for PPC) */
+ /* compiles the instruction "addi 0, 0, n" as li 0, n */
+ );
+}
+
+#elif defined(__ppc__) && defined(__APPLE__)
+
+static void *lifo_pop(t_lifo *lifo) {
+ register void *data;
+ register long a, b;
+ asm {
+ addi lifo, lifo, 4
+ loop:
+ lwarx a, 0, lifo /* creates a reservation on lifo */
+ cmpwi a, 0 /* test if the lifo is empty */
+ beq- empty
+ lwz b, 0(a) /* next cell in b */
+ sync /* synchronize instructions */
+ stwcx. b, 0, lifo /* if the reservation is not altered */
+ /* modify lifo top */
+ bne- loop /* otherwise: loop and try again */
+
+ addi lifo, lifo, 4
+ dec:
+ lwarx b, 0, lifo /* creates a reservation on lifo->count */
+ addi b, b, -1 /* dec count */
+ sync /* synchronize instructions */
+ stwcx. b, 0, lifo /* conditionnal store */
+ bne- dec
+
+ empty:
+ mr data, a
+ }
+ return data;
+}
+
+static void lifo_push (register t_lifo * lifo, register void * data)
+{
+ register long tmp;
+ asm {
+ addi lifo, lifo, 4
+ loop:
+ lwarx tmp, 0, lifo /* creates a reservation on lifo */
+ stw tmp, 0(data) /* link the new cell to the lifo */
+ sync /* synchronize instructions */
+ stwcx. data, 0, lifo /* if the reservation is not altered */
+ /* modify lifo top */
+ bne- loop /* otherwise: loop and try again */
+
+ addi lifo, lifo, 4
+ inc:
+ lwarx tmp, 0, lifo /* creates a reservation on lifo->count */
+ addi tmp, tmp, 1 /* inc count */
+ sync /* synchronize instructions */
+ stwcx. tmp, 0, lifo /* conditionnal store */
+ bne- inc
+ }
+}
+
+
+
+#elif defined(__GNUC__) && (defined(_X86_) || defined(__i386__) || defined(__i586__) || defined(__i686__))
+
+static void* lifo_pop(t_lifo* lifo)
+{
+ void * data = 0;
+ __asm__ __volatile__ (
+ "# LFPOP \n\t"
+ "pushl %%ebx \n\t"
+ "pushl %%ecx \n\t"
+ "movl 4(%%esi), %%edx \n\t"
+ "movl (%%esi), %%eax \n\t"
+ "testl %%eax, %%eax \n\t"
+ "jz 2f \n"
+ "1:\t"
+ "movl (%%eax), %%ebx \n\t"
+ "movl %%edx, %%ecx \n\t"
+ "incl %%ecx \n\t"
+ LOCK "cmpxchg8b (%%esi) \n\t"
+ "jz 2f \n\t"
+ "testl %%eax, %%eax \n\t"
+ "jnz 1b \n"
+ "2:\t"
+ "popl %%ecx \n\t"
+ "popl %%ebx \n\t"
+ :"=a" (data)
+ :"S" (&lifo->top)
+ :"memory", "edx");
+ return data;
+}
+
+static void lifo_push(t_lifo * lifo, void * data)
+{
+ __asm__ __volatile__ (
+ "# LFPUSH \n\t"
+ "pushl %%ebx \n\t"
+ "pushl %%ecx \n\t"
+ "movl 0(%%esi), %%eax \n\t"
+ "movl 4(%%esi), %%edx \n"
+ "1:\t"
+ "movl %%eax, %%ebx \n\t"
+ "incl %%ebx \n\t"
+ "movl %%edx, (%%ecx) \n\t"
+ LOCK "cmpxchg8b (%%esi) \n\t"
+ "jnz 1b \n\t"
+ "popl %%ecx \n\t"
+ "popl %%ebx \n\t"
+ :/* no output */
+ :"S" (lifo), "c" (data)
+ :"memory", "eax", "edx");
+}
+
+#elif defined(__GNUC__) && defined(__x86_64__)
+
+/* this will not work for all revisions of the amd64 architecture ... */
+
+static void* lifo_pop(t_lifo* lifo)
+{
+ void * data = 0;
+ __asm__ __volatile__ (
+ "# LFPOP \n\t"
+ "push %%rbx \n\t"
+ "push %%rcx \n\t"
+ "mov 8(%%rdi), %%rdx \n\t"
+ "mov (%%rdi), %%rax \n\t"
+ "test %%rax, %%rax \n\t"
+ "jz 2f \n"
+ "1:\t"
+ "mov (%%rax), %%rbx \n\t"
+ "mov %%rdx, %%rcx \n\t"
+ "inc %%rcx \n\t"
+ LOCK "cmpxchg16b (%%rdi) \n\t"
+ "jz 2f \n\t"
+ "test %%rax, %%rax \n\t"
+ "jnz 1b \n"
+ "2:\t"
+ "pop %%rcx \n\t"
+ "pop %%rbx \n\t"
+ :"=a" (data)
+ :"D" (&lifo->top)
+ :"memory", "rdx");
+ return data;
+}
+
+static void lifo_push(t_lifo * lifo, void * data)
+{
+ __asm__ __volatile__ (
+ "# LFPUSH \n\t"
+ "push %%rbx \n\t"
+ "push %%rcx \n\t"
+ "mov 0(%%rdi), %%rax \n\t"
+ "mov 8(%%rdi), %%rdx \n"
+ "1:\t"
+ "mov %%rax, %%rbx \n\t"
+ "inc %%rbx \n\t"
+ "mov %%rdx, (%%rcx) \n\t"
+ LOCK "cmpxchg16b (%%rdi) \n\t"
+ "jnz 1b \n\t"
+ "pop %%rcx \n\t"
+ "pop %%rbx \n\t"
+ :/* no output */
+ :"D" (lifo), "c" (data)
+ :"memory", "rax", "rdx");
+}
+
+#elif defined(_WIN32) && defined(_MSC_VER)
+
+static void* lifo_pop(t_lifo* lifo)
+{
+ __asm
+ {
+ push ebx
+ push ecx
+ push edx
+ push esi
+ mov esi, lifo
+ add esi, 4
+ mov edx, dword ptr [esi+4]
+ mov eax, dword ptr [esi]
+ test eax, eax
+ jz _end
+ _loop:
+ mov ebx, dword ptr [eax]
+ mov ecx, edx
+ inc ecx
+ LOCK cmpxchg8b qword ptr [esi]
+ jz _end
+ test eax, eax
+ jnz _loop
+ _end:
+ pop esi
+ pop edx
+ pop ecx
+ pop ebx
+ }
+}
+
+static void lifo_push(t_lifo * lifo, void * data)
+{
+ __asm
+ {
+ push eax
+ push ebx
+ push ecx
+ push edx
+ push esi
+ mov esi, lifo
+ mov eax, dword ptr [esi]
+ mov ecx, data
+ mov edx, dword ptr 4[esi]
+ _loop:
+ mov ebx, eax
+ inc ebx
+ mov [ecx], edx
+ LOCK cmpxchg8b qword ptr [esi]
+ jnz _loop
+ pop esi
+ pop edx
+ pop ecx
+ pop ebx
+ pop eax
+ }
+}
+
+
+#else
+#error lockfree fifos not available on this platform
+#endif
+
+static void lifo_init(t_lifo* lifo) {
+ lifo->ic = 0;
+ lifo->top = 0;
+ lifo->oc = 0;
+}
+
+t_fifo *fifo_init(void) {
+ t_fifo *ret = (t_fifo *)malloc(sizeof(t_fifo));
+ lifo_init(&ret->in);
+ lifo_init(&ret->out);
+ return ret;
+}
+
+void fifo_destroy(t_fifo *fifo) {
+ void *data;
+ do data = fifo_get(fifo); while (data);
+ free(fifo);
+ return;
+}
+
+void fifo_put(t_fifo *fifo, void *data) {lifo_push(&fifo->in, data);}
+
+void* fifo_get(t_fifo *fifo) {
+ void *data;
+ t_lifo *out = &fifo->out;
+ data = lifo_pop(out);
+ if (!data) {
+ void *tmp;
+ t_lifo *in = &fifo->in;
+ data = lifo_pop(in);
+ if (data) {
+ while((tmp = lifo_pop(in))) {
+ lifo_push(out, data);
+ data = tmp;
+ }
+ }
+
+ }
+ return data;
+}
+
+#endif
diff --git a/desiredata/src/m_pd.h b/desiredata/src/m_pd.h
new file mode 100644
index 00000000..cb1a7c72
--- /dev/null
+++ b/desiredata/src/m_pd.h
@@ -0,0 +1,936 @@
+/* Copyright (c) 2006-2007 Mathieu Bouchard.
+ Copyright (c) 1997-1999 Miller Puckette.
+ For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ WARRANTIES, see the file, "LICENSE.txt", in this distribution. */
+
+/* PD_PLUSPLUS_FACE is not considered as part of the main interface for externals,
+ even though it has become the main interface for internals. please don't rely on
+ it outside of the desiredata source code */
+
+#ifndef __m_pd_h_
+
+#if defined(_LANGUAGE_C_PLUS_PLUS) || defined(__cplusplus)
+#include <iostream>
+
+#ifdef __cplusplus
+template <class K, class V> class t_hash /* : t_pd */ {
+ struct entry {
+ K k;
+ V v;
+ struct entry *next;
+ };
+ long capa;
+ long n;
+ entry **tab;
+/* when iterating: */
+ long i;
+ entry *m_next;
+public:
+ t_hash(long capa_) : capa(capa_), n(0), i(0) {
+ tab = new entry *[capa];
+ for (long j=0; j<capa; j++) tab[j]=0;
+ }
+ ~t_hash() {
+ for (long j=0; j<capa; j++) while (tab[j]) del(tab[j]->k);
+ delete[] tab;
+ }
+ size_t size() {return n;}
+ V get(K k) {
+ long h = hash(k);
+ for (entry *e=tab[h]; e; e=e->next) {if (e->k==k) return e->v;}
+ return 0;
+ }
+ void set(K k, V v) {
+ long h = hash(k);
+ for (entry *e=tab[h]; e; e=e->next) {if (e->k==k) {e->v=v; return;}}
+ entry *nu = new entry; nu->k=k; nu->v=v; nu->next=tab[h];
+ n++;
+ tab[h] = nu;
+ }
+ V del(K k) {
+ long h = hash(k);
+ for (entry **ep=&tab[h]; *ep; ep=&(*ep)->next) {
+ if ((*ep)->k==k) {
+ V v=(*ep)->v;
+ entry *next=(*ep)->next;
+ delete *ep; n--;
+ *ep = next;
+ return v;
+ }
+ }
+ return 0;
+ }
+ int exists(K k) {
+ long h = hash(k);
+ for (entry *e=tab[h]; e; e=e->next) {if (e->k==k) return 1;}
+ return 0;
+ }
+ void start() {i=0; m_next=0;}
+ int next(K *kp, V *vp) {
+ while (!m_next && i<capa) m_next = tab[i++];
+ if (m_next) {
+ *kp = m_next->k;
+ *vp = m_next->v;
+ m_next = m_next->next;
+ return 1;
+ }
+ return 0;
+ }
+ #define hash_foreach(k,v,h) for (h->start(); h->next(&k,&v); )
+ long hash(K k) {return (((long)k*0x54321) & 0x7FFFFFFF)%capa;}
+};
+#endif
+
+extern "C" {
+#endif
+
+#define PD_MAJOR_VERSION 1
+#define PD_MINOR_VERSION 0
+#define PD_DEVEL_VERSION 0
+#define PD_TEST_VERSION ""
+
+/* old name for "MSW" flag -- we have to take it for the sake of many old
+"nmakefiles" for externs, which will define NT and not MSW */
+#if (defined(_WIN32) || defined(NT)) && !defined(MSW)
+#define MSW
+#endif
+
+#ifdef __CYGWIN__
+#define UNISTD
+#endif
+
+#ifdef _MSC_VER
+/* #pragma warning( disable : 4091 ) */
+#pragma warning( disable : 4305 ) /* uncast const double to float */
+#pragma warning( disable : 4244 ) /* uncast float/int conversion etc. */
+#pragma warning( disable : 4101 ) /* unused automatic variables */
+#endif /* _MSC_VER */
+
+ /* the external storage class is "extern" in GCC; in MS-C it's ugly. */
+#if defined(MSW) && !defined (__GNUC__)
+#ifdef PD_INTERNAL
+#define EXTERN __declspec(dllexport) extern
+#else
+#define EXTERN __declspec(dllimport) extern
+#endif /* PD_INTERNAL */
+#else
+#define EXTERN extern
+#endif /* MSW */
+
+#if !defined(_SIZE_T) && !defined(_SIZE_T_)
+#include <stddef.h>
+#endif
+
+#include <stdarg.h>
+
+#define MAXPDSTRING 1000 /* use this for anything you want */
+#define MAXPDARG 5 /* max number of args we can typecheck today */
+
+/* signed and unsigned integer types the size of a pointer: */
+/* GG: long is the size of a pointer */
+typedef long t_int;
+
+typedef float t_float; /* a floating-point number at most the same size */
+typedef float t_floatarg; /* floating-point type for function calls */
+
+typedef struct _class t_class;
+typedef struct _outlet t_outlet;
+typedef struct _inlet t_inlet;
+typedef struct _clock t_clock;
+typedef struct _glist t_glist, t_canvas;
+
+#ifdef PD_PLUSPLUS_FACE
+struct t_pd {
+ t_class *_class;
+};
+#else
+typedef t_class *t_pd; /* pure datum: nothing but a class pointer */
+#endif
+
+typedef struct _symbol {
+ char *name; /* the const string that represents this symbol */
+ t_pd *thing; /* pointer to the target of a receive-symbol or to the bindlist of several targets */
+ struct _symbol *next; /* brochette of all symbols (only for permanent symbols) */
+ size_t refcount; /* refcount<0 means that the symbol is permanent */
+ size_t n; /* size of name (support for NUL characters) */
+} t_symbol;
+#define s_name name
+#define s_thing thing
+#define s_next next
+
+#ifdef PD_PLUSPLUS_FACE
+typedef struct t_list : t_pd {
+#else
+typedef struct t_list {
+ t_pd *pd;
+#endif
+ struct _atom *v;
+ size_t capa;
+ size_t refcount;
+ size_t n;
+} t_list, t_binbuf;
+
+typedef struct _array t_array; /* g_canvas.h */
+
+/* pointers to glist and array elements go through a "stub" which sticks
+around after the glist or array is freed. The stub itself is deleted when
+both the glist/array is gone and the refcount is zero, ensuring that no
+gpointers are pointing here. */
+
+#ifdef PD_PLUSPLUS_FACE
+typedef struct _gpointer {
+ union {
+ struct _scalar *scalar; /* scalar we're in (if glist) */
+ union word *w; /* raw data (if array) */
+ };
+ union {
+ struct _glist *canvas;
+ struct _array *array;
+ struct t_text *o;
+ };
+ size_t dummy;
+ size_t refcount;
+//#define gs_refcount refcount
+#define gs_refcount canvas->refcount
+} t_gpointer;
+#else
+typedef struct _gpointer {
+ union {
+ struct _scalar *gp_scalar; /* scalar we're in (if glist) */
+ union word *gp_w; /* raw data (if array) */
+ } gp_un;
+ union {
+ struct _glist *canvas;
+ struct _array *array;
+ struct _text *o;
+ } un;
+ size_t dummy;
+ size_t refcount;
+//#define gs_refcount un.canvas->gl_obj.refcount
+#define gs_refcount refcount
+} t_gpointer;
+#endif
+
+#define w_list w_canvas
+typedef union word {
+ t_float w_float; /* A_FLOAT */
+ t_symbol *w_symbol; /* A_SYMBOL or A_DOLLSYM */
+ t_gpointer *w_gpointer; /* A_POINTER */
+ t_array *w_array; /* DT_ARRAY */
+ struct _glist *w_canvas; /* DT_LIST */
+ t_int w_index; /* A_SEMI or A_COMMA or A_DOLLAR */
+} t_word;
+
+typedef enum {
+ A_NULL, /* non-type: represents end of typelist */
+ A_FLOAT, A_SYMBOL, A_POINTER, /* stable elements */
+ A_SEMI, A_COMMA, /* radioactive elements of the first kind */
+ A_DEFFLOAT, A_DEFSYM, /* pseudo-types for optional (DEFault) arguments */
+ A_DOLLAR, A_DOLLSYM, /* radioactive elements of the second kind */
+ A_GIMME, /* non-type: represents varargs */
+ A_CANT, /* bottom type: type constraint is impossible */
+ A_ATOM /* top type: type constraint doesn't constrain */
+} t_atomtype;
+
+#define A_DEFSYMBOL A_DEFSYM /* better name for this */
+
+typedef struct _atom {
+ t_atomtype a_type;
+ union word a_w;
+#ifdef __cplusplus
+ operator float () {return a_w.w_float;}
+ operator t_symbol *() {return a_w.w_symbol;}
+ //bool operator == (_atom &o) {return a_type==o.a_type && a_w.w_index==o.a_w.w_index;}
+ //bool operator != (_atom &o) {return a_type!=o.a_type || a_w.w_index!=o.a_w.w_index;}
+#endif
+} t_atom;
+
+struct t_arglist {long c; t_atom v[0];};
+
+typedef unsigned long long uint64;
+
+/* t_appendix is made of the things that logically ought to be in t_gobj but have been put in a
+ separate memory space because this allows most externals to work unmodified on both DesireData
+ and non-DesireData systems. The equivalent in the Tcl side is really part of every view object. */
+typedef struct t_appendix {
+ t_canvas *canvas; /* the holder of this object */
+/* actual observable */
+ size_t nobs; /* number of spies */
+ struct _gobj **obs; /* I spy with my little I */
+/* miscellaneous */
+#ifdef __cplusplus
+ t_hash<t_symbol *, t_arglist *> *visual;
+#else
+ void *visual;
+#endif
+ long index; /* index of an object within its canvas scope. */
+ uint64 elapsed;
+} t_appendix;
+t_appendix *appendix_new (struct _gobj *master);
+void appendix_free(struct _gobj *self);
+void appendix_save(struct _gobj *master, t_binbuf *b);
+
+#ifdef PD_PLUSPLUS_FACE
+#define g_pd _class
+typedef struct _gobj : t_pd {
+#else
+typedef struct _gobj /* a graphical object */
+{
+ t_pd g_pd; /* pure datum header (class) */
+#endif
+ t_appendix *dix;
+#define g_adix dix
+#ifdef PD_PLUSPLUS_FACE
+ _gobj *next();
+#endif
+} t_gobj;
+
+#ifdef PD_PLUSPLUS_FACE
+typedef struct _outconnect : _gobj {
+ struct _outconnect *next;
+ t_pd *oc_to;
+ struct t_text *from;
+ struct t_text *to;
+ short outlet, inlet;
+} t_outconnect, t_wire;
+#define oc_next next
+#else
+typedef struct _outconnect t_outconnect;
+#endif
+
+#ifdef PD_PLUSPLUS_FACE
+typedef struct _scalar : t_gobj {
+#else
+typedef struct _scalar /* a graphical object holding data */
+{
+ t_gobj sc_gobj; /* header for graphical object */
+#endif
+ t_symbol *t; /* template name (LATER replace with pointer) */
+ t_word v[1]; /* indeterminate-length array of words */
+} t_scalar;
+
+#define sc_template t
+#define sc_vec v
+
+#ifdef PD_PLUSPLUS_FACE
+typedef struct t_text : t_gobj {
+#else
+typedef struct _text /* patchable object - graphical, with text */
+{
+ t_gobj te_g; /* header for graphical object */
+#endif
+ t_binbuf *binbuf; /* holder for the text */
+ t_outlet *outlet; /* linked list of outlets */
+ t_inlet *inlet; /* linked list of inlets */
+ short x,y; /* x&y location (within the toplevel) */
+ int refcount; /* there used to be a bitfield here, which may be a problem with ms-bitfields (?) */
+#ifdef PD_PLUSPLUS_FACE
+ t_inlet * in(int n);
+ t_outlet *out(int n);
+#endif
+} t_text, t_object;
+
+#define te_binbuf binbuf
+#define te_outlet outlet
+#define te_inlet inlet
+#define te_xpix x
+#define te_ypix y
+#define te_width width
+#define te_type type
+
+#define ob_outlet te_outlet
+#define ob_inlet te_inlet
+#define ob_binbuf te_binbuf
+#ifdef PD_PLUSPLUS_FACE
+#define te_pd g_pd
+#define ob_pd g_pd
+#else
+#define te_pd te_g.g_pd
+#define ob_pd te_g.g_pd
+#endif
+#define ob_g te_g
+
+/* don't take those three types for cash (on average). they're lying because the type system can't express what there is to be expressed. */
+typedef void (*t_method)(void);
+typedef void *(*t_newmethod)(void);
+typedef void (*t_gotfn)(void *x, ...);
+
+/* ---------------- pre-defined objects and symbols --------------*/
+EXTERN t_pd pd_objectmaker; /* factory for creating "object" boxes */
+EXTERN t_pd pd_canvasmaker; /* factory for creating canvases */
+EXTERN t_symbol s_pointer, s_float, s_symbol;
+EXTERN t_symbol s_bang, s_list, s_anything, s_signal;
+EXTERN t_symbol s__N, s__X, s_x, s_y, s_;
+
+/* --------- central message system ----------- */
+EXTERN void pd_typedmess(t_pd *x, t_symbol *s, int argc, t_atom *argv);
+EXTERN void pd_forwardmess(t_pd *x, int argc, t_atom *argv);
+EXTERN t_symbol *gensym(const char *s);
+EXTERN t_symbol *gensym2(const char *s, size_t n);
+EXTERN t_symbol *symprintf(const char *s, ...);
+EXTERN t_gotfn getfn(t_pd *x, t_symbol *s);
+EXTERN t_gotfn zgetfn(t_pd *x, t_symbol *s);
+EXTERN void nullfn(void);
+EXTERN void pd_vmess(t_pd *x, t_symbol *s, char *fmt, ...);
+#define mess0(x,s) (getfn((x),(s))((x)))
+#define mess1(x,s,a) (getfn((x),(s))((x),(a)))
+#define mess2(x,s,a,b) (getfn((x),(s))((x),(a),(b)))
+#define mess3(x,s,a,b,c) (getfn((x),(s))((x),(a),(b),(c)))
+#define mess4(x,s,a,b,c,d) (getfn((x),(s))((x),(a),(b),(c),(d)))
+#define mess5(x,s,a,b,c,d,e) (getfn((x),(s))((x),(a),(b),(c),(d),(e)))
+EXTERN void obj_list(t_object *x, t_symbol *s, int argc, t_atom *argv);
+EXTERN t_pd *pd_newest(void); /* multiclient race conditions? */
+
+/* --------------- memory management -------------------- */
+EXTERN void *getbytes(size_t nbytes); /* deprecated, use malloc() */
+EXTERN void *copybytes(void *src, size_t nbytes);
+EXTERN void freebytes(void *x, size_t nbytes); /* deprecated, use free() */
+EXTERN void *resizebytes(void *x, size_t oldsize, size_t newsize); /* deprecated, use realloc() */
+
+/* T.Grill - functions for aligned memory (according to CPU SIMD architecture) */
+EXTERN void *getalignedbytes(size_t nbytes);
+EXTERN void *copyalignedbytes(void *src, size_t nbytes);
+EXTERN void freealignedbytes(void *x,size_t nbytes);
+EXTERN void *resizealignedbytes(void *x,size_t oldsize, size_t newsize);
+/* -------------------- atoms ----------------------------- */
+
+#define atom_decref(atom) (void)42
+#define atom_incref(atom) (void)42
+#define SETATOM(atom,type,field,value) (atom_decref(atom), (atom)->a_type=type, (atom)->a_w.field=value, atom_incref(atom))
+#define SETSEMI(atom) SETATOM(atom,A_SEMI, w_index,0)
+#define SETCOMMA(atom) SETATOM(atom,A_COMMA, w_index,0)
+#define SETPOINTER(atom, gp) SETATOM(atom,A_POINTER,w_gpointer,(gp)) /* looks unsafe... */
+#define SETFLOAT(atom, f) SETATOM(atom,A_FLOAT, w_float,(f))
+#define SETSYMBOL(atom, s) SETATOM(atom,A_SYMBOL, w_symbol,(s))
+#define SETSTRING(atom, s) SETATOM(atom,A_SYMBOL, w_symbol,gensym(s))
+#define SETDOLLAR(atom, n) SETATOM(atom,A_DOLLAR, w_index,(n))
+#define SETDOLLSYM(atom, s) SETATOM(atom,A_DOLLSYM,w_symbol,(s))
+
+EXTERN t_float atom_getfloat( t_atom *a);
+EXTERN t_int atom_getint( t_atom *a);
+EXTERN t_symbol *atom_getsymbol(t_atom *a); /* this call causes a t_symbol to become ternal */
+EXTERN const char *atom_getstring(t_atom *a); /* the return value should be used only immediately */
+EXTERN t_float atom_getfloatarg( int which, int argc, t_atom *argv);
+EXTERN t_int atom_getintarg( int which, int argc, t_atom *argv);
+EXTERN t_symbol *atom_getsymbolarg(int which, int argc, t_atom *argv);
+EXTERN const char *atom_getstringarg(int which, int argc, t_atom *argv); /* see above */
+
+EXTERN t_symbol *atom_gensym( t_atom *a);
+
+/* this function should produce a literal, whereas getstring gives the exact string */
+EXTERN void atom_string(t_atom *a, char *buf, unsigned int bufsize);
+#ifdef __cplusplus
+EXTERN void atom_ostream(t_atom *a, std::ostream &buf);
+inline std::ostream &operator <<(std::ostream &buf, t_atom *a) {atom_ostream(a,buf); return buf;}
+#endif
+
+/* goes with desiredata's CLASS_NEWATOM */
+EXTERN void atom_init(t_atom *a, size_t n);
+EXTERN void atom_copy(t_atom *a, t_atom *b, size_t n);
+EXTERN void atom_delete(t_atom *a, size_t n);
+
+/* ------------------ binbufs --------------- */
+
+EXTERN t_binbuf *binbuf_new(void);
+EXTERN void binbuf_free(t_binbuf *x);
+EXTERN t_binbuf *binbuf_duplicate(t_binbuf *y);
+
+EXTERN void binbuf_text(t_binbuf *x, char *text, size_t size);
+EXTERN void binbuf_gettext(t_binbuf *x, char **bufp, int *lengthp);
+EXTERN char *binbuf_gettext2(t_binbuf *x);
+EXTERN void binbuf_clear(t_binbuf *x);
+EXTERN void binbuf_add(t_binbuf *x, int argc, t_atom *argv);
+EXTERN void binbuf_addv(t_binbuf *x, char *fmt, ...);
+EXTERN void binbuf_addbinbuf(t_binbuf *x, t_binbuf *y);
+EXTERN void binbuf_addsemi(t_binbuf *x);
+EXTERN void binbuf_restore(t_binbuf *x, int argc, t_atom *argv);
+EXTERN void binbuf_print(t_binbuf *x);
+EXTERN int binbuf_getnatom(t_binbuf *x);
+EXTERN t_atom *binbuf_getvec(t_binbuf *x);
+EXTERN void binbuf_eval(t_binbuf *x, t_pd *target, int argc, t_atom *argv);
+EXTERN int binbuf_read( t_binbuf *b, char *filename, char *dirname, int flags);
+EXTERN int binbuf_read_via_canvas(t_binbuf *b, char *filename, t_canvas *canvas, int flags);
+EXTERN int binbuf_read_via_path( t_binbuf *b, char *filename, char *dirname, int flags);
+EXTERN int binbuf_write( t_binbuf *x, char *filename, char *dir, int flags);
+EXTERN void binbuf_evalfile(t_symbol *name, t_symbol *dir);
+EXTERN t_symbol *binbuf_realizedollsym(t_symbol *s, int ac, t_atom *av, int tonew);
+
+/* ------------------ clocks --------------- */
+
+EXTERN t_clock *clock_new(void *owner, t_method fn);
+EXTERN void clock_set(t_clock *x, double systime);
+EXTERN void clock_delay(t_clock *x, double delaytime);
+EXTERN void clock_unset(t_clock *x);
+EXTERN double clock_getlogicaltime(void);
+EXTERN double clock_getsystime(void); /* OBSOLETE; use clock_getlogicaltime() */
+EXTERN double clock_gettimesince(double prevsystime);
+EXTERN double clock_getsystimeafter(double delaytime);
+EXTERN void clock_free(t_clock *x);
+
+/* ----------------- pure data ---------------- */
+EXTERN t_pd *pd_new(t_class *cls);
+EXTERN void pd_free(t_pd *x);
+EXTERN void pd_bind( t_pd *x, t_symbol *s);
+EXTERN void pd_unbind(t_pd *x, t_symbol *s);
+EXTERN t_pd *pd_findbyclass(t_symbol *s, t_class *c);
+EXTERN void pd_pushsym(t_pd *x);
+EXTERN void pd_popsym( t_pd *x);
+EXTERN t_symbol *pd_getfilename(void);
+EXTERN t_symbol *pd_getdirname(void);
+EXTERN void pd_bang( t_pd *x);
+EXTERN void pd_pointer( t_pd *x, t_gpointer *gp);
+EXTERN void pd_float( t_pd *x, t_float f);
+EXTERN void pd_symbol( t_pd *x, t_symbol *s);
+EXTERN void pd_string( t_pd *x, const char *s); /* makes a refcounted symbol (copying s) */
+EXTERN void pd_list( t_pd *x, t_symbol *s, int argc, t_atom *argv);
+
+#ifdef PD_PLUSPLUS_FACE
+#define pd_class(x) ((x)->_class)
+#else
+#define pd_class(x) (*(x))
+#endif
+
+EXTERN void gobj_subscribe (t_gobj *self, t_gobj *observer);
+EXTERN void gobj_unsubscribe (t_gobj *self, t_gobj *observer);
+EXTERN void gobj_changed (t_gobj *self, const char *k);
+EXTERN void gobj_changed2 (t_gobj *self, int argc, t_atom *argv);
+EXTERN void gobj_changed3 (t_gobj *self, t_gobj *origin, int argc, t_atom *argv);
+
+/* ----------------- pointers ---------------- */
+EXTERN void gpointer_init(t_gpointer *gp);
+EXTERN void gpointer_copy(const t_gpointer *gpfrom, t_gpointer *gpto);
+EXTERN void gpointer_unset(t_gpointer *gp);
+EXTERN int gpointer_check(const t_gpointer *gp, int headok);
+
+/* ----------------- patchable "objects" -------------- */
+/* already defined
+EXTERN_STRUCT _inlet;
+#define t_inlet struct _inlet
+EXTERN_STRUCT _outlet;
+#define t_outlet struct _outlet
+*/
+EXTERN t_inlet *inlet_new(t_object *owner, t_pd *dest, t_symbol *s1, t_symbol *s2);
+EXTERN t_inlet *pointerinlet_new(t_object *owner, t_gpointer *gp);
+EXTERN t_inlet *floatinlet_new(t_object *owner, t_float *fp);
+EXTERN t_inlet *symbolinlet_new(t_object *owner, t_symbol **sp);
+EXTERN t_inlet *stringinlet_new(t_object *owner, t_symbol **sp); /* for future use */
+EXTERN t_inlet *signalinlet_new(t_object *owner, t_float f);
+EXTERN void inlet_free(t_inlet *x);
+
+EXTERN t_outlet *outlet_new(t_object *owner, t_symbol *s);
+EXTERN void outlet_bang( t_outlet *x);
+EXTERN void outlet_pointer( t_outlet *x, t_gpointer *gp);
+EXTERN void outlet_float( t_outlet *x, t_float f);
+EXTERN void outlet_symbol( t_outlet *x, t_symbol *s);
+EXTERN void outlet_string( t_outlet *x, const char *s); /* makes a refcounted symbol (copying s) */
+EXTERN void outlet_atom( t_outlet *x, t_atom *a);
+EXTERN void outlet_list( t_outlet *x, t_symbol *s, int argc, t_atom *argv);
+EXTERN void outlet_anything(t_outlet *x, t_symbol *s, int argc, t_atom *argv);
+EXTERN t_symbol *outlet_getsymbol(t_outlet *x);
+EXTERN void outlet_free(t_outlet *x);
+EXTERN t_object *pd_checkobject(t_pd *x);
+
+/* -------------------- canvases -------------- */
+
+EXTERN void glob_setfilename(void *dummy, t_symbol *name, t_symbol *dir);
+EXTERN void canvas_setargs(int argc, t_atom * argv );
+EXTERN void canvas_getargs(int *argcp, t_atom **argvp);
+EXTERN t_symbol *canvas_getcurrentdir(void);
+EXTERN t_glist *canvas_getcurrent(void);
+/* if result==0 then it will allocate a result and return it */
+EXTERN char *canvas_makefilename(t_glist *c, char *file, char *result, int resultsize);
+EXTERN t_symbol *canvas_getdir(t_glist *x);
+EXTERN void canvas_dataproperties(t_glist *x, t_scalar *sc, t_binbuf *b);
+EXTERN int canvas_open( t_canvas *x, const char *name, const char *ext, char * dirresult, char **nameresult, unsigned int size, int bin);
+EXTERN int canvas_open2(t_canvas *x, const char *name, const char *ext, char **dirresult, char **nameresult, int bin);
+
+/* -------------------- classes -------------- */
+
+#define CLASS_DEFAULT 0 /* flags for new classes below */
+#define CLASS_PD 1
+#define CLASS_GOBJ 2
+#define CLASS_PATCHABLE 3
+#define CLASS_NOINLET 8
+#define CLASS_NEWATOMS 16
+#define CLASS_TYPEMASK 3
+
+#ifdef __cplusplus
+typedef int t_atomtypearg;
+#else
+typedef t_atomtype t_atomtypearg;
+#endif
+
+EXTERN t_class *class_find (t_symbol *s);
+EXTERN t_class *class_new( t_symbol *name,t_newmethod nu,t_method freem,size_t size,int flags,t_atomtypearg arg1, ...);
+EXTERN t_class *class_new2(const char *name,t_newmethod nu,t_method freem,size_t size,int flags,const char *sig);
+EXTERN void class_addcreator( t_newmethod nu, t_symbol *sel, t_atomtypearg arg1, ...);
+EXTERN void class_addcreator2(const char *name, t_newmethod nu, const char *sig);
+EXTERN void class_addmethod( t_class *c, t_method fn, t_symbol *sel, t_atomtypearg arg1, ...);
+EXTERN void class_addmethod2( t_class *c, t_method fn, const char *sel, const char *sig);
+#define class_new2(NAME,NU,FREE,SIZE,FLAGS,SIG) class_new2(NAME,(t_newmethod)NU,(t_method)FREE,SIZE,FLAGS,SIG)
+#define class_addcreator2(NAME,NU,SIG) class_addcreator2(NAME,(t_newmethod)NU,SIG)
+#define class_addmethod2(NAME,METH,SEL,SIG) class_addmethod2(NAME,(t_method)METH,SEL,SIG)
+
+EXTERN void class_addbang( t_class *c, t_method fn);
+EXTERN void class_addpointer( t_class *c, t_method fn);
+EXTERN void class_doaddfloat( t_class *c, t_method fn);
+EXTERN void class_addsymbol( t_class *c, t_method fn);
+EXTERN void class_addstring( t_class *c, t_method fn); /* for future use */
+EXTERN void class_addlist( t_class *c, t_method fn);
+EXTERN void class_addanything(t_class *c, t_method fn);
+EXTERN void class_sethelpsymbol(t_class *c, t_symbol *s);
+EXTERN char *class_getname(t_class *c);
+EXTERN char *class_gethelpname(t_class *c);
+EXTERN void class_setdrawcommand(t_class *c);
+EXTERN int class_isdrawcommand(t_class *c);
+EXTERN void class_domainsignalin(t_class *c, int onset);
+#define CLASS_MAINSIGNALIN(c, type, field) \
+ class_domainsignalin(c, (char *)(&((type *)0)->field) - (char *)0)
+
+/* in "class" observer: observable calls this to notify of a change */
+typedef void (*t_notice)( t_gobj *x, t_gobj *origin, int argc, t_atom *argv);
+EXTERN void class_setnotice(t_class *c, t_notice notice);
+
+/* in "class" observable: observable sends initial data to observer */
+/* this is called by gobj_subscribe to find out all the indirect subscriptions of aggregators. */
+/* every class that redefines this is an aggregator; every aggregator should redefine this. */
+/* "calling super" is done by calling gobj_onsubscribe with same args */
+typedef void (*t_onsubscribe)(t_gobj *x, t_gobj *observer);
+EXTERN void class_setonsubscribe(t_class *c, t_onsubscribe onsubscribe);
+EXTERN void gobj_onsubscribe(t_gobj *x, t_gobj *observer); /* default handler, that you may inherit from */
+
+/* prototype for functions to save Pd's to a binbuf */
+typedef void (*t_savefn)(t_gobj *x, t_binbuf *b);
+EXTERN void class_setsavefn(t_class *c, t_savefn f);
+EXTERN t_savefn class_getsavefn(t_class *c);
+
+#ifndef PD_CLASS_DEF
+#define class_addbang(x, y) class_addbang( (x), (t_method)(y))
+#define class_addpointer(x, y) class_addpointer( (x), (t_method)(y))
+#define class_addfloat(x, y) class_doaddfloat( (x), (t_method)(y))
+#define class_addsymbol(x, y) class_addsymbol( (x), (t_method)(y))
+#define class_addstring(x, y) class_addstring( (x), (t_method)(y)) /* for future use */
+#define class_addlist(x, y) class_addlist( (x), (t_method)(y))
+#define class_addanything(x, y) class_addanything((x), (t_method)(y))
+#endif
+
+EXTERN void class_settip(t_class *x,t_symbol* s);
+EXTERN void inlet_settip(t_inlet* i,t_symbol* s);
+EXTERN void class_setfieldnames(t_class *x, const char *s); /* where s is split on spaces and tokenized */
+EXTERN int class_getfieldindex(t_class *x, const char *s);
+typedef int (*t_loader)(t_canvas *canvas, char *classname);
+EXTERN void sys_register_loader(t_loader loader);
+
+/* ------------ printing --------------------------------- */
+EXTERN void post(const char *fmt, ...);
+EXTERN void startpost(const char *fmt, ...);
+EXTERN void poststring(const char *s);
+EXTERN void postfloat(float f);
+EXTERN void postatom(int argc, t_atom *argv);
+EXTERN void endpost(void);
+EXTERN void error(const char *fmt, ...);
+EXTERN void verror(const char *fmt, va_list args);
+EXTERN void verbose(int level, const char *fmt, ...);
+EXTERN void bug(const char *fmt, ...);
+EXTERN void pd_error(void *object, const char *fmt, ...) /*__attribute__ ((deprecated))*/;
+EXTERN void sys_logerror(const char *object, const char *s);
+EXTERN void sys_unixerror(const char *object);
+EXTERN void sys_ouch(void);
+
+/* ------------ system interface routines ------------------- */
+EXTERN int sys_isreadablefile(const char *name);
+EXTERN void sys_bashfilename(const char *from, char *to);
+EXTERN void sys_unbashfilename(const char *from, char *to);
+EXTERN int open_via_path(const char *name, const char *ext, const char *dir,
+ char *dirresult, char **nameresult, unsigned int size, int bin);
+EXTERN int open_via_path2(const char *dir, const char *name, const char *ext, char **dirresult, char **nameresult, int bin);
+
+EXTERN int sched_geteventno(void);
+EXTERN double sys_getrealtime(void);
+
+
+/* ------------ threading ------------------- */
+/* T.Grill - see m_sched.c */
+EXTERN void sys_lock(void);
+EXTERN void sys_unlock(void);
+EXTERN int sys_trylock(void);
+EXTERN int sys_timedlock(int microsec);
+/* tb: to be called at idle time */
+EXTERN void sys_callback(t_int (*callback) (t_int* argv), t_int* argv, t_int argc);
+
+/* --------------- signals ----------------------------------- */
+
+typedef float t_sample;
+#define MAXLOGSIG 32
+#define MAXSIGSIZE (1 << MAXLOGSIG)
+
+/* this doesn't really have to do with C++, just with getting rid of prefixes */
+#ifdef PD_PLUSPLUS_FACE
+struct t_signal {
+ int n;
+ t_sample *v;
+ float sr;
+ int refcount;
+ int isborrowed;
+ t_signal *borrowedfrom;
+ t_signal *nextfree;
+ t_signal *nextused;
+ int vecsize;
+};
+#else
+typedef struct _signal {
+ int s_n; /* number of points in the array */
+ t_sample *s_vec; /* the array */
+ float s_sr; /* sample rate */
+ int s_refcount; /* number of times used */
+ int s_isborrowed; /* whether we're going to borrow our array */
+ struct _signal *s_borrowedfrom; /* signal to borrow it from */
+ struct _signal *s_nextfree; /* next in freelist */
+ struct _signal *s_nextused; /* next in used list */
+ int s_vecsize; /* allocated size of array in points */
+} t_signal;
+#endif
+
+typedef t_int *(*t_perfroutine)(t_int *args);
+
+/* tb: exporting basic arithmetic dsp functions {
+ * for (n % 8) != 0 */
+EXTERN t_int *zero_perform(t_int *args);
+EXTERN t_int *copy_perform(t_int *args);
+EXTERN t_int *plus_perform( t_int *args); EXTERN t_int *scalarplus_perform( t_int *args);
+EXTERN t_int *minus_perform(t_int *args); EXTERN t_int *scalarminus_perform(t_int *args);
+EXTERN t_int *times_perform(t_int *args); EXTERN t_int *scalartimes_perform(t_int *args);
+EXTERN t_int *over_perform( t_int *args); EXTERN t_int *scalarover_perform( t_int *args);
+EXTERN t_int *max_perform( t_int *args); EXTERN t_int *scalarmax_perform( t_int *args);
+EXTERN t_int *min_perform( t_int *args); EXTERN t_int *scalarmin_perform( t_int *args);
+EXTERN t_int *sig_tilde_perform(t_int *args);
+EXTERN t_int *clip_perform(t_int *args);
+
+/* for (n % 8) == 0 */
+EXTERN t_int *zero_perf8(t_int *args);
+EXTERN t_int *copy_perf8(t_int *args);
+EXTERN t_int *plus_perf8( t_int *args); EXTERN t_int *scalarplus_perf8( t_int *args);
+EXTERN t_int *minus_perf8(t_int *args); EXTERN t_int *scalarminus_perf8(t_int *args);
+EXTERN t_int *times_perf8(t_int *args); EXTERN t_int *scalartimes_perf8(t_int *args);
+EXTERN t_int *over_perf8( t_int *args); EXTERN t_int *scalarover_perf8( t_int *args);
+EXTERN t_int *max_perf8( t_int *args); EXTERN t_int *scalarmax_perf8( t_int *args);
+EXTERN t_int *min_perf8( t_int *args); EXTERN t_int *scalarmin_perf8( t_int *args);
+EXTERN t_int *sqr_perf8(t_int *args);
+EXTERN t_int *sig_tilde_perf8(t_int *args);
+
+/* for (n % 8) == 0 && aligned signal vectors
+ * check with simd_checkX functions !!! */
+EXTERN t_int *zero_perf_simd(t_int *args);
+EXTERN t_int *copy_perf_simd(t_int *args);
+EXTERN t_int *plus_perf_simd( t_int *args); EXTERN t_int *scalarplus_perf_simd( t_int *args);
+EXTERN t_int *minus_perf_simd(t_int *args); EXTERN t_int *scalarminus_perf_simd(t_int *args);
+EXTERN t_int *times_perf_simd(t_int *args); EXTERN t_int *scalartimes_perf_simd(t_int *args);
+EXTERN t_int *over_perf_simd( t_int *args); EXTERN t_int *scalarover_perf_simd( t_int *args);
+EXTERN t_int *max_perf_simd( t_int *args); EXTERN t_int *scalarmax_perf_simd( t_int *args);
+EXTERN t_int *min_perf_simd( t_int *args); EXTERN t_int *scalarmin_perf_simd( t_int *args);
+EXTERN t_int *sqr_perf_simd(t_int *args);
+EXTERN t_int *sig_tilde_perf_simd(t_int *args);
+EXTERN t_int *clip_perf_simd(t_int *args);
+/* } tb */
+
+EXTERN void dsp_add_plus(t_sample *in1, t_sample *in2, t_sample *out, int n);
+EXTERN void dsp_add_copy(t_sample *in, t_sample *out, int n);
+EXTERN void dsp_add_scalarcopy(t_sample *in, t_sample *out, int n);
+EXTERN void dsp_add_zero(t_sample *out, int n);
+
+EXTERN int sys_getblksize(void);
+EXTERN float sys_getsr(void);
+EXTERN int sys_get_inchannels(void);
+EXTERN int sys_get_outchannels(void);
+
+EXTERN void dsp_add(t_perfroutine f, int n, ...);
+EXTERN void dsp_addv(t_perfroutine f, int n, t_int *vec);
+EXTERN void pd_fft(float *buf, int npoints, int inverse);
+EXTERN int ilog2(int n);
+
+EXTERN void mayer_fht(float *fz, int n);
+EXTERN void mayer_fft(int n, float *real, float *imag);
+EXTERN void mayer_ifft(int n, float *real, float *imag);
+EXTERN void mayer_realfft(int n, float *real);
+EXTERN void mayer_realifft(int n, float *real);
+
+EXTERN float *cos_table;
+#define LOGCOSTABSIZE 9
+#define COSTABSIZE (1<<LOGCOSTABSIZE)
+
+EXTERN int canvas_suspend_dsp(void);
+EXTERN void canvas_resume_dsp(int oldstate);
+EXTERN void canvas_update_dsp(void);
+EXTERN int canvas_dspstate;
+
+/* IOhannes { (up/downsampling) */
+/* use zero-padding to generate samples inbetween */
+#define RESAMPLE_ZERO 0
+/* use sample-and-hold to generate samples inbetween */
+#define RESAMPLE_HOLD 1
+/* use linear interpolation to generate samples inbetween */
+#define RESAMPLE_LINEAR 2
+/* not a real up/downsampling:
+ * upsampling: copy the original vector to the first part of the upsampled vector; the rest is zero
+ * downsampling: take the first part of the original vector as the downsampled vector
+ * WHAT FOR: we often want to process only the first half of an FFT-signal (the rest is redundant)
+ */
+#define RESAMPLE_BLOCK 3
+
+#define RESAMPLE_DEFAULT RESAMPLE_ZERO
+
+typedef struct _resample {
+ int method; /* up/downsampling method ID */
+ t_int downsample; /* downsampling factor */
+ t_int upsample; /* upsampling factor */
+#ifdef PD_PLUSPLUS_FACE
+ t_float *v; /* here we hold the resampled data */
+ int n;
+#else
+ t_float *vec;
+ int s_n;
+#endif
+ t_float *coeffs; /* coefficients for filtering... */
+ int coefsize;
+ t_float *buffer; /* buffer for filtering */
+ int bufsize;
+} t_resample;
+
+EXTERN void resample_init(t_resample *x);
+EXTERN void resample_free(t_resample *x);
+EXTERN void resample_dsp(t_resample *x, t_sample *in, int insize, t_sample *out, int outsize, int method);
+EXTERN void resamplefrom_dsp(t_resample *x, t_sample *in, int insize, int outsize, int method);
+EXTERN void resampleto_dsp(t_resample *x, t_sample *out, int insize, int outsize, int method);
+/* } IOhannes */
+
+/* tb: exporting basic simd coded dsp functions { */
+
+/* vectorized, not simd functions*/
+EXTERN void zerovec_8(t_float *dst,int n);
+EXTERN void setvec_8(t_float *dst,t_float v,int n);
+EXTERN void copyvec_8(t_float *dst,const t_float *src,int n);
+EXTERN void addvec_8(t_float *dst,const t_float *src,int n);
+EXTERN void testcopyvec_8(t_float *dst,const t_float *src,int n);
+EXTERN void testaddvec_8(t_float *dst,const t_float *src,int n);
+/* EXTERN float sumvec_8(t_float* in, t_int n); */
+
+/* vectorized, simd functions *
+ * dst and src are assumed to be aligned */
+EXTERN void zerovec_simd(t_float *dst,int n);
+EXTERN void setvec_simd(t_float *dst,t_float v,int n);
+EXTERN void copyvec_simd(t_float *dst,const t_float *src,int n);
+EXTERN void addvec_simd(t_float *dst,const t_float *src,int n);
+EXTERN void testcopyvec_simd(t_float *dst,const t_float *src,int n);
+EXTERN void testaddvec_simd(t_float *dst,const t_float *src,int n);
+/* EXTERN float sumvec_simd(t_float* in, t_int n); */
+EXTERN void copyvec_simd_unalignedsrc(t_float *dst,const t_float *src,int n);
+
+/* not vectorized, not simd functions */
+EXTERN void copyvec(t_float *dst,const t_float *src,int n);
+EXTERN void addvec(t_float *dst,const t_float *src,int n);
+EXTERN void zerovec(t_float *dst, int n);
+
+EXTERN int simd_runtime_check(void);
+EXTERN int simd_check1(t_int n, t_float* ptr1);
+EXTERN int simd_check2(t_int n, t_float* ptr1, t_float* ptr2);
+EXTERN int simd_check3(t_int n, t_float* ptr1, t_float* ptr2, t_float* ptr3);
+
+/* } tb */
+
+
+/* ----------------------- utility functions for signals -------------- */
+EXTERN float mtof(float);
+EXTERN float ftom(float);
+EXTERN float rmstodb(float);
+EXTERN float powtodb(float);
+EXTERN float dbtorms(float);
+EXTERN float dbtopow(float);
+
+EXTERN float q8_sqrt(float);
+EXTERN float q8_rsqrt(float);
+#ifndef N32
+EXTERN float qsqrt(float); /* old names kept for extern compatibility */
+EXTERN float qrsqrt(float);
+#endif
+/* --------------------- data --------------------------------- */
+
+/* graphical arrays */
+typedef struct _garray t_garray;
+
+EXTERN t_class *garray_class;
+EXTERN int garray_getfloatarray(t_garray *x, int *size, t_float **vec);
+EXTERN float garray_get(t_garray *x, t_symbol *s, t_int indx);
+EXTERN void garray_redraw(t_garray *x);
+EXTERN int garray_npoints(t_garray *x);
+EXTERN char *garray_vec(t_garray *x);
+EXTERN void garray_resize(t_garray *x, t_floatarg f);
+EXTERN void garray_usedindsp(t_garray *x);
+EXTERN void garray_setsaveit(t_garray *x, int saveit);
+EXTERN double garray_updatetime(t_garray *x);
+
+EXTERN t_class *scalar_class;
+
+EXTERN t_float *value_get(t_symbol *s);
+EXTERN void value_release(t_symbol *s);
+EXTERN int value_getfloat(t_symbol *s, t_float *f);
+EXTERN int value_setfloat(t_symbol *s, t_float f);
+
+/* ------- GUI interface - functions to send strings to TK --------- */
+EXTERN void sys_vgui(char *fmt, ...);
+EXTERN void sys_gui(char *s);
+
+extern t_class *glob_pdobject; /* object to send "pd" messages */
+
+/*------------- Max 0.26 compatibility --------------------*/
+
+#define t_getbytes getbytes
+#define t_freebytes freebytes
+#define t_resizebytes resizebytes
+#define typedmess pd_typedmess
+#define vmess pd_vmess
+
+/* A definition to help gui objects straddle 0.34-0.35 changes. If this is
+defined, there is a "te_xpix" field in objects, not a "te_xpos" as before: */
+
+#define PD_USE_TE_XPIX
+
+#ifdef __i386__
+/* a test for NANs and denormals. Should only be necessary on i386. */
+#define PD_BADFLOAT(f) ((((*(unsigned int*)&(f))&0x7f800000)==0) || \
+ (((*(unsigned int*)&(f))&0x7f800000)==0x7f800000))
+/* more stringent test: anything not between 1e-19 and 1e19 in absolute val */
+#define PD_BIGORSMALL(f) ((((*(unsigned int*)&(f))&0x60000000)==0) || \
+ (((*(unsigned int*)&(f))&0x60000000)==0x60000000))
+#else
+#define PD_BADFLOAT(f) 0
+#define PD_BIGORSMALL(f) 0
+#endif
+
+/* tb: wrapper for PD_BIGORSMALL macro */
+EXTERN void testcopyvec(t_float *dst,const t_float *src,int n);
+EXTERN void testaddvec(t_float *dst,const t_float *src,int n);
+
+/* tb's fifos */
+typedef struct _fifo t_fifo;
+/* function prototypes */
+EXTERN t_fifo * fifo_init(void);
+EXTERN void fifo_destroy(t_fifo*);
+/* fifo_put() and fifo_get are the only threadsafe functions!!! */
+EXTERN void fifo_put(t_fifo*, void*);
+EXTERN void* fifo_get(t_fifo*);
+
+#if defined(_LANGUAGE_C_PLUS_PLUS) || defined(__cplusplus)
+}
+#endif
+
+#define __m_pd_h_
+#endif /* __m_pd_h_ */
+
+/* removed functions:
+ sys_fontwidth, sys_fontheight, t_widgetbehavior, class_setproperties,
+ class_setwidget, class_setparentwidget, class_parentwidget, pd_getparentwidget,
+ sys_pretendguibytes, sys_queuegui, sys_unqueuegui, getzbytes,
+ gfxstub_new, gfxstub_deleteforkey
+ removed fields: te_width, te_type.
+ */
+/* externs that use g_next directly can't work with desiredata: gui/state, clone, dyn, dynext, toxy, cyclone */
diff --git a/desiredata/src/m_sched.c b/desiredata/src/m_sched.c
new file mode 100644
index 00000000..b4e0fc1a
--- /dev/null
+++ b/desiredata/src/m_sched.c
@@ -0,0 +1,654 @@
+/* Copyright (c) 1997-1999 Miller Puckette.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* scheduling stuff */
+
+#include "desire.h"
+#include <stdlib.h>
+
+/* for timeval */
+#ifdef UNISTD
+#include <sys/time.h>
+#endif
+#ifdef __CYGWIN__
+#include <sys/time.h>
+#endif
+#ifdef MSW
+#include "winsock.h"
+#endif
+
+#include "assert.h"
+
+/* LATER consider making this variable. It's now the LCM of all sample
+ rates we expect to see: 32000, 44100, 48000, 88200, 96000. */
+#define TIMEUNITPERSEC (32.*441000.)
+
+/* T.Grill - enable PD global thread locking - sys_lock, sys_unlock, sys_trylock functions */
+#define THREAD_LOCKING
+#include "pthread.h"
+#include "time.h"
+
+static int sys_quit;
+double sys_time;
+static double sys_time_per_msec = TIMEUNITPERSEC / 1000.;
+
+/* tb: { */
+int sys_keepsched = 1; /* if 0: change scheduler mode */
+int sys_callbackscheduler = 0; /* if 1: change scheduler to callback based dsp */
+static void run_idle_callbacks(int microsec);
+t_fifo * callback_fifo = NULL;
+/* tb: }*/
+
+int sys_usecsincelastsleep ();
+int sys_sleepgrain;
+
+typedef void (*t_clockmethod)(void *client);
+
+#ifdef UNISTD
+#include <unistd.h>
+#endif
+
+struct _clock {
+ double settime;
+ void *owner;
+ t_clockmethod fn;
+ struct _clock *next;
+};
+
+t_clock *clock_setlist;
+t_clock *clock_new(void *owner, t_method fn) {
+ t_clock *x = (t_clock *)malloc(sizeof(*x));
+ x->settime = -1;
+ x->owner = owner;
+ x->fn = (t_clockmethod)fn;
+ x->next = 0;
+ return x;
+}
+
+void clock_unset(t_clock *x) {
+ if (x->settime >= 0) {
+ if (x == clock_setlist) clock_setlist = x->next;
+ else {
+ t_clock *x2 = clock_setlist;
+ while (x2->next != x) x2 = x2->next;
+ x2->next = x->next;
+ }
+ x->settime = -1;
+ }
+}
+
+/* set the clock to call back at an absolute system time */
+void clock_set(t_clock *x, double setticks) {
+ if (setticks < sys_time) setticks = sys_time;
+ clock_unset(x);
+ x->settime = setticks;
+ if (clock_setlist && clock_setlist->settime <= setticks) {
+ t_clock *cbefore, *cafter;
+ for (cbefore = clock_setlist, cafter = clock_setlist->next; cbefore; cbefore = cafter, cafter = cbefore->next) {
+ if (!cafter || cafter->settime > setticks) {
+ cbefore->next = x;
+ x->next = cafter;
+ return;
+ }
+ }
+ } else x->next = clock_setlist, clock_setlist = x;
+}
+
+/* set the clock to call back after a delay in msec */
+void clock_delay(t_clock *x, double delaytime) {
+ clock_set(x, sys_time + sys_time_per_msec * delaytime);
+}
+
+/* get current logical time. We don't specify what units this is in;
+ use clock_gettimesince() to measure intervals from time of this call.
+ This was previously, incorrectly named "clock_getsystime"; the old
+ name is aliased to the new one in m_pd.h. */
+double clock_getlogicaltime () {return sys_time;}
+
+/* OBSOLETE NAME */
+double clock_getsystime () {return sys_time;}
+
+/* elapsed time in milliseconds since the given system time */
+double clock_gettimesince(double prevsystime) {
+ return (sys_time - prevsystime)/sys_time_per_msec;
+}
+
+/* what value the system clock will have after a delay */
+double clock_getsystimeafter(double delaytime) {
+ return sys_time + sys_time_per_msec * delaytime;
+}
+
+void clock_free(t_clock *x) {
+ clock_unset(x);
+ free(x);
+}
+
+/* the following routines maintain a real-execution-time histogram of the
+various phases of real-time execution. */
+
+static int sys_bin[] = {0, 2, 5, 10, 20, 30, 50, 100, 1000};
+#define NBIN (sizeof(sys_bin)/sizeof(*sys_bin))
+#define NHIST 10
+static int sys_histogram[NHIST][NBIN];
+static double sys_histtime;
+static int sched_diddsp, sched_didpoll, sched_didnothing;
+
+void sys_clearhist () {
+ unsigned i,j;
+ for (i=0; i<NHIST; i++) for (j=0; j<NBIN; j++) sys_histogram[i][j] = 0;
+ sys_histtime = sys_getrealtime();
+ sched_diddsp = sched_didpoll = sched_didnothing = 0;
+}
+
+void sys_printhist () {
+ for (int i=0; i<NHIST; i++) {
+ int doit = 0;
+ for (unsigned int j=0; j<NBIN; j++) if (sys_histogram[i][j]) doit = 1;
+ if (doit) {
+ post("%2d %8d %8d %8d %8d %8d %8d %8d %8d", i,
+ sys_histogram[i][0], sys_histogram[i][1], sys_histogram[i][2], sys_histogram[i][3],
+ sys_histogram[i][4], sys_histogram[i][5], sys_histogram[i][6], sys_histogram[i][7]);
+ }
+ }
+ post("dsp %d, pollgui %d, nothing %d", sched_diddsp, sched_didpoll, sched_didnothing);
+}
+
+static int sys_histphase;
+
+int sys_addhist(int phase) {
+ int phasewas = sys_histphase;
+ double newtime = sys_getrealtime();
+ int msec = int((newtime-sys_histtime)*1000.);
+ for (int j=NBIN-1; j >= 0; j--) {
+ if (msec >= sys_bin[j]) {
+ sys_histogram[phasewas][j]++;
+ break;
+ }
+ }
+ sys_histtime = newtime;
+ sys_histphase = phase;
+ return phasewas;
+}
+
+#define NRESYNC 20
+
+struct t_resync {
+ int ntick;
+ int error;
+};
+
+static int oss_resyncphase = 0;
+static int oss_nresync = 0;
+static t_resync oss_resync[NRESYNC];
+
+static char *(oss_errornames[]) = {
+"unknown",
+"ADC blocked",
+"DAC blocked",
+"A/D/A sync",
+"data late",
+"xrun",
+"sys_lock timeout"
+};
+
+void glob_audiostatus (void *dummy) {
+ int nresync, nresyncphase, i;
+ nresync = oss_nresync >= NRESYNC ? NRESYNC : oss_nresync;
+ nresyncphase = oss_resyncphase - 1;
+ post("audio I/O error history:");
+ post("seconds ago\terror type");
+ for (i = 0; i < nresync; i++) {
+ int errtype;
+ if (nresyncphase < 0) nresyncphase += NRESYNC;
+ errtype = oss_resync[nresyncphase].error;
+ if (errtype < 0 || errtype > 4) errtype = 0;
+ post("%9.2f\t%s", (sched_diddsp - oss_resync[nresyncphase].ntick)
+ * ((double)sys_schedblocksize) / sys_dacsr, oss_errornames[errtype]);
+ nresyncphase--;
+ }
+}
+
+static int sched_diored;
+static int sched_dioredtime;
+static int sched_meterson;
+
+void sys_log_error(int type) {
+ oss_resync[oss_resyncphase].ntick = sched_diddsp;
+ oss_resync[oss_resyncphase].error = type;
+ oss_nresync++;
+ if (++oss_resyncphase == NRESYNC) oss_resyncphase = 0;
+ if (type != ERR_NOTHING && !sched_diored && (sched_diddsp >= sched_dioredtime)) {
+ sys_vgui("pdtk_pd_dio 1\n");
+ sched_diored = 1;
+ }
+ sched_dioredtime = sched_diddsp + (int)(sys_dacsr /(double)sys_schedblocksize);
+}
+
+static int sched_lastinclip, sched_lastoutclip, sched_lastindb, sched_lastoutdb;
+
+static void sched_pollformeters () {
+ int inclip, outclip, indb, outdb;
+ static int sched_nextmeterpolltime, sched_nextpingtime;
+ /* if there's no GUI but we're running in "realtime", here is
+ where we arrange to ping the watchdog every 2 seconds. */
+#ifdef __linux__
+ if (sys_hipriority && (sched_diddsp - sched_nextpingtime > 0)) {
+ glob_watchdog(0);
+ /* ping every 2 seconds */
+ sched_nextpingtime = sched_diddsp + 2*(int)(sys_dacsr /(double)sys_schedblocksize);
+ }
+#endif
+ if (sched_diddsp - sched_nextmeterpolltime < 0) return;
+ if (sched_diored && sched_diddsp-sched_dioredtime > 0) {
+ sys_vgui("pdtk_pd_dio 0\n");
+ sched_diored = 0;
+ }
+ if (sched_meterson) {
+ float inmax, outmax;
+ sys_getmeters(&inmax, &outmax);
+ indb = int(0.5 + rmstodb(inmax));
+ outdb = int(0.5 + rmstodb(outmax));
+ inclip = inmax > 0.999;
+ outclip = outmax >= 1.0;
+ } else {
+ indb = outdb = 0;
+ inclip = outclip = 0;
+ }
+ if (inclip != sched_lastinclip || outclip != sched_lastoutclip
+ || indb != sched_lastindb || outdb != sched_lastoutdb) {
+ sys_vgui("pdtk_pd_meters %d %d %d %d\n", indb, outdb, inclip, outclip);
+ sched_lastinclip = inclip;
+ sched_lastoutclip = outclip;
+ sched_lastindb = indb;
+ sched_lastoutdb = outdb;
+ }
+ sched_nextmeterpolltime = sched_diddsp + (int)(sys_dacsr /(double)sys_schedblocksize);
+}
+
+void glob_meters(void *dummy, float f) {
+ if (f == 0) sys_getmeters(0, 0);
+ sched_meterson = (f != 0);
+ sched_lastinclip = sched_lastoutclip = sched_lastindb = sched_lastoutdb = -1;
+}
+
+#if 0
+void glob_foo(void *dummy, t_symbol *s, int argc, t_atom *argv) {
+ if (argc) sys_clearhist();
+ else sys_printhist();
+}
+#endif
+
+extern void dsp_tick ();
+
+static int sched_usedacs = 0;
+static double sched_referencerealtime, sched_referencelogicaltime;
+double sys_time_per_dsp_tick;
+
+void sched_set_using_dacs(int flag) {
+ sched_usedacs = flag;
+ if (!flag) {
+ sched_referencerealtime = sys_getrealtime();
+ sched_referencelogicaltime = clock_getlogicaltime();
+ }
+ sys_time_per_dsp_tick = (TIMEUNITPERSEC) * ((double)sys_schedblocksize) / sys_dacsr;
+}
+
+static void run_clock_callbacks(double next_sys_time) {
+ if (clock_setlist && clock_setlist->settime <= next_sys_time) {
+ do {
+ t_clock *c = clock_setlist;
+ sys_time = c->settime;
+ clock_unset(c); /* the compiler should easily inline this */
+ outlet_setstacklim();
+ c->fn(c->owner);
+ } while (clock_setlist && clock_setlist->settime <= next_sys_time);
+ }
+}
+
+/* take the scheduler forward one DSP tick, also handling clock timeouts */
+void sched_tick(double next_sys_time) {
+ run_clock_callbacks(next_sys_time);
+ sys_time = next_sys_time;
+ sched_diddsp++; /* rethink: how to get rid of this stupid histogram??? */
+ dsp_tick();
+ /* rethink: should we really do all this midi messaging in the realtime thread ? */
+ sys_pollmidiqueue();
+ sys_setmiditimediff(0, 1e-6 * sys_schedadvance);
+}
+
+
+/*
+Here is Pd's "main loop." This routine dispatches clock timeouts and DSP
+"ticks" deterministically, and polls for input from MIDI and the GUI. If
+we're left idle we also poll for graphics updates; but these are considered
+lower priority than the rest.
+
+The time source is normally the audio I/O subsystem via the "sys_send_dacs()"
+call. This call returns true if samples were transferred; false means that
+the audio I/O system is still busy with previous transfers.
+*/
+
+void sys_pollmidiqueue ();
+void sys_initmidiqueue ();
+
+void canvas_stop_dsp ();
+
+int m_scheduler () {
+ int idlecount = 0;
+ sys_time_per_dsp_tick = (TIMEUNITPERSEC) * ((double)sys_schedblocksize) / sys_dacsr;
+ /* T.Grill - lock mutex */
+ sys_lock();
+ sys_clearhist();
+ /* tb: adapt sleepgrain with advance */
+ sys_update_sleepgrain();
+ sched_set_using_dacs(0); /* tb: dsp is switched off */
+ sys_initmidiqueue();
+ while (!sys_quit) {
+ if (!sys_callbackscheduler || !sched_usedacs)
+ while (sys_keepsched) {
+ int didsomething = 0;
+ int timeforward;
+ waitfortick:
+ if (sched_usedacs) {
+ timeforward = sys_send_dacs();
+ /* if dacs remain "idle" for 1 sec, they're hung up. */
+ if (timeforward != 0)
+ idlecount = 0;
+ else {
+ idlecount++;
+ if (!(idlecount & 31)) {
+ static double idletime;
+ /* on 32nd idle, start a clock watch; every 32 ensuing idles, check it */
+ if (idlecount == 32) idletime = sys_getrealtime();
+ else if (sys_getrealtime() - idletime > 1.) {
+ post("audio I/O stuck... closing audio");
+ sys_close_audio();
+ sched_set_using_dacs(0);
+ canvas_stop_dsp(); /* added by matju 2007.06.30 */
+ goto waitfortick;
+ }
+ }
+ }
+ } else {
+ if (1000. * (sys_getrealtime() - sched_referencerealtime) > clock_gettimesince(sched_referencelogicaltime))
+ timeforward = SENDDACS_YES;
+ else timeforward = SENDDACS_NO;
+ }
+ sys_setmiditimediff(0, 1e-6 * sys_schedadvance);
+ if (timeforward != SENDDACS_NO) sched_tick(sys_time + sys_time_per_dsp_tick);
+ if (timeforward == SENDDACS_YES) didsomething = 1;
+ sys_pollmidiqueue();
+ if (sys_pollgui()) didsomething = 1;
+ /* test for idle; if so, do graphics updates. */
+ if (!didsomething) {
+ sched_pollformeters();
+ /* tb: call idle callbacks */
+ if (timeforward != SENDDACS_SLEPT) run_idle_callbacks(sys_sleepgrain);
+ }
+ }
+ else /* tb: scheduler for callback-based dsp scheduling */
+ while(sys_keepsched) {
+ /* tb: allow the audio callback to run */
+ sys_unlock();
+ sys_microsleep(sys_sleepgrain);
+ sys_lock();
+ sys_pollmidiqueue();
+ sys_setmiditimediff(0, 1e-6 * sys_schedadvance);
+ if (sys_pollgui()) continue;
+ /* do graphics updates and run idle callbacks */
+ sched_pollformeters();
+ }
+ sys_keepsched = 1;
+ }
+ sys_close_audio();
+ sys_unlock();
+ return 0;
+}
+
+/* ------------ thread locking ------------------- */
+/* added by Thomas Grill */
+
+#ifdef THREAD_LOCKING
+static pthread_mutex_t sys_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t sys_cond = PTHREAD_COND_INITIALIZER;
+
+void sys_lock () {
+ pthread_mutex_lock(&sys_mutex);
+}
+void sys_unlock () {
+ pthread_mutex_unlock(&sys_mutex);
+ pthread_cond_signal(&sys_cond);
+}
+int sys_trylock () {
+ return pthread_mutex_trylock(&sys_mutex);
+}
+
+/* tb { */
+#include <errno.h>
+
+#ifdef MSW
+/* gettimeofday isn't available on windoze ... */
+int gettimeofday (struct timeval *tv, void* tz) {
+ __int64 now; /* time since 1 Jan 1601 in 100ns */
+ GetSystemTimeAsFileTime ((FILETIME*) &now);
+ tv->tv_usec = (long) ((now / 10LL) % 1000000LL);
+ tv->tv_sec = (long) ((now - 116444736000000000LL) / 10000000LL);
+ return 0;
+}
+#endif
+
+#if 0
+/* osx doesn't define a pthread_mutex_timedlock ... maybe someday
+ it will ... */
+int sys_timedlock(int microsec) {
+ struct timespec timeout;
+ struct timeval now;
+ /* timedlock seems to have a resolution of 1ms */
+ if (microsec < 1000) microsec = 1000;
+ gettimeofday(&now,0);
+ timeout.tv_sec = now.tv_sec;
+ timeout.tv_nsec = (now.tv_usec + microsec) * 1000;
+ while (timeout.tv_nsec > 1e9) {
+ timeout.tv_sec += 1;
+ timeout.tv_nsec -= 1e9;
+ }
+ int ret = pthread_mutex_timedlock(&sys_mutex, &timeout);
+ if (ret) post("timeout, %d", ret);
+ return ret;
+}
+#else
+
+int sys_timedlock(int microsec) {
+ struct timespec timeout;
+ struct timeval now;
+ if (sys_trylock() == 0) return 0;
+ if (microsec < 1000) microsec = 1000;
+ gettimeofday(&now,0);
+ timeout.tv_sec = now.tv_sec;
+ timeout.tv_nsec = (now.tv_usec + microsec) * 1000;
+ while (timeout.tv_nsec > 1000000000) {
+ timeout.tv_sec += 1;
+ timeout.tv_nsec -= 1000000000;
+ }
+ /* in case the lock has been released during the system call, try
+ again before waiting for the signal */
+ if (sys_trylock() == 0) return 0;
+ return pthread_cond_timedwait(&sys_cond, &sys_mutex, &timeout);
+}
+#endif
+/* tb } */
+
+#else
+void sys_lock () {}
+void sys_unlock () {}
+int sys_trylock () { return 0; }
+int sys_timedlock (int microsec) { return 0; }
+#endif
+
+/* ------------ soft quit ------------------- */
+/* added by Thomas Grill -
+ just set the quit flag for the scheduler loop
+ this is useful for applications using the PD shared library to signal the scheduler to terminate
+*/
+
+void sys_exit () {
+ sys_keepsched = 0;
+ sys_quit = 1;
+}
+
+/* tb: place callbacks in scheduler
+ * { */
+/* linked list of callbacks; callback will be freed after returning 0 */
+struct t_sched_callback {
+ struct t_sched_callback *next; /* next callback in ringbuffer / in fifo */
+ t_int (*function)(t_int *argv);
+ t_int *argv;
+ t_int argc;
+};
+
+void sys_callback(t_int (*callback)(t_int* argv), t_int* argv, t_int argc) {
+ t_sched_callback* noo = (t_sched_callback *)malloc(sizeof(t_sched_callback));
+ noo->function = callback;
+ if (argv && argc) {
+ noo->argv = (t_int*) copybytes (argv, argc * sizeof (t_int));
+ noo->argc = argc;
+ } else {
+ noo->argc = 0;
+ noo->argv = 0;
+ }
+ noo->next = 0;
+ if (!callback_fifo) callback_fifo = fifo_init();
+ fifo_put(callback_fifo, noo);
+}
+
+void sys_init_idle_callbacks () {
+ callback_fifo = fifo_init(); /* tb: initialize fifo for idle callbacks */
+}
+
+static t_sched_callback *ringbuffer_head = NULL;
+
+void run_all_idle_callbacks () {
+ t_sched_callback *new_callback;
+ /* append idle callback to ringbuffer */
+ while ((new_callback = (t_sched_callback*) fifo_get(callback_fifo))) {
+ t_sched_callback *next;
+ /* set the next field to 0 ... it might be set in the fifo */
+ new_callback->next = 0;
+ if (!ringbuffer_head) {
+ ringbuffer_head = new_callback;
+ } else {
+ next = ringbuffer_head;
+ while (next->next) next = next->next;
+ next->next = new_callback;
+ }
+ }
+ if (ringbuffer_head) {
+ t_sched_callback *idle_callback = ringbuffer_head;
+ t_sched_callback *last = 0;
+ t_sched_callback *next;
+ do {
+ int status;
+ status = (idle_callback->function)(idle_callback->argv);
+ switch (status) {
+ /* callbacks returning 0 will be deleted */
+ case 0:
+ next = idle_callback->next;
+ if (idle_callback->argv) free(idle_callback->argv);
+ free((void*)idle_callback);
+ if (!last) ringbuffer_head = next; else last->next = next;
+ idle_callback = next;
+ /* callbacks returning 1 will be run again */
+ case 1:
+ break;
+ /* callbacks returning 2 will be run during the next idle callback */
+ case 2:
+ last = idle_callback;
+ idle_callback = idle_callback->next;
+ }
+ } while (idle_callback);
+ }
+}
+
+static void run_idle_callbacks(int microsec) {
+ t_sched_callback *new_callback;
+ double stop = sys_getrealtime()*1.e6 + (double)microsec;
+ /* append idle callback to ringbuffer */
+ while ((new_callback = (t_sched_callback*) fifo_get(callback_fifo))) {
+ /* set the next field to NULL ... it might be set in the fifo */
+ new_callback->next = 0;
+ if (!ringbuffer_head) {
+ ringbuffer_head = new_callback;
+ } else {
+ t_sched_callback *next = ringbuffer_head;
+ while (next->next != 0)
+ next = next->next;
+ next->next = new_callback;
+ }
+ }
+ if (ringbuffer_head) {
+ double remain = stop - sys_getrealtime() * 1.e6;
+ t_sched_callback *idle_callback = ringbuffer_head;
+ t_sched_callback *last = 0;
+ t_sched_callback *next;
+ do {
+// sys_lock();
+ int status = idle_callback->function(idle_callback->argv);
+// sys_unlock();
+ switch (status) {
+ /* callbacks returning 0 will be deleted */
+ case 0:
+ next = idle_callback->next;
+ if (idle_callback->argc) free(idle_callback->argv);
+ free((void*)idle_callback);
+ if (!last) ringbuffer_head = next; else last->next = next;
+ idle_callback = next;
+ /* callbacks returning 1 will be run again */
+ case 1:
+ break;
+ /* callbacks returning 2 will be run during the next idle callback */
+ case 2:
+ last = idle_callback;
+ idle_callback = idle_callback->next;
+ }
+ remain = stop-sys_getrealtime()*1.e6;
+ } while (idle_callback && remain>0);
+ /* sleep for the rest of the time */
+ if(remain > 0) {
+ sys_unlock();
+ sys_microsleep(int(remain));
+ sys_lock();
+ }
+ } else {
+ sys_unlock();
+ sys_microsleep(microsec);
+ sys_lock();
+ }
+}
+/* } tb */
+
+void sys_setscheduler(int scheduler) {
+ sys_keepsched = 0;
+ sys_callbackscheduler = scheduler;
+ return;
+}
+
+int sys_getscheduler () {return sys_callbackscheduler;}
+
+static t_int sys_xrun_notification_callback(t_int *dummy) {
+ t_symbol *pd = gensym("pd");
+ t_symbol *xrun = gensym("xrun");
+ typedmess(pd->s_thing, xrun, 0, 0);
+ return 0;
+}
+
+void sys_xrun_notification () {sys_callback(sys_xrun_notification_callback, 0, 0);}
+
+static t_int sys_lock_timeout_notification_callback(t_int *dummy) {
+ t_symbol *pd = gensym("pd");
+ t_symbol *timeout = gensym("sys_lock_timeout");
+ typedmess(pd->s_thing, timeout, 0, 0);
+ return 0;
+}
+
+void sys_lock_timeout_notification () {sys_callback(sys_lock_timeout_notification_callback, 0, 0);}
diff --git a/desiredata/src/m_simd.c b/desiredata/src/m_simd.c
new file mode 100644
index 00000000..1c0cb021
--- /dev/null
+++ b/desiredata/src/m_simd.c
@@ -0,0 +1,145 @@
+/*
+ Implementation of general vectorized functions
+ added by T.Grill
+*/
+
+#include "m_pd.h"
+#include "m_simd.h"
+
+void zerovec_8(t_float *dst,int n)
+{
+ for(n >>= 3; n--; dst += 8) {
+ dst[0] = dst[1] = dst[2] = dst[3] = dst[4] = dst[5] = dst[6] = dst[7] = 0;
+ }
+}
+
+void setvec_8(t_float *dst,t_float v,int n)
+{
+ for(n >>= 3; n--; dst += 8) {
+ dst[0] = dst[1] = dst[2] = dst[3] = dst[4] = dst[5] = dst[6] = dst[7] = v;
+ }
+}
+
+void copyvec_8(t_float *dst,const t_float *src,int n)
+{
+ for(n >>= 3; n--; src += 8,dst += 8) {
+ dst[0] = src[0],dst[1] = src[1],dst[2] = src[2],dst[3] = src[3];
+ dst[4] = src[4],dst[5] = src[5],dst[6] = src[6],dst[7] = src[7];
+ }
+}
+
+void addvec_8(t_float *dst,const t_float *src,int n)
+{
+ for(n >>= 3; n--; src += 8,dst += 8) {
+ dst[0] += src[0],dst[1] += src[1],dst[2] += src[2],dst[3] += src[3];
+ dst[4] += src[4],dst[5] += src[5],dst[6] += src[6],dst[7] += src[7];
+ }
+}
+
+void copyvec(t_float *dst,const t_float *src,int n)
+{
+ while(n--)
+ *dst++ = *src++;
+}
+
+void zerovec(t_float *dst, int n)
+{
+ while(n--)
+ *dst++ = 0;
+}
+
+
+void addvec(t_float *dst,const t_float *src,int n)
+{
+ while(n--)
+ *dst++ += *src++;
+}
+
+
+void testcopyvec_8(t_float *dst,const t_float *src,int n)
+{
+ while(n--) {
+ *(dst++) = (PD_BIGORSMALL(*src) ? 0 : *src); src++;
+ }
+}
+
+void testcopyvec(t_float *dst,const t_float *src,int n)
+{
+ testcopyvec_8(dst, src, n);
+}
+
+void testaddvec_8(t_float *dst,const t_float *src,int n)
+{
+ while(n--) {
+ *(dst++) += (PD_BIGORSMALL(*src) ? 0 : *src); src++;
+ }
+}
+
+void testaddvec(t_float *dst,const t_float *src,int n)
+{
+ testaddvec_8(dst, src, n);
+}
+
+
+int simd_check1(t_int n, t_float* ptr1)
+{
+ return SIMD_CHECK1(n,ptr1);
+}
+
+int simd_check2(t_int n, t_float* ptr1, t_float* ptr2)
+{
+ return SIMD_CHECK2(n,ptr1,ptr2);
+}
+
+int simd_check3(t_int n, t_float* ptr1, t_float* ptr2, t_float* ptr3)
+{
+ return SIMD_CHECK3(n,ptr1,ptr2,ptr3);
+}
+
+
+
+#ifdef DONTUSESIMD
+int simd_runtime_check()
+{
+ return 0;
+}
+
+/* tb: wrapper for simd functions */
+void zerovec_simd(t_float *dst,int n)
+{
+ zerovec_8(dst,n);
+}
+
+void setvec_simd(t_float *dst,t_float v,int n)
+{
+ setvec_8(dst,v,n);
+}
+
+void copyvec_simd(t_float *dst,const t_float *src,int n)
+{
+ copyvec_8(dst,src,n);
+}
+
+void copyvec_simd_unalignedsrc(t_float *dst,const t_float *src,int n)
+{
+ copyvec_8(dst,src,n);
+}
+
+void addvec_simd(t_float *dst,const t_float *src,int n)
+{
+ addvec_8(dst,src,n);
+}
+
+void testcopyvec_simd(t_float *dst,const t_float *src,int n)
+{
+ testcopyvec_8(dst,src,n);
+}
+
+void testaddvec_simd(t_float *dst,const t_float *src,int n)
+{
+ testaddvec_8(dst,src,n);
+}
+
+
+#endif /* DONTUSESIMD */
+
diff --git a/desiredata/src/m_simd.h b/desiredata/src/m_simd.h
new file mode 100644
index 00000000..feeb78e0
--- /dev/null
+++ b/desiredata/src/m_simd.h
@@ -0,0 +1,82 @@
+/* Definitions for SIMD functionality; added by T.Grill */
+#ifndef __M_SIMD_H
+#define __M_SIMD_H
+
+/* general vector functions */
+void zerovec_8(t_float *dst,int n);
+void setvec_8(t_float *dst,t_float v,int n);
+void copyvec_8(t_float *dst,const t_float *src,int n);
+void addvec_8(t_float *dst,const t_float *src,int n);
+void testcopyvec_8(t_float *dst,const t_float *src,int n);
+void testaddvec_8(t_float *dst,const t_float *src,int n);
+
+#define SIMD_BYTEALIGN (128/8)
+
+/* how many floats do we calculate in the loop of a SIMD codelet? */
+#define SIMD_BLOCK 16 /* must be a power of 2 */
+
+//#if defined(__GNUC__) && (defined(_X86_) || defined(__i386__) || defined(__i586__) || defined(__i686__))
+#ifdef SIMD_SSE /* Intel SSE with GNU C */ /* ought to add this in configure.in */
+t_int *sigwrap_perf_simd(t_int *w);
+void line_tilde_slope_simd(t_float* out, t_int n, t_float* value, t_float* slopes, t_float* slopestep);
+float env_tilde_accum_simd(t_float* in, t_float* hp, t_int n);
+t_int* sigsqrt_perf_simd(t_int *w);
+t_int* sigrsqrt_perf_simd(t_int *w);
+float peakvec_simd(t_float* vec, t_int n, t_float cur_max);
+#endif
+
+//#if defined(__GNUC__) && defined(__POWERPC__) && defined(__ALTIVEC__)
+#ifdef SIMD_ALTIVEC /* Altivec with GNU C ( -faltivec must be given as a compiler option! ) */ /* ought to add this in configure.in */
+ #include "m_simd_ve_gcc.h"
+#endif
+
+#ifdef DONTUSESIMD
+ /* This is used when there's no implementation of SIMD code for the current platform and/or compiler */
+ /* These are the functions that can be coded for SIMD */
+ #define zero_perf_simd zero_perf8
+ #define copy_perf_simd copy_perf8
+ #define sig_tilde_perf_simd sig_tilde_perf8
+ #define sigwrap_perf_simd sigwrap_perform
+ #define line_tilde_slope_simd line_tilde_slope
+ #define env_tilde_accum_simd env_tilde_accum_8 /* it's a bad place to set that here since there's no public prototype */
+ #define plus_perf_simd plus_perf8
+ #define scalarplus_perf_simd scalarplus_perf8
+ #define minus_perf_simd minus_perf8
+ #define scalarminus_perf_simd scalarminus_perf8
+ #define times_perf_simd times_perf8
+ #define scalartimes_perf_simd scalartimes_perf8
+ #define sqr_perf_simd sqr_perf8
+ #define over_perf_simd over_perf8
+ #define scalarover_perf_simd scalarover_perf8
+ #define min_perf_simd min_perf8
+ #define scalarmin_perf_simd scalarmin_perf8
+ #define max_perf_simd max_perf8
+ #define scalarmax_perf_simd scalarmax_perf8
+ #define clip_perf_simd clip_perform /* SIMD not implemented */
+ #define sigwrap_perf_simd sigwrap_perform /* SIMD not implemented */
+ #define sigsqrt_perf_simd sigsqrt_perform /* SIMD not implemented */
+ #define sigrsqrt_perf_simd sigrsqrt_perform /* SIMD not implemented */
+ #define peakvec_simd peakvec
+ /* #define sum_vecsimd sumvec_8 */
+#endif
+
+/* check if n meets the requirements for SIMD codelets */
+#define SIMD_CHKCNT(n) ( ((n)&(SIMD_BLOCK-1)) == 0 )
+/* check if a pointer is correctly aligned for SIMD codelets */
+#define SIMD_CHKALIGN(ptr) ( ((size_t)(ptr) & (SIMD_BYTEALIGN-1)) == 0 )
+/* check n and 1 pointer at once */
+#define SIMD_CHECK1(n,ptr1) (SIMD_CHKCNT(n) && SIMD_CHKALIGN(ptr1) && simd_runtime_check())
+/* check n and 2 pointers at once */
+#define SIMD_CHECK2(n,ptr1,ptr2) (SIMD_CHKCNT(n) && SIMD_CHKALIGN(ptr1) && SIMD_CHKALIGN(ptr2) && simd_runtime_check())
+/* check n and 3 pointers at once */
+#define SIMD_CHECK3(n,ptr1,ptr2,ptr3) (SIMD_CHKCNT(n) && SIMD_CHKALIGN(ptr1) && SIMD_CHKALIGN(ptr2) && SIMD_CHKALIGN(ptr3) && simd_runtime_check())
+
+/* T.Grill - bit alignment for signal vectors (must be a multiple of 8!) */
+/* if undefined no alignment occurs */
+#ifdef SIMD_BYTEALIGN
+ #define VECTORALIGNMENT (SIMD_BYTEALIGN*8)
+#else
+ #define VECTORALIGNMENT 128
+#endif
+
+#endif /* __M_SIMD_H */
diff --git a/desiredata/src/m_simd_sse_gcc.c b/desiredata/src/m_simd_sse_gcc.c
new file mode 100644
index 00000000..17182a59
--- /dev/null
+++ b/desiredata/src/m_simd_sse_gcc.c
@@ -0,0 +1,1131 @@
+/*
+ Implementation of SIMD functionality for Intel SSE with GCC compiler
+ added by T.Grill
+*/
+
+#include "m_pd.h"
+#include "m_simd.h"
+
+#if defined(__GNUC__) && (defined(_X86_) || defined(__i386__) || defined(__i586__) || defined(__i686__)) && !(defined DONTUSESIMD)
+
+
+/* TB: adapted from thomas' vc routines */
+
+/* dst is assumed to be aligned */
+void zerovec_simd(t_float *dst,int n)
+{
+ asm(
+ ".set T_FLOAT,4 \n" /* sizeof(t_float) */
+ "xorps %%xmm0, %%xmm0 \n" /* zero value */
+ "shr $4, %0 \n"
+
+ /* should we do more loop unrolling? */
+ /* *dst = 0 */
+ "1: \n"
+ "movaps %%xmm0, (%1) \n"
+ "movaps %%xmm0, 4*T_FLOAT(%1) \n"
+ "movaps %%xmm0, 8*T_FLOAT(%1) \n"
+ "movaps %%xmm0, 12*T_FLOAT(%1) \n"
+
+ "addl $16*T_FLOAT,%1 \n"
+ "loop 1b \n"
+ :
+ :"c"(n),"r"(dst)
+ :"%xmm0");
+}
+
+/* dst is assumed to be aligned */
+void setvec_simd(t_float *dst,t_float v,int n)
+{
+ asm(
+ ".set T_FLOAT,4 \n" /* sizeof(t_float) */
+ "movss (%2),%%xmm0 \n"
+ "shufps $0,%%xmm0,%%xmm0 \n" /* load value */
+ "shr $4,%0 \n"
+
+ /* should we do more loop unrolling? */
+ /* *dst = v */
+ "1: \n"
+ "movaps %%xmm0, (%1) \n"
+ "movaps %%xmm0, 4*T_FLOAT(%1) \n"
+ "movaps %%xmm0, 8*T_FLOAT(%1) \n"
+ "movaps %%xmm0, 12*T_FLOAT(%1) \n"
+
+ "addl $16*T_FLOAT,%1 \n"
+ "loop 1b \n"
+ :
+ :"c"(n),"r"(dst),"r"(&v)
+ :"%xmm0");
+}
+
+
+/* dst and src are assumed to be aligned */
+void copyvec_simd(t_float *dst,const t_float *src,int n)
+{
+ asm(
+ ".set T_FLOAT,4 \n" /* sizeof(t_float) */
+ "shr $4, %0 \n"
+
+ /* loop: *dst = *src */
+ "1: \n"
+ "movaps (%1), %%xmm0 \n"
+ "movaps 4*T_FLOAT(%1), %%xmm1 \n"
+ "movaps 8*T_FLOAT(%1), %%xmm2 \n"
+ "movaps 12*T_FLOAT(%1), %%xmm3 \n"
+ "movaps %%xmm0, (%2) \n"
+ "movaps %%xmm1, 4*T_FLOAT(%2) \n"
+ "movaps %%xmm2, 8*T_FLOAT(%2) \n"
+ "movaps %%xmm3, 12*T_FLOAT(%2) \n"
+
+
+ "addl $16*T_FLOAT,%1 \n"
+ "addl $16*T_FLOAT,%2 \n"
+ "loop 1b \n"
+ :
+ :"c"(n),"r"(src),"r"(dst)
+ :"%xmm0","%xmm1","%xmm2","%xmm3");
+}
+
+/* dst is assumed to be aligned */
+void copyvec_simd_unalignedsrc(t_float *dst,const t_float *src,int n)
+{
+ asm(
+ ".set T_FLOAT,4 \n" /* sizeof(t_float) */
+ "shr $4, %0 \n"
+
+ /* loop: *dst = *src */
+ "1: \n"
+ "movups (%1), %%xmm0 \n"
+ "movups 4*T_FLOAT(%1), %%xmm1 \n"
+ "movups 8*T_FLOAT(%1), %%xmm2 \n"
+ "movups 12*T_FLOAT(%1), %%xmm3 \n"
+ "movaps %%xmm0, (%2) \n"
+ "movaps %%xmm1, 4*T_FLOAT(%2) \n"
+ "movaps %%xmm2, 8*T_FLOAT(%2) \n"
+ "movaps %%xmm3, 12*T_FLOAT(%2) \n"
+
+
+ "addl $16*T_FLOAT,%1 \n"
+ "addl $16*T_FLOAT,%2 \n"
+ "loop 1b \n"
+ :
+ :"c"(n),"r"(src),"r"(dst)
+ :"%xmm0","%xmm1","%xmm2","%xmm3");
+}
+
+
+/* dst and src are assumed to be aligned */
+void addvec_simd(t_float *dst,const t_float *src,int n)
+{
+ asm(
+ ".set T_FLOAT,4 \n" /* sizeof(t_float) */
+ "shr $4, %0 \n"
+
+ /* loop: *dst += *src */
+ "1: \n"
+ "movaps (%2,%3),%%xmm0 \n"
+ "movaps (%1,%3),%%xmm1 \n"
+ "addps %%xmm0,%%xmm1 \n"
+ "movaps %%xmm1,(%2,%3) \n"
+
+ "movaps 4*T_FLOAT(%2,%3),%%xmm0 \n"
+ "movaps 4*T_FLOAT(%1,%3),%%xmm1 \n"
+ "addps %%xmm0,%%xmm1 \n"
+ "movaps %%xmm1,4*T_FLOAT(%2,%3) \n"
+
+ "movaps 8*T_FLOAT(%2,%3),%%xmm0 \n"
+ "movaps 8*T_FLOAT(%1,%3),%%xmm1 \n"
+ "addps %%xmm0,%%xmm1 \n"
+ "movaps %%xmm1,8*T_FLOAT(%2,%3) \n"
+
+ "movaps 12*T_FLOAT(%2,%3),%%xmm0 \n"
+ "movaps 12*T_FLOAT(%1,%3),%%xmm1 \n"
+ "addps %%xmm0,%%xmm1 \n"
+ "movaps %%xmm1,12*T_FLOAT(%2,%3) \n"
+
+ "addl $16*T_FLOAT,%3 \n"
+ "loop 1b \n"
+ :
+ : "c"(n),"r"(src),"r"(dst),"r"(0)
+ : "%xmm0","%xmm1","%xmm2","%xmm3","%xmm4","%xmm5","%xmm6","%xmm7");
+}
+
+
+void testcopyvec_simd(t_float *dst,const t_float *src,int n)
+{
+
+ asm(
+ ".section .rodata \n"
+ ".align 16 \n"
+ "2: \n"
+ ".long 1610612736 \n" /* bitmask */
+ ".long 1610612736 \n" /* 0x60000000 */
+ ".long 1610612736 \n"
+ ".long 1610612736 \n"
+
+ ".set T_FLOAT,4 \n"
+ ".text \n"
+
+ "shr $4, %0 \n"
+ "movaps (2b), %%xmm0 \n" /* xmm0 = bitmask */
+ "xorps %%xmm1, %%xmm1 \n" /* xmm1 = 0x0 */
+
+
+ "1: \n"
+ "movaps (%1), %%xmm2 \n"
+ "movaps %%xmm2, %%xmm3 \n"
+ "andps %%xmm0, %%xmm3 \n"
+ "movaps %%xmm3, %%xmm4 \n"
+ "cmpneqps %%xmm0, %%xmm3 \n"
+ "cmpneqps %%xmm1, %%xmm4 \n"
+ "andps %%xmm4, %%xmm3 \n"
+ "andps %%xmm3, %%xmm2 \n"
+ "movaps %%xmm2, (%2) \n"
+
+ "movaps 4*T_FLOAT(%1), %%xmm2 \n"
+ "movaps %%xmm2, %%xmm3 \n"
+ "andps %%xmm0, %%xmm3 \n"
+ "movaps %%xmm3, %%xmm4 \n"
+ "cmpneqps %%xmm0, %%xmm3 \n"
+ "cmpneqps %%xmm1, %%xmm4 \n"
+ "andps %%xmm4, %%xmm3 \n"
+ "andps %%xmm3, %%xmm2 \n"
+ "movaps %%xmm2, 4*T_FLOAT(%2) \n"
+
+ "movaps 8*T_FLOAT(%1), %%xmm2 \n"
+ "movaps %%xmm2, %%xmm3 \n"
+ "andps %%xmm0, %%xmm3 \n"
+ "movaps %%xmm3, %%xmm4 \n"
+ "cmpneqps %%xmm0, %%xmm3 \n"
+ "cmpneqps %%xmm1, %%xmm4 \n"
+ "andps %%xmm4, %%xmm3 \n"
+ "andps %%xmm3, %%xmm2 \n"
+ "movaps %%xmm2, 8*T_FLOAT(%2) \n"
+
+ "movaps 12*T_FLOAT(%1), %%xmm2 \n"
+ "movaps %%xmm2, %%xmm3 \n"
+ "andps %%xmm0, %%xmm3 \n"
+ "movaps %%xmm3, %%xmm4 \n"
+ "cmpneqps %%xmm0, %%xmm3 \n"
+ "cmpneqps %%xmm1, %%xmm4 \n"
+ "andps %%xmm4, %%xmm3 \n"
+ "andps %%xmm3, %%xmm2 \n"
+ "movaps %%xmm2, 12*T_FLOAT(%2) \n"
+
+
+ "addl $16*T_FLOAT,%1 \n"
+ "addl $16*T_FLOAT,%2 \n"
+ "decl %0 \n"
+ "jne 1b \n"
+ :
+ :"c"(n),"r"(src),"r"(dst)
+ :"%xmm0","%xmm1","%xmm2","%xmm3", "%xmm4");
+}
+
+
+void testaddvec_simd(t_float *dst,const t_float *src,int n)
+{
+ asm(
+ ".section .rodata \n"
+ ".align 16 \n"
+ "2: \n"
+ ".long 1610612736 \n" /* bitmask */
+ ".long 1610612736 \n" /* 0x60000000 */
+ ".long 1610612736 \n"
+ ".long 1610612736 \n"
+
+ ".set T_FLOAT,4 \n"
+ ".text \n"
+
+ "shr $4, %0 \n"
+ "movaps (2b), %%xmm0 \n" /* xmm0 = bitmask */
+ "xorps %%xmm1, %%xmm1 \n" /* xmm1 = 0x0 */
+
+
+ "1: \n"
+ "movaps (%1), %%xmm2 \n"
+ "movaps (%2), %%xmm5 \n"
+ "movaps %%xmm2, %%xmm3 \n"
+ "andps %%xmm0, %%xmm3 \n"
+ "movaps %%xmm3, %%xmm4 \n"
+ "cmpneqps %%xmm0, %%xmm3 \n"
+ "cmpneqps %%xmm1, %%xmm4 \n"
+ "andps %%xmm4, %%xmm3 \n"
+ "andps %%xmm3, %%xmm2 \n"
+ "addps %%xmm2, %%xmm5 \n"
+ "movaps %%xmm5, (%2) \n"
+
+ "movaps 4*T_FLOAT(%1), %%xmm2 \n"
+ "movaps 4*T_FLOAT(%2), %%xmm5 \n"
+ "movaps %%xmm2, %%xmm3 \n"
+ "andps %%xmm0, %%xmm3 \n"
+ "movaps %%xmm3, %%xmm4 \n"
+ "cmpneqps %%xmm0, %%xmm3 \n"
+ "cmpneqps %%xmm1, %%xmm4 \n"
+ "andps %%xmm4, %%xmm3 \n"
+ "andps %%xmm3, %%xmm2 \n"
+ "addps %%xmm2, %%xmm5 \n"
+ "movaps %%xmm5, 4*T_FLOAT(%2) \n"
+
+ "movaps 8*T_FLOAT(%1), %%xmm2 \n"
+ "movaps 8*T_FLOAT(%2), %%xmm5 \n"
+ "movaps %%xmm2, %%xmm3 \n"
+ "andps %%xmm0, %%xmm3 \n"
+ "movaps %%xmm3, %%xmm4 \n"
+ "cmpneqps %%xmm0, %%xmm3 \n"
+ "cmpneqps %%xmm1, %%xmm4 \n"
+ "andps %%xmm4, %%xmm3 \n"
+ "andps %%xmm3, %%xmm2 \n"
+ "addps %%xmm2, %%xmm5 \n"
+ "movaps %%xmm5, 8*T_FLOAT(%2) \n"
+
+ "movaps 12*T_FLOAT(%1), %%xmm2 \n"
+ "movaps 12*T_FLOAT(%2), %%xmm5 \n"
+ "movaps %%xmm2, %%xmm3 \n"
+ "andps %%xmm0, %%xmm3 \n"
+ "movaps %%xmm3, %%xmm4 \n"
+ "cmpneqps %%xmm0, %%xmm3 \n"
+ "cmpneqps %%xmm1, %%xmm4 \n"
+ "andps %%xmm4, %%xmm3 \n"
+ "andps %%xmm3, %%xmm2 \n"
+ "addps %%xmm2, %%xmm5 \n"
+ "movaps %%xmm5, 12*T_FLOAT(%2) \n"
+
+
+ "addl $16*T_FLOAT,%1 \n"
+ "addl $16*T_FLOAT,%2 \n"
+ "decl %0 \n"
+ "jne 1b \n"
+ :
+ :"c"(n),"r"(src),"r"(dst)
+ :"%xmm0","%xmm1","%xmm2","%xmm3", "%xmm4", "%xmm5");
+}
+
+
+t_int *zero_perf_simd(t_int *w)
+{
+ zerovec_simd((t_float *)w[1],w[2]);
+ return w+3;
+}
+
+t_int *copy_perf_simd(t_int *w)
+{
+ copyvec_simd((t_float *)w[2],(const t_float *)w[1],w[3]);
+ return w+4;
+}
+
+t_int *sig_tilde_perf_simd(t_int *w)
+{
+ setvec_simd((t_float *)w[2],*(const t_float *)w[1],w[3]);
+ return w+4;
+}
+
+
+t_int *plus_perf_simd (t_int * w)
+{
+ asm(
+ ".set T_FLOAT,4 \n"
+
+ "shrl $4, %3 \n" /* divide by 16 */
+
+ /* loop: *out = *in1 + *in2 */
+ "1: \n"
+ "movaps (%0,%4), %%xmm0 \n"
+ "movaps (%1,%4), %%xmm1 \n"
+ "addps %%xmm1, %%xmm0 \n"
+ "movaps %%xmm0, (%2,%4) \n"
+
+ "movaps 4*T_FLOAT(%0,%4), %%xmm2 \n"
+ "movaps 4*T_FLOAT(%1,%4), %%xmm3 \n"
+ "addps %%xmm3, %%xmm2 \n"
+ "movaps %%xmm2, 4*T_FLOAT(%2,%4) \n"
+
+ "movaps 8*T_FLOAT(%0,%4), %%xmm4 \n"
+ "movaps 8*T_FLOAT(%1,%4), %%xmm5 \n"
+ "addps %%xmm5, %%xmm4 \n"
+ "movaps %%xmm4, 8*T_FLOAT(%2,%4) \n"
+
+ "movaps 12*T_FLOAT(%0,%4), %%xmm6 \n"
+ "movaps 12*T_FLOAT(%1,%4), %%xmm7 \n"
+ "addps %%xmm7, %%xmm6 \n"
+ "movaps %%xmm6, 12*T_FLOAT(%2,%4) \n"
+
+ "addl $16*T_FLOAT, %4 \n"
+ "loop 1b \n"
+ :
+ /* in1, in2, out, n */
+ :"r"(w[1]),"r"(w[2]),"r"(w[3]),"c"(w[4]),"r"(0)
+ :"%xmm0","%xmm1","%xmm2","%xmm3","%xmm4","%xmm5","%xmm6","%xmm7"
+ );
+ return w+5;
+}
+
+
+t_int *scalarplus_perf_simd(t_int *w)
+{
+ asm(
+ ".set T_FLOAT,4 \n"
+
+ "movss (%1), %%xmm0 \n"
+ "shufps $0, %%xmm0, %%xmm0 \n"
+ "shrl $4, %3 \n" /* divide by 16 */
+
+ /* loop: *out = *in + value */
+ "1: \n"
+ "movaps (%0), %%xmm1 \n"
+ "addps %%xmm0, %%xmm1 \n"
+ "movaps %%xmm1, (%2) \n"
+
+ "movaps 4*T_FLOAT(%0), %%xmm2 \n"
+ "addps %%xmm0, %%xmm2 \n"
+ "movaps %%xmm2, 4*T_FLOAT(%2) \n"
+
+ "movaps 8*T_FLOAT(%0), %%xmm3 \n"
+ "addps %%xmm0, %%xmm3 \n"
+ "movaps %%xmm3, 8*T_FLOAT(%2) \n"
+
+ "movaps 12*T_FLOAT(%0), %%xmm4 \n"
+ "addps %%xmm0, %%xmm4 \n"
+ "movaps %%xmm4, 12*T_FLOAT(%2) \n"
+
+ "addl $16*T_FLOAT, %0 \n"
+ "addl $16*T_FLOAT, %2 \n"
+ "loop 1b \n"
+ :
+ /* in, value, out, n */
+ :"r"(w[1]),"r"(w[2]),"r"(w[3]),"c"(w[4])
+ :"%xmm0", "%xmm1","%xmm2","%xmm3","%xmm4"
+ );
+ return w+5;
+}
+
+t_int *minus_perf_simd(t_int *w)
+{
+ asm(
+ ".set T_FLOAT,4 \n"
+
+ "shrl $4, %3 \n" /* divide by 16 */
+
+ /* loop: *out = *in1 - *in2 */
+ "1: \n"
+ "movaps (%0,%4), %%xmm0 \n"
+ "movaps (%1,%4), %%xmm1 \n"
+ "subps %%xmm1, %%xmm0 \n"
+ "movaps %%xmm0, (%2,%4) \n"
+
+ "movaps 4*T_FLOAT(%0,%4), %%xmm2 \n"
+ "movaps 4*T_FLOAT(%1,%4), %%xmm3 \n"
+ "subps %%xmm3, %%xmm2 \n"
+ "movaps %%xmm2, 4*T_FLOAT(%2,%4) \n"
+
+ "movaps 8*T_FLOAT(%0,%4), %%xmm4 \n"
+ "movaps 8*T_FLOAT(%1,%4), %%xmm5 \n"
+ "subps %%xmm5, %%xmm4 \n"
+ "movaps %%xmm4, 8*T_FLOAT(%2,%4) \n"
+
+ "movaps 12*T_FLOAT(%0,%4), %%xmm6 \n"
+ "movaps 12*T_FLOAT(%1,%4), %%xmm7 \n"
+ "subps %%xmm7, %%xmm6 \n"
+ "movaps %%xmm6, 12*T_FLOAT(%2,%4) \n"
+
+ "addl $16*T_FLOAT, %4 \n"
+ "loop 1b \n"
+ :
+ /* in1, in2, out, n */
+ :"r"(w[1]),"r"(w[2]),"r"(w[3]),"c"(w[4]),"r"(0)
+ :"%xmm0","%xmm1","%xmm2","%xmm3","%xmm4","%xmm5","%xmm6","%xmm7"
+ );
+ return w+5;
+}
+
+t_int* scalarminus_perf_simd(t_int *w)
+{
+ asm(
+ ".set T_FLOAT,4 \n"
+
+ "movss (%1), %%xmm0 \n"
+ "shufps $0, %%xmm0, %%xmm0 \n"
+ "shrl $4, %3 \n" /* divide by 16 */
+
+ /* loop: *out = *in - value */
+ "1: \n"
+ "movaps (%0), %%xmm1 \n"
+ "subps %%xmm0, %%xmm1 \n"
+ "movaps %%xmm1, (%2) \n"
+
+ "movaps 4*T_FLOAT(%0), %%xmm2 \n"
+ "subps %%xmm0, %%xmm2 \n"
+ "movaps %%xmm2, 4*T_FLOAT(%2) \n"
+
+ "movaps 8*T_FLOAT(%0), %%xmm3 \n"
+ "subps %%xmm0, %%xmm3 \n"
+ "movaps %%xmm3, 8*T_FLOAT(%2) \n"
+
+ "movaps 12*T_FLOAT(%0), %%xmm4 \n"
+ "subps %%xmm0, %%xmm4 \n"
+ "movaps %%xmm4, 12*T_FLOAT(%2) \n"
+
+ "addl $16*T_FLOAT, %0 \n"
+ "addl $16*T_FLOAT, %2 \n"
+ "loop 1b \n"
+ :
+ /* in, value, out, n */
+ :"r"(w[1]),"r"(w[2]),"r"(w[3]),"c"(w[4])
+ :"%xmm0","%xmm1","%xmm2","%xmm3","%xmm4"
+ );
+ return w+5;
+}
+
+
+t_int *times_perf_simd(t_int *w)
+{
+ asm(
+ ".set T_FLOAT,4 \n"
+
+ "shrl $4, %3 \n" /* divide by 16 */
+
+ /* loop: *out = *in1 * *in2 */
+ "1: \n"
+ "movaps (%0,%4), %%xmm0 \n"
+ "movaps (%1,%4), %%xmm1 \n"
+ "mulps %%xmm1, %%xmm0 \n"
+ "movaps %%xmm0, (%2,%4) \n"
+
+ "movaps 4*T_FLOAT(%0,%4), %%xmm2 \n"
+ "movaps 4*T_FLOAT(%1,%4), %%xmm3 \n"
+ "mulps %%xmm3, %%xmm2 \n"
+ "movaps %%xmm2, 4*T_FLOAT(%2,%4) \n"
+
+ "movaps 8*T_FLOAT(%0,%4), %%xmm4 \n"
+ "movaps 8*T_FLOAT(%1,%4), %%xmm5 \n"
+ "mulps %%xmm5, %%xmm4 \n"
+ "movaps %%xmm4, 8*T_FLOAT(%2,%4) \n"
+
+ "movaps 12*T_FLOAT(%0,%4), %%xmm6 \n"
+ "movaps 12*T_FLOAT(%1,%4), %%xmm7 \n"
+ "mulps %%xmm7, %%xmm6 \n"
+ "movaps %%xmm6, 12*T_FLOAT(%2,%4) \n"
+
+ "addl $16*T_FLOAT, %4 \n"
+ "loop 1b \n"
+ :
+ /* in1, in2, out, n */
+ :"r"(w[1]),"r"(w[2]),"r"(w[3]),"c"(w[4]),"r"(0)
+ :"%xmm0","%xmm1","%xmm2","%xmm3","%xmm4","%xmm5","%xmm6","%xmm7"
+ );
+ return w+5;
+}
+
+t_int* scalartimes_perf_simd(t_int *w)
+{
+ asm(
+ ".set T_FLOAT,4 \n"
+
+ "movss (%1), %%xmm0 \n"
+ "shufps $0, %%xmm0, %%xmm0 \n"
+ "shrl $4, %3 \n" /* divide by 16 */
+
+ /* loop: *out = *in * value */
+ "1: \n"
+ "movaps (%0), %%xmm1 \n"
+ "mulps %%xmm0, %%xmm1 \n"
+ "movaps %%xmm1, (%2) \n"
+
+ "movaps 4*T_FLOAT(%0), %%xmm2 \n"
+ "mulps %%xmm0, %%xmm2 \n"
+ "movaps %%xmm2, 4*T_FLOAT(%2) \n"
+
+ "movaps 8*T_FLOAT(%0), %%xmm3 \n"
+ "mulps %%xmm0, %%xmm3 \n"
+ "movaps %%xmm3, 8*T_FLOAT(%2) \n"
+
+ "movaps 12*T_FLOAT(%0), %%xmm4 \n"
+ "mulps %%xmm0, %%xmm4 \n"
+ "movaps %%xmm4, 12*T_FLOAT(%2) \n"
+
+ "addl $16*T_FLOAT, %0 \n"
+ "addl $16*T_FLOAT, %2 \n"
+ "loop 1b \n"
+ :
+ /* in, value, out, n */
+ :"r"(w[1]),"r"(w[2]),"r"(w[3]),"c"(w[4])
+ :"%xmm0","%xmm1","%xmm2","%xmm3","%xmm4"
+ );
+ return w+5;
+}
+
+t_int *sqr_perf_simd(t_int *w)
+{
+ asm(
+ ".set T_FLOAT,4 \n"
+
+ "shrl $4, %2 \n" /* divide by 16 */
+
+ /* loop: *out = *in * *in */
+ "1: \n"
+ "movaps (%0,%3), %%xmm0 \n"
+ "mulps %%xmm0, %%xmm0 \n"
+ "movaps %%xmm0, (%1) \n"
+
+ "movaps 4*T_FLOAT(%0,%3), %%xmm1 \n"
+ "mulps %%xmm1, %%xmm1 \n"
+ "movaps %%xmm1, 4*T_FLOAT(%1) \n"
+
+ "movaps 8*T_FLOAT(%0,%3), %%xmm2 \n"
+ "mulps %%xmm2, %%xmm2 \n"
+ "movaps %%xmm2, 8*T_FLOAT(%1) \n"
+
+ "movaps 12*T_FLOAT(%0,%3), %%xmm3 \n"
+ "mulps %%xmm3, %%xmm3 \n"
+ "movaps %%xmm3, 12*T_FLOAT(%1) \n"
+
+ "addl $16*T_FLOAT, %1 \n"
+ "addl $16*T_FLOAT, %3 \n"
+ "loop 1b \n"
+ :
+ /* in, out, n */
+ :"r"(w[1]),"r"(w[2]),"c"(w[3]),"r"(0)
+ :"%xmm0","%xmm1","%xmm2","%xmm3"
+ );
+ return w+4;
+}
+
+
+t_int* over_perf_simd(t_int * w)
+{
+ asm(
+ ".set T_FLOAT,4 \n"
+
+ "shrl $4, %3 \n" /* divide by 16 */
+
+ /* loop: *out = *in1 / *in2 */
+ "1: \n"
+ "movaps (%0,%4), %%xmm0 \n"
+ "movaps (%1,%4), %%xmm1 \n"
+ "divps %%xmm1, %%xmm0 \n"
+ "movaps %%xmm0, (%2,%4) \n"
+
+ "movaps 4*T_FLOAT(%0,%4), %%xmm2 \n"
+ "movaps 4*T_FLOAT(%1,%4), %%xmm3 \n"
+ "divps %%xmm3, %%xmm2 \n"
+ "movaps %%xmm2, 4*T_FLOAT(%2,%4) \n"
+
+ "movaps 8*T_FLOAT(%0,%4), %%xmm4 \n"
+ "movaps 8*T_FLOAT(%1,%4), %%xmm5 \n"
+ "divps %%xmm5, %%xmm4 \n"
+ "movaps %%xmm4, 8*T_FLOAT(%2,%4) \n"
+
+ "movaps 12*T_FLOAT(%0,%4), %%xmm6 \n"
+ "movaps 12*T_FLOAT(%1,%4), %%xmm7 \n"
+ "divps %%xmm7, %%xmm6 \n"
+ "movaps %%xmm6, 12*T_FLOAT(%2,%4) \n"
+
+ "addl $16*T_FLOAT, %4 \n"
+ "loop 1b \n"
+ :
+ /* in1, in2, out, n */
+ :"r"(w[1]),"r"(w[2]),"r"(w[3]),"c"(w[4]),"r"(0)
+ :"%xmm0","%xmm1","%xmm2","%xmm3","%xmm4","%xmm5","%xmm6","%xmm7"
+ );
+ return w+5;
+}
+
+t_int* scalarover_perf_simd(t_int *w)
+{
+ asm(
+ ".set T_FLOAT,4 \n"
+
+ "movss (%1), %%xmm0 \n"
+ "shufps $0, %%xmm0, %%xmm0 \n"
+ "shrl $4, %3 \n" /* divide by 16 */
+
+ /* loop: *out = *in / value */
+ "1: \n"
+ "movaps (%0), %%xmm1 \n"
+ "divps %%xmm0, %%xmm1 \n"
+ "movaps %%xmm1, (%2) \n"
+
+ "movaps 4*T_FLOAT(%0), %%xmm2 \n"
+ "divps %%xmm0, %%xmm2 \n"
+ "movaps %%xmm2, 4*T_FLOAT(%2) \n"
+
+ "movaps 8*T_FLOAT(%0), %%xmm3 \n"
+ "divps %%xmm0, %%xmm3 \n"
+ "movaps %%xmm3, 8*T_FLOAT(%2) \n"
+
+ "movaps 12*T_FLOAT(%0), %%xmm4 \n"
+ "divps %%xmm0, %%xmm4 \n"
+ "movaps %%xmm4, 12*T_FLOAT(%2) \n"
+
+ "addl $16*T_FLOAT, %0 \n"
+ "addl $16*T_FLOAT, %2 \n"
+ "loop 1b \n"
+ :
+ /* in, value, out, n */
+ :"r"(w[1]),"r"(w[2]),"r"(w[3]),"c"(w[4])
+ :"%xmm0","%xmm1","%xmm2","%xmm3","%xmm4"
+ );
+ return w+5;
+}
+
+
+t_int* min_perf_simd(t_int * w)
+{
+ asm(
+ ".set T_FLOAT,4 \n"
+
+ "shrl $4, %3 \n" /* divide by 16 */
+
+ /* loop: *out = min (*in1, *in2) */
+ "1: \n"
+ "movaps (%0,%4), %%xmm0 \n"
+ "movaps (%1,%4), %%xmm1 \n"
+ "minps %%xmm1, %%xmm0 \n"
+ "movaps %%xmm0, (%2,%4) \n"
+
+ "movaps 4*T_FLOAT(%0,%4), %%xmm2 \n"
+ "movaps 4*T_FLOAT(%1,%4), %%xmm3 \n"
+ "minps %%xmm3, %%xmm2 \n"
+ "movaps %%xmm2, 4*T_FLOAT(%2,%4) \n"
+
+ "movaps 8*T_FLOAT(%0,%4), %%xmm4 \n"
+ "movaps 8*T_FLOAT(%1,%4), %%xmm5 \n"
+ "minps %%xmm5, %%xmm4 \n"
+ "movaps %%xmm4, 8*T_FLOAT(%2,%4) \n"
+
+ "movaps 12*T_FLOAT(%0,%4), %%xmm6 \n"
+ "movaps 12*T_FLOAT(%1,%4), %%xmm7 \n"
+ "minps %%xmm7, %%xmm6 \n"
+ "movaps %%xmm6, 12*T_FLOAT(%2,%4) \n"
+
+ "addl $16*T_FLOAT, %4 \n"
+ "loop 1b \n"
+ :
+ /* in1, in2, out, n */
+ :"r"(w[1]),"r"(w[2]),"r"(w[3]),"c"(w[4]),"r"(0)
+ :"%xmm0","%xmm1","%xmm2","%xmm3","%xmm4","%xmm5","%xmm6","%xmm7"
+ );
+ return w+5;
+}
+
+
+t_int* scalarmin_perf_simd(t_int *w)
+{
+ asm(
+ ".set T_FLOAT,4 \n"
+
+ "movss (%1), %%xmm0 \n"
+ "shufps $0, %%xmm0, %%xmm0 \n"
+ "shrl $4, %3 \n" /* divide by 16 */
+
+ /* loop: *out = min(*in, value) */
+ "1: \n"
+ "movaps (%0), %%xmm1 \n"
+ "minps %%xmm0, %%xmm1 \n"
+ "movaps %%xmm1, (%2) \n"
+
+ "movaps 4*T_FLOAT(%0), %%xmm2 \n"
+ "minps %%xmm0, %%xmm2 \n"
+ "movaps %%xmm2, 4*T_FLOAT(%2) \n"
+
+ "movaps 8*T_FLOAT(%0), %%xmm3 \n"
+ "minps %%xmm0, %%xmm3 \n"
+ "movaps %%xmm3, 8*T_FLOAT(%2) \n"
+
+ "movaps 12*T_FLOAT(%0), %%xmm4 \n"
+ "minps %%xmm0, %%xmm4 \n"
+ "movaps %%xmm4, 12*T_FLOAT(%2) \n"
+
+ "addl $16*T_FLOAT, %0 \n"
+ "addl $16*T_FLOAT, %2 \n"
+ "loop 1b \n"
+ :
+ /* in, value, out, n */
+ :"r"(w[1]),"r"(w[2]),"r"(w[3]),"c"(w[4])
+ :"%xmm0","%xmm1","%xmm2","%xmm3","%xmm4"
+ );
+ return w+5;
+}
+
+
+t_int* max_perf_simd(t_int * w)
+{
+ asm(
+ ".set T_FLOAT,4 \n"
+
+ "shrl $4, %3 \n" /* divide by 16 */
+
+ /* loop: *out = max (*in1, *in2) */
+ "1: \n"
+ "movaps (%0,%4), %%xmm0 \n"
+ "movaps (%1,%4), %%xmm1 \n"
+ "maxps %%xmm1, %%xmm0 \n"
+ "movaps %%xmm0, (%2,%4) \n"
+
+ "movaps 4*T_FLOAT(%0,%4), %%xmm2 \n"
+ "movaps 4*T_FLOAT(%1,%4), %%xmm3 \n"
+ "maxps %%xmm3, %%xmm2 \n"
+ "movaps %%xmm2, 4*T_FLOAT(%2,%4) \n"
+
+ "movaps 8*T_FLOAT(%0,%4), %%xmm4 \n"
+ "movaps 8*T_FLOAT(%1,%4), %%xmm5 \n"
+ "maxps %%xmm5, %%xmm4 \n"
+ "movaps %%xmm4, 8*T_FLOAT(%2,%4) \n"
+
+ "movaps 12*T_FLOAT(%0,%4), %%xmm6 \n"
+ "movaps 12*T_FLOAT(%1,%4), %%xmm7 \n"
+ "maxps %%xmm7, %%xmm6 \n"
+ "movaps %%xmm6, 12*T_FLOAT(%2,%4) \n"
+
+ "addl $16*T_FLOAT, %4 \n"
+ "loop 1b \n"
+ :
+ /* in1, in2, out, n */
+ :"r"(w[1]),"r"(w[2]),"r"(w[3]),"c"(w[4]),"r"(0)
+ :"%xmm0","%xmm1","%xmm2","%xmm3","%xmm4","%xmm5","%xmm6","%xmm7"
+ );
+ return w+5;
+}
+
+
+t_int* scalarmax_perf_simd(t_int *w)
+{
+ asm(
+ ".set T_FLOAT,4 \n"
+
+ "movss (%1), %%xmm0 \n"
+ "shufps $0, %%xmm0, %%xmm0 \n"
+ "shrl $4, %3 \n" /* divide by 16 */
+
+ /* loop: *out = max(*in, value) */
+ "1: \n"
+ "movaps (%0), %%xmm1 \n"
+ "maxps %%xmm0, %%xmm1 \n"
+ "movaps %%xmm1, (%2) \n"
+
+ "movaps 4*T_FLOAT(%0), %%xmm2 \n"
+ "maxps %%xmm0, %%xmm2 \n"
+ "movaps %%xmm2, 4*T_FLOAT(%2) \n"
+
+ "movaps 8*T_FLOAT(%0), %%xmm3 \n"
+ "maxps %%xmm0, %%xmm3 \n"
+ "movaps %%xmm3, 8*T_FLOAT(%2) \n"
+
+ "movaps 12*T_FLOAT(%0), %%xmm4 \n"
+ "maxps %%xmm0, %%xmm4 \n"
+ "movaps %%xmm4, 12*T_FLOAT(%2) \n"
+
+ "addl $16*T_FLOAT, %0 \n"
+ "addl $16*T_FLOAT, %2 \n"
+ "loop 1b \n"
+ :
+ /* in, value, out, n */
+ :"r"(w[1]),"r"(w[2]),"r"(w[3]),"c"(w[4])
+ :"%xmm0","%xmm1","%xmm2","%xmm3","%xmm4"
+ );
+ return w+5;
+}
+
+t_int* clip_perf_simd(t_int *w)
+{
+ asm(
+ ".set T_FLOAT,4 \n"
+
+ "movss (%2), %%xmm0 \n" /* lo */
+ "shufps $0, %%xmm0, %%xmm0 \n"
+ "movss (%3), %%xmm1 \n" /* hi */
+ "shufps $0, %%xmm1, %%xmm1 \n"
+
+ "shrl $4, %4 \n" /* divide by 16 */
+
+ /* loop: *out = min ( max (lo, *in), hi )*/
+ "1: \n"
+ "movaps (%0), %%xmm2 \n"
+ "maxps %%xmm0, %%xmm2 \n"
+ "minps %%xmm1, %%xmm2 \n"
+ "movaps %%xmm2, (%1) \n"
+
+ "movaps 4*T_FLOAT(%0), %%xmm3 \n"
+ "maxps %%xmm0, %%xmm3 \n"
+ "minps %%xmm1, %%xmm3 \n"
+ "movaps %%xmm3, 4*T_FLOAT(%1) \n"
+
+ "movaps 8*T_FLOAT(%0), %%xmm4 \n"
+ "maxps %%xmm0, %%xmm4 \n"
+ "minps %%xmm1, %%xmm4 \n"
+ "movaps %%xmm4, 8*T_FLOAT(%1) \n"
+
+ "movaps 12*T_FLOAT(%0), %%xmm5 \n"
+ "maxps %%xmm0, %%xmm5 \n"
+ "minps %%xmm1, %%xmm5 \n"
+ "movaps %%xmm5, 12*T_FLOAT(%1) \n"
+
+ "addl $16*T_FLOAT, %0 \n"
+ "addl $16*T_FLOAT, %1 \n"
+ "loop 1b \n"
+ :
+ /* in, out, lo, hi, n */
+ :"r"(w[1]),"r"(w[2]),"r"(w[3]),"r"(w[4]),"c"(w[5])
+ :"%xmm0","%xmm1","%xmm2","%xmm3","%xmm4","%xmm5"
+ );
+ return w+6;
+}
+
+
+t_int* sigsqrt_perf_simd(t_int *w)
+{
+ asm(
+ ".set T_FLOAT,4 \n"
+
+ "shrl $4, %2 \n" /* divide by 16 */
+
+ /* loop: *out = sqrt(*in) */
+ "1: \n"
+ "movaps (%0), %%xmm0 \n"
+ "sqrtps %%xmm0, %%xmm0 \n"
+ "movaps %%xmm0, (%1) \n"
+
+ "movaps 4*T_FLOAT(%0), %%xmm1 \n"
+ "sqrtps %%xmm1, %%xmm1 \n"
+ "movaps %%xmm1, 4*T_FLOAT(%1) \n"
+
+ "movaps 8*T_FLOAT(%0), %%xmm2 \n"
+ "sqrtps %%xmm2, %%xmm2 \n"
+ "movaps %%xmm2, 8*T_FLOAT(%1) \n"
+
+ "movaps 12*T_FLOAT(%0), %%xmm3 \n"
+ "sqrtps %%xmm3, %%xmm3 \n"
+ "movaps %%xmm3, 12*T_FLOAT(%1) \n"
+
+ "addl $16*T_FLOAT, %0 \n"
+ "addl $16*T_FLOAT, %1 \n"
+ "loop 1b \n"
+ :
+ /* in, out, n */
+ :"r"(w[1]),"r"(w[2]),"c"(w[3])
+ :"%xmm0","%xmm1","%xmm2","%xmm3"
+ );
+ return w+4;
+}
+
+
+t_int* sigrsqrt_perf_simd(t_int *w)
+{
+ asm(
+ ".set T_FLOAT,4 \n"
+
+ "shrl $4, %2 \n" /* divide by 16 */
+
+ /* loop: *out = sqrt(*in) */
+ "1: \n"
+ "movaps (%0), %%xmm0 \n"
+ "rsqrtps %%xmm0, %%xmm0 \n"
+ "movaps %%xmm0, (%1) \n"
+
+ "movaps 4*T_FLOAT(%0), %%xmm1 \n"
+ "rsqrtps %%xmm1, %%xmm1 \n"
+ "movaps %%xmm1, 4*T_FLOAT(%1) \n"
+
+ "movaps 8*T_FLOAT(%0), %%xmm2 \n"
+ "rsqrtps %%xmm2, %%xmm2 \n"
+ "movaps %%xmm2, 8*T_FLOAT(%1) \n"
+
+ "movaps 12*T_FLOAT(%0), %%xmm3 \n"
+ "rsqrtps %%xmm3, %%xmm3 \n"
+ "movaps %%xmm3, 12*T_FLOAT(%1) \n"
+
+ "addl $16*T_FLOAT, %0 \n"
+ "addl $16*T_FLOAT, %1 \n"
+ "loop 1b \n"
+ :
+ /* in, out, n */
+ :"r"(w[1]),"r"(w[2]),"c"(w[3])
+ :"%xmm0","%xmm1","%xmm2","%xmm3"
+ );
+ return w+4;
+}
+
+
+/* TB: runtime check */
+int simd_runtime_check()
+{
+ unsigned int eax, edx, ret;
+ __asm__("push %%ebx \n" /* ebx might be used as PIC register :-( */
+ "cpuid \n"
+ "pop %%ebx \n"
+ : "=a"(eax),"=d"(edx) : "a" (1): "cx");
+ ret = 0x2000000 & edx;
+ return (ret);
+}
+
+float env_tilde_accum_simd(t_float* in, t_float* hp, t_int n)
+{
+ float ret;
+ asm(
+ ".set T_FLOAT,4 \n"
+
+ "shrl $4, %2 \n" /* divide by 16 */
+ "xorps %%xmm2, %%xmm2 \n" /* zero values */
+ "xorps %%xmm3, %%xmm3 \n"
+ "xorps %%xmm4, %%xmm4 \n"
+ "xorps %%xmm5, %%xmm5 \n"
+
+
+ "1: \n"
+ "movaps -4*T_FLOAT(%1), %%xmm0 \n"
+ "movhlps %%xmm0, %%xmm1 \n" /* reversing xmm0 CHECK!!!*/
+ "shufps $68, %%xmm1, %%xmm0 \n"
+ "movaps (%3), %%xmm1 \n"
+ "mulps %%xmm0, %%xmm0 \n"
+ "mulps %%xmm1, %%xmm0 \n"
+ "addps %%xmm0, %%xmm2 \n"
+
+ "movaps -8*T_FLOAT(%1), %%xmm0 \n"
+ "movhlps %%xmm0, %%xmm1 \n" /* reversing xmm0 */
+ "shufps $68, %%xmm1, %%xmm0 \n"
+ "movaps 4*T_FLOAT(%3), %%xmm1 \n"
+ "mulps %%xmm0, %%xmm0 \n"
+ "mulps %%xmm1, %%xmm0 \n"
+ "addps %%xmm0, %%xmm2 \n"
+
+ "movaps -12*T_FLOAT(%1), %%xmm0 \n"
+ "movhlps %%xmm0, %%xmm1 \n" /* reversing xmm0 */
+ "shufps $68, %%xmm1, %%xmm0 \n"
+ "movaps 8*T_FLOAT(%3), %%xmm1 \n"
+ "mulps %%xmm0, %%xmm0 \n"
+ "mulps %%xmm1, %%xmm0 \n"
+ "addps %%xmm0, %%xmm2 \n"
+
+ "movaps -16*T_FLOAT(%1), %%xmm0 \n"
+ "movhlps %%xmm0, %%xmm1 \n" /* reversing xmm0 */
+ "shufps $68, %%xmm1, %%xmm0 \n"
+ "movaps 12*T_FLOAT(%3), %%xmm1 \n"
+ "mulps %%xmm0, %%xmm0 \n"
+ "mulps %%xmm1, %%xmm0 \n"
+ "addps %%xmm0, %%xmm2 \n"
+
+ "addl $-16*T_FLOAT,%1 \n"
+ "addl $16*T_FLOAT,%3 \n"
+ "loop 1b \n"
+
+ "movhlps %%xmm2, %%xmm3 \n" /* unpack xmm0 */
+ "movups %%xmm2, %%xmm4 \n"
+ "movups %%xmm3, %%xmm5 \n"
+ "shufps $81, %%xmm4, %%xmm4 \n"
+ "shufps $81, %%xmm5, %%xmm5 \n"
+
+ "addss %%xmm2, %%xmm3 \n"
+ "addss %%xmm3, %%xmm4 \n"
+ "addss %%xmm4, %%xmm5 \n"
+
+ "movss %%xmm5, (%0) \n"
+
+ :
+ :"r"(&ret),"r"(in),"c"(n), "r"(hp)
+ :"%xmm0","%xmm1","%xmm2","%xmm3", "%xmm4", "%xmm5");
+ return ret;
+}
+
+
+float peakvec_simd(t_float* vec, t_int n, t_float cur_max)
+{
+ asm(
+ ".section .rodata \n"
+ ".align 16 \n"
+ "2: \n"
+ ".long 2147483647 \n" /* bitmask for abs */
+ ".long 2147483647 \n" /* 0x7fffffff */
+ ".long 2147483647 \n"
+ ".long 2147483647 \n"
+
+ ".set T_FLOAT,4 \n"
+ ".text \n"
+
+ "shrl $4, %2 \n" /* divide by 16 */
+ "movaps (2b), %%xmm0 \n"
+
+ "movss (%0), %%xmm5 \n" /* cur_max */
+ "shufps $0, %%xmm5, %%xmm5 \n"
+
+ "1: \n"
+ "movaps (%1), %%xmm1 \n"
+ "andps %%xmm0, %%xmm1 \n"
+ "maxps %%xmm1, %%xmm5 \n"
+
+ "movaps 4*T_FLOAT(%1), %%xmm1 \n"
+ "andps %%xmm0, %%xmm1 \n"
+ "maxps %%xmm1, %%xmm5 \n"
+
+ "movaps 8*T_FLOAT(%1), %%xmm1 \n"
+ "andps %%xmm0, %%xmm1 \n"
+ "maxps %%xmm1, %%xmm5 \n"
+
+ "movaps 12*T_FLOAT(%1), %%xmm1 \n"
+ "andps %%xmm0, %%xmm1 \n"
+ "maxps %%xmm1, %%xmm5 \n"
+
+ "addl $16*T_FLOAT, %1 \n"
+ "loop 1b \n"
+
+ "movhlps %%xmm5, %%xmm2 \n"
+ "movaps %%xmm5, %%xmm3 \n"
+ "movaps %%xmm2, %%xmm4 \n"
+ "shufps $81, %%xmm3, %%xmm3 \n"
+ "shufps $81, %%xmm4, %%xmm4 \n"
+
+ "maxss %%xmm2, %%xmm3 \n"
+ "maxss %%xmm3, %%xmm4 \n"
+ "maxss %%xmm4, %%xmm5 \n"
+
+ "movss %%xmm5, (%0) \n"
+
+ :
+ :"r"(&cur_max), "r"(vec),"c"(n)
+ :"%xmm0","%xmm1","%xmm2","%xmm3", "%xmm4", "%xmm5");
+
+ return cur_max;
+}
+
+void line_tilde_slope_simd(t_float* out, t_int n, t_float* value,
+ t_float* slopes, t_float* slopestep)
+{
+ asm(
+ ".set T_FLOAT,4 \n"
+ "movss (%2),%%xmm0 \n" /* value */
+ "shufps $0, %%xmm0, %%xmm0 \n"
+ "movaps (%3), %%xmm1 \n" /* slopes */
+
+ "addps %%xmm1, %%xmm0 \n" /* compute first output */
+
+ "movss (%4), %%xmm2 \n" /* slopestep */
+ "shufps $0, %%xmm2, %%xmm2 \n"
+
+ "shrl $4, %1 \n" /* n>>4 */
+
+ "1: \n"
+ "movaps %%xmm0, (%0) \n"
+ "addps %%xmm2, %%xmm0 \n"
+
+ "movaps %%xmm0, 4*T_FLOAT(%0) \n"
+ "addps %%xmm2, %%xmm0 \n"
+
+ "movaps %%xmm0, 8*T_FLOAT(%0) \n"
+ "addps %%xmm2, %%xmm0 \n"
+
+ "movaps %%xmm0, 12*T_FLOAT(%0) \n"
+ "addps %%xmm2, %%xmm0 \n"
+
+
+ "addl $16*T_FLOAT, %0 \n"
+ "loop 1b \n"
+
+
+ :
+ :"r"(out),"c"(n), "r"(value), "r"(slopes),
+ "r"(slopestep)
+ :"%xmm0", "%xmm1", "%xmm2");
+
+}
+
+#endif
+
diff --git a/desiredata/src/m_simd_ve_gcc.c b/desiredata/src/m_simd_ve_gcc.c
new file mode 100644
index 00000000..1f08d748
--- /dev/null
+++ b/desiredata/src/m_simd_ve_gcc.c
@@ -0,0 +1,748 @@
+/*
+ Implementation of SIMD functionality for Apple Velocity Engine (AltiVec) with GCC compiler
+ added by T.Grill
+*/
+
+#include "m_pd.h"
+#include "m_simd.h"
+
+#if defined(__GNUC__) && defined(__POWERPC__) && defined(__ALTIVEC__)
+
+//#define USEVECLIB
+
+#ifdef USEVECLIB
+#include <vecLib/vDSP.h>
+#include <vecLib/vfp.h>
+#endif
+
+/* functions for unaligned vector data - taken from http://developer.apple.com/hardware/ve/alignment.html */
+
+/* T.Grill - this first version _should_ work! but it doesn't... */
+#if 0
+#define LoadUnaligned(v) (vec_perm( vec_ld( 0, (const vector float *)(v) ), vec_ld( 16, (const vector float *)(v) ), vec_lvsl( 0, (float *) (v) ) ))
+#else
+/* instead take the slower second one */
+static vector float LoadUnaligned(const float *v)
+{
+ union tmpstruct { float f[4]; vector float vec; } tmp;
+ tmp.f[0] = *(float *)v;
+ return vec_splat(vec_ld(0,&tmp.vec),0);
+}
+#endif
+
+
+#define IsVectorAligned(where) ((unsigned long)(where)&(sizeof(vector float)-1) == 0)
+/*
+#define LoadValue(where) (IsVectorAligned((void *)(where))?vec_splat(vec_ld(0,(vector float *)(where)),0):LoadUnaligned((vector float *)(where)))
+*/
+/* always assume unaligned */
+#define LoadValue(where) LoadUnaligned((const float *)(where))
+
+void zerovec_simd(t_float *dst,int n)
+{
+ const vector float zero = (vector float)(0);
+ for(n >>= 4; n--; dst += 16) {
+ vec_st(zero, 0,dst);
+ vec_st(zero,16,dst);
+ vec_st(zero,32,dst);
+ vec_st(zero,48,dst);
+ }
+}
+
+void setvec_simd(t_float *dst,t_float v,int n)
+{
+ const vector float arg = LoadValue(&v);
+ for(n >>= 4; n--; dst += 16) {
+ vec_st(arg, 0,dst);
+ vec_st(arg,16,dst);
+ vec_st(arg,32,dst);
+ vec_st(arg,48,dst);
+ }
+}
+
+void copyvec_simd(t_float *dst,const t_float *src,int n)
+{
+ for(n >>= 4; n--; src += 16,dst += 16) {
+ vector float a1 = vec_ld( 0,src);
+ vector float a2 = vec_ld(16,src);
+ vector float a3 = vec_ld(32,src);
+ vector float a4 = vec_ld(48,src);
+ vec_st(a1, 0,dst);
+ vec_st(a2,16,dst);
+ vec_st(a3,32,dst);
+ vec_st(a4,48,dst);
+ }
+}
+
+void addvec_simd(t_float *dst,const t_float *src,int n)
+{
+#ifdef USEVECLIB
+ vadd(dst,1,src,1,dst,1,n);
+#else
+ for(n >>= 4; n--; src += 16,dst += 16) {
+ vector float a1 = vec_ld( 0,dst),b1 = vec_ld( 0,src);
+ vector float a2 = vec_ld(16,dst),b2 = vec_ld(16,src);
+ vector float a3 = vec_ld(32,dst),b3 = vec_ld(32,src);
+ vector float a4 = vec_ld(48,dst),b4 = vec_ld(48,src);
+
+ a1 = vec_add(a1,b1);
+ a2 = vec_add(a2,b2);
+ a3 = vec_add(a3,b3);
+ a4 = vec_add(a4,b4);
+
+ vec_st(a1, 0,dst);
+ vec_st(a2,16,dst);
+ vec_st(a3,32,dst);
+ vec_st(a4,48,dst);
+ }
+#endif
+}
+
+/* no bad float testing for PPC! */
+void testcopyvec_simd(t_float *dst,const t_float *src,int n)
+{
+ copyvec_simd(dst,src,n);
+}
+
+void testaddvec_simd(t_float *dst,const t_float *src,int n)
+{
+ addvec_simd(dst,src,n);
+}
+
+
+t_int *zero_perf_simd(t_int *w)
+{
+ zerovec_simd((t_float *)w[1],w[2]);
+ return w+3;
+}
+
+t_int *copy_perf_simd(t_int *w)
+{
+ copyvec_simd((t_float *)w[2],(const t_float *)w[1],w[3]);
+ return w+4;
+}
+
+t_int *sig_tilde_perf_simd(t_int *w)
+{
+ setvec_simd((t_float *)w[2],*(const t_float *)w[1],w[3]);
+ return w+4;
+}
+
+t_int *plus_perf_simd(t_int *w)
+{
+#ifdef USEVECLIB
+ vadd((const t_float *)w[1],1,(const t_float *)w[2],1,(t_float *)w[3],1,w[4]);
+#else
+ const t_float *src1 = (const t_float *)w[1];
+ const t_float *src2 = (const t_float *)w[2];
+ t_float *dst = (t_float *)w[3];
+ int n = w[4]>>4;
+
+ for(; n--; src1 += 16,src2 += 16,dst += 16) {
+ vector float a1 = vec_ld( 0,src1),b1 = vec_ld( 0,src2);
+ vector float a2 = vec_ld(16,src1),b2 = vec_ld(16,src2);
+ vector float a3 = vec_ld(32,src1),b3 = vec_ld(32,src2);
+ vector float a4 = vec_ld(48,src1),b4 = vec_ld(48,src2);
+
+ a1 = vec_add(a1,b1);
+ a2 = vec_add(a2,b2);
+ a3 = vec_add(a3,b3);
+ a4 = vec_add(a4,b4);
+
+ vec_st(a1, 0,dst);
+ vec_st(a2,16,dst);
+ vec_st(a3,32,dst);
+ vec_st(a4,48,dst);
+ }
+#endif
+ return w+5;
+}
+
+t_int *scalarplus_perf_simd(t_int *w)
+{
+ const t_float *src = (const t_float *)w[1];
+ const vector float arg = LoadValue(w[2]);
+ t_float *dst = (t_float *)w[3];
+ int n = w[4]>>4;
+
+ for(; n--; src += 16,dst += 16) {
+ vector float a1 = vec_ld( 0,src);
+ vector float a2 = vec_ld(16,src);
+ vector float a3 = vec_ld(32,src);
+ vector float a4 = vec_ld(48,src);
+
+ a1 = vec_add(a1,arg);
+ a2 = vec_add(a2,arg);
+ a3 = vec_add(a3,arg);
+ a4 = vec_add(a4,arg);
+
+ vec_st(a1, 0,dst);
+ vec_st(a2,16,dst);
+ vec_st(a3,32,dst);
+ vec_st(a4,48,dst);
+ }
+ return w+5;
+}
+
+t_int *minus_perf_simd(t_int *w)
+{
+#if 0 //def USEVECLIB
+ /* vsub is buggy for some OSX versions! */
+ vsub((const t_float *)w[1],1,(const t_float *)w[2],1,(t_float *)w[3],1,w[4]);
+#else
+ const t_float *src1 = (const t_float *)w[1];
+ const t_float *src2 = (const t_float *)w[2];
+ t_float *dst = (t_float *)w[3];
+ int n = w[4]>>4;
+
+ for(; n--; src1 += 16,src2 += 16,dst += 16) {
+ vector float a1 = vec_ld( 0,src1),b1 = vec_ld( 0,src2);
+ vector float a2 = vec_ld(16,src1),b2 = vec_ld(16,src2);
+ vector float a3 = vec_ld(32,src1),b3 = vec_ld(32,src2);
+ vector float a4 = vec_ld(48,src1),b4 = vec_ld(48,src2);
+
+ a1 = vec_sub(a1,b1);
+ a2 = vec_sub(a2,b2);
+ a3 = vec_sub(a3,b3);
+ a4 = vec_sub(a4,b4);
+
+ vec_st(a1, 0,dst);
+ vec_st(a2,16,dst);
+ vec_st(a3,32,dst);
+ vec_st(a4,48,dst);
+ }
+#endif
+ return w+5;
+}
+
+t_int *scalarminus_perf_simd(t_int *w)
+{
+ const t_float *src = (const t_float *)w[1];
+ const vector float arg = LoadValue(w[2]);
+ t_float *dst = (t_float *)w[3];
+ int n = w[4]>>4;
+
+ for(; n--; src += 16,dst += 16) {
+ vector float a1 = vec_ld( 0,src);
+ vector float a2 = vec_ld(16,src);
+ vector float a3 = vec_ld(32,src);
+ vector float a4 = vec_ld(48,src);
+
+ a1 = vec_sub(a1,arg);
+ a2 = vec_sub(a2,arg);
+ a3 = vec_sub(a3,arg);
+ a4 = vec_sub(a4,arg);
+
+ vec_st(a1, 0,dst);
+ vec_st(a2,16,dst);
+ vec_st(a3,32,dst);
+ vec_st(a4,48,dst);
+ }
+ return w+5;
+}
+
+t_int *times_perf_simd(t_int *w)
+{
+#ifdef USEVECLIB
+ vmul((const t_float *)w[1],1,(const t_float *)w[2],1,(t_float *)w[3],1,w[4]);
+#else
+ const t_float *src1 = (const t_float *)w[1];
+ const t_float *src2 = (const t_float *)w[2];
+ t_float *dst = (t_float *)w[3];
+ const vector float zero = (vector float)(0);
+ int n = w[4]>>4;
+
+ for(; n--; src1 += 16,src2 += 16,dst += 16) {
+ vector float a1 = vec_ld( 0,src1),b1 = vec_ld( 0,src2);
+ vector float a2 = vec_ld(16,src1),b2 = vec_ld(16,src2);
+ vector float a3 = vec_ld(32,src1),b3 = vec_ld(32,src2);
+ vector float a4 = vec_ld(48,src1),b4 = vec_ld(48,src2);
+
+ a1 = vec_madd(a1,b1,zero);
+ a2 = vec_madd(a2,b2,zero);
+ a3 = vec_madd(a3,b3,zero);
+ a4 = vec_madd(a4,b4,zero);
+
+ vec_st(a1, 0,dst);
+ vec_st(a2,16,dst);
+ vec_st(a3,32,dst);
+ vec_st(a4,48,dst);
+ }
+#endif
+ return w+5;
+}
+
+t_int *scalartimes_perf_simd(t_int *w)
+{
+#ifdef USEVECLIB
+ vsmul((const t_float *)w[1],1,(t_float *)w[2],(t_float *)w[3],1,w[4]);
+#else
+ const t_float *src = (const t_float *)w[1];
+ const vector float arg = LoadValue(w[2]);
+ t_float *dst = (t_float *)w[3];
+ const vector float zero = (vector float)(0);
+ int n = w[4]>>4;
+
+ for(; n--; src += 16,dst += 16) {
+ vector float a1 = vec_ld( 0,src);
+ vector float a2 = vec_ld(16,src);
+ vector float a3 = vec_ld(32,src);
+ vector float a4 = vec_ld(48,src);
+
+ a1 = vec_madd(a1,arg,zero);
+ a2 = vec_madd(a2,arg,zero);
+ a3 = vec_madd(a3,arg,zero);
+ a4 = vec_madd(a4,arg,zero);
+
+ vec_st(a1, 0,dst);
+ vec_st(a2,16,dst);
+ vec_st(a3,32,dst);
+ vec_st(a4,48,dst);
+ }
+#endif
+ return w+5;
+}
+
+t_int *sqr_perf_simd(t_int *w)
+{
+#ifdef USEVECLIB
+ vsq((const t_float *)w[1],1,(t_float *)w[2],1,w[3]);
+#else
+ const t_float *src = (const t_float *)w[1];
+ t_float *dst = (t_float *)w[2];
+ const vector float zero = (vector float)(0);
+ int n = w[3]>>4;
+
+ for(; n--; src += 16,dst += 16) {
+ vector float a1 = vec_ld( 0,src);
+ vector float a2 = vec_ld(16,src);
+ vector float a3 = vec_ld(32,src);
+ vector float a4 = vec_ld(48,src);
+
+ a1 = vec_madd(a1,a1,zero);
+ a2 = vec_madd(a2,a2,zero);
+ a3 = vec_madd(a3,a3,zero);
+ a4 = vec_madd(a4,a4,zero);
+
+ vec_st(a1, 0,dst);
+ vec_st(a2,16,dst);
+ vec_st(a3,32,dst);
+ vec_st(a4,48,dst);
+ }
+#endif
+ return w+4;
+}
+
+t_int *over_perf_simd(t_int *w)
+{
+ const t_float *src1 = (const t_float *)w[1];
+ const t_float *src2 = (const t_float *)w[2];
+ t_float *dst = (t_float *)w[3];
+ const vector float zero = (vector float)(0);
+ const vector float one = (vector float)(1);
+ int n = w[4]>>4;
+
+ for(; n--; src1 += 16,src2 += 16,dst += 16) {
+#ifdef USEVECLIB
+ /* no zero checking here */
+ vec_st(vdivf(vec_ld( 0,src1),vec_ld( 0,src2)), 0,dst);
+ vec_st(vdivf(vec_ld(16,src1),vec_ld(16,src2)),16,dst);
+ vec_st(vdivf(vec_ld(32,src1),vec_ld(32,src2)),32,dst);
+ vec_st(vdivf(vec_ld(48,src1),vec_ld(48,src2)),48,dst);
+#else
+ vector float data1 = vec_ld( 0,src2);
+ vector float data2 = vec_ld(16,src2);
+ vector float data3 = vec_ld(32,src2);
+ vector float data4 = vec_ld(48,src2);
+
+ vector unsigned char mask1 = vec_nor((vector unsigned char)vec_cmpeq(data1,zero),(vector unsigned char)zero); /* bit mask... all 0 for data = 0., all 1 else */
+ vector unsigned char mask2 = vec_nor((vector unsigned char)vec_cmpeq(data2,zero),(vector unsigned char)zero); /* bit mask... all 0 for data = 0., all 1 else */
+ vector unsigned char mask3 = vec_nor((vector unsigned char)vec_cmpeq(data3,zero),(vector unsigned char)zero); /* bit mask... all 0 for data = 0., all 1 else */
+ vector unsigned char mask4 = vec_nor((vector unsigned char)vec_cmpeq(data4,zero),(vector unsigned char)zero); /* bit mask... all 0 for data = 0., all 1 else */
+
+ /* make estimated reciprocal and zero out NANs */
+ vector float tmp1 = vec_re(data1);
+ vector float tmp2 = vec_re(data2);
+ vector float tmp3 = vec_re(data3);
+ vector float tmp4 = vec_re(data4);
+
+ tmp1 = (vector float)vec_and((vector unsigned char)tmp1,mask1);
+ tmp2 = (vector float)vec_and((vector unsigned char)tmp2,mask2);
+ tmp3 = (vector float)vec_and((vector unsigned char)tmp3,mask3);
+ tmp4 = (vector float)vec_and((vector unsigned char)tmp4,mask4);
+
+ data1 = vec_madd( vec_nmsub( tmp1, data1, one ), tmp1, tmp1 );
+ data2 = vec_madd( vec_nmsub( tmp2, data2, one ), tmp2, tmp2 );
+ data3 = vec_madd( vec_nmsub( tmp3, data3, one ), tmp3, tmp3 );
+ data4 = vec_madd( vec_nmsub( tmp4, data4, one ), tmp4, tmp4 );
+
+ tmp1 = vec_ld( 0,src1);
+ tmp2 = vec_ld(16,src1);
+ tmp3 = vec_ld(32,src1);
+ tmp4 = vec_ld(48,src1);
+
+ data1 = vec_madd(tmp1,data1,zero);
+ data2 = vec_madd(tmp2,data2,zero);
+ data3 = vec_madd(tmp3,data3,zero);
+ data4 = vec_madd(tmp4,data4,zero);
+
+ vec_st(data1, 0,dst);
+ vec_st(data2,16,dst);
+ vec_st(data3,32,dst);
+ vec_st(data4,48,dst);
+#endif
+ }
+ return w+5;
+}
+
+t_int *scalarover_perf_simd(t_int *w)
+{
+ t_float *dst = (t_float *)w[3];
+ const vector float zero = (vector float)(0);
+ int n = w[4]>>4;
+
+ if(*(t_float *)w[2]) {
+ const t_float *src = (const t_float *)w[1];
+#ifdef USEVECLIB
+ float arg = *(t_float *)w[2]?1./ *(t_float *)w[2]: 0;
+ vsmul(src,1,&arg,dst,1,w[4]);
+#else
+ const vector float v = LoadValue(w[2]);
+ const vector float one = (vector float)(1);
+
+ vector float estimate = vec_re(v);
+ vector float arg = vec_madd( vec_nmsub( estimate, v, one ), estimate, estimate );
+
+ for(; n--; src += 16,dst += 16) {
+ vector float a1 = vec_ld( 0,src);
+ vector float a2 = vec_ld(16,src);
+ vector float a3 = vec_ld(32,src);
+ vector float a4 = vec_ld(48,src);
+
+ a1 = vec_madd(a1,arg,zero);
+ a2 = vec_madd(a2,arg,zero);
+ a3 = vec_madd(a3,arg,zero);
+ a4 = vec_madd(a4,arg,zero);
+
+ vec_st(a1, 0,dst);
+ vec_st(a2,16,dst);
+ vec_st(a3,32,dst);
+ vec_st(a4,48,dst);
+ }
+#endif
+ }
+ else {
+ /* zero all output */
+ for(; n--; dst += 16) {
+ vec_st(zero, 0,dst);
+ vec_st(zero,16,dst);
+ vec_st(zero,32,dst);
+ vec_st(zero,48,dst);
+ }
+ }
+ return w+5;
+}
+
+t_int *min_perf_simd(t_int *w)
+{
+ const t_float *src1 = (const t_float *)w[1];
+ const t_float *src2 = (const t_float *)w[2];
+ t_float *dst = (t_float *)w[3];
+ int n = w[4]>>4;
+
+ for(; n--; src1 += 16,src2 += 16,dst += 16) {
+ vector float a1 = vec_ld( 0,src1),b1 = vec_ld( 0,src2);
+ vector float a2 = vec_ld(16,src1),b2 = vec_ld(16,src2);
+ vector float a3 = vec_ld(32,src1),b3 = vec_ld(32,src2);
+ vector float a4 = vec_ld(48,src1),b4 = vec_ld(48,src2);
+
+ a1 = vec_min(a1,b1);
+ a2 = vec_min(a2,b2);
+ a3 = vec_min(a3,b3);
+ a4 = vec_min(a4,b4);
+
+ vec_st(a1, 0,dst);
+ vec_st(a2,16,dst);
+ vec_st(a3,32,dst);
+ vec_st(a4,48,dst);
+ }
+ return w+5;
+}
+
+t_int *scalarmin_perf_simd(t_int *w)
+{
+ const t_float *src = (const t_float *)w[1];
+ const vector float arg = LoadValue(w[2]);
+ t_float *dst = (t_float *)w[3];
+ int n = w[4]>>4;
+
+ for(; n--; src += 16,dst += 16) {
+ vector float a1 = vec_ld( 0,src);
+ vector float a2 = vec_ld(16,src);
+ vector float a3 = vec_ld(32,src);
+ vector float a4 = vec_ld(48,src);
+
+ a1 = vec_min(a1,arg);
+ a2 = vec_min(a2,arg);
+ a3 = vec_min(a3,arg);
+ a4 = vec_min(a4,arg);
+
+ vec_st(a1, 0,dst);
+ vec_st(a2,16,dst);
+ vec_st(a3,32,dst);
+ vec_st(a4,48,dst);
+ }
+ return w+5;
+}
+
+t_int *max_perf_simd(t_int *w)
+{
+ const t_float *src1 = (const t_float *)w[1];
+ const t_float *src2 = (const t_float *)w[2];
+ t_float *dst = (t_float *)w[3];
+ int n = w[4]>>4;
+
+ for(; n--; src1 += 16,src2 += 16,dst += 16) {
+ vector float a1 = vec_ld( 0,src1),b1 = vec_ld( 0,src2);
+ vector float a2 = vec_ld(16,src1),b2 = vec_ld(16,src2);
+ vector float a3 = vec_ld(32,src1),b3 = vec_ld(32,src2);
+ vector float a4 = vec_ld(48,src1),b4 = vec_ld(48,src2);
+
+ a1 = vec_max(a1,b1);
+ a2 = vec_max(a2,b2);
+ a3 = vec_max(a3,b3);
+ a4 = vec_max(a4,b4);
+
+ vec_st(a1, 0,dst);
+ vec_st(a2,16,dst);
+ vec_st(a3,32,dst);
+ vec_st(a4,48,dst);
+ }
+ return w+5;
+}
+
+t_int *scalarmax_perf_simd(t_int *w)
+{
+ const t_float *src = (const t_float *)w[1];
+ const vector float arg = LoadValue(w[2]);
+ t_float *dst = (t_float *)w[3];
+ int n = w[4]>>4;
+
+ for(; n--; src += 16,dst += 16) {
+ vector float a1 = vec_ld( 0,src);
+ vector float a2 = vec_ld(16,src);
+ vector float a3 = vec_ld(32,src);
+ vector float a4 = vec_ld(48,src);
+
+ a1 = vec_max(a1,arg);
+ a2 = vec_max(a2,arg);
+ a3 = vec_max(a3,arg);
+ a4 = vec_max(a4,arg);
+
+ vec_st(a1, 0,dst);
+ vec_st(a2,16,dst);
+ vec_st(a3,32,dst);
+ vec_st(a4,48,dst);
+ }
+ return w+5;
+}
+
+t_int *clip_perf_simd(t_int *w)
+{
+ const t_float *src = (const t_float *)w[1];
+ t_float *dst = (t_float *)w[2];
+ const vector float lo = LoadValue(w[3]);
+ const vector float hi = LoadValue(w[4]);
+ int n = w[5]>>4;
+
+ for(; n--; src += 16,dst += 16) {
+ vector float data1 = vec_ld( 0,src);
+ vector float data2 = vec_ld(16,src);
+ vector float data3 = vec_ld(32,src);
+ vector float data4 = vec_ld(48,src);
+
+ vector unsigned char mlo1 = (vector unsigned char)vec_cmple(data1,lo); /* bit mask data <= lo */
+ vector unsigned char mlo2 = (vector unsigned char)vec_cmple(data2,lo); /* bit mask data <= lo */
+ vector unsigned char mlo3 = (vector unsigned char)vec_cmple(data3,lo); /* bit mask data <= lo */
+ vector unsigned char mlo4 = (vector unsigned char)vec_cmple(data4,lo); /* bit mask data <= lo */
+
+ vector unsigned char mhi1 = (vector unsigned char)vec_cmpge(data1,hi); /* bit mask data >= hi */
+ vector unsigned char mhi2 = (vector unsigned char)vec_cmpge(data2,hi); /* bit mask data >= hi */
+ vector unsigned char mhi3 = (vector unsigned char)vec_cmpge(data3,hi); /* bit mask data >= hi */
+ vector unsigned char mhi4 = (vector unsigned char)vec_cmpge(data4,hi); /* bit mask data >= hi */
+
+ data1 = (vector float)vec_and((vector unsigned char)data1,vec_nor(mlo1,mhi1));
+ data2 = (vector float)vec_and((vector unsigned char)data2,vec_nor(mlo2,mhi2));
+ data3 = (vector float)vec_and((vector unsigned char)data3,vec_nor(mlo3,mhi3));
+ data4 = (vector float)vec_and((vector unsigned char)data4,vec_nor(mlo4,mhi4));
+
+ mlo1 = vec_and((vector unsigned char)lo,mlo1);
+ mlo2 = vec_and((vector unsigned char)lo,mlo2);
+ mlo3 = vec_and((vector unsigned char)lo,mlo3);
+ mlo4 = vec_and((vector unsigned char)lo,mlo4);
+
+ mhi1 = vec_and((vector unsigned char)hi,mhi1);
+ mhi2 = vec_and((vector unsigned char)hi,mhi2);
+ mhi3 = vec_and((vector unsigned char)hi,mhi3);
+ mhi4 = vec_and((vector unsigned char)hi,mhi4);
+
+ data1 = (vector float)vec_or(vec_or(mlo1,mhi1),(vector unsigned char)data1);
+ data2 = (vector float)vec_or(vec_or(mlo2,mhi2),(vector unsigned char)data2);
+ data3 = (vector float)vec_or(vec_or(mlo3,mhi3),(vector unsigned char)data3);
+ data4 = (vector float)vec_or(vec_or(mlo4,mhi4),(vector unsigned char)data4);
+
+ vec_st(data1, 0,dst);
+ vec_st(data2,16,dst);
+ vec_st(data3,32,dst);
+ vec_st(data4,48,dst);
+ }
+ return w+6;
+}
+
+t_int *sigwrap_perf_simd(t_int *w)
+{
+ const t_float *src = (const t_float *)w[1];
+ t_float *dst = (t_float *)w[2];
+ int n = w[3]>>4;
+
+ for(; n--; src += 16,dst += 16) {
+ vector float data1 = vec_ld( 0,src);
+ vector float data2 = vec_ld(16,src);
+ vector float data3 = vec_ld(32,src);
+ vector float data4 = vec_ld(48,src);
+
+ data1 = vec_sub(data1,vec_floor(data1));
+ data2 = vec_sub(data2,vec_floor(data2));
+ data3 = vec_sub(data3,vec_floor(data3));
+ data4 = vec_sub(data4,vec_floor(data4));
+
+ vec_st(data1, 0,dst);
+ vec_st(data2,16,dst);
+ vec_st(data3,32,dst);
+ vec_st(data4,48,dst);
+ }
+ return w+4;
+}
+
+t_int *sigsqrt_perf_simd(t_int *w)
+{
+ const t_float *src = (const t_float *)w[1];
+ t_float *dst = (t_float *)w[2];
+ int n = w[3]>>4;
+
+ const vector float zero = (vector float)(0);
+ const vector float oneHalf = (vector float)(0.5);
+ const vector float one = (vector float)(1.0);
+
+ for(; n--; src += 16,dst += 16) {
+ /* http://developer.apple.com/hardware/ve/algorithms.html
+
+ Just as in Miller's scalar sigsqrt_perform,
+ first a rsqrt estimate is calculated which is then refined by one round of Newton-Raphson.
+ Here, to avoid branching a mask is generated which zeroes out eventual resulting NANs.
+ */
+
+#ifdef USEVECLIB
+ /* no zero checking here */
+ vec_st(vsqrtf(vec_ld( 0,src)), 0,dst);
+ vec_st(vsqrtf(vec_ld(16,src)),16,dst);
+ vec_st(vsqrtf(vec_ld(32,src)),32,dst);
+ vec_st(vsqrtf(vec_ld(48,src)),48,dst);
+#else
+ vector float data1 = vec_ld( 0,src);
+ vector float data2 = vec_ld(16,src);
+ vector float data3 = vec_ld(32,src);
+ vector float data4 = vec_ld(48,src);
+
+ const vector unsigned char mask1 = vec_nor((vector unsigned char)vec_cmple(data1,zero),(vector unsigned char)zero); /* bit mask... all 0 for data <= 0., all 1 else */
+ const vector unsigned char mask2 = vec_nor((vector unsigned char)vec_cmple(data2,zero),(vector unsigned char)zero); /* bit mask... all 0 for data <= 0., all 1 else */
+ const vector unsigned char mask3 = vec_nor((vector unsigned char)vec_cmple(data3,zero),(vector unsigned char)zero); /* bit mask... all 0 for data <= 0., all 1 else */
+ const vector unsigned char mask4 = vec_nor((vector unsigned char)vec_cmple(data4,zero),(vector unsigned char)zero); /* bit mask... all 0 for data <= 0., all 1 else */
+
+ const vector float estimate1 = (vector float)vec_and((vector unsigned char)vec_rsqrte(data1),mask1);
+ const vector float estimate2 = (vector float)vec_and((vector unsigned char)vec_rsqrte(data2),mask2);
+ const vector float estimate3 = (vector float)vec_and((vector unsigned char)vec_rsqrte(data3),mask3);
+ const vector float estimate4 = (vector float)vec_and((vector unsigned char)vec_rsqrte(data4),mask4);
+
+ /* this can still be improved.... */
+ data1 = vec_madd(data1,vec_madd( vec_nmsub( data1, vec_madd( estimate1, estimate1, zero ), one ), vec_madd( estimate1, oneHalf, zero ), estimate1 ), zero);
+ data2 = vec_madd(data2,vec_madd( vec_nmsub( data2, vec_madd( estimate2, estimate2, zero ), one ), vec_madd( estimate2, oneHalf, zero ), estimate2 ), zero);
+ data3 = vec_madd(data3,vec_madd( vec_nmsub( data3, vec_madd( estimate3, estimate3, zero ), one ), vec_madd( estimate3, oneHalf, zero ), estimate3 ), zero);
+ data4 = vec_madd(data4,vec_madd( vec_nmsub( data4, vec_madd( estimate4, estimate4, zero ), one ), vec_madd( estimate4, oneHalf, zero ), estimate4 ), zero);
+
+ vec_st(data1, 0,dst);
+ vec_st(data2,16,dst);
+ vec_st(data3,32,dst);
+ vec_st(data4,48,dst);
+#endif
+ }
+ return w+4;
+}
+
+/* Attention: there's a difference to sigsqrt_perform which delivers non-zero for a zero input... i don't think the latter is intended... */
+t_int *sigrsqrt_perf_simd(t_int *w)
+{
+ const t_float *src = (const t_float *)w[1];
+ t_float *dst = (t_float *)w[2];
+ int n = w[3]>>4;
+
+ const vector float zero = (vector float)(0);
+ const vector float oneHalf = (vector float)(0.5);
+ const vector float one = (vector float)(1.0);
+
+ for(; n--; src += 16,dst += 16) {
+ /* http://developer.apple.com/hardware/ve/algorithms.html
+
+ Just as in Miller's scalar sigrsqrt_perform,
+ first a rsqrt estimate is calculated which is then refined by one round of Newton-Raphson.
+ Here, to avoid branching a mask is generated which zeroes out eventual resulting NANs.
+ */
+
+#ifdef USEVECLIB
+ /* no zero checking here */
+ vec_st(vrsqrtf(vec_ld( 0,src)), 0,dst);
+ vec_st(vrsqrtf(vec_ld(16,src)),16,dst);
+ vec_st(vrsqrtf(vec_ld(32,src)),32,dst);
+ vec_st(vrsqrtf(vec_ld(48,src)),48,dst);
+#else
+ vector float data1 = vec_ld( 0,src);
+ vector float data2 = vec_ld(16,src);
+ vector float data3 = vec_ld(32,src);
+ vector float data4 = vec_ld(48,src);
+
+ const vector unsigned char mask1 = vec_nor((vector unsigned char)vec_cmple(data1,zero),(vector unsigned char)zero); /* bit mask... all 0 for data <= 0., all 1 else */
+ const vector unsigned char mask2 = vec_nor((vector unsigned char)vec_cmple(data2,zero),(vector unsigned char)zero); /* bit mask... all 0 for data <= 0., all 1 else */
+ const vector unsigned char mask3 = vec_nor((vector unsigned char)vec_cmple(data3,zero),(vector unsigned char)zero); /* bit mask... all 0 for data <= 0., all 1 else */
+ const vector unsigned char mask4 = vec_nor((vector unsigned char)vec_cmple(data4,zero),(vector unsigned char)zero); /* bit mask... all 0 for data <= 0., all 1 else */
+
+ const vector float estimate1 = (vector float)vec_and((vector unsigned char)vec_rsqrte(data1),mask1);
+ const vector float estimate2 = (vector float)vec_and((vector unsigned char)vec_rsqrte(data2),mask2);
+ const vector float estimate3 = (vector float)vec_and((vector unsigned char)vec_rsqrte(data3),mask3);
+ const vector float estimate4 = (vector float)vec_and((vector unsigned char)vec_rsqrte(data4),mask4);
+
+ data1 = vec_nmsub( data1, vec_madd( estimate1, estimate1, zero ), one );
+ data2 = vec_nmsub( data2, vec_madd( estimate2, estimate2, zero ), one );
+ data3 = vec_nmsub( data3, vec_madd( estimate3, estimate3, zero ), one );
+ data4 = vec_nmsub( data4, vec_madd( estimate4, estimate4, zero ), one );
+
+ data1 = vec_madd( data1, vec_madd( estimate1, oneHalf, zero ), estimate1 );
+ data2 = vec_madd( data2, vec_madd( estimate2, oneHalf, zero ), estimate2 );
+ data3 = vec_madd( data3, vec_madd( estimate3, oneHalf, zero ), estimate3 );
+ data4 = vec_madd( data4, vec_madd( estimate4, oneHalf, zero ), estimate4 );
+
+ vec_st(data1, 0,dst);
+ vec_st(data2,16,dst);
+ vec_st(data3,32,dst);
+ vec_st(data4,48,dst);
+#endif
+ }
+ return w+4;
+}
+
+int simd_runtime_check()
+{
+ return 1;
+}
+
+
+#endif
diff --git a/desiredata/src/m_simd_ve_gcc.h b/desiredata/src/m_simd_ve_gcc.h
new file mode 100644
index 00000000..f58ca42f
--- /dev/null
+++ b/desiredata/src/m_simd_ve_gcc.h
@@ -0,0 +1,18 @@
+/* SIMD functionality for Apple Velocity Engine (AltiVec) with GCC compiler; added by T.Grill */
+#ifndef __M_SIMD_VE_GCC_H
+#define __M_SIMD_VE_GCC_H
+#include "m_pd.h"
+
+/* SIMD functions for VE with GCC */
+t_int *sigwrap_perf_simd(t_int *w);
+t_int *sigsqrt_perf_simd(t_int *w);
+t_int *sigrsqrt_perf_simd(t_int *w);
+
+/* SIMD not implemented */
+#define env_tilde_accum_simd env_tilde_accum_8
+#define copyvec_simd_unalignedsrc copyvec_8
+/* #define sum_vecsimd sumvec_8 */
+#define line_tilde_slope_simd line_tilde_slope
+#define peakvec_simd peakvec
+
+#endif /* __M_SIMD_VE_GCC_H */
diff --git a/desiredata/src/main.c b/desiredata/src/main.c
new file mode 100644
index 00000000..cf4a6593
--- /dev/null
+++ b/desiredata/src/main.c
@@ -0,0 +1,17 @@
+/* this file is separate because it is outside of libpd.so */
+
+extern "C" int sys_main(int argc, char **argv);
+#if _MSC_VER
+#include <windows.h>
+#include <stdio.h>
+int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
+ __try {
+ sys_main(__argc,__argv);
+ } __finally {
+ printf("caught an exception; stopping\n");
+ }
+}
+#else /* not MSVC */
+int main(int argc, char **argv) {return sys_main(argc, argv);}
+#endif
+
diff --git a/desiredata/src/makefile.in b/desiredata/src/makefile.in
new file mode 100644
index 00000000..69acc76d
--- /dev/null
+++ b/desiredata/src/makefile.in
@@ -0,0 +1,122 @@
+EXT= @EXT@
+LIBSUFFIX = @LIBSUFFIX@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+bindir = @bindir@
+includedir = @includedir@
+libdir = @libdir@
+mandir = @mandir@
+# varibles to match packages/Makefile.buildlayout so that they can be easily
+# overridden when building Pd-extended builds. <hans@at.or.at>
+libpddir = $(libdir)/pd
+pddocdir = $(libpddir)/doc
+libpdbindir = $(libpddir)/bin
+
+MORECFLAGS = @MORECFLAGS@
+LDFLAGS = @LDFLAGS@
+LDSOFLAGS = @LDSOFLAGS@
+CPPFLAGS = -DDESIRE -DDONTUSESIMD -DPD @CPPFLAGS@
+CFLAGS = $(CPPFLAGS) @CFLAGS@ $(MORECFLAGS)
+CFLAGS += -Wall -Wextra -Wno-unused-parameter -I.
+CFLAGS += -DINSTALL_PREFIX=\"$(prefix)\"
+
+SRCXX = desire.c kernel.c builtins.c builtins_dsp.c s_path.c s_inter.c s_main.c \
+ m_sched.c s_loader.c d_soundfile.c d_ugen.c s_audio.c s_midi.c @AUDIOSRC@ @MIDISRC@
+SRC = m_fifo.c m_simd.c d_mayer_fft.c d_fftroutine.c
+OBJ = $(SRCXX:.c=.o) $(SRC:.c=.o)
+SO = libpd$(LIBSUFFIX)
+
+# ------------------ targets ------------------------------------
+
+.PHONY: bin externs all
+
+all: bin externs
+
+bin: pd pd-watchdog pdsend pdreceive
+
+$(SRCXX:.c=.o): %.o: %.c config.log
+ $(CXX) $(CFLAGS) -xc++ -c -o $*.o $*.c
+
+$(SRC:.c=.o): %.o: %.c config.log
+ $(CC) $(CFLAGS) -Wno-parentheses -Wno-switch -Wstrict-prototypes -c -o $*.o $*.c
+
+$(SO): $(OBJ) config.log
+ $(CXX) $(LDSOFLAGS) $(LDFLAGS) $(DBG_CFLAGS) -o $(SO) $(OBJ)
+
+pd: $(OBJ) config.log $(SO) main.c
+ $(CXX) $(LDFLAGS) $(DBG_CFLAGS) $$PWD/$(SO) main.c -o pd
+
+pd-watchdog: s_watchdog.c
+ $(CC) $(CFLAGS) $(STRIPFLAG) -o pd-watchdog s_watchdog.c
+
+pdsend: u_pdsend.c
+ $(CC) $(CFLAGS) $(STRIPFLAG) -o pdsend u_pdsend.c
+
+pdreceive: u_pdreceive.c
+ $(CC) $(CFLAGS) $(STRIPFLAG) -o pdreceive u_pdreceive.c
+
+externs:
+ cd ../extra; for ext in bonk~ choice expr~ fiddle~ loop~ lrshift~ pique sigmund~; do \
+ cd $$ext; make @EXTERNTARGET@ || break; cd ..; done
+
+install: all
+ install -d $(DESTDIR)$(bindir)
+ install -d $(DESTDIR)$(libpdbindir)
+ for file in defaults.ddrc pkgIndex.tcl pre8.5.tcl poe.tcl bgerror.tcl; do \
+ install $$file $(DESTDIR)$(libpdbindir)/$$file; done
+ cp -r locale $(DESTDIR)$(libpdbindir)
+ cp -r ../icons $(DESTDIR)$(libpddir)
+ install $(BINARYMODE) $(SO) $(DESTDIR)$(libdir)/$(SO)
+ test -w /etc/ld.so.cache && ldconfig || true
+ $(CXX) $(LDFLAGS) $(DBG_CFLAGS) -lpd main.c -o $(DESTDIR)$(bindir)/pd
+ install -m755 desire.tk $(DESTDIR)$(bindir)/desire
+ install -m755 pdsend $(DESTDIR)$(bindir)/pdsend
+ install -m755 pdreceive $(DESTDIR)$(bindir)/pdreceive
+ install -m755 pd-watchdog $(DESTDIR)$(libpdbindir)/pd-watchdog
+ mkdir -p $(DESTDIR)$(pddocdir)
+ cp -pr ../doc/* $(DESTDIR)$(pddocdir)
+ cp -pr ../extra/* $(DESTDIR)$(libpddir)
+ # rm -f $(DESTDIR)$(libpddir)/extra/*/*.o
+ install -d $(DESTDIR)$(includedir)
+ for file in m_pd.h desire.h; do install -m644 $$file $(DESTDIR)$(includedir)/$$file; done
+ install -d $(DESTDIR)$(mandir)/man1
+ for page in pd.1 pdsend.1 pdreceive.1; do \
+ gzip < ../man/$$page > $(DESTDIR)$(mandir)/man1/$$page.gz; chmod 644 $(DESTDIR)$(mandir)/man1/$$page.gz; done
+
+local-clean:
+ -rm -f *.o pd pdsend pdreceive pd-watchdog m_stamp.c
+ -rm -f *~
+ -(cd ../doc/6.externs; rm -f *.pd_linux)
+ -rm -f makefile.deps
+ touch makefile.deps
+ chmod 666 makefile.deps
+
+extra-clean:
+ -rm -f `find ../extra/ -name "*.pd_*"`
+ -rm -f tags
+
+clean: extra-clean local-clean
+
+distclean: clean
+ -rm -f config.cache config.log config.status makefile tags \
+ autom4te.cache/output.* autom4te.cache/traces.* autom4te.cache/requests
+ -rmdir autom4te.cache
+ -rm -rf autom4te-*.cache
+
+tags: $(SRC) $(GSRC); ctags *.[ch]
+
+depend: makefile.deps
+
+makefile.deps: makefile
+ $(CXX) $(CPPFLAGS) -MM $(SRC) $(SRCXX) > makefile.deps
+
+uninstall:
+ rm -f -r $(DESTDIR)$(libpddir)
+ rm -f $(DESTDIR)$(libdir)/libpd*
+ cd $(DESTDIR)$(bindir); rm pd pdsend pdreceive
+ cd $(DESTDIR)$(includedir); rm m_pd.h desire.h
+ cd $(DESTDIR)$(mandir)/man1; rm pd.1.gz pdsend.1.gz pdreceive.1.gz
+
+include makefile.deps
+
+# echo $$LD_LIBRARY_PATH | sed 's/:/\n/g' | grep -q '^$(DESTDIR)$(libdir)$$'
diff --git a/desiredata/src/notes.txt b/desiredata/src/notes.txt
new file mode 100644
index 00000000..26393dfb
--- /dev/null
+++ b/desiredata/src/notes.txt
@@ -0,0 +1,300 @@
+---------------- dolist --------------------
+done:
+plug-in support
+atan2 inlets switched
+queued graphics updates for tables, number boxes
+cut/paste text (needs more testing)
+add standard bindings (ctl-o, etc) to dialogs
+separate audio on/off from nchans
+setuid flag in configure script
+settings saver (registry in Windows; .pdrc in linux; defaults system in OSX?)
+ audio API
+ MIDI -- fix to read MIDI on startup (rest works?)
+ path
+ startup flags
+ libs
+better params:
+ extra flag for path
+ startup flags
+ startup libraries
+printout to pd window
+startup from GUI
+%x to %lx in all "tags" to make 64-bit safe
+portaudio_pd files into src
+t_int to int in binbuf_addv
+64-bit fix to externs makefiles
+new filter objects: cpole~, fpole~, etc.
+put in Wini's RME ALSA code; there are still bugs...
+portaudio fixed for inchans != outchans, e.g., emi emagic (2/6)
+sprout inlets/outlets on objects whose creation failed.
+uploaded to CVS
+bug fix: click on minaturized subpatch fails to "vis" it
+bug fix: CK on Oct. 4 (crash changing font size)
+sched_idle hook
+fixed startup flags, path, etc. so that spaces, "," chars, etc., are allowed
+configure script fixed to handle enable- and disable- correctly
+fixed spaces in "startup" dialog
+
+doc:
+document env~ second argument (and why is it no less than 1/10 of first???)
+vibrato example
+
+problems:
+'[' in numbox label breaks it (Yury Sept. 3)
+soundfiles with 3-byte samples buzz for the first readsf buffer (bug/x.pd)
+read xx.txt in "bad" gives warnings
+writesf -- "open" without "0" misses closing the previous file.
+Also writesf~ acts differently if DSP is off when "open" is sent?
+qlist - 'next 1' seems not to work
+Krzysztof's qlist_next reentrancy bug
+don't draw in/outlets on gui objects in graph-on-parent
+font size should depend on subpatch/abstraction
+moving a bang toward top of window creates problem
+check what happens when going back and forth between graph-on-parent
+get rid of messages causing renaming; try to prevent patches closing themselves.
+dac~/ adc~/ block~ incompatibility
+scofo reports error on reading score1.txt
+rfft~ loses nyquist bin -- see "to hell with it" comment in d_fft.c
+open_via_path() followed by close() fails in windows? [can't reproduce]
+loading e-mailed patches without removing headers crashes pd
+pd $1 bug ($1 is saved as it was evaluated, not as '$1')
+data copy/paste doesn't check templates aren't changed
+figure out why Pd sometimes crashes when you close example after adding fields
+check if _vsnprintf with zero argument in windows works any better...
+
+next release:
+update portmusic to latest
+IEM guis to use queued updates
+pixel font sizes
+pd to find running ones (pd -new to defeat)
+"enter" into object box to create new one (also, changing borders? forking?)
+tab to jump to a connected object (first one?) (shift-tab to back up?)
+tables:
+ if there's just one array, don't do stringent hit check.
+ array click protection (Krzysztof's suggestion)
+ make graph labels persistent and add to dialog
+ object to get/set table size; random; quantile
+ flag to hide array names
+queued graphics updates for IEMGUIs and scalars
+document tabwrite~_start
+think of a way to embed abstractions in a patch
+make watchdog work for MACOSX
+GOP bounding box object
+IEMGUIs better default font size
+search path to include both calling patch and abstraction, if different
+abstraction reload shouldn't have to vis everyone
+addcomma message to message
+pasting should look at current mouse location
+delete-in-rectangle message to Pds
+put serial object in main dist (see rat@telecoma, Apr. 25; winfried May 22)
+open/save panel to take messages to init directory, and to set extent list
+flags to defeat pre-loading specified classes
+expr to parse exponential notation
+
+
+data:
+arrays of non-existent templates crash
+vget, vset traversal objects
+cursor to show (x, y) location
+better hit detection (getrect is too greedy; try tk's "current" tag for canvas)
+click on points of plot
+typing & dragging drawnumbers
+fix templates to be loaded on demand and belong to a globally known patch
+test and debug list elements of templates
+sublists should display on parent if desired?
+sublists seem not to handle canvas allocation right (get.pd->pointer.pd bug)
+scalar hook to catch the mouse
+protect against "plots" going away while you drag on them
+
+more features:
+
+-Wno-unused to -Wno-unused-paramter and clean up unused automatic variables
+security module system in 2.6 - see the kernel module replacing jackstart
+signal inlets to sense signals; fix +~ etc, vcf~, biquad~, other filters
+mess with RME ALSA some more; ALSA readn doesn't work yet; use mmap?
+try to reduce startup time
+investigate gcc 3.3 warnings; try to reinstate -fstrict-aliasing
+message dialog not to disappear
+why does changing the name of an explode in jupiter patch take so long?
+close-subwindows menu item
+show results of opening audio and MIDI on dialogs
+windows escape from control-C
+settable netsend and netreceive port numbers
+new: abs~, nexttick~, extend threshold~ and snapshot~ (vthreshold~ etc)
+incorporate pddp doc
+try again to fix the font scene
+look at prctl(2) for FP exception handling
+??? have a way to disambiguate externs from different libs???
+netsend separate thread
+netreceive (and netsend?) message to set port number
+think about x and y scale preservation when changing between graph and object
+show outlines of objects even when graph is "open"
+graph_vis() to decorate graphs when they're toplevel (parent_glist == 0)
+get graphs to expand to hold their contents
+suita.chopin.edu.pl/~czaja/miXed/externs/xeq.html -- MIDI file reader
+in glist_delete, consider why this can't be just "vis 0" -- why do we need it?
+closebang
+check that -blocksize really reflects in audiobuf calc for Hammerfall
+makefile to have make install depend on make local.
+Float method for random
+figure out list, message objects
+separate control over alsaindev and alsaoutdev
+put in something for tilde order forcing
+extensible "toolbar" so people can add external GUI objects
+allow spaces in paths
+variable send and receive -- check how max/MSP does it?
+number boxes to darken for typing and/or received messages
+dialog to change lib flag and path
+pique~ and fiddle~ unification (notice pique filtering is different!)
+new message box look
+figure out what to do when "pd sym" conflicts with window title as in Pluton?
+
+MAX compatibilty:
+trigger 1 (on Pd, outputs 0; on Max?)
+
+LATER
+bonk~ file path handling
+unify arrays and garrays
+dialog to give values of $1, ... for the canvas
+bang at end of line~, tabwrite~, etc.
+recording to part of a table
+printout to main window
+should sys_bail kill all "threads" on the way out?
+check a_valid usage
+allow backslashes (or else really disallow them)
+icon & desktop integration
+vreadsf~
+benchmarking
+flash menu when accelerator hits?
+fix edit mode menu item
+fancier text editing
+tools (reassigns meaning of primary click)
+get gui to notice early EOF
+rewrite t_getbytes properly
+obj_new should do a longjmp on out-of-memory
+
+--------------------- source notes --------------------------
+
+0. structure definition roadmap. First, the containment tree of things
+that can be sent messages ("pure data"). (note that t_object and t_text,
+and t_graph and t_canvas, should be unified...)
+
+------------ BFFORE 0.35: ---------
+m_pd.h t_pd anything with a class
+ t_gobj "graphic object"
+ t_text text object
+g_canvas.h
+ t_glist list of graphic objects
+g_canvas.c t_canvas Pd "document"
+
+------------ AFTER 0.35: ---------
+m_pd.h t_pd anything with a class
+ t_gobj "graphic object"
+ t_text patchable object, AKA t_object
+g_canvas.h t_glist list of graphic objects, AKA t_canvas
+
+... and other structures:
+g_canvas.h t_selection -- linked list of gobjs
+ t_editor -- editor state, allocated for visible glists
+m_imp.h t_methodentry -- method handler
+ t_widgetbehavior -- class-dependent editing behavior for gobjs
+ t_parentwidgetbehavior -- objects' behavior on parent window
+ t_class -- method definitions, instance size, flags, etc.
+
+
+1. C coding style. The source should pass most "warnings" of C compilers
+(-Wall on linux, for instance; see the makefile.) Some informalities
+are intentional, for instance the loose use of function prototypes (see
+below) and uncast conversions from longer to shorter numerical formats.
+The code doesn't respect "const" yet.
+
+1.1. Prefixes in structure elements. The names of structure elements always
+have a K&R-style prefix, as in ((t_atom)x)->a_type, where the "a_" prefix
+indicates "atom." This is intended to enhance readability (although the
+convention arose from a limitation of early C compilers.) Common prefixes are
+"w_" (word), "a_" (atom), "s_" (symbol), "ob_" (object), "te_" (text object),
+"g_" (graphical object), and "gl_" (glist, a list of graphical objects). Also,
+global symbols sometimes get prefixes, as in "s_float" (the symbol whose string
+is "float). Typedefs are prefixed by "t_". Most _private_ structures, i.e.,
+structures whose definitions appear in a ".c" file, are prefixed by "x_".
+
+1.2. Function arguments. Many functions take as their first
+argument a pointer named "x", which is a pointer to a structure suggested
+by the function prefix; e.g., canvas_dirty(x, n) where "x" points to a canvas
+(t_canvas *x).
+
+1.3. Function Prototypes. Functions which are used in at least two different
+files (besides where they originate) are prototyped in the appropriate include
+file. Functions which are provided in one file and used in one other are
+prototyped right where they are used. This is just to keep the size of the
+".h" files down for readability's sake.
+
+1.4. Whacko private terminology. Some terms are lifted from other historically
+relevant programs, notably "ugen" (which is just a tilde object; see d_ugen.c.)
+
+1.5. Spacing. Tabs are 8 spaces; indentation is 4 spaces. Indenting
+curly brackets are by themselves on their own lines, as in:
+
+ if (x)
+ {
+ x = 0;
+ }
+
+Lines should fit within 80 spaces.
+
+2. Max patch-level compatibility. "Import" and "Export" functions are
+provided which aspire to strict compatibility with 0.26 patches (ISPW version),
+but which don't get anywhere close to that yet. Where possible, features
+appearing on the Mac will comeday also be provided; for instance, the connect
+message on the Mac offers segmented patch cords; these will devolve into
+straight lines in Pd. Many, many UI objects in Opcode Max will not appear in
+Pd, at least at first.
+
+3. Compatibility with Max 0.26 "externs", i.e., source-level compatibility. Pd
+objects follow the style of 0.26 objects as closely as possible, making
+exceptions in cases where the 0.26 model is clearly deficient. These are:
+
+3.1. Anything involving the MacIntosh "Handle" data type is changed to use
+char * or void * instead.
+
+3.2. Pd passes true single-precision floating-point arguments to methods;
+Max uses double.
+Typedefs are provided:
+ t_floatarg, t_intarg for arguments passed by the message system
+ t_float, t_int for the "word" union (in atoms, for example.)
+
+3.3. Badly-named entities got name changes:
+
+ w_long --> w_int (in the "union word" structure)
+
+3.4. Many library functions are renamed and have different arguments;
+I hope to provide an include file to alias them when compiling Max externs.
+
+4. Function name prefixes.
+Many function names have prefixes which indicate what "package" they belong
+to. The exceptions are:
+ typedmess, vmess, getfn, gensym (m_class.c)
+ getbytes, freebytes, resizebytes (m_memory.c)
+ post, error, bug (s_print.c)
+which are all frequently called and which don't fit into simple categories.
+Important packages are:
+(pd-gui:) pdgui -- everything
+(pd:) pd -- functions common to all "pd" objects
+ obj -- fuctions common to all "patchable" objects ala Max
+ sys -- "system" level functions
+ binbuf -- functions manipulating binbufs
+ class -- functions manipulating classes
+ (other) -- functions common to the named Pd class
+
+5. Source file prefixes.
+PD:
+s system interface
+m message system
+g graphics stuff
+d DSP objects
+x control objects
+z other
+
+PD-GUI:
+t TK front end
+
diff --git a/desiredata/src/pkgIndex.tcl b/desiredata/src/pkgIndex.tcl
new file mode 100644
index 00000000..40115eba
--- /dev/null
+++ b/desiredata/src/pkgIndex.tcl
@@ -0,0 +1,15 @@
+# Tcl package index file, version 1.1
+# This file is generated by the "pkg_mkIndex" command
+# and sourced either when an application starts up or
+# by a "package unknown" script. It invokes the
+# "package ifneeded" command to set up package-related
+# information so that packages will be loaded automatically
+# in response to "package require" commands. When this
+# script is sourced, the variable $dir must contain the
+# full path name of this file's directory.
+
+package ifneeded kb-mode 0.1 [list source [file join $dir kb-mode.tcl]]
+package ifneeded poe 0.1 [list source [file join $dir poe.tcl]]
+package ifneeded pre8.5 8.4 [list source [file join $dir pre8.5.tcl]]
+package ifneeded bgerror 8.4 [list source [file join $dir bgerror.tcl]]
+package ifneeded dzinc 0.1 [list source [file join $dir dzinc.tcl]]
diff --git a/desiredata/src/plusminus b/desiredata/src/plusminus
new file mode 100755
index 00000000..553f84fa
--- /dev/null
+++ b/desiredata/src/plusminus
@@ -0,0 +1,42 @@
+#!/usr/bin/env ruby
+# plusminus, Copyright © 2004 by Mathieu Bouchard
+# this program makes stats about a unified diff (diff -u) output.
+# for example, run this command: cvs diff -u | ./plusminus
+# NOTE: the -u option is required! (you can put it in ~/.cvsrc)
+
+puts "-"*64
+
+$plustot=0
+$minustot=0
+
+def show
+ printf "%20s %+5d %+5d (net %+5d)\n", $file, $plus, -$minus, $plus-$minus
+end
+
+loop{
+ line = gets
+ break if not line
+ if /^diff/.match line then
+ x = line.split(/\s+/)
+ $plustot+=$plus if $plus
+ $minustot+=$minus if $minus
+ show if $file
+ $file = x[-1]
+ $on=false
+ $plus=0
+ $minus=0
+ elsif /^\@\@/ =~ line then $on=true
+ elsif $on and /^\+/ =~ line then $plus+=1
+ elsif $on and /^\-/ =~ line then $minus+=1
+ end
+}
+
+$plustot+=$plus if $plus
+$minustot+=$minus if $minus
+show if $file
+
+$file="total"
+$plus=$plustot
+$minus=$minustot
+puts "-"*64
+show
diff --git a/desiredata/src/poe.tcl b/desiredata/src/poe.tcl
new file mode 100644
index 00000000..89ddfc78
--- /dev/null
+++ b/desiredata/src/poe.tcl
@@ -0,0 +1,281 @@
+# $Id: poe.tcl,v 1.1.2.2.2.27 2007-10-15 15:58:13 chunlee Exp $
+#----------------------------------------------------------------#
+# POETCL
+#
+# Copyright (c) 2005,2006 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.desire-client.txt 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.
+#
+# Note that this is not under the same license as the rest of PureData.
+# Even the DesireData server-side modifications stay on the same license
+# as the rest of PureData.
+#
+#-----------------------------------------------------------------------------------#
+
+# (please distinguish between what this is and what dataflow is)
+# note, the toplevel class is called "thing".
+
+package provide poe 0.1
+
+if {$tcl_version < 8.5} {package require pre8.5}
+set nextid 0
+set _(Class:_class) Class
+set _(Class:_super) {Thing}
+set have_expand [expr ![catch {set a {foo bar}; list {expand}$a}]]
+proc proc* {name args body} {
+ set argl {}
+ foreach arg $args {set arg [lindex $arg 0]; lappend argl "$arg=\$$arg"}
+ if {[regexp {_unknown$} $name]} {
+ proc $name $args "upvar 1 selector ___; puts \"\[VTgreen\]CALL TO PROC $name selector=\$___ [join $argl " "]\[VTgrey\]\"; $body"
+ } else {
+ if {![regexp "return" $body]} {
+ set body "time {$body}"
+ proc $name $args "puts \"\[VTgreen\]CALL TO PROC $name [join $argl " "], \[VTred\]\[lrange \[split \[$body\] \] 0 1\] \[VTgrey\]\""
+ } {
+ proc $name $args "puts \"\[VTgreen\]CALL TO PROC $name [join $argl " "]\[VTgrey\]\"; $body"
+ }
+ }
+}
+
+#proc Class_def {self selector args body} {
+# global _; if {![info exists _($self:_class)]} {error "unknown class '$self'"}
+# proc ${self}_$selector "self $args" "global _; [regsub -all @(\[\\w\\?\]+) $body _(\$self:\\1)]"
+#}
+#proc def {class selector args body} {$class def $selector $args $body}
+
+proc expand_macros {body} {
+ return [regsub -all @(\\\$?\[\\w\\?\]+) $body _(\$self:\\1)]
+}
+
+proc def {self selector argnames body} {
+ global _ __trace __args
+ if {![info exists _($self:_class)]} {error "unknown class '$self'"}
+ set name ${self}_$selector
+ #if {$name == "Canvas_motion_wrap"} {set body "puts \[time {$body}\]"}
+ set argnames [concat [list self] $argnames]
+ if {([info exists __trace($self:$selector)] || [info exists __trace(*:$selector)]
+ || [info exists __trace($self:*)] || [info exists __trace(*:*)])
+ && ![info exists __trace($self:!$selector)]
+ && ![info exists __trace(*:!$selector)]
+ } {
+ proc* $name $argnames "global _; [expand_macros $body]"
+ } {
+ proc $name $argnames "global _; [expand_macros $body]"
+ }
+ set __args($name) $argnames
+ #trace add execution ${self}_$selector enter dedebug
+}
+
+proc class_new {self {super {Thing}}} {
+ global _
+ set _($self:_class) Class
+ set _($self:_super) $super
+ set _($self:subclasses) {}
+ foreach sup $super {lappend _($sup:subclasses) $self}
+ proc ${self}_new {args} "global _
+ set self \[format o%07x \$::nextid\]
+ incr ::nextid
+ set _(\$self:_class) $self
+ setup_dispatcher \$self
+ eval [concat \[list \$self init\] \$args]
+ return \$self
+ "
+ proc ${self}_new_as {self args} "global _
+ if {\[info exists _(\$self:_class)\]} {error \"object '\\$self' already exists\" }
+ set _(\$self:_class) $self
+ setup_dispatcher \$self
+ eval [concat \[list \$self init\] \$args]
+ return \$self
+ "
+ setup_dispatcher $self
+}
+
+# TODO: remove duplicates in lookup
+proc lookup_method {class selector methodsv ancestorsv} {
+ global _
+ upvar $methodsv methods
+ upvar $ancestorsv ancestors
+ set name ${class}_$selector
+ if {[llength [info procs $name]]} {lappend methods $name}
+ lappend ancestors $class
+ foreach super $_($class:_super) {lookup_method $super $selector methods ancestors}
+}
+
+proc cache_method {class selector} {
+ global _ __
+ set methods {}; set ancestors {}
+ lookup_method $class $selector methods ancestors
+ if {![llength $methods]} {set methods [cache_method $class unknown]}
+ set __($class:$selector) $methods
+ return $methods
+}
+
+if {$have_expand} {
+ set dispatch {
+ set i 0; set class $::_($self:_class)
+ if {[catch {set methods $::__($class:$selector)}]} {set methods [cache_method $class $selector]}
+ [lindex $methods 0] $self {expand}$args
+ }
+} else {
+ set dispatch {
+ set i 0; set class $::_($self:_class)
+ if {[catch {set methods $::__($class:$selector)}]} {set methods [cache_method $class $selector]}
+ eval [concat [list [lindex $methods 0] $self] $args]
+ }
+}
+proc setup_dispatcher {self} {
+ if {[llength [info commands $self]]} {rename $self old_$self}
+ proc $self {selector args} [regsub -all {\$self} $::dispatch $self]
+}
+
+set super {
+ upvar 1 self self
+ upvar 2 methods methods i oi
+ set i [expr {1+$oi}]
+ if {[llength $methods] < $i} {error "no more supermethods"}
+}
+if {$have_expand} {
+ append super {[lindex $methods $i] $self {expand}$args}
+} else {
+ append super {eval [concat [list [lindex $methods $i] $self] $args]}
+}
+proc super {args} $super
+
+class_new Thing {}
+#set _(Thing:_super) {}
+def Thing init {} {}
+def Thing == {other} {return [expr ![string compare $self $other]]}
+
+# virtual destructor
+def Thing delete {} {
+ foreach elem [array names _ $self:*] {array unset _ $elem}
+ rename $self ""
+}
+
+def Thing vars {} {
+ set n [string length $self:]
+ set ks [list]
+ foreach k [array names _] {
+ if {0==[string compare -length $n $self: $k]} {lappend ks [string range $k $n end]}
+ }
+ return $ks
+}
+
+def Thing inspect {} {
+ set t [list "#<$self: "]
+ foreach k [lsort [$self vars]] {lappend t "$k=[list $@$k] "}
+ lappend t ">"
+ return [join $t ""]
+}
+
+def Thing class {} {return $@_class}
+
+def Thing unknown {args} {
+ upvar 1 selector selector class class
+ error "no such method '$selector' for object '$self'\nwith ancestors {[Class_ancestors $class]}"
+}
+
+class_new Class
+
+# those return only the direct neighbours in the hierarchy
+def Class superclasses {} {return $@_super}
+def Class subclasses {} {return $@subclasses}
+
+# those look recursively.
+def Class ancestors {} {
+ #if {[info exists @ancestors]} {}
+ set r [list $self]
+ foreach super $@_super {eval [concat [list lappend r] [$super ancestors]]}
+ return $r
+}
+def Class <= {class} {return [expr [lsearch [$self ancestors] $class]>=0]}
+
+# note: [luniq] is actually defined in desire.tk
+def Class methods {} {
+ set methods {}
+ set anc [$self ancestors]
+ foreach class $anc {
+ foreach name [info procs ${class}_*] {
+ lappend methods [join [lrange [split $name _] 1 end] _]
+ }
+ }
+ return [luniq [lsort $methods]]
+}
+
+# those are static methods, and poe.tcl doesn't distinguish them yet.
+def Class new { args} {eval [concat [list ${self}_new ] $args]}
+def Class new_as {id args} {eval [concat [list ${self}_new_as $id] $args]}
+
+#-----------------------------------------------------------------------------------#
+
+# this makes me think of Maximus-CBCS...
+proc VTgrey {} {return "\x1b\[0m"}
+proc VTred {} {return "\x1b\[0;1;31m"}
+proc VTgreen {} {return "\x1b\[0;1;32m"}
+proc VTyellow {} {return "\x1b\[0;1;33m"}
+proc VTblue {} {return "\x1b\[0;1;34m"}
+proc VTmagenta {} {return "\x1b\[0;1;35m"}
+proc VTcyan {} {return "\x1b\[0;1;36m"}
+proc VTwhite {} {return "\x1b\[0;1;37m"}
+
+proc error_text {} {
+ set e $::errorInfo
+ regsub -all " invoked from within\n" $e "" e
+ regsub -all "\n \\(" $e " (" e
+ regsub -all {\n[^\n]*procedure \"(::unknown|super)\"[^\n]*\n} $e "\n" e
+ regsub -all {\n\"\[lindex \$methods 0\][^\n]*\n} $e "\n" e
+ regsub -all {\s*while executing\s*\n} $e "\n" e
+ #regsub {\n$} $e "" e
+ return $e
+}
+set suicidal 0
+proc error_dump {} {
+ puts "[VTred]Exception:[VTgrey] [error_text]"
+ if {$::suicidal} {exit 1}
+}
+
+proc tracedef {class method {when enter}} {
+ global __trace
+ set __trace($class:$method) $when
+}
+
+proc yell {var key args} {
+ global $key
+ puts "[VTyellow]HEY! at [info level -1] set $key [list $::_($key)][VTgrey]"
+}
+
+proc object_table {} {
+ set n 0
+ puts "poe.tcl object_table: {"
+ foreach o [lsort [array names ::_ *:_class]] {
+ set oo [lindex [split $o :] 0]
+ set class $::_($o)
+ incr by_class($class)
+ puts " $oo is a $class"
+ incr n
+ }
+ puts "} ($n objects)"
+ set n 0
+ puts "poe.tcl class_stats: {"
+ foreach o [array names by_class] {
+ puts " class $o has $by_class($o) objects"
+ incr n
+ }
+ puts "} ($n classes)"
+}
+
+proc object_exists {self} {info exists ::_($self:_class)}
diff --git a/desiredata/src/pre8.5.tcl b/desiredata/src/pre8.5.tcl
new file mode 100644
index 00000000..c4b289c5
--- /dev/null
+++ b/desiredata/src/pre8.5.tcl
@@ -0,0 +1,209 @@
+package provide pre8.5 8.4
+
+proc lremove {args} {
+ array set opts {-all 0 pattern -exact}
+ while {[string match -* [lindex $args 0]]} {
+ switch -glob -- [lindex $args 0] {
+ -a* { set opts(-all) 1 }
+ -g* { set opts(pattern) -glob }
+ -r* { set opts(pattern) -regexp }
+ -- { set args [lreplace $args 0 0]; break }
+ default {return -code error "unknown option \"[lindex $args 0]\""}
+ }
+ set args [lreplace $args 0 0]
+ }
+ set l [lindex $args 0]
+ foreach i [join [lreplace $args 0 0]] {
+ if {[set ix [lsearch $opts(pattern) $l $i]] == -1} continue
+ set l [lreplace $l $ix $ix]
+ if {$opts(-all)} {
+ while {[set ix [lsearch $opts(pattern) $l $i]] != -1} {
+ set l [lreplace $l $ix $ix]
+ }
+ }
+ }
+ return $l
+}
+if {![llength [info commands dict]]} {
+ proc lassign {list args} {
+ foreach elem $list varName $args {
+ upvar 1 $varName var
+ set var $elem
+ }
+ }
+ proc dict {cmd args} {
+ uplevel 1 [linsert $args 0 _dict_$cmd]
+ }
+ proc _dict_get {dv args} {
+ if {![llength $args]} {return $dv} else {
+ array set dvx $dv
+ set key [lindex $args 0]
+ set dv $dvx($key)
+ set args [lrange $args 1 end]
+ return [eval [linsert $args 0 _dict_get $dv]]
+ }
+ }
+ proc _dict_exists {dv key args} {
+ array set dvx $dv
+ set r [info exists dvx($key)]
+ if {!$r} {return 0}
+ if {[llength $args]} {
+ return [eval [linsert $args 0 _dict_exists $dvx($key) ]]
+ } else {return 1}
+ }
+ proc _dict_set {dvar key value args } {
+ upvar 1 $dvar dv
+ if {![info exists dv]} {set dv [list]}
+ array set dvx $dv
+ if {![llength $args]} {
+ set dvx($key) $value
+ } else {
+ eval [linsert $args 0 _dict_set dvx($key) $value]
+ }
+ set dv [array get dvx]
+ }
+ proc _dict_unset {dvar key args} {
+ upvar 1 $dvar mydvar
+ if {![info exists mydvar]} {return}
+ array set dv $mydvar
+ if {![llength $args]} {
+ if {[info exists dv($key)]} {
+ unset dv($key)
+ }
+ } else {
+ eval [linsert $args 0 _dict_unset dv($key) ]
+ }
+ set mydvar [array get dv]
+ return {}
+ }
+ proc _dict_keys {dv {pat *}} {
+ array set dvx $dv
+ return [array names dvx $pat]
+ }
+ proc _dict_append {dvar key {args}} {
+ upvar 1 $dvar dv
+ if {![info exists dv]} {set dv [list]}
+ array set dvx $dv
+ eval [linsert $args 0 append dvx($key) ]
+ set dv [array get dvx]
+ }
+ proc _dict_create {args} {
+ return $args
+ }
+ proc _dict_filter {dv ftype args} {
+ set r [list]
+ foreach {globpattern} $args {break}
+ foreach {varlist script} $args {break}
+
+ switch $ftype {
+ key {
+ foreach {key value} $dv {
+ if {[string match $globpattern $key]} {
+ lappend r $key $value
+ }
+ }
+ }
+ value {
+ foreach {key value} $dv {
+ if {[string match $globpattern $value]} {
+ lappend r $key $value
+ }
+ }
+ }
+ script {
+ foreach {Pkey Pval} $varlist {break}
+ upvar 1 $Pkey key $Pval value
+ foreach {key value} $dv {
+ if {[uplevel 1 $script]} {
+ lappend r $key $value
+ }
+ }
+ }
+ default {
+ error "Wrong filter type"
+ }
+ }
+ return $r
+ }
+ proc _dict_for {kv dict body} {
+ uplevel 1 [list foreach $kv $dict $body]
+ }
+ proc _dict_incr {dvar key {incr 1}} {
+ upvar 1 $dvar dv
+ if {![info exists dv]} {set dv [list]}
+ array set dvx $dv
+ if {![info exists dvx($key)]} {set dvx($key) 0}
+ incr dvx($key) $incr
+ set dv [array get dvx]
+ }
+ proc _dict_info {dv} {
+ return "Dictionary is represented as plain list"
+ }
+ proc _dict_lappend {dvar key args} {
+ upvar 1 $dvar dv
+ if {![info exists dv]} {set dv [list]}
+ array set dvx $dv
+ eval [linsert $args 0 lappend dvx($key)]
+ set dv [array get dvx]
+ }
+ proc _dict_merge {args} {
+ foreach dv $args {
+ array set dvx $dv
+ }
+ array get dvx
+ }
+ proc _dict_replace {dv args} {
+ foreach {k v} $args {
+ _dict_set dv $k $v
+ }
+ return $dv
+ }
+ proc _dict_remove {dv args} {
+ foreach k $args {
+ _dict_unset dv $k
+ }
+ return $dv
+ }
+ proc _dict_size {dv} {
+ return [expr {[llength $dv]/2}]
+ }
+ proc _dict_values {dv {gp *}} {
+ set r [list]
+ foreach {k v} $dv {
+ if {[string match $gp $v]} {
+ lappend r $v
+ }
+ }
+ return $r
+ }
+ proc _dict_update {dvar args} {
+ set name [string map {: {} ( {} ) {}} $dvar]
+ upvar 1 $dvar dv
+ upvar 1 _my_dict_array$name local
+
+ array set local $dv
+ foreach {k v} [lrange $args 0 end-1] {
+ if {[info exists local($k)]} {
+ if {![uplevel 1 [list info exists $v]]} {
+ uplevel 1 [list upvar 0 _my_dict_array${name}($k) $v]
+ } else {
+ uplevel 1 [list set $v $local($k)]
+ }
+ }
+ }
+ set code [catch {uplevel 1 [lindex $args end]} res]
+
+ foreach {k v} [lrange $args 0 end-1] {
+ if {[uplevel 1 [list info exists $v]]} {
+ set local($k) [uplevel 1 [list set $v]]
+ } else {
+ unset -nocomplain local($k)
+ }
+ }
+ set dv [array get local]
+ unset local
+
+ return -code $code $res
+ }
+
+} \ No newline at end of file
diff --git a/desiredata/src/profile_dd.tcl b/desiredata/src/profile_dd.tcl
new file mode 100644
index 00000000..12c98a56
--- /dev/null
+++ b/desiredata/src/profile_dd.tcl
@@ -0,0 +1,20 @@
+
+if 1 {
+ puts "profiler version [package require profiler]"
+ profiler::init
+ # try just: prof
+ # or try: prof calls
+ proc prof {{arg totalRuntime}} {
+ set dump [profiler::dump]
+ #foreach {a b} $dump {foreach {c d} $b {set prof($a:$c) $d}}
+ set top [profiler::sortFunctions $arg]
+ foreach entry $top {
+ mset {k v} $entry
+ if {!$v} {continue}
+ puts [format "%8d %s" $v $k]
+ }
+ }
+}
+if 0 {
+ load matjuprofiler/matjuprofiler.so
+}
diff --git a/desiredata/src/rules.txt b/desiredata/src/rules.txt
new file mode 100644
index 00000000..ec6c56b3
--- /dev/null
+++ b/desiredata/src/rules.txt
@@ -0,0 +1,42 @@
+Those rules are in no particular order.
+Written by matju, on 2007.07.11 - ...
+
+#000: Tk-specific Tcl code goes in *.tk files; Tk-independent Tcl code is allowed to go in *.tcl files.
+ Exceptions: debug.tcl ...
+
+#001: Long source files are usually better than short files because they are easier to search in, with most editors.
+
+#002: It's better to make classes/procs/defs smaller but not to the extent that there are too many of them.
+
+#003: Accessing an object's privates directly, is likely to cause trouble in the future. All @variables are private, but
+ methods may also be marked as private or protected, by a visible comment where the definition is. (C++ variables are
+ not necessarily like that, mostly because of compatibility with classic pd)
+
+#004: Indentation is whatever you like as long as it's locally consistent. Tab stops (of the tab key) are at multiples of 8,
+ but indentation could be 2, 4, 8. (It's a bad idea to use less than 2 or more than 8). Open-braces don't deserve their
+ own line, but close-braces do, at least because of how the diff program works.
+
+#005: Screen width is assumed to be about 125 characters, not 80. This is especially useful for cutting down the need
+ to wrap lines. Newlines that have to do with linewrap get confused with meaningful newlines. Blank lines should be
+ used sparsely: the more there are blank lines, the less meaningful they are. If you want blank lines everywhere,
+ change the spacing of your font.
+
+#006: Short pieces of code that are quite repetitive but not completely, should be put on one line each and organised into
+ alternating columns of recurrent and non-recurrent material. This highlights patterns in code. e.g.:
+ for (int i=0; i<ninlets ; i++) x->inlets [i]->name = gensprintf( "inlet #%d",i);
+ for (int i=0; i<noutlets; i++) x->outlets[i]->name = gensprintf("outlet #%d",i);
+
+#007(Tcl): an attribute is a reader method named like "some_noun", which has no args and returns a value and/or a writer
+ method named like "some_noun=", which takes one arg (or more?) and returns no value. Together they are seen as
+ manipulating a variable. If the variable directly exists in the object, it should be called "@some_noun". The "="
+ suffix should be only used for that purpose. (we should think about whether to accept multiple args, because other
+ languages with a similar concept only allow one arg in the writer)
+
+#008(Tcl): Nouns like "visibility" that are simpler as adjectives and whose main purpose is to return a yes/no value, can
+ be named like "visible?" and are declined in the same way, e.g. "visible?=" and "@visible?". The "?" suffix should be
+ only used for that purpose.
+
+#009(Tcl): use :: instead of proc global.
+
+#010: make variables as local as it makes sense: don't make them global if they'd fit well in an object; don't put them in
+ an object if they belong inside of a def or proc (fully local).
diff --git a/desiredata/src/s_audio.c b/desiredata/src/s_audio.c
new file mode 100644
index 00000000..0bcf85f4
--- /dev/null
+++ b/desiredata/src/s_audio.c
@@ -0,0 +1,724 @@
+/* Copyright (c) 2003, Miller Puckette and others.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* machine-independent (well, mostly!) audio layer. Stores and recalls
+ audio settings from argparse routine and from dialog window.
+*/
+
+#define PD_PLUSPLUS_FACE
+#include "m_pd.h"
+#include "s_stuff.h"
+#include "m_simd.h"
+#include <stdio.h>
+#ifdef UNISTD
+#include <unistd.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sstream>
+
+#define SYS_DEFAULTCH 2
+#define SYS_MAXCH 100
+typedef long t_pa_sample;
+#define SYS_SAMPLEWIDTH sizeof(t_pa_sample)
+#define SYS_BYTESPERCHAN (sys_dacblocksize * SYS_SAMPLEWIDTH)
+#define SYS_XFERSAMPS (SYS_DEFAULTCH*sys_dacblocksize)
+#define SYS_XFERSIZE (SYS_SAMPLEWIDTH * SYS_XFERSAMPS)
+#define MAXNDEV 100
+#define DEVDESCSIZE 80
+
+extern t_audioapi pa_api, jack_api, oss_api, alsa_api, sgi_api, mmio_api, asio_api;
+
+t_sample *sys_soundin;
+t_sample *sys_soundout;
+float sys_dacsr;
+
+using namespace std;
+
+static t_audioapi *sys_audio() {
+#ifdef USEAPI_PORTAUDIO
+ if (sys_audioapi == API_PORTAUDIO) return &pa_api;
+#endif
+#ifdef USEAPI_JACK
+ if (sys_audioapi == API_JACK) return &jack_api;
+#endif
+#ifdef USEAPI_OSS
+ if (sys_audioapi == API_OSS) return &oss_api;
+#endif
+#ifdef USEAPI_ALSA
+ if (sys_audioapi == API_ALSA) return &alsa_api;
+#endif
+#ifdef USEAPI_SGI
+ if (sys_audioapi == API_SGI) return &sgi_api;
+#endif
+#ifdef USEAPI_MMIO
+ if (sys_audioapi == API_MMIO) return &mmio_api;
+#endif
+#ifdef USEAPI_ASIO
+ if (sys_audioapi == API_ASIO) return &asio_api;
+#endif
+ post("sys_close_audio: unknown API %d", sys_audioapi);
+ sys_inchannels = sys_outchannels = 0;
+ sched_set_using_dacs(0); /* tb: dsp is switched off */
+ return 0;
+}
+
+static void audio_getdevs(char *indevlist, int *nindevs, char *outdevlist, int *noutdevs, int *canmulti, int maxndev, int devdescsize);
+
+/* these are set in this file when opening audio, but then may be reduced,
+ even to zero, in the system dependent open_audio routines. */
+int sys_inchannels;
+int sys_outchannels;
+int sys_advance_samples; /* scheduler advance in samples */
+int sys_blocksize = 0; /* audio I/O block size in sample frames */
+#ifndef API_DEFAULT
+#define API_DEFAULT 0
+#endif
+int sys_audioapi = API_DEFAULT;
+int sys_dacblocksize;
+int sys_schedblocksize;
+int sys_meters; /* true if we're metering */
+static float sys_inmax; /* max input amplitude */
+static float sys_outmax; /* max output amplitude */
+int sys_schedadvance; /* scheduler advance in microseconds */
+
+/* the "state" is normally one if we're open and zero otherwise; but if the state is one,
+ we still haven't necessarily opened the audio hardware; see audio_isopen() below. */
+static int audio_state;
+
+/* last requested parameters */
+static t_audiodevs audio_in;
+static t_audiodevs audio_out;
+static int audio_rate;
+static int audio_dacblocksize;
+static int audio_advance;
+static int audio_scheduler;
+
+extern int sys_callbackscheduler;
+
+float peakvec(t_float* vec, t_int n, t_float cur_max);
+static float (*peak_fp)(t_float*, t_int, t_float) = peakvec;
+
+static int audio_isopen() {
+ return audio_state && ((audio_in.ndev > 0 && audio_in.chdev[0] > 0)
+ || (audio_out.ndev > 0 && audio_out.chdev[0] > 0));
+}
+
+extern "C" void sys_get_audio_params(t_audiodevs *in, t_audiodevs *out, int *prate, int *pdacblocksize, int *padvance, int *pscheduler) {
+ in->ndev = audio_in.ndev;
+ out->ndev = audio_out.ndev;
+ for (int i=0; i<MAXAUDIOINDEV; i++) {in ->dev[i] = audio_in.dev[i]; in->chdev[i] = audio_in.chdev[i];}
+ for (int i=0; i<MAXAUDIOOUTDEV; i++) {out->dev[i] = audio_out.dev[i]; out->chdev[i] = audio_out.chdev[i];}
+ *prate = audio_rate;
+ *pdacblocksize = audio_dacblocksize;
+ *padvance = audio_advance;
+ *pscheduler = audio_scheduler;
+}
+
+void sys_save_audio_params(
+int nindev, int *indev, int *chindev,
+int noutdev, int *outdev, int *choutdev,
+int rate, int dacblocksize, int advance, int scheduler) {
+ audio_in.ndev = nindev;
+ audio_out.ndev = noutdev;
+ for (int i=0; i<MAXAUDIOINDEV; i++) {audio_in.dev[i] = indev[i]; audio_in.chdev[i] = chindev[i];}
+ for (int i=0; i<MAXAUDIOOUTDEV; i++) {audio_out.dev[i] = outdev[i]; audio_out.chdev[i] = choutdev[i];}
+ audio_rate = rate;
+ audio_dacblocksize = dacblocksize;
+ audio_advance = advance;
+ audio_scheduler = scheduler;
+}
+
+extern "C" void sys_open_audio2(t_audiodevs *in, t_audiodevs *out, int rate, int dacblocksize, int advance, int scheduler) {
+ sys_open_audio(in->ndev, in->dev, in->ndev, in->chdev,
+ out->ndev, out->dev, out->ndev, out->chdev, rate, dacblocksize, advance, scheduler, 1);
+}
+
+/* init routines for any API which needs to set stuff up before any other API gets used. This is only true of OSS so far. */
+#ifdef USEAPI_OSS
+void oss_init();
+#endif
+
+static void audio_init() {
+ static int initted = 0;
+ if (initted) return;
+ initted = 1;
+#ifdef USEAPI_OSS
+ oss_init();
+#endif
+}
+
+/* set channels and sample rate. */
+void sys_setchsr(int chin, int chout, int sr, int dacblocksize) {
+ int inbytes = (chin ? chin : 2) * (sys_dacblocksize*sizeof(float));
+ int outbytes = (chout ? chout : 2) * (sys_dacblocksize*sizeof(float));
+ if (dacblocksize != (1<<ilog2(dacblocksize))) {
+ dacblocksize = 1<<ilog2(dacblocksize);
+ post("warning: adjusting dac~blocksize to power of 2: %d", dacblocksize);
+ }
+ sys_dacblocksize = dacblocksize;
+ sys_schedblocksize = dacblocksize;
+ sys_inchannels = chin;
+ sys_outchannels = chout;
+ sys_dacsr = double(sr);
+ sys_advance_samples = max(int(sys_schedadvance*sys_dacsr/1000000.),sys_dacblocksize);
+ if (sys_soundin) freealignedbytes(sys_soundin,inbytes);
+ sys_soundin = (t_float *)getalignedbytes(inbytes);
+ memset(sys_soundin, 0, inbytes);
+ if (sys_soundout) freealignedbytes(sys_soundout,outbytes);
+ sys_soundout = (t_float *)getalignedbytes(outbytes);
+ memset(sys_soundout, 0, outbytes);
+ /* tb: modification for simd-optimized peak finding */
+ if (SIMD_CHKCNT(sys_inchannels * sys_dacblocksize) &&
+ SIMD_CHKCNT(sys_outchannels * sys_dacblocksize))
+ peak_fp = peakvec_simd;
+ else peak_fp = peakvec;
+ if (sys_verbose) post("input channels = %d, output channels = %d", sys_inchannels, sys_outchannels);
+ canvas_resume_dsp(canvas_suspend_dsp());
+}
+
+/* ----------------------- public routines ----------------------- */
+
+/* open audio devices (after cleaning up the specified device and channel vectors). The audio devices are "zero based"
+ (i.e. "0" means the first one.) We also save the cleaned-up device specification so that we
+ can later re-open audio and/or show the settings on a dialog window. */
+void sys_open_audio(int nindev, int *indev, int nchindev, int *chindev, int noutdev, int *outdev, int nchoutdev,
+int *choutdev, int rate, int dacblocksize, int advance, int schedmode, int enable) {
+ int defaultchannels = SYS_DEFAULTCH;
+ int realinchans[MAXAUDIOINDEV], realoutchans[MAXAUDIOOUTDEV];
+ char indevlist[MAXNDEV*DEVDESCSIZE], outdevlist[MAXNDEV*DEVDESCSIZE];
+ int indevs = 0, outdevs = 0, canmulti = 0;
+ audio_getdevs(indevlist, &indevs, outdevlist, &outdevs, &canmulti, MAXNDEV, DEVDESCSIZE);
+ if (sys_externalschedlib) return;
+ if (sys_inchannels || sys_outchannels) sys_close_audio();
+ if (rate < 1) rate = DEFAULTSRATE;
+ if (dacblocksize < 1) dacblocksize = DEFDACBLKSIZE;
+ if (advance <= 0) advance = DEFAULTADVANCE;
+ audio_init();
+ /* Since the channel vector might be longer than the audio device vector, or vice versa, we fill the shorter one
+ in to match the longer one. Also, if both are empty, we fill in one device (the default) and two channels. */
+ if (nindev == -1) { /* no input audio devices specified */
+ if (nchindev == -1) {
+ if (indevs >= 1) {
+ nchindev=1;
+ chindev[0] = defaultchannels;
+ nindev = 1;
+ indev[0] = DEFAULTAUDIODEV;
+ } else nindev = nchindev = 0;
+ } else {
+ for (int i=0; i<MAXAUDIOINDEV; i++) indev[i] = i;
+ nindev = nchindev;
+ }
+ } else {
+ if (nchindev == -1) {
+ nchindev = nindev;
+ for (int i=0; i<nindev; i++) chindev[i] = defaultchannels;
+ } else if (nchindev > nindev) {
+ for (int i=nindev; i<nchindev; i++) {
+ if (i == 0) indev[0] = DEFAULTAUDIODEV; else indev[i] = indev[i-1] + 1;
+ }
+ nindev = nchindev;
+ } else if (nchindev < nindev) {
+ for (int i=nchindev; i<nindev; i++) {
+ if (i == 0) chindev[0] = defaultchannels; else chindev[i] = chindev[i-1];
+ }
+ nindev = nchindev;
+ }
+ }
+ if (noutdev == -1) { /* not set */
+ if (nchoutdev == -1) {
+ if (outdevs >= 1) {
+ nchoutdev=1;
+ choutdev[0]=defaultchannels;
+ noutdev=1;
+ outdev[0] = DEFAULTAUDIODEV;
+ } else nchoutdev = noutdev = 0;
+ } else {
+ for (int i=0; i<MAXAUDIOOUTDEV; i++) outdev[i] = i;
+ noutdev = nchoutdev;
+ }
+ } else {
+ if (nchoutdev == -1) {
+ nchoutdev = noutdev;
+ for (int i=0; i<noutdev; i++) choutdev[i] = defaultchannels;
+ } else if (nchoutdev > noutdev) {
+ for (int i=noutdev; i<nchoutdev; i++) {
+ if (i == 0) outdev[0] = DEFAULTAUDIODEV; else outdev[i] = outdev[i-1] + 1;
+ }
+ noutdev = nchoutdev;
+ } else if (nchoutdev < noutdev) {
+ for (int i=nchoutdev; i<noutdev; i++) {
+ if (i == 0) choutdev[0] = defaultchannels; else choutdev[i] = choutdev[i-1];
+ }
+ noutdev = nchoutdev;
+ }
+ }
+ /* count total number of input and output channels */
+ int inchans=0, outchans=0;
+ for (int i=0; i < nindev; i++) inchans += (realinchans[i] = (chindev[i] > 0 ? chindev[i] : 0));
+ for (int i=0; i < noutdev; i++) outchans += (realoutchans[i] = (choutdev[i] > 0 ? choutdev[i] : 0));
+ /* if no input or output devices seem to have been specified, this really means just disable audio, which we now do. */
+ if (!inchans && !outchans) enable = 0;
+ sys_schedadvance = advance * 1000;
+ sys_setchsr(inchans, outchans, rate, dacblocksize);
+ sys_log_error(ERR_NOTHING);
+ if (enable) {
+ /* for alsa, only one device is supported; it may be open for both input and output. */
+#ifdef USEAPI_PORTAUDIO
+ if (sys_audioapi == API_PORTAUDIO)
+ pa_open_audio(inchans, outchans, rate, advance,
+ (noutdev > 0 ? indev[0] : 0),
+ (noutdev > 0 ? outdev[0] : 0), schedmode);
+ else
+#endif
+#ifdef USEAPI_JACK
+ if (sys_audioapi == API_JACK)
+ jack_open_audio((nindev > 0 ? realinchans[0] : 0),
+ (noutdev > 0 ? realoutchans[0] : 0), rate, schedmode);
+ else
+#endif
+ if (sys_audioapi == API_OSS || sys_audioapi == API_ALSA || sys_audioapi == API_MMIO)
+ sys_audio()->open_audio(nindev, indev, nchindev, realinchans, noutdev, outdev, nchoutdev, realoutchans, rate, -42);
+ else if (sys_audioapi == API_SGI)
+ sys_audio()->open_audio(nindev, indev, nchindev, chindev, noutdev, outdev, nchoutdev, choutdev, rate, -42);
+ else if (sys_audioapi == API_ASIO)
+ sys_audio()->open_audio(nindev, indev, nchindev, chindev, noutdev, outdev, nchoutdev, choutdev, rate, schedmode);
+ else post("unknown audio API specified");
+ }
+ sys_save_audio_params(nindev, indev, chindev, noutdev, outdev, choutdev, int(sys_dacsr), sys_dacblocksize, advance, schedmode);
+ if (sys_inchannels == 0 && sys_outchannels == 0) enable = 0;
+ audio_state = enable;
+ sys_vgui("set pd_whichapi %d\n", audio_isopen() ? sys_audioapi : 0);
+ sched_set_using_dacs(enable);
+ sys_update_sleepgrain();
+ if (enable) {
+ t_atom argv[1];
+ t_symbol *selector = gensym("audio_started");
+ t_symbol *pd = gensym("pd");
+ SETFLOAT(argv, 1.);
+ typedmess(pd->s_thing, selector, 1, argv);
+ }
+}
+
+void sys_close_audio() {
+ /* jsarlo { (*/
+ if (sys_externalschedlib) return;
+ /* } jsarlo */
+ if (!audio_isopen()) return;
+ if (sys_audio()) sys_audio()->close_audio();
+ else post("sys_close_audio: unknown API %d", sys_audioapi);
+ sys_inchannels = sys_outchannels = 0;
+ sched_set_using_dacs(0); /* tb: dsp is switched off */
+}
+
+/* open audio using whatever parameters were last used */
+void sys_reopen_audio() {
+ t_audiodevs in, out;
+ int rate, dacblocksize, advance, scheduler;
+ sys_close_audio();
+ sys_get_audio_params(&in,&out,&rate, &dacblocksize, &advance, &scheduler);
+ sys_open_audio2(&in,&out, rate, dacblocksize, advance, scheduler);
+}
+
+/* tb: default value of peak_fp {*/
+float peakvec(t_float* vec, t_int n, t_float cur_max) {
+ for (int i=0; i<n; i++) {
+ float f = *vec++;
+ if (f > cur_max) cur_max = f;
+ else if (-f > cur_max) cur_max = -f;
+ }
+ return cur_max;
+}
+/* } */
+
+void sys_peakmeters() {
+ if (sys_inchannels) sys_inmax = peak_fp(sys_soundin, sys_inchannels * sys_dacblocksize, sys_inmax);
+ if (sys_outchannels) sys_outmax = peak_fp(sys_soundout,sys_outchannels * sys_dacblocksize, sys_outmax);
+}
+
+int sys_send_dacs() {
+ if (sys_meters) sys_peakmeters();
+ if (sys_audio()) return sys_audio()->send_dacs();
+ post("unknown API");
+ return 0;
+}
+
+float sys_getsr() {return sys_dacsr;}
+int sys_get_outchannels() {return sys_outchannels;}
+int sys_get_inchannels() {return sys_inchannels;}
+
+void sys_getmeters(float *inmax, float *outmax) {
+ if (inmax) {
+ sys_meters = 1;
+ *inmax = sys_inmax;
+ *outmax = sys_outmax;
+ } else sys_meters = 0;
+ sys_inmax = sys_outmax = 0;
+}
+
+static void audio_getdevs(char *indevlist, int *nindevs, char *outdevlist, int *noutdevs, int *canmulti, int maxndev, int devdescsize) {
+ audio_init();
+ if (sys_audio()) sys_audio()->getdevs(indevlist, nindevs, outdevlist, noutdevs, canmulti, maxndev, devdescsize);
+ else {*nindevs = *noutdevs = 0;}
+}
+
+static void sys_listaudiodevs() {
+ char indevlist[MAXNDEV*DEVDESCSIZE], outdevlist[MAXNDEV*DEVDESCSIZE];
+ int nindevs = 0, noutdevs = 0, canmulti = 0;
+ audio_getdevs(indevlist, &nindevs, outdevlist, &noutdevs, &canmulti, MAXNDEV, DEVDESCSIZE);
+ /* To agree with command line flags, normally start at 1; but microsoft "MMIO" device list starts at 0 (the "mapper"). */
+ /* (see also sys_mmio variable in s_main.c) */
+ if (!nindevs) post("no audio input devices found");
+ else {
+ post("audio input devices:");
+ for (int i=0; i<nindevs; i++) post("%d. %s", i + (sys_audioapi != API_MMIO), indevlist + i * DEVDESCSIZE);
+ }
+ if (!noutdevs) post("no audio output devices found");
+ else {
+ post("audio output devices:");
+ for (int i=0; i<noutdevs; i++) post("%d. %s", i + (sys_audioapi != API_MMIO), outdevlist + i * DEVDESCSIZE);
+ }
+ post("API number %d", sys_audioapi);
+}
+
+/* start an audio settings dialog window */
+void glob_audio_properties(t_pd *dummy, t_floatarg flongform) {
+ /* these are the devices you're using: */
+ t_audiodevs in,out;
+ int rate, dacblocksize, advance, scheduler;
+ /* these are all the devices on your system: */
+ char indevlist[MAXNDEV*DEVDESCSIZE], outdevlist[MAXNDEV*DEVDESCSIZE];
+ int nindevs = 0, noutdevs = 0, canmulti = 0;
+ audio_getdevs(indevlist, &nindevs, outdevlist, &noutdevs, &canmulti, MAXNDEV, DEVDESCSIZE);
+ ostringstream indevliststring; for (int i=0; i<nindevs; i++) indevliststring << " {" << (indevlist + i*DEVDESCSIZE) << "}";
+ ostringstream outdevliststring; for (int i=0; i<noutdevs; i++) outdevliststring << " {" << (outdevlist + i*DEVDESCSIZE) << "}";
+ sys_get_audio_params(&in,&out,&rate,&dacblocksize,&advance,&scheduler);
+ if (in.ndev > 1 || out.ndev > 1) flongform = 1;
+ ostringstream indevs; for (int i=0; i< in.ndev; i++) indevs << " " << in.dev [i];
+ ostringstream outdevs; for (int i=0; i<out.ndev; i++) outdevs << " " << out.dev[i];
+ ostringstream inchans; for (int i=0; i< in.ndev; i++) inchans << " " << in.chdev[i];
+ ostringstream outchans; for (int i=0; i<out.ndev; i++) outchans << " " << out.chdev[i];
+ sys_vgui("pdtk_audio_dialog {%s} {%s} {%s} {%s} {%s} {%s} %d %d %d %d %d\n",
+ indevliststring .str().data()+1, indevs.str().data()+1, inchans.str().data()+1,
+ outdevliststring.str().data()+1, outdevs.str().data()+1, outchans.str().data()+1,
+ rate, dacblocksize, advance, canmulti, flongform!=0);
+}
+
+/* new values from dialog window */
+void glob_audio_dialog(t_pd *dummy, t_symbol *s, int argc, t_atom *argv) {
+ int nindev=0, noutdev=0;
+ int newindev[4], newinchan[4], newoutdev[4], newoutchan[4];
+ /* the new values the dialog came back with: */
+ int newrate = atom_getintarg(16, argc, argv);
+ int newdacblocksize = atom_getintarg(17, argc, argv);
+ int newadvance = atom_getintarg(18, argc, argv);
+ int newschedmode = atom_getintarg(19, argc, argv);
+ for (int i=0; i<4; i++) {
+ newindev[i] = atom_getintarg(i, argc, argv);
+ newinchan[i] = atom_getintarg(i+4, argc, argv);
+ newoutdev[i] = atom_getintarg(i+8, argc, argv);
+ newoutchan[i] = atom_getintarg(i+12, argc, argv);
+ }
+ for (int i=0; i<4; i++) {
+ if (newinchan[i]) {
+ newindev[nindev] = newindev[i];
+ newinchan[nindev] = newinchan[i];
+ nindev++;
+ }
+ }
+ for (int i=0; i<4; i++) {
+ if (newoutchan[i]) {
+ newoutdev[noutdev] = newoutdev[i];
+ newoutchan[noutdev] = newoutchan[i];
+ noutdev++;
+ }
+ }
+ sys_close_audio();
+ sys_open_audio(nindev, newindev, nindev, newinchan,
+ noutdev, newoutdev, noutdev, newoutchan,
+ newrate, newdacblocksize, newadvance, newschedmode, 1);
+}
+
+extern void sgi_listaudiodevs();
+void sys_listdevs() {
+ if (sys_audioapi == API_PORTAUDIO) sys_listaudiodevs(); else
+#ifdef USEAPI_JACK
+ if (sys_audioapi == API_JACK) jack_listdevs(); else
+#endif
+ if (sys_audioapi == API_OSS) sys_listaudiodevs(); else
+ if (sys_audioapi == API_ALSA) sys_listaudiodevs(); else
+#ifdef USEAPI_SGI
+ if (sys_audioapi == API_SGI) sgi_listaudiodevs(); else
+#endif
+ if (sys_audioapi == API_MMIO) sys_listaudiodevs(); else
+ post("unknown API");
+ sys_listmididevs();
+}
+
+void sys_setblocksize(int n) {
+ if (n < 1) n = 1;
+ if (n != (1 << ilog2(n))) post("warning: adjusting blocksize to power of 2: %d", (n = (1 << ilog2(n))));
+ sys_blocksize = n;
+}
+
+void sys_set_audio_api(int which) {
+ sys_audioapi = which;
+ if (sys_verbose) post("sys_audioapi %d", sys_audioapi);
+}
+
+void glob_audio_setapi(t_pd *dummy, t_floatarg f) {
+ int newapi = int(f);
+ if (newapi != sys_audioapi) {
+ if (newapi != sys_audioapi) {
+ sys_close_audio();
+ sys_audioapi = newapi;
+ /* bash device params back to default */
+ audio_in.ndev = audio_out.ndev = 1;
+ audio_in.dev[0] = audio_out.dev[0] = DEFAULTAUDIODEV;
+ audio_in.chdev[0] = audio_out.chdev[0] = SYS_DEFAULTCH;
+ }
+ sched_set_using_dacs(0);
+/* glob_audio_properties(0, 0); */
+ }
+}
+
+/* start or stop the audio hardware */
+void sys_set_audio_state(int onoff) {
+ if (onoff) { /* start */
+ if (!audio_isopen()) sys_reopen_audio();
+ } else {
+ if (audio_isopen()) sys_close_audio();
+ }
+ sched_set_using_dacs(onoff);
+ sys_setscheduler(sys_getscheduler()); /* tb: reset scheduler */
+ audio_state = onoff;
+}
+
+void sys_get_audio_apis(char *buf) {
+ int n = 0;
+ strcpy(buf, "{ ");
+#ifdef USEAPI_OSS
+ sprintf(buf + strlen(buf), "{OSS %d} ", API_OSS); n++;
+#endif
+#ifdef USEAPI_ASIO
+ sprintf(buf + strlen(buf), "{ASIO %d} ", API_ASIO); n++;
+#endif
+#ifdef USEAPI_MMIO
+ sprintf(buf + strlen(buf), "{\"standard (MMIO)\" %d} ", API_MMIO); n++;
+#endif
+#ifdef USEAPI_ALSA
+ sprintf(buf + strlen(buf), "{ALSA %d} ", API_ALSA); n++;
+#endif
+#ifdef USEAPI_PORTAUDIO
+#ifdef __APPLE__
+ sprintf(buf + strlen(buf), "{\"standard (portaudio)\" %d} ", API_PORTAUDIO); n++;
+#else
+ sprintf(buf + strlen(buf), "{portaudio %d} ", API_PORTAUDIO); n++;
+#endif
+#endif
+#ifdef USEAPI_SGI
+ sprintf(buf + strlen(buf), "{SGI %d} ", API_SGI); n++;
+#endif
+#ifdef USEAPI_JACK
+ sprintf(buf + strlen(buf), "{jack %d} ", API_JACK); n++;
+#endif
+ strcat(buf, "}");
+}
+
+#ifdef USEAPI_ALSA
+void alsa_putzeros(int iodev, int n);
+void alsa_getzeros(int iodev, int n);
+void alsa_printstate();
+#endif
+
+/* debugging */
+void glob_foo(void *dummy, t_symbol *s, int argc, t_atom *argv) {
+ t_symbol *arg = atom_getsymbolarg(0, argc, argv);
+ if (arg == gensym("restart")) sys_reopen_audio();
+#ifdef USEAPI_ALSA
+ /* what's the matter here? what should be the value of iodev??? */
+ else if (arg == gensym("alsawrite")) alsa_putzeros(0, atom_getintarg(1, argc, argv));
+ else if (arg == gensym("alsaread")) alsa_getzeros(0, atom_getintarg(1, argc, argv));
+ else if (arg == gensym("print")) alsa_printstate();
+#endif
+}
+
+/* tb: message-based audio configuration
+ * supported by vibrez.net { */
+void glob_audio_samplerate(t_pd * dummy, t_float f) {
+ t_audiodevs in, out;
+ int rate, dacblocksize, advance, scheduler;
+ if (f == sys_getsr()) return;
+ sys_get_audio_params(&in,&out,&rate, &dacblocksize, &advance, &scheduler);
+ sys_close_audio();
+ sys_open_audio(in.ndev, in.dev, in.ndev, in.chdev, out.ndev, out.dev, out.ndev, out.chdev,
+ (int)f, dacblocksize, advance, scheduler, 1);
+}
+
+void glob_audio_api(t_pd *dummy, t_float f) {
+ int newapi = (int)f;
+ sys_close_audio();
+ sys_audioapi = newapi;
+}
+
+void glob_audio_delay(t_pd *dummy, t_float f) {
+ t_audiodevs in,out;
+ int rate, dacblocksize, advance, scheduler;
+ if ((int)f == audio_advance) return;
+ sys_get_audio_params(&in,&out, &rate, &dacblocksize, &advance, &scheduler);
+ sys_close_audio();
+ sys_open_audio(in.ndev, in.dev, in.ndev, in.chdev, out.ndev, out.dev, out.ndev, out.chdev,
+ rate, dacblocksize, (int) f, scheduler, 1);
+}
+
+void glob_audio_dacblocksize(t_pd * dummy, t_float f) {
+ t_audiodevs in,out;
+ int rate, dacblocksize, advance, scheduler;
+ if ((int)f == audio_dacblocksize) return;
+ sys_get_audio_params(&in,&out, &rate, &dacblocksize, &advance, &scheduler);
+ sys_close_audio();
+ sys_open_audio2(&in,&out, rate, (int)f, advance, scheduler);
+}
+
+void glob_audio_scheduler(t_pd * dummy, t_float f) {
+ t_audiodevs in,out;
+ int rate, dacblocksize, advance, scheduler;
+ if ((int)f == sys_callbackscheduler) return;
+ scheduler = f!=0;
+ sys_get_audio_params(&in,&out, &rate, &dacblocksize, &advance, &scheduler);
+ sys_close_audio();
+ sys_open_audio2(&in,&out, rate, dacblocksize, advance, scheduler);
+ if (scheduler != sys_callbackscheduler) {
+ if (scheduler == 1) {
+ post("switched to callback-based scheduler");
+ } else {
+ post("switched to traditional scheduler");
+ }
+ } else post("couldn't change scheduler");
+}
+
+void glob_audio_device(t_pd *dummy, t_symbol *s, int argc, t_atom *argv) {
+ t_audiodevs in,out;
+ int rate, dacblocksize, advance, scheduler;
+ sys_get_audio_params(&in,&out, &rate, &dacblocksize, &advance, &scheduler);
+ out.ndev = in.ndev = (int)atom_getfloatarg(0, argc, argv);
+ for (int i=0; i<MAXAUDIOINDEV; i++) {
+ out.dev [i] = in.dev [i] = int(atom_getfloatarg(i*2+1, argc, argv));
+ out.chdev[i] = in.chdev[i] = int(atom_getfloatarg(i*2+2, argc, argv));
+ }
+ sys_close_audio();
+ sys_open_audio2(&in,&out, rate, dacblocksize, advance, scheduler);
+}
+
+void glob_audio_device_in(t_pd *dummy, t_symbol *s, int argc, t_atom *argv) {
+ t_audiodevs in,out;
+ int rate, dacblocksize, advance, scheduler;
+ sys_get_audio_params(&in,&out, &rate, &dacblocksize, &advance, &scheduler);
+ in.ndev = (int)atom_getfloatarg(0, argc, argv);
+ for (int i=0; i<MAXAUDIOINDEV; i=i+2) {
+ in.dev [i] = atom_getintarg(i+1, argc, argv);
+ in.chdev[i] = atom_getintarg(i+2, argc, argv);
+ }
+ sys_close_audio();
+ sys_open_audio2(&in,&out,rate, dacblocksize, advance, scheduler);
+}
+
+void glob_audio_device_out(t_pd *dummy, t_symbol *s, int argc, t_atom *argv) {
+ t_audiodevs in,out;
+ int rate, dacblocksize, advance, scheduler;
+ sys_get_audio_params(&in,&out, &rate, &dacblocksize, &advance, &scheduler);
+ out.ndev = (int)atom_getfloatarg(0, argc, argv);
+ /* i+=2 ? isn't that a bug??? */
+ for (int i=0; i<MAXAUDIOOUTDEV; i+=2) {
+ out.dev [i] = atom_getintarg(i+1, argc, argv);
+ out.chdev[i] = atom_getintarg(i+2, argc, argv);
+ }
+ sys_close_audio();
+ sys_open_audio2(&in,&out, rate, dacblocksize, advance, scheduler);
+}
+
+/* some general helper functions */
+void sys_update_sleepgrain() {
+ sys_sleepgrain = sys_schedadvance/4;
+ if (sys_sleepgrain < 1000) sys_sleepgrain = 1000;
+ else if (sys_sleepgrain > 5000) sys_sleepgrain = 5000;
+}
+
+/* t_audiodevs are the ones you're using; char[] are all the devices available. */
+void glob_audio_getaudioindevices(t_pd * dummy, t_symbol *s, int ac, t_atom *av) {
+ t_audiodevs in,out;
+ int rate, dacblocksize, advance, scheduler;
+ int nindevs = 0, noutdevs = 0, canmulti = 0;
+ t_atom argv[MAXNDEV];
+ int f = ac ? (int)atom_getfloatarg(0,ac,av) : -1;
+ t_symbol *selector = gensym("audioindev");
+ t_symbol *pd = gensym("pd");
+ char indevlist[MAXNDEV*DEVDESCSIZE], outdevlist[MAXNDEV*DEVDESCSIZE];
+ audio_getdevs(indevlist, &nindevs, outdevlist, &noutdevs, &canmulti, MAXNDEV, DEVDESCSIZE);
+ sys_get_audio_params(&in,&out, &rate, &dacblocksize, &advance, &scheduler);
+ if (f < 0) {
+ for (int i=0; i<nindevs; i++) SETSTRING(argv+i,indevlist+i*DEVDESCSIZE);
+ typedmess(pd->s_thing, selector, nindevs, argv);
+ } else if (f < nindevs) {
+ SETSTRING(argv, indevlist + f * DEVDESCSIZE);
+ typedmess(pd->s_thing, selector, 1, argv);
+ }
+}
+void glob_audio_getaudiooutdevices(t_pd * dummy, t_symbol *s, int ac, t_atom *av) {
+ t_audiodevs in,out;
+ int rate, dacblocksize, advance, scheduler;
+ int nindevs = 0, noutdevs = 0, canmulti = 0;
+ t_atom argv[MAXNDEV];
+ int f = ac ? (int)atom_getfloatarg(0,ac,av) : -1;
+ t_symbol *selector = gensym("audiooutdev");
+ t_symbol *pd = gensym("pd");
+ char indevlist[MAXNDEV*DEVDESCSIZE], outdevlist[MAXNDEV*DEVDESCSIZE];
+ audio_getdevs(indevlist, &nindevs, outdevlist, &noutdevs, &canmulti, MAXNDEV, DEVDESCSIZE);
+ sys_get_audio_params(&in,&out, &rate, &dacblocksize, &advance, &scheduler);
+ if (f < 0) {
+ for (int i=0; i<noutdevs; i++) SETSYMBOL(argv+i, gensym(outdevlist+i*DEVDESCSIZE));
+ typedmess(pd->s_thing, selector, noutdevs, argv);
+ } else if (f < noutdevs) {
+ SETSTRING(argv, outdevlist + f * DEVDESCSIZE);
+ typedmess(pd->s_thing, selector, 1, argv);
+ }
+}
+
+/* some prototypes from s_audio_portaudio.c */
+extern void pa_getcurrent_devices();
+extern void pa_getaudioininfo(t_float f);
+extern void pa_getaudiooutinfo(t_float f);
+extern void pa_test_setting (int ac, t_atom *av);
+extern void pa_get_asio_latencies(t_float f);
+
+void glob_audio_getaudioininfo(t_pd * dummy, t_float f) {
+#if defined(USEAPI_PORTAUDIO) && !defined(PABLIO)
+ if (sys_audioapi == API_PORTAUDIO) pa_getaudioininfo(f);
+#endif
+}
+void glob_audio_getaudiooutinfo(t_pd * dummy, t_float f) {
+#if defined(USEAPI_PORTAUDIO) && !defined(PABLIO)
+ if (sys_audioapi == API_PORTAUDIO) pa_getaudiooutinfo(f);
+#endif
+}
+void glob_audio_testaudiosetting(t_pd * dummy, t_symbol *s, int ac, t_atom *av) {
+#if defined(USEAPI_PORTAUDIO) && !defined(PABLIO)
+ if (sys_audioapi == API_PORTAUDIO) pa_test_setting (ac, av);
+#endif
+}
+void glob_audio_getcurrent_devices() {
+#if defined(USEAPI_PORTAUDIO) && !defined(PABLIO)
+ if (sys_audioapi == API_PORTAUDIO) pa_getcurrent_devices();
+#endif
+}
+void glob_audio_asio_latencies(t_pd * dummy, t_float f) {
+#if defined(USEAPI_PORTAUDIO) && !defined(PABLIO)
+ if (sys_audioapi == API_PORTAUDIO) pa_get_asio_latencies(f);
+#endif
+}
+
+/* tb } */
diff --git a/desiredata/src/s_audio_alsa.c b/desiredata/src/s_audio_alsa.c
new file mode 100644
index 00000000..d3d1b3f1
--- /dev/null
+++ b/desiredata/src/s_audio_alsa.c
@@ -0,0 +1,594 @@
+/* Copyright (c) 1997-2003 Guenter Geiger, Miller Puckette, Larry Troxler, Winfried Ritsch, Karl MacMillan, and others.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* this file inputs and outputs audio using the ALSA API available on linux. */
+
+/* support for ALSA pcmv2 api by Karl MacMillan<karlmac@peabody.jhu.edu> */
+/* support for ALSA MMAP noninterleaved by Winfried Ritsch, IEM */
+
+#include <alsa/asoundlib.h>
+
+#include "m_pd.h"
+#include "s_stuff.h"
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <sched.h>
+#include <sys/mman.h>
+#include "s_audio_alsa.h"
+
+/* Defines */
+#define DEBUG(x) x
+#define DEBUG2(x) {x;}
+
+/* needed for alsa 0.9 compatibility: */
+#if (SND_LIB_MAJOR < 1)
+#define ALSAAPI9
+#endif
+
+//static void alsa_close_audio();
+static void alsa_checkiosync();
+static void alsa_numbertoname(int iodev, char *devname, int nchar);
+static int alsa_jittermax;
+static void alsa_close_audio();
+#define ALSA_DEFJITTERMAX 3
+
+ /* don't assume we can turn all 31 bits when doing float-to-fix;
+ otherwise some audio drivers (e.g. Midiman/ALSA) wrap around. */
+#define FMAX 0x7ffff000
+#define CLIP32(x) (((x)>FMAX)?FMAX:((x) < -FMAX)?-FMAX:(x))
+
+static char *alsa_snd_buf;
+static int alsa_snd_bufsize;
+static int alsa_buf_samps;
+static snd_pcm_status_t *alsa_status;
+static int alsa_usemmap;
+
+t_alsa_dev alsa_indev[ALSA_MAXDEV];
+t_alsa_dev alsa_outdev[ALSA_MAXDEV];
+int alsa_nindev;
+int alsa_noutdev;
+
+static void check_error(int err, const char *why) {if (err<0) error("%s: %s", why, snd_strerror(err));}
+
+static int alsaio_canmmap(t_alsa_dev *dev) {
+ snd_pcm_hw_params_t *hw_params;
+ int err1, err2;
+ snd_pcm_hw_params_alloca(&hw_params);
+ err1 = snd_pcm_hw_params_any(dev->a_handle, hw_params);
+ if (err1 < 0) {
+ check_error(err1,"Broken configuration: no configurations available");
+ return 0;
+ }
+ err1 = snd_pcm_hw_params_set_access(dev->a_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);
+ if (err1 < 0) {
+ err2 = snd_pcm_hw_params_set_access(dev->a_handle, hw_params, SND_PCM_ACCESS_MMAP_NONINTERLEAVED);
+ } else err2 = -1;
+#if 0
+ error("err 1 %d (%s), err2 %d (%s)", err1, snd_strerror(err1), err2, snd_strerror(err2));
+#endif
+ return err1<0 && err2>=0;
+}
+
+static int alsaio_setup(t_alsa_dev *dev, int out, int *channels, int *rate, int nfrags, int frag_size) {
+ int bufsizeforthis, err;
+ snd_pcm_hw_params_t* hw_params;
+ unsigned int tmp_uint;
+ snd_pcm_uframes_t tmp_snd_pcm_uframes;
+ if (sys_verbose) {
+ if (out) post("configuring sound output...");
+ else post("configuring sound input...");
+ }
+ /* set hardware parameters... */
+ snd_pcm_hw_params_alloca(&hw_params);
+ /* get the default params */
+ err = snd_pcm_hw_params_any(dev->a_handle, hw_params);
+ check_error(err, "snd_pcm_hw_params_any");
+ /* try to set interleaved access */
+ err = snd_pcm_hw_params_set_access(dev->a_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);
+ if (err < 0) return -1;
+ check_error(err, "snd_pcm_hw_params_set_access");
+ /* Try to set 32 bit format first */
+ err = snd_pcm_hw_params_set_format(dev->a_handle, hw_params, SND_PCM_FORMAT_S32);
+ if (err<0) {
+ error("PD-ALSA: 32 bit format not available - using 16");
+ err = snd_pcm_hw_params_set_format(dev->a_handle, hw_params,SND_PCM_FORMAT_S16);
+ check_error(err, "snd_pcm_hw_params_set_format");
+ dev->a_sampwidth = 2;
+ } else dev->a_sampwidth = 4;
+ if (sys_verbose) post("Sample width set to %d bytes", dev->a_sampwidth);
+ /* set the subformat */
+ err = snd_pcm_hw_params_set_subformat(dev->a_handle, hw_params, SND_PCM_SUBFORMAT_STD);
+ check_error(err, "snd_pcm_hw_params_set_subformat");
+ /* set the number of channels */
+ tmp_uint = *channels;
+ err = snd_pcm_hw_params_set_channels_min(dev->a_handle, hw_params, &tmp_uint);
+ check_error(err, "snd_pcm_hw_params_set_channels");
+ if (tmp_uint != (unsigned)*channels) post("ALSA: set input channels to %d", tmp_uint);
+ *channels = tmp_uint;
+ dev->a_channels = *channels;
+ /* set the sampling rate */
+ err = snd_pcm_hw_params_set_rate_min(dev->a_handle, hw_params, (unsigned int *)rate, 0);
+ check_error(err, "snd_pcm_hw_params_set_rate_min (input)");
+#if 0
+ err = snd_pcm_hw_params_get_rate(hw_params, &subunitdir);
+ post("input sample rate %d", err);
+#endif
+ /* set the period - ie frag size */
+ /* LATER try this to get a recommended period size...
+ right now, it trips an assertion failure in ALSA lib */
+#ifdef ALSAAPI9
+ err = snd_pcm_hw_params_set_period_size_near(dev->a_handle, hw_params, (snd_pcm_uframes_t)frag_size, 0);
+#else
+ tmp_snd_pcm_uframes = frag_size;
+ err = snd_pcm_hw_params_set_period_size_near(dev->a_handle, hw_params, &tmp_snd_pcm_uframes, 0);
+#endif
+ check_error(err, "snd_pcm_hw_params_set_period_size_near (input)");
+ /* set the number of periods - ie numfrags */
+#ifdef ALSAAPI9
+ err = snd_pcm_hw_params_set_periods_near(dev->a_handle, hw_params, nfrags, 0);
+#else
+ tmp_uint = nfrags;
+ err = snd_pcm_hw_params_set_periods_near(dev->a_handle, hw_params, &tmp_uint, 0);
+#endif
+ check_error(err, "snd_pcm_hw_params_set_periods_near (input)");
+ /* set the buffer size */
+#ifdef ALSAAPI9
+ err = snd_pcm_hw_params_set_buffer_size_near(dev->a_handle, hw_params, nfrags * frag_size);
+#else
+ tmp_snd_pcm_uframes = nfrags * frag_size;
+ err = snd_pcm_hw_params_set_buffer_size_near(dev->a_handle, hw_params, &tmp_snd_pcm_uframes);
+#endif
+ check_error(err, "snd_pcm_hw_params_set_buffer_size_near (input)");
+ err = snd_pcm_hw_params(dev->a_handle, hw_params);
+ check_error(err, "snd_pcm_hw_params (input)");
+ /* set up the buffer */
+ bufsizeforthis = sys_dacblocksize * dev->a_sampwidth * *channels;
+ if (alsa_snd_buf) {
+ if (alsa_snd_bufsize < bufsizeforthis) {
+ if (!(alsa_snd_buf = (char *)realloc(alsa_snd_buf, bufsizeforthis))) {error("out of memory"); return 0;}
+ memset(alsa_snd_buf, 0, bufsizeforthis);
+ alsa_snd_bufsize = bufsizeforthis;
+ }
+ } else {
+ if (!(alsa_snd_buf = (char *)malloc(bufsizeforthis))) {error("out of memory"); return 0;}
+ memset(alsa_snd_buf, 0, bufsizeforthis);
+ alsa_snd_bufsize = bufsizeforthis;
+ }
+ return 1;
+}
+
+/* return 0 on success */
+int alsa_open_audio(
+int naudioindev, int * audioindev, int nchindev, int * chindev,
+int naudiooutdev, int *audiooutdev, int nchoutdev, int *choutdev, int rate, int dummy) {
+ int err, inchans = 0, outchans = 0;
+ char devname[512];
+ int frag_size = (sys_blocksize ? sys_blocksize : ALSA_DEFFRAGSIZE);
+ int nfrags, i, iodev, dev2;
+ nfrags = int(sys_schedadvance * (float)rate / (1e6 * frag_size));
+ /* save our belief as to ALSA's buffer size for later */
+ alsa_buf_samps = nfrags * frag_size;
+ alsa_nindev = alsa_noutdev = 0;
+ alsa_jittermax = ALSA_DEFJITTERMAX;
+ if (sys_verbose) post("audio buffer set to %d", (int)(0.001 * sys_schedadvance));
+ for (iodev = 0; iodev < naudioindev; iodev++) {
+ alsa_numbertoname(audioindev[iodev], devname, 512);
+ err = snd_pcm_open(&alsa_indev[alsa_nindev].a_handle, devname, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK);
+ check_error(err, "snd_pcm_open (input)");
+ if (err < 0)
+ continue;
+ alsa_indev[alsa_nindev].a_devno = audioindev[iodev];
+ snd_pcm_nonblock(alsa_indev[alsa_nindev].a_handle, 1);
+ if (sys_verbose)
+ post("opened input device name %s", devname);
+ alsa_nindev++;
+ }
+ for (iodev = 0; iodev < naudiooutdev; iodev++) {
+ alsa_numbertoname(audiooutdev[iodev], devname, 512);
+ err = snd_pcm_open(&alsa_outdev[alsa_noutdev].a_handle, devname, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
+ check_error(err, "snd_pcm_open (output)");
+ if (err < 0)
+ continue;
+ alsa_outdev[alsa_noutdev].a_devno = audiooutdev[iodev];
+ snd_pcm_nonblock(alsa_outdev[alsa_noutdev].a_handle, 1);
+ alsa_noutdev++;
+ }
+ if (!alsa_nindev && !alsa_noutdev) goto blewit;
+ /* If all the open devices support mmap_noninterleaved, let's call Wini's code in s_audio_alsamm.c */
+ alsa_usemmap = 1;
+ for (iodev = 0; iodev < alsa_nindev ; iodev++) if (!alsaio_canmmap(&alsa_indev [iodev])) alsa_usemmap = 0;
+ for (iodev = 0; iodev < alsa_noutdev; iodev++) if (!alsaio_canmmap(&alsa_outdev[iodev])) alsa_usemmap = 0;
+ if (alsa_usemmap) {
+ post("using mmap audio interface");
+ if (alsamm_open_audio(rate)) goto blewit; else return 0;
+ }
+ for (iodev = 0; iodev < alsa_nindev; iodev++) {
+ int channels = chindev[iodev];
+ if (alsaio_setup(&alsa_indev[iodev], 0, &channels, &rate, nfrags, frag_size) < 0) goto blewit;
+ inchans += channels;
+ }
+ for (iodev = 0; iodev < alsa_noutdev; iodev++) {
+ int channels = choutdev[iodev];
+ if (alsaio_setup(&alsa_outdev[iodev], 1, &channels, &rate, nfrags, frag_size) < 0) goto blewit;
+ outchans += channels;
+ }
+ if (!inchans && !outchans)
+ goto blewit;
+ for (iodev = 0; iodev < alsa_nindev ; iodev++) snd_pcm_prepare( alsa_indev[iodev].a_handle);
+ for (iodev = 0; iodev < alsa_noutdev; iodev++) snd_pcm_prepare(alsa_outdev[iodev].a_handle);
+ /* if duplex we can link the channels so they start together */
+ for (iodev = 0; iodev < alsa_nindev; iodev++) {
+ for (dev2 = 0; dev2 < alsa_noutdev; dev2++) {
+ if (alsa_indev[iodev].a_devno == alsa_outdev[iodev].a_devno) {
+ snd_pcm_link(alsa_indev[iodev].a_handle,alsa_outdev[iodev].a_handle);
+ }
+ }
+ }
+ /* allocate the status variables */
+ if (!alsa_status) {
+ err = snd_pcm_status_malloc(&alsa_status);
+ check_error(err, "snd_pcm_status_malloc");
+ }
+ /* fill the buffer with silence */
+ memset(alsa_snd_buf, 0, alsa_snd_bufsize);
+ if (outchans) {
+ i = (frag_size * nfrags)/sys_dacblocksize + 1;
+ while (i--) {
+ for (iodev = 0; iodev < alsa_noutdev; iodev++)
+ snd_pcm_writei(alsa_outdev[iodev].a_handle, alsa_snd_buf, sys_dacblocksize);
+ }
+ } else if (inchans) {
+ for (iodev = 0; iodev < alsa_nindev; iodev++)
+ if ((err = snd_pcm_start(alsa_indev[iodev].a_handle)) < 0) check_error(err, "input start failed");
+ }
+ return 0;
+blewit:
+ sys_inchannels = 0;
+ sys_outchannels = 0;
+ alsa_close_audio();
+ return 1;
+}
+
+void alsa_close_audio() {
+ int err;
+ if (alsa_usemmap) {
+ alsamm_close_audio();
+ return;
+ }
+ for (int iodev=0; iodev<alsa_nindev; iodev++) {
+ err = snd_pcm_close(alsa_indev[iodev].a_handle);
+ check_error(err, "snd_pcm_close (input)");
+ }
+ for (int iodev=0; iodev<alsa_noutdev; iodev++) {
+ err = snd_pcm_close(alsa_outdev[iodev].a_handle);
+ check_error(err, "snd_pcm_close (output)");
+ }
+ alsa_nindev = alsa_noutdev = 0;
+}
+
+int alsa_send_dacs() {
+#ifdef DEBUG_ALSA_XFER
+ static int xferno = 0;
+ static int callno = 0;
+#endif
+ static double timenow;
+ double timelast;
+ t_sample *fp1, *fp2;
+ int i, j, k, iodev, result, ch;
+ int chansintogo, chansouttogo;
+ unsigned int transfersize;
+ if (alsa_usemmap) return alsamm_send_dacs();
+ if (!alsa_nindev && !alsa_noutdev) return SENDDACS_NO;
+ chansintogo = sys_inchannels;
+ chansouttogo = sys_outchannels;
+ transfersize = sys_dacblocksize;
+ timelast = timenow;
+ timenow = sys_getrealtime();
+#ifdef DEBUG_ALSA_XFER
+ if (timenow - timelast > 0.050) post("(%d)", int(1000 * (timenow - timelast)));
+ callno++;
+#endif
+ alsa_checkiosync(); /* check I/O are in sync and data not late */
+ for (iodev = 0; iodev < alsa_nindev; iodev++) {
+ snd_pcm_status(alsa_indev[iodev].a_handle, alsa_status);
+ if (snd_pcm_status_get_avail(alsa_status) < transfersize) return SENDDACS_NO;
+ }
+ for (iodev = 0; iodev < alsa_noutdev; iodev++) {
+ snd_pcm_status(alsa_outdev[iodev].a_handle, alsa_status);
+ if (snd_pcm_status_get_avail(alsa_status) < transfersize) return SENDDACS_NO;
+ }
+ /* do output */
+ for (iodev = 0, fp1 = sys_soundout, ch = 0; iodev < alsa_noutdev; iodev++) {
+ int thisdevchans = alsa_outdev[iodev].a_channels;
+ int chans = (chansouttogo < thisdevchans ? chansouttogo : thisdevchans);
+ chansouttogo -= chans;
+ if (alsa_outdev[iodev].a_sampwidth == 4) {
+ for (i = 0; i < chans; i++, ch++, fp1 += sys_dacblocksize)
+ for (j = ch, k = sys_dacblocksize, fp2 = fp1; k--; j += thisdevchans, fp2++) {
+ float s1 = *fp2 * INT32_MAX;
+ ((t_alsa_sample32 *)alsa_snd_buf)[j] = CLIP32(int(s1));
+ }
+ for (; i < thisdevchans; i++, ch++)
+ for (j = ch, k = sys_dacblocksize; k--; j += thisdevchans) ((t_alsa_sample32 *)alsa_snd_buf)[j] = 0;
+ } else {
+ for (i = 0; i < chans; i++, ch++, fp1 += sys_dacblocksize)
+ for (j = ch, k = sys_dacblocksize, fp2 = fp1; k--; j += thisdevchans, fp2++) {
+ int s = int(*fp2 * 32767.);
+ if (s > 32767) s = 32767; else if (s < -32767) s = -32767;
+ ((t_alsa_sample16 *)alsa_snd_buf)[j] = s;
+ }
+ for (; i < thisdevchans; i++, ch++)
+ for (j = ch, k = sys_dacblocksize; k--; j += thisdevchans) ((t_alsa_sample16 *)alsa_snd_buf)[j] = 0;
+ }
+ result = snd_pcm_writei(alsa_outdev[iodev].a_handle, alsa_snd_buf, transfersize);
+ if (result != (int)transfersize) {
+ #ifdef DEBUG_ALSA_XFER
+ if (result >= 0 || errno == EAGAIN) post("ALSA: write returned %d of %d", result, transfersize);
+ else error("ALSA: write: %s", snd_strerror(errno));
+ post("inputcount %d, outputcount %d, outbufsize %d",
+ inputcount, outputcount, (ALSA_EXTRABUFFER + sys_advance_samples) * alsa_outdev[iodev].a_sampwidth * outchannels);
+ #endif
+ sys_log_error(ERR_DACSLEPT);
+ return SENDDACS_NO;
+ }
+
+ /* zero out the output buffer */
+ memset(sys_soundout, 0, sys_dacblocksize * sizeof(*sys_soundout) *
+ sys_outchannels);
+ if (sys_getrealtime() - timenow > 0.002) {
+ #ifdef DEBUG_ALSA_XFER
+ post("output %d took %d msec", callno, int(1000 * (timenow - timelast)));
+ #endif
+ timenow = sys_getrealtime();
+ sys_log_error(ERR_DACSLEPT);
+ }
+ }
+ /* do input */
+ for (iodev = 0, fp1 = sys_soundin, ch = 0; iodev < alsa_nindev; iodev++) {
+ int thisdevchans = alsa_indev[iodev].a_channels;
+ int chans = (chansintogo < thisdevchans ? chansintogo : thisdevchans);
+ chansouttogo -= chans;
+ result = snd_pcm_readi(alsa_indev[iodev].a_handle, alsa_snd_buf, transfersize);
+ if (result < (int)transfersize) {
+#ifdef DEBUG_ALSA_XFER
+ if (result<0) error("snd_pcm_read %d %d: %s", callno, xferno, snd_strerror(errno));
+ else post("snd_pcm_read %d %d returned only %d", callno, xferno, result);
+ post("inputcount %d, outputcount %d, inbufsize %d",
+ inputcount, outputcount, (ALSA_EXTRABUFFER + sys_advance_samples) * alsa_indev[iodev].a_sampwidth * inchannels);
+#endif
+ sys_log_error(ERR_ADCSLEPT);
+ return SENDDACS_NO;
+ }
+ if (alsa_indev[iodev].a_sampwidth == 4) {
+ for (int i=0; i<chans; i++, ch++, fp1 += sys_dacblocksize) {
+ for (j = ch, k = sys_dacblocksize, fp2 = fp1; k--; j += thisdevchans, fp2++)
+ *fp2 = (float) ((t_alsa_sample32 *)alsa_snd_buf)[j] * (1./ INT32_MAX);
+ }
+ } else {
+ for (int i=0; i<chans; i++, ch++, fp1 += sys_dacblocksize) {
+ for (j = ch, k = sys_dacblocksize, fp2 = fp1; k--; j += thisdevchans, fp2++)
+ *fp2 = (float) ((t_alsa_sample16 *)alsa_snd_buf)[j] * 3.051850e-05;
+ }
+ }
+ }
+#ifdef DEBUG_ALSA_XFER
+ xferno++;
+#endif
+ if (sys_getrealtime() - timenow > 0.002) {
+#ifdef DEBUG_ALSA_XFER
+ post("routine took %d msec", int(1000 * (sys_getrealtime() - timenow)));
+#endif
+ sys_log_error(ERR_ADCSLEPT);
+ }
+ return SENDDACS_YES;
+}
+
+void alsa_printstate() {
+ int result, iodev = 0;
+ snd_pcm_sframes_t indelay, outdelay;
+ if (sys_audioapi != API_ALSA) {
+ error("restart-audio: implemented for ALSA only.");
+ return;
+ }
+ if (sys_inchannels) {
+ result = snd_pcm_delay(alsa_indev[iodev].a_handle, &indelay);
+ if (result<0) error("snd_pcm_delay 1 failed"); else post( "in delay %d", indelay);
+ }
+ if (sys_outchannels) {
+ result = snd_pcm_delay(alsa_outdev[iodev].a_handle, &outdelay);
+ if (result<0) error("snd_pcm_delay 2 failed"); else post("out delay %d", outdelay);
+ }
+ post("sum %d (%d mod 64)", indelay + outdelay, (indelay+outdelay)%64);
+ post("buf samples %d", alsa_buf_samps);
+}
+
+
+void alsa_resync() {
+ int i, result, iodev = 0;
+ if (sys_audioapi != API_ALSA) {
+ error("restart-audio: implemented for ALSA only.");
+ return;
+ }
+ memset(alsa_snd_buf, 0, alsa_indev[iodev].a_sampwidth * sys_dacblocksize * sys_outchannels);
+ for (i = 0; i < 1000000; i++) {
+ result = snd_pcm_writei(alsa_outdev[iodev].a_handle, alsa_snd_buf, sys_dacblocksize);
+ if (result != (int)sys_dacblocksize) break;
+ }
+ post("%d written", i);
+}
+
+void alsa_putzeros(int iodev, int n) {
+ int result;
+ memset(alsa_snd_buf, 0, alsa_outdev[iodev].a_sampwidth * sys_dacblocksize * alsa_outdev[iodev].a_channels);
+ for (int i=0; i<n; i++) {
+ result = snd_pcm_writei(alsa_outdev[iodev].a_handle, alsa_snd_buf, sys_dacblocksize);
+#if 0
+ if (result != sys_dacblocksize) post("result %d", result);
+#endif
+ }
+ /* post ("putzeros %d", n); */
+}
+
+void alsa_getzeros(int iodev, int n) {
+ int i, result;
+ for (i = 0; i < n; i++) {
+ result = snd_pcm_readi(alsa_indev[iodev].a_handle, alsa_snd_buf, sys_dacblocksize);
+#if 0
+ if (result != sys_dacblocksize)
+ post("result %d", result);
+#endif
+ }
+ /* post ("getzeros %d", n); */
+}
+
+/* call this only if both input and output are open */
+static void alsa_checkiosync() {
+ int result, giveup = 1000, alreadylogged = 0;
+ snd_pcm_sframes_t minphase, maxphase, thisphase, outdelay;
+ while (1) {
+ if (giveup-- <= 0) {
+ post("tried but couldn't sync A/D/A");
+ alsa_jittermax += 1;
+ return;
+ }
+ minphase = 0x7fffffff;
+ maxphase = -0x7fffffff;
+ for (int iodev=0; iodev<alsa_noutdev; iodev++) {
+ result = snd_pcm_delay(alsa_outdev[iodev].a_handle, &outdelay);
+ if (result < 0) {
+ snd_pcm_prepare(alsa_outdev[iodev].a_handle);
+ result = snd_pcm_delay(alsa_outdev[iodev].a_handle, &outdelay);
+ }
+ if (result<0) {
+ error("output snd_pcm_delay failed: %s", snd_strerror(result));
+ if (snd_pcm_status(alsa_outdev[iodev].a_handle, alsa_status)<0) error("output snd_pcm_status failed");
+ else post("astate %d", snd_pcm_status_get_state(alsa_status));
+ return;
+ }
+ thisphase = alsa_buf_samps - outdelay;
+ if (thisphase < minphase) minphase = thisphase;
+ if (thisphase > maxphase) maxphase = thisphase;
+ if (outdelay < 0)
+ sys_log_error(ERR_DATALATE), alreadylogged = 1;
+ }
+ for (int iodev=0; iodev<alsa_nindev; iodev++) {
+ result = snd_pcm_delay(alsa_indev[iodev].a_handle, &thisphase);
+ if (result < 0) {
+ snd_pcm_prepare(alsa_indev[iodev].a_handle);
+ result = snd_pcm_delay(alsa_indev[iodev].a_handle, &thisphase);
+ }
+ if (result < 0) {
+ error("output snd_pcm_delay failed: %s", snd_strerror(result));
+ if (snd_pcm_status(alsa_outdev[iodev].a_handle, alsa_status) < 0) error("output snd_pcm_status failed");
+ else post("astate %d", snd_pcm_status_get_state(alsa_status));
+ return;
+ }
+ if (thisphase < minphase) minphase = thisphase;
+ if (thisphase > maxphase) maxphase = thisphase;
+ }
+ /* the "correct" position is for all the phases to be exactly equal;
+ but since we only make corrections sys_dacblocksize samples at a time,
+ we just ask that the spread be not more than 3/4 of a block. */
+ if (maxphase <= minphase + (alsa_jittermax * (sys_dacblocksize / 4))) break;
+ if (!alreadylogged) sys_log_error(ERR_RESYNC), alreadylogged = 1;
+ for (int iodev=0; iodev<alsa_noutdev; iodev++) {
+ result = snd_pcm_delay(alsa_outdev[iodev].a_handle, &outdelay);
+ if (result < 0) break;
+ thisphase = alsa_buf_samps - outdelay;
+ if (thisphase > minphase + sys_dacblocksize) {
+ alsa_putzeros(iodev, 1);
+#if DEBUGSYNC
+ post("putz %d %d", (int)thisphase, (int)minphase);
+#endif
+ }
+ }
+ for (int iodev=0; iodev<alsa_nindev; iodev++) {
+ result = snd_pcm_delay(alsa_indev[iodev].a_handle, &thisphase);
+ if (result < 0) break;
+ if (thisphase > minphase + sys_dacblocksize) {
+ alsa_getzeros(iodev, 1);
+#if DEBUGSYNC
+ post("getz %d %d", (int)thisphase, (int)minphase);
+#endif
+ }
+ }
+ }
+#if DEBUGSYNC
+ if (alreadylogged) post("done");
+#endif
+}
+
+static int alsa_nnames = 0;
+static char **alsa_names = 0;
+
+void alsa_adddev(char *name) {
+ if (alsa_nnames) alsa_names = (char **)t_resizebytes(alsa_names, alsa_nnames*sizeof(char *), (alsa_nnames+1)*sizeof(char *));
+ else alsa_names = (char **)t_getbytes(sizeof(char *));
+ alsa_names[alsa_nnames] = gensym(name)->s_name;
+ alsa_nnames++;
+}
+
+static void alsa_numbertoname(int devno, char *devname, int nchar) {
+ int ndev = 0, cardno = -1;
+ while (!snd_card_next(&cardno) && cardno >= 0) ndev++;
+ if (devno < 2*ndev) {
+ if (devno & 1) snprintf(devname, nchar, "plughw:%d", devno/2);
+ else snprintf(devname, nchar, "hw:%d", devno/2);
+ } else if (devno <2*ndev + alsa_nnames)
+ snprintf(devname, nchar, "%s", alsa_names[devno - 2*ndev]);
+ else snprintf(devname, nchar, "???");
+}
+
+/* For each hardware card found, we list two devices, the "hard" and
+ "plug" one. The card scan is derived from portaudio code. */
+void alsa_getdevs(char *indevlist, int *nindevs, char *outdevlist, int *noutdevs, int *canmulti, int maxndev, int devdescsize) {
+ int ndev = 0, cardno = -1, i, j;
+ *canmulti = 2; /* supports multiple devices */
+ while (!snd_card_next(&cardno) && cardno >= 0) {
+ snd_ctl_t *ctl;
+ snd_ctl_card_info_t *info;
+ char devname[80];
+ char *desc;
+ if (2 * ndev + 2 > maxndev) break;
+ /* apparently, "cardno" is just a counter; but check that here */
+ if (ndev != cardno) post("oops: ALSA cards not reported in order?");
+ sprintf(devname, "hw:%d", cardno);
+ /* post("try %s..", devname); */
+ if (snd_ctl_open(&ctl, devname, 0) >= 0) {
+ snd_ctl_card_info_malloc(&info);
+ snd_ctl_card_info(ctl, info);
+ desc = strdup(snd_ctl_card_info_get_name(info));
+ snd_ctl_card_info_free(info);
+ } else {
+ error("ALSA card scan error");
+ desc = strdup("???");
+ }
+ sprintf(indevlist + 2*ndev * devdescsize, "%s (hardware)", desc);
+ sprintf(indevlist + (2*ndev+1) * devdescsize, "%s (plug-in)", desc);
+ sprintf(outdevlist + 2*ndev * devdescsize, "%s (hardware)", desc);
+ sprintf(outdevlist + (2*ndev+1) * devdescsize, "%s (plug-in)", desc);
+ ndev++;
+ free(desc);
+ }
+ for (i = 0, j = 2*ndev; i < alsa_nnames; i++, j++) {
+ if (j >= maxndev) break;
+ snprintf(indevlist + j * devdescsize, devdescsize, "%s", alsa_names[i]);
+ }
+ *nindevs = *noutdevs = j;
+}
+
+struct t_audioapi alsa_api = {
+ alsa_open_audio,
+ alsa_close_audio,
+ alsa_send_dacs,
+ alsa_getdevs,
+};
diff --git a/desiredata/src/s_audio_alsa.h b/desiredata/src/s_audio_alsa.h
new file mode 100644
index 00000000..986bc1f5
--- /dev/null
+++ b/desiredata/src/s_audio_alsa.h
@@ -0,0 +1,40 @@
+/* Copyright (c) 1997- Guenter Geiger, Miller Puckette, Larry Troxler,
+* Winfried Ritsch, Karl MacMillan, and others.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+
+typedef int16_t t_alsa_sample16;
+typedef int32_t t_alsa_sample32;
+#define ALSA_SAMPLEWIDTH_16 sizeof(t_alsa_sample16)
+#define ALSA_SAMPLEWIDTH_32 sizeof(t_alsa_sample32)
+#define ALSA_XFERSIZE16 (signed int)(sizeof(t_alsa_sample16) * sys_dacblocksize)
+#define ALSA_XFERSIZE32 (signed int)(sizeof(t_alsa_sample32) * sys_dacblocksize)
+#define ALSA_MAXDEV 4
+#define ALSA_JITTER 1024
+#define ALSA_EXTRABUFFER 2048
+#define ALSA_DEFFRAGSIZE 64
+#define ALSA_DEFNFRAG 12
+
+#ifndef INT32_MAX
+#define INT32_MAX 0x7fffffff
+#endif
+
+typedef struct _alsa_dev
+{
+ snd_pcm_t *a_handle;
+ int a_devno;
+ int a_sampwidth;
+ int a_channels;
+ char **a_addr;
+ int a_synced;
+} t_alsa_dev;
+
+extern t_alsa_dev alsa_indev[ALSA_MAXDEV];
+extern t_alsa_dev alsa_outdev[ALSA_MAXDEV];
+extern int alsa_nindev;
+extern int alsa_noutdev;
+
+int alsamm_open_audio(int rate);
+void alsamm_close_audio(void);
+int alsamm_send_dacs(void);
diff --git a/desiredata/src/s_audio_alsamm.c b/desiredata/src/s_audio_alsamm.c
new file mode 100644
index 00000000..ef3e28a8
--- /dev/null
+++ b/desiredata/src/s_audio_alsamm.c
@@ -0,0 +1,889 @@
+/* Copyright (c) 1997-2003 Guenter Geiger, Miller Puckette, Larry Troxler,
+* Winfried Ritsch, Karl MacMillan, and others.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+/*
+ this audiodriverinterface inputs and outputs audio data using
+ the ALSA MMAP API available on linux.
+ this is optimized for hammerfall cards and does not make an attempt to be general
+ now, please adapt to your needs or let me know ...
+ constrains now:
+ - audio Card with ALSA-Driver > 1.0.3,
+ - alsa-device (preferable hw) with MMAP NONINTERLEAVED SIGNED-32Bit features
+ - up to 4 cards with has to be hardwaresynced
+ (winfried)
+*/
+#include <alsa/asoundlib.h>
+#include "m_pd.h"
+#include "s_stuff.h"
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <sched.h>
+#include "s_audio_alsa.h"
+
+/* needed for alsa 0.9 compatibility: */
+#if (SND_LIB_MAJOR < 1)
+#define ALSAAPI9
+#endif
+/* sample type magic ...
+ Hammerfall/HDSP/DSPMADI cards always 32Bit where lower 8Bit not used (played) in AD/DA,
+ but can have some bits set (subchannel coding)
+*/
+#define ALSAMM_SAMPLEWIDTH_32 sizeof(t_alsa_sample32)
+
+#ifndef INT32_MAX
+#define INT32_MAX 0x7fffffff
+#endif
+
+/* maybe:
+ don't assume we can turn all 31 bits when doing float-to-fix;
+ otherwise some audio drivers (e.g. Midiman/ALSA) wrap around.
+ but not now on hammerfall (w)
+*/
+
+/* 24 Bit are used so MAX Samplevalue not INT32_MAX ??? */
+#define F32MAX 0x7fffff00
+#define CLIP32(x) (((x)>F32MAX)?F32MAX:((x) < -F32MAX)?-F32MAX:(x))
+
+#define ALSAMM_FORMAT SND_PCM_FORMAT_S32
+/*
+ maximum of 4 devices
+ you can mix rme9632,hdsp9632 (18 chans) rme9652,hdsp9652 (26 chans), dsp-madi (64 chans)
+ if synced
+*/
+
+/*
+ we need same samplerate, buffertime and so on for
+ each card soo we use global vars...
+ time is in us, size in frames (i hope so ;-)
+*/
+static unsigned int alsamm_sr = 0;
+static unsigned int alsamm_buffertime = 0;
+static unsigned int alsamm_buffersize = 0;
+
+static bool debug=0;
+
+/* bad style: we asume all cards give the same answer at init so we make this vars global
+ to have a faster access in writing reading during send_dacs */
+static snd_pcm_sframes_t alsamm_period_size;
+static unsigned int alsamm_periods;
+static snd_pcm_sframes_t alsamm_buffer_size;
+
+/* if more than this sleep detected, should be more than periodsize/samplerate ??? */
+static double sleep_time;
+
+/* now we just sum all inputs/outputs of used cards to a global count
+ and use them all
+ ... later we should just use some channels of each card for pd
+ so we reduce the overhead of using alsways all channels,
+ and zero the rest once at start,
+ because rme9652 and hdsp forces us to use all channels
+ in mmap mode...
+
+Note on why:
+ normally hdsp and dspmadi can handle channel
+ count from one to all since they can switch on/off
+ the dma for them to reduce pci load, but this is only
+ implemented in alsa low level drivers for dspmadi now and maybe fixed for hdsp in future
+*/
+
+static int alsamm_inchannels = 0;
+static int alsamm_outchannels = 0;
+
+/* Defines */
+ #define WATCH_PERIODS 90
+ static int in_avail[WATCH_PERIODS];
+ static int out_avail[WATCH_PERIODS];
+ static int in_offset[WATCH_PERIODS];
+ static int out_offset[WATCH_PERIODS];
+ static int out_cm[WATCH_PERIODS];
+ static char *outaddr[WATCH_PERIODS];
+ static char *inaddr[WATCH_PERIODS];
+ static int xruns_watch[WATCH_PERIODS];
+ static int broken_opipe;
+
+ static int dac_send = 0;
+ static int alsamm_xruns = 0;
+
+static void show_availist() {
+ for(int i=1; i<WATCH_PERIODS; i++){
+ post("%2d:avail i=%7d %s o=%7d(%5d), offset i=%7d %s o=%7d, ptr i=%12p o=%12p, %d xruns ",
+ i,in_avail[i],(out_avail[i] != in_avail[i])? "!=" : "==" , out_avail[i],out_cm[i],
+ in_offset[i],(out_offset[i] != in_offset[i])? "!=" : "==" , out_offset[i],
+ inaddr[i], outaddr[i], xruns_watch[i]);
+ }
+}
+
+/* protos */
+static int set_hwparams(snd_pcm_t *handle, snd_pcm_hw_params_t *params, int *chs);
+static int set_swparams(snd_pcm_t *handle, snd_pcm_sw_params_t *swparams, int playback);
+static int alsamm_start();
+static int alsamm_stop();
+
+/* for debugging attach output of alsa mesages to stdout stream */
+snd_output_t* alsa_stdout;
+
+static void check_error(int err, const char *why) {if (err < 0) error("%s: %s", why, snd_strerror(err));}
+
+int alsamm_open_audio(int rate) {
+ int err;
+ snd_pcm_hw_params_t* hw_params;
+ snd_pcm_sw_params_t* sw_params;
+ /* fragsize is an old concept now use periods, used to be called fragments. */
+ /* Be aware in ALSA periodsize can be in bytes, where buffersize is in frames,
+ but sometimes buffersize is in bytes and periods in frames, crazy alsa...
+ ...we use periodsize and buffersize in frames */
+ int i;
+ snd_pcm_hw_params_alloca(&hw_params);
+ snd_pcm_sw_params_alloca(&sw_params);
+ /* see add_devname */
+ /* first have a look which cards we can get and set up device infos for them */
+ /* init some structures */
+ for(i=0;i < ALSA_MAXDEV;i++){
+ alsa_indev[i].a_synced=alsa_outdev[i].a_synced=0;
+ alsa_indev[i].a_channels=alsa_outdev[i].a_channels=-1; /* query defaults */
+ }
+ alsamm_inchannels = 0;
+ alsamm_outchannels = 0;
+ /* opening alsa debug channel */
+ err = snd_output_stdio_attach(&alsa_stdout, stdout, 0);
+ if (err < 0) {
+ check_error(err,"attaching alsa debug Output to stdout failed");
+ /* return; no so bad ... and never should happe */
+ }
+ /*
+ Weak failure prevention:
+ first card found (out then in) is used as a reference for parameter,
+ so this set the globals and other cards hopefully dont change them
+ */
+ alsamm_sr = rate;
+ /* set the asked buffer time (alsa buffertime in us)*/
+ alsamm_buffertime = alsamm_buffersize = 0;
+ if(sys_blocksize == 0)
+ alsamm_buffertime = sys_schedadvance;
+ else
+ alsamm_buffersize = sys_blocksize;
+ if(sys_verbose)
+ post("syschedadvance=%d us(%d Samples)so buffertime max should be this=%d"
+ "or sys_blocksize=%d (samples) to use buffersize=%d",
+ sys_schedadvance,sys_advance_samples,alsamm_buffertime,
+ sys_blocksize,alsamm_buffersize);
+ alsamm_periods = 0; /* no one wants periods setting from command line ;-) */
+ for(i=0;i<alsa_noutdev;i++) {
+ /* post("open audio out %d, of %lx, %d",i,&alsa_device[i],
+ alsa_outdev[i].a_handle); */
+ err = set_hwparams(alsa_outdev[i].a_handle, hw_params, &(alsa_outdev[i].a_channels));
+ if (err<0) {check_error(err,"playback device hwparam_set error:"); continue;}
+ err = set_swparams(alsa_outdev[i].a_handle, sw_params,1);
+ if (err<0) {check_error(err,"playback device swparam_set error:"); continue;}
+ alsamm_outchannels += alsa_outdev[i].a_channels;
+ alsa_outdev[i].a_addr = (char **)malloc(sizeof(char *)*alsa_outdev[i].a_channels);
+ if(alsa_outdev[i].a_addr == NULL) {
+ check_error(errno,"playback device outaddr allocation error:");
+ continue;
+ }
+ memset(alsa_outdev[i].a_addr, 0, sizeof(char*) * alsa_outdev[i].a_channels);
+ post("playback device with %d channels and buffer_time %d us opened",
+ alsa_outdev[i].a_channels, alsamm_buffertime);
+ }
+ for(i=0;i<alsa_nindev;i++) {
+ if(sys_verbose) post("capture card %d:--------------------",i);
+ if((err = set_hwparams(alsa_indev[i].a_handle, hw_params, &(alsa_indev[i].a_channels))) < 0) {
+ check_error(err,"capture device hwparam_set error:");
+ continue;
+ }
+ alsamm_inchannels += alsa_indev[i].a_channels;
+ if((err = set_swparams(alsa_indev[i].a_handle, sw_params,0)) < 0){
+ check_error(err,"capture device swparam_set error:");
+ continue;
+ }
+ alsa_indev[i].a_addr = (char **)malloc(sizeof(char*)*alsa_indev[i].a_channels);
+ if(alsa_indev[i].a_addr == NULL){
+ check_error(errno,"capture device inaddr allocation error:");
+ continue;
+ }
+ memset(alsa_indev[i].a_addr, 0, sizeof(char*) * alsa_indev[i].a_channels);
+ if(sys_verbose) post("capture device with %d channels and buffertime %d us opened", alsa_indev[i].a_channels,alsamm_buffertime);
+ }
+ /* check for linked handles of input for each output*/
+ for(int i=0; i<(alsa_noutdev < alsa_nindev ? alsa_noutdev:alsa_nindev); i++) {
+ if (alsa_outdev[i].a_devno == alsa_indev[i].a_devno) {
+ if ((err = snd_pcm_link(alsa_indev[i].a_handle, alsa_outdev[i].a_handle)) == 0) {
+ alsa_indev[i].a_synced = alsa_outdev[i].a_synced = 1;
+ if(sys_verbose) post("Linking in and outs of card %d",i);
+ } else check_error(err,"could not link in and outs");
+ }
+ }
+ /* some globals */
+ sleep_time = (float) alsamm_period_size/ (float) alsamm_sr;
+ if (debug) {
+ /* start ---------------------------- */
+ if(sys_verbose) post("open_audio: after dacsend=%d (xruns=%d)done",dac_send,alsamm_xruns);
+ alsamm_xruns = dac_send = 0; /* reset debug */
+ /* start alsa in open or better in send_dacs once ??? we will see */
+ for(i=0;i<alsa_noutdev;i++) snd_pcm_dump(alsa_outdev[i].a_handle, alsa_stdout);
+ for(i=0;i<alsa_nindev;i++) snd_pcm_dump( alsa_indev[i].a_handle, alsa_stdout);
+ fflush(stdout);
+ }
+ sys_setchsr(alsamm_inchannels, alsamm_outchannels, alsamm_sr, sys_dacblocksize);
+ alsamm_start();
+ /* report success */
+ return 0;
+}
+
+void alsamm_close_audio() {
+ int i,err;
+ if(debug&&sys_verbose) post("closing devices");
+ alsamm_stop();
+ for(i=0;i< alsa_noutdev;i++) {
+ //if(debug&&sys_verbose) post("unlink audio out %d, of %lx",i,used_outdevice[i]);
+ if(alsa_outdev[i].a_synced != 0){
+ if((err = snd_pcm_unlink(alsa_outdev[i].a_handle)) < 0) check_error(err, "snd_pcm_unlink (output)");
+ alsa_outdev[i].a_synced = 0;
+ }
+ if((err = snd_pcm_close(alsa_outdev[i].a_handle)) <= 0) check_error(err, "snd_pcm_close (output)");
+ if(alsa_outdev[i].a_addr) {
+ free(alsa_outdev[i].a_addr);
+ alsa_outdev[i].a_addr = NULL;
+ }
+ alsa_outdev[i].a_channels = 0;
+ }
+ for(i=0;i< alsa_nindev;i++) {
+ err = snd_pcm_close(alsa_indev[i].a_handle);
+ if(sys_verbose) check_error(err, "snd_pcm_close (input)");
+ if(alsa_indev[i].a_addr){
+ free(alsa_indev[i].a_addr);
+ alsa_indev[i].a_addr = NULL;
+ }
+ alsa_indev[i].a_channels = 0;
+ }
+ alsa_nindev = alsa_noutdev = 0;
+ if(debug) {
+ if(sys_verbose) post("close_audio: after dacsend=%d (xruns=%d)done",dac_send,alsamm_xruns);
+ alsamm_xruns = dac_send = 0;
+ }
+}
+
+/* ------- PCM INITS --------------------------------- */
+static int set_hwparams(snd_pcm_t *handle, snd_pcm_hw_params_t *params,int *chs) {
+#ifndef ALSAAPI9
+ unsigned int rrate;
+ int err, dir;
+ /* choose all parameters */
+ err = snd_pcm_hw_params_any(handle, params);
+ if (err < 0) {
+ check_error(err,"Broken configuration: no configurations available");
+ return err;
+ }
+ /* set the nointerleaved read/write format */
+ err = snd_pcm_hw_params_set_access(handle, params,
+ SND_PCM_ACCESS_MMAP_NONINTERLEAVED);
+ if (err >= 0) {
+ if(debug&&sys_verbose) post("Access type %s available","SND_PCM_ACCESS_MMAP_NONINTERLEAVED");
+ }
+ else{
+ check_error(err,"No Accesstype SND_PCM_ACCESS_MMAP_NONINTERLEAVED");
+ return err;
+ }
+ /* set the sample format */
+ err = snd_pcm_hw_params_set_format(handle, params, ALSAMM_FORMAT);
+ if (err < 0) {
+ check_error(err,"Sample format not available for playback");
+ return err;
+ }
+ if(debug&&sys_verbose) post("Setting format to %s",snd_pcm_format_name(ALSAMM_FORMAT));
+ /* first check samplerate since channels numbers are samplerate dependend (double speed) */
+ /* set the stream rate */
+ rrate = alsamm_sr;
+ if(debug&&sys_verbose) post("Samplerate request: %i Hz",rrate);
+ dir=-1;
+ err = snd_pcm_hw_params_set_rate_near(handle, params, &rrate, &dir);
+ if (err < 0) {
+ check_error(err,"Rate not available");
+ return err;
+ }
+ if (rrate != alsamm_sr) {
+ post("Warning: rate %iHz doesn't match requested %iHz", rrate,alsamm_sr);
+ alsamm_sr = rrate;
+ }
+ else
+ if(sys_verbose)
+ post("Samplerate is set to %iHz",alsamm_sr);
+ /* Info on channels */
+ {
+ int maxchs,minchs,channels = *chs;
+ if((err = snd_pcm_hw_params_get_channels_max(params,
+ (unsigned int *)&maxchs)) < 0){
+ check_error(err,"Getting channels_max not available");
+ return err;
+ }
+ if((err = snd_pcm_hw_params_get_channels_min(params,
+ (unsigned int *)&minchs)) < 0){
+ check_error(err,"Getting channels_min not available");
+ return err;
+ }
+ if(debug&&sys_verbose) post("Getting channels:min=%d, max= %d for request=%d",minchs,maxchs,channels);
+ if(channels < 0)channels=maxchs;
+ if(channels > maxchs)channels = maxchs;
+ if(channels < minchs)channels = minchs;
+ if(channels != *chs) post("requested channels=%d but used=%d",*chs,channels);
+ *chs = channels;
+ if(debug&&sys_verbose) post("trying to use channels: %d",channels);
+ }
+ /* set the count of channels */
+ err = snd_pcm_hw_params_set_channels(handle, params, *chs);
+ if (err < 0) {
+ check_error(err,"Channels count not available");
+ return err;
+ }
+ /* testing for channels */
+ if((err = snd_pcm_hw_params_get_channels(params,(unsigned int *)chs)) < 0)
+ check_error(err,"Get channels not available");
+ else if(debug&&sys_verbose) post("When setting channels count and got %d",*chs);
+ /* if buffersize is set use this instead buffertime */
+ if(alsamm_buffersize > 0) {
+ if(debug&&sys_verbose) post("hw_params: ask for max buffersize of %d samples", (unsigned int) alsamm_buffersize);
+ alsamm_buffer_size = alsamm_buffersize;
+ err = snd_pcm_hw_params_set_buffer_size_near(handle, params, (unsigned long *)&alsamm_buffer_size);
+ if (err < 0) {
+ check_error(err,"Unable to set max buffer size");
+ return err;
+ }
+ }
+ else {
+ if(alsamm_buffertime <= 0) /* should never happen, but use 20ms */
+ alsamm_buffertime = 20000;
+ if(debug&&sys_verbose) post("hw_params: ask for max buffertime of %d ms", (unsigned int) (alsamm_buffertime*0.001) );
+ err = snd_pcm_hw_params_set_buffer_time_near(handle, params, &alsamm_buffertime, &dir);
+ if (err < 0) {
+ check_error(err,"Unable to set max buffer time");
+ return err;
+ }
+ }
+ err = snd_pcm_hw_params_get_buffer_time(params,
+ (unsigned int *)&alsamm_buffertime, &dir);
+ if (err < 0) {
+ check_error(err,"Unable to get buffer time");
+ return err;
+ }
+ if(debug&&sys_verbose) post("hw_params: got buffertime to %f ms", float(alsamm_buffertime*0.001));
+ err = snd_pcm_hw_params_get_buffer_size(params, (unsigned long *)&alsamm_buffer_size);
+ if (err < 0) {
+ check_error(err,"Unable to get buffer size");
+ return err;
+ }
+ if(debug&&sys_verbose) post("hw_params: got buffersize to %d samples",(int) alsamm_buffer_size);
+ err = snd_pcm_hw_params_get_period_size(params, (unsigned long *)&alsamm_period_size, &dir);
+ if (err > 0) {
+ check_error(err,"Unable to get period size");
+ return err;
+ }
+ if(debug&&sys_verbose) post("Got period size of %d", (int) alsamm_period_size);
+ {
+ unsigned int pmin,pmax;
+ err = snd_pcm_hw_params_get_periods_min(params, &pmin, &dir);
+ if (err > 0) {
+ check_error(err,"Unable to get period size");
+ return err;
+ }
+ err = snd_pcm_hw_params_get_periods_min(params, &pmax, &dir);
+ if (err > 0) {
+ check_error(err,"Unable to get period size");
+ return err;
+ }
+ /* use maximum of periods */
+ if( alsamm_periods <= 0)
+ alsamm_periods = pmax;
+ alsamm_periods = (alsamm_periods > pmax)?pmax:alsamm_periods;
+ alsamm_periods = (alsamm_periods < pmin)?pmin:alsamm_periods;
+ err = snd_pcm_hw_params_set_periods(handle, params, alsamm_periods, dir);
+ if (err > 0) {
+ check_error(err,"Unable to set periods");
+ return err;
+ }
+ err = snd_pcm_hw_params_get_periods(params, &pmin, &dir);
+ if (err > 0) {
+ check_error(err,"Unable to get periods");
+ return err;
+ }
+ if(debug&&sys_verbose) post("Got periods of %d, where periodsmin=%d, periodsmax=%d",alsamm_periods,pmin,pmax);
+ }
+ /* write the parameters to device */
+ err = snd_pcm_hw_params(handle, params);
+ if (err < 0) {
+ check_error(err,"Unable to set hw params");
+ return err;
+ }
+#endif /* ALSAAPI9 */
+ return 0;
+}
+
+static int set_swparams(snd_pcm_t *handle, snd_pcm_sw_params_t *swparams, int playback) {
+#ifndef ALSAAPI9
+ int err;
+ snd_pcm_uframes_t ps,ops;
+ snd_pcm_uframes_t bs,obs;
+ /* get the current swparams */
+ err = snd_pcm_sw_params_current(handle, swparams);
+ if (err < 0) {
+ check_error(err,"Unable to determine current swparams for playback");
+ return err;
+ }
+ /* AUTOSTART: start the transfer on each write/commit ??? */
+ snd_pcm_sw_params_get_start_threshold(swparams, &obs);
+ err = snd_pcm_sw_params_set_start_threshold(handle, swparams, 0U);
+ if (err < 0) {
+ check_error(err,"Unable to set start threshold mode");
+ return err;
+ }
+ snd_pcm_sw_params_get_start_threshold(swparams, &bs);
+ if(debug&&sys_verbose) post("sw_params: got start_thresh_hold= %d (was %d)",(int) bs,(int)obs);
+ /* AUTOSTOP: never stop the machine */
+ snd_pcm_sw_params_get_stop_threshold(swparams, &obs);
+ err = snd_pcm_sw_params_set_stop_threshold(handle, swparams, (snd_pcm_uframes_t)-1);
+ if (err < 0) {
+ check_error(err,"Unable to set stop threshold mode");
+ return err;
+ }
+ snd_pcm_sw_params_get_stop_threshold(swparams, &bs);
+ if(debug&&sys_verbose) post("sw_params: set stop_thresh_hold= %d (was %d)", (int) bs,(int)obs);
+ /* AUTOSILENCE: silence if overrun.... */
+ snd_pcm_sw_params_get_silence_threshold (swparams, &ops);
+ if ((err = snd_pcm_sw_params_set_silence_threshold (handle, swparams, alsamm_period_size)) < 0) {
+ check_error (err,"cannot set silence threshold for");
+ return -1;
+ }
+ snd_pcm_sw_params_get_silence_threshold (swparams, &ps);
+ if(debug&&sys_verbose) post("sw_params: set silence_threshold = %d (was %d)", (int) ps,(int)ops);
+ snd_pcm_sw_params_get_silence_size (swparams, &ops);
+ if ((err = snd_pcm_sw_params_set_silence_size(handle, swparams, alsamm_period_size)) < 0) {
+ check_error (err,"cannot set silence size for");
+ return -1;
+ }
+ snd_pcm_sw_params_get_silence_size (swparams, &ps);
+ if(debug&&sys_verbose) post("sw_params: set silence_size = %d (was %d)", (int) ps,(int)ops);
+ /* AVAIL: allow the transfer when at least period_size samples can be processed */
+ snd_pcm_sw_params_get_avail_min(swparams, &ops);
+ err = snd_pcm_sw_params_set_avail_min(handle, swparams, sys_dacblocksize/2);
+ if (err < 0) {
+ check_error(err,"Unable to set avail min for");
+ return err;
+ }
+ snd_pcm_sw_params_get_avail_min(swparams, &ps);
+ if(debug&&sys_verbose) post("sw_params: set avail_min= %d (was %d)", (int) ps, (int) ops);
+ /* ALIGN: align all transfers to 1 sample */
+ snd_pcm_sw_params_get_xfer_align(swparams, &ops);
+ err = snd_pcm_sw_params_set_xfer_align(handle, swparams, 1);
+ if (err < 0) {
+ check_error(err,"Unable to set transfer align for playback");
+ return err;
+ }
+ snd_pcm_sw_params_get_xfer_align(swparams, &ps);
+ if(debug&&sys_verbose) post("sw_params: set xfer_align = %d (was %d)", (int) ps, (int) ops);
+ /* write the parameters to the playback device */
+ err = snd_pcm_sw_params(handle, swparams);
+ if (err < 0) {
+ check_error(err,"Unable to set sw params");
+ return err;
+ }
+ if(debug&&sys_verbose) post("set sw finished");
+#else
+ post("alsa: need version 1.0 or above for mmap operation");
+#endif /* ALSAAPI9 */
+ return 0;
+}
+
+/* ALSA Transfer helps */
+
+/* xrun_recovery is called if time to late or error
+ Note: use outhandle if synced i/o
+ the devices are linked so prepare
+ has only be called on out,
+ hopefully resume too...
+*/
+static int xrun_recovery(snd_pcm_t *handle, int err) {
+ if (debug) alsamm_xruns++; /* count xruns */
+ if (err == -EPIPE) { /* under-run */
+ err = snd_pcm_prepare(handle);
+ if (err < 0) check_error(err,"Can't recovery from underrun, prepare failed.");
+ err = snd_pcm_start(handle);
+ if (err < 0) check_error(err,"Can't start when recover from underrun.");
+ return 0;
+ } else if (err == -ESTRPIPE) {
+ while ((err = snd_pcm_resume(handle)) == -EAGAIN)
+ sleep(1); /* wait until the suspend flag is released */
+ if (err < 0) {
+ err = snd_pcm_prepare(handle);
+ if (err<0) check_error(err,"Can't recovery from suspend, prepare failed.");
+ err = snd_pcm_start(handle);
+ if (err<0) check_error(err,"Can't start when recover from underrun.");
+ }
+ return 0;
+ }
+ return err;
+}
+
+/* note that snd_pcm_avail has to be called before using this funtion */
+static int alsamm_get_channels(snd_pcm_t *dev, snd_pcm_uframes_t *avail, snd_pcm_uframes_t *offset, int nchns, char **addr) {
+ int err = 0;
+ const snd_pcm_channel_area_t *mm_areas;
+ if (nchns > 0 && avail != NULL && offset != NULL) {
+ if ((err = snd_pcm_mmap_begin(dev, &mm_areas, offset, avail)) < 0){
+ check_error(err,"setmems: begin_mmap failure ???");
+ return err;
+ }
+ for (int chn = 0; chn < nchns; chn++) {
+ const snd_pcm_channel_area_t *a = &mm_areas[chn];
+ addr[chn] = (char *) a->addr + ((a->first + a->step * *offset) / 8);
+ }
+ return err;
+ }
+ return -1;
+}
+
+static int alsamm_start() {
+ int err = 0;
+ int devno;
+ int chn;
+ /* first prepare for in/out */
+ for(devno=0; devno<alsa_noutdev; devno++) {
+ snd_pcm_uframes_t offset, avail;
+ t_alsa_dev *dev = &alsa_outdev[devno];
+ /* snd_pcm_prepare also in xrun, but cannot harm here */
+ if ((err = snd_pcm_prepare (dev->a_handle)) < 0) {
+ check_error (err,"outcard prepare error for playback");
+ return err;
+ }
+ offset = 0;
+ avail = snd_pcm_avail_update(dev->a_handle);
+ if (avail != (snd_pcm_uframes_t) alsamm_buffer_size) {
+ check_error (avail,"full buffer not available at start");
+ }
+ /* cleaning out mmap buffer before start */
+ if(debug&&sys_verbose) post("start: set mems for avail=%d,offset=%d at buffersize=%d",avail,offset,alsamm_buffer_size);
+ if(avail > 0) {
+ int comitted = 0;
+ if ((err = alsamm_get_channels(dev->a_handle, &avail, &offset, dev->a_channels,dev->a_addr)) < 0) {
+ check_error(err,"setting initial out channelspointer failure ?");
+ continue;
+ }
+ for (chn = 0; chn < dev->a_channels; chn++)
+ memset(dev->a_addr[chn],0,avail*ALSAMM_SAMPLEWIDTH_32);
+ comitted = snd_pcm_mmap_commit (dev->a_handle, offset, avail);
+ avail = snd_pcm_avail_update(dev->a_handle);
+ if(debug&&sys_verbose) post("start: now channels cleared, out with avail=%d, offset=%d,comitted=%d",avail,offset,comitted);
+ }
+ /* now start, should be autostarted */
+ avail = snd_pcm_avail_update(dev->a_handle);
+ if(debug&&sys_verbose) post("start: finish start, out with avail=%d, offset=%d",avail,offset);
+ /* we have no autostart so anyway start*/
+ if ((err = snd_pcm_start (dev->a_handle)) < 0) {
+ check_error (err,"could not start playback");
+ }
+ }
+ for(devno = 0;devno < alsa_nindev;devno++){
+ snd_pcm_uframes_t ioffset, iavail;
+ t_alsa_dev *dev = &alsa_indev[devno];
+ /* if devices are synced then dont need to prepare
+ hopefully dma in aereas allready filled correct by the card */
+ if(dev->a_synced == 0) {
+ if ((err = snd_pcm_prepare (dev->a_handle)) < 0) {
+ check_error (err,"incard prepare error for capture");
+ /* return err;*/
+ }
+ }
+ ioffset = 0;
+ iavail = snd_pcm_avail_update (dev->a_handle);
+ /* cleaning out mmap buffer before start */
+ if (debug) post("start in: set in mems for avail=%d,offset=%d at buffersize=%d",iavail,ioffset,alsamm_buffer_size);
+ if (iavail > (snd_pcm_uframes_t) 0) {
+ if (debug) post("empty buffer not available at start, since avail %d != %d buffersize", iavail, alsamm_buffer_size);
+ if ((err = alsamm_get_channels(dev->a_handle, &iavail, &ioffset, dev->a_channels,dev->a_addr)) < 0) {
+ check_error(err,"getting in channelspointer failure ????");
+ continue;
+ }
+ snd_pcm_mmap_commit (dev->a_handle, ioffset, iavail);
+ iavail = snd_pcm_avail_update (dev->a_handle);
+ if (debug) post("start in now avail=%d",iavail);
+ }
+ if (debug) post("start: init inchannels with avail=%d, offset=%d",iavail,ioffset);
+ /* if devices are synced then dont need to start */
+ /* start with autostart , but anyway start */
+ if(dev->a_synced == 0) {
+ if ((err = snd_pcm_start (dev->a_handle)) < 0) {
+ check_error (err,"could not start capture");
+ continue;
+ }
+ }
+ }
+ return err;
+}
+
+static int alsamm_stop() {
+ int err = 0;
+ /* first stop in... */
+ for(int devno=0; devno<alsa_nindev; devno++) {
+ t_alsa_dev *dev = &alsa_indev[devno];
+ if(sys_verbose) post("stop in device %d",devno);
+ int err = snd_pcm_drop(dev->a_handle);
+ if (err<0) check_error(err,"channel flush for capture failed");
+ }
+ /* then outs */
+ for(int devno=0; devno<alsa_noutdev;devno++) {
+ t_alsa_dev *dev = &alsa_outdev[devno];
+ if(sys_verbose) post("stop out device %d",devno);
+ int err = snd_pcm_drop(dev->a_handle);
+ if (err<0) check_error(err,"channel flush for playback failed");
+ }
+ if (debug) show_availist();
+ return err;
+}
+
+/* ---------- ADC/DAC tranfer in the main loop ------- */
+/* I see: (a guess as a documentation)
+ all DAC data is in sys_soundout array with
+ sys_dacblocksize (mostly 64) for each channels which
+ if we have more channels opened then dac-channels = sys_outchannels
+ we have to zero (silence them), which should be done once.
+
+Problems to solve:
+
+ a) Since in ALSA MMAP, the MMAP reagion can change (dont ask me why)
+ we have to do it each cycle or we say on RME HAMMERFALL/HDSP/DSPMADI
+ it never changes to it once. so maybe we can do it once in open
+
+ b) we never know if inputs are synced and zero them if not,
+ except we use the control interface to check for, but this is
+ a systemcall we cannot afford in RT Loops so we just dont
+ and if not it will click... users fault ;-)))
+*/
+
+int alsamm_send_dacs() {
+ static double timenow,timelast;
+ t_sample *fpo, *fpi, *fp1, *fp2;
+ int i, err, devno;
+ snd_pcm_sframes_t size;
+ snd_pcm_sframes_t commitres;
+ snd_pcm_state_t state;
+ snd_pcm_sframes_t ooffset, oavail;
+ snd_pcm_sframes_t ioffset, iavail;
+ /* unused channels should be zeroed out on startup (open) and stay this */
+ int inchannels = sys_inchannels;
+ int outchannels = sys_outchannels;
+ timelast = sys_getrealtime();
+ if (debug) {
+ if(dac_send++ < 0)
+ post("dac send called in %d, out %d, xrun %d",inchannels,outchannels, alsamm_xruns);
+ if(alsamm_xruns && (alsamm_xruns % 1000) == 0)
+ post("1000 xruns accoured");
+ if(dac_send < WATCH_PERIODS){
+ out_cm[dac_send] = -1;
+ in_avail[dac_send] = out_avail[dac_send] = -1;
+ in_offset[dac_send] = out_offset[dac_send] = -1;
+ outaddr[dac_send] = inaddr[dac_send] = NULL;
+ xruns_watch[dac_send] = alsamm_xruns;
+ }
+ }
+ if (!inchannels && !outchannels) return SENDDACS_NO;
+ /* here we should check if in and out samples are here.
+ but, the point is if out samples available also in sample should,
+ so we dont make a precheck of insamples here and let outsample check be the
+ the first of the forst card.
+ */
+ /* OUTPUT Transfer */
+ fpo = sys_soundout;
+ for(devno = 0;devno < alsa_noutdev;devno++){
+ t_alsa_dev *dev = &alsa_outdev[devno];
+ snd_pcm_t *out = dev->a_handle;
+ int ochannels =dev->a_channels;
+ /* how much samples available ??? */
+ oavail = snd_pcm_avail_update(out);
+ /* only one reason i can think about,
+ the driver stopped and says broken pipe
+ so this should not happen if we have enough stopthreshhold
+ but if try to restart with next commit
+ */
+ if (oavail < 0) {
+ if (debug) broken_opipe++;
+ err = xrun_recovery(out, -EPIPE);
+ if (err < 0) {
+ check_error(err,"otavail<0 recovery failed");
+ return SENDDACS_NO;
+ }
+ oavail = snd_pcm_avail_update(out);
+ }
+ /* check if we are late and have to (able to) catch up */
+ /* xruns will be ignored since you cant do anything since already happend */
+ state = snd_pcm_state(out);
+ if (state == SND_PCM_STATE_XRUN) {
+ err = xrun_recovery(out, -EPIPE);
+ if (err < 0) {
+ check_error(err,"DAC XRUN recovery failed");
+ return SENDDACS_NO;
+ }
+ oavail = snd_pcm_avail_update(out);
+ } else if (state == SND_PCM_STATE_SUSPENDED) {
+ err = xrun_recovery(out, -ESTRPIPE);
+ if (err < 0) {
+ check_error(err,"DAC SUSPEND recovery failed");
+ return SENDDACS_NO;
+ }
+ oavail = snd_pcm_avail_update(out);
+ }
+ if(debug && dac_send < WATCH_PERIODS){
+ out_avail[dac_send] = oavail;
+ }
+ /* we only transfer transfersize of bytes request,
+ this should only happen on first card otherwise we got a problem :-(()*/
+ if(oavail < sys_dacblocksize) return SENDDACS_NO;
+ /* transfer now */
+ size = sys_dacblocksize;
+ fp1 = fpo;
+ ooffset = 0;
+ /* since this can go over a buffer boundery we maybe need two steps to
+ transfer (normally when buffersize is a multiple of transfersize
+ this should never happen) */
+ while (size > 0) {
+ int chn;
+ snd_pcm_sframes_t oframes;
+ oframes = size;
+ err = alsamm_get_channels(out, (unsigned long *)&oframes, (unsigned long *)&ooffset,ochannels,dev->a_addr);
+ if(debug && dac_send < WATCH_PERIODS){
+ out_offset[dac_send] = ooffset;
+ outaddr[dac_send] = (char *) dev->a_addr[0];
+ }
+ if (err < 0) {
+ if ((err = xrun_recovery(out, err)) < 0) {
+ check_error(err,"MMAP begins avail error");
+ break; /* next card please */
+ }
+ }
+ /* transfer into memory */
+ for (chn = 0; chn < ochannels; chn++) {
+ t_alsa_sample32 *buf = (t_alsa_sample32 *)dev->a_addr[chn];
+ /* osc(buf, oframes, (dac_send%1000 < 500)?-100.0:-10.0,440,&(indexes[chn])); */
+ for (i = 0, fp2 = fp1 + chn*sys_dacblocksize; i < oframes; i++,fp2++) {
+ float s1 = *fp2 * F32MAX;
+ /* better but slower, better never clip ;-)
+ buf[i]= CLIP32(s1); */
+ buf[i]= ((int) s1 & 0xFFFFFF00);
+ *fp2 = 0.0;
+ }
+ }
+ commitres = snd_pcm_mmap_commit(out, ooffset, oframes);
+ if (commitres < 0 || commitres != oframes) {
+ if ((err = xrun_recovery(out, commitres >= 0 ? -EPIPE : commitres)) < 0) {
+ check_error(err,"MMAP commit error");
+ return SENDDACS_NO;
+ }
+ }
+ if(debug && dac_send < WATCH_PERIODS) out_cm[dac_send] = oframes;
+ fp1 += oframes;
+ size -= oframes;
+ } /* while size */
+ fpo += ochannels*sys_dacblocksize;
+ }/* for devno */
+ fpi = sys_soundin; /* star first card first channel */
+ for(devno = 0;devno < alsa_nindev;devno++){
+ t_alsa_dev *dev = &alsa_indev[devno];
+ snd_pcm_t *in = dev->a_handle;
+ int ichannels = dev->a_channels;
+ iavail = snd_pcm_avail_update(in);
+ if (iavail < 0) {
+ err = xrun_recovery(in, iavail);
+ if (err < 0) {
+ check_error(err,"input avail update failed");
+ return SENDDACS_NO;
+ }
+ iavail=snd_pcm_avail_update(in);
+ }
+ state = snd_pcm_state(in);
+ if (state == SND_PCM_STATE_XRUN) {
+ err = xrun_recovery(in, -EPIPE);
+ if (err < 0) {
+ check_error(err,"ADC XRUN recovery failed");
+ return SENDDACS_NO;
+ }
+ iavail=snd_pcm_avail_update(in);
+ } else if (state == SND_PCM_STATE_SUSPENDED) {
+ err = xrun_recovery(in, -ESTRPIPE);
+ if (err < 0) {
+ check_error(err,"ADC SUSPEND recovery failed");
+ return SENDDACS_NO;
+ }
+ iavail=snd_pcm_avail_update(in);
+ }
+ /* only transfer full transfersize or nothing */
+ if(iavail < sys_dacblocksize){
+ return SENDDACS_NO;
+ }
+ size = sys_dacblocksize;
+ fp1 = fpi;
+ ioffset = 0;
+ /* since sysdata can go over a driver buffer boundery we maybe need two steps to
+ transfer (normally when buffersize is a multiple of transfersize
+ this should never happen) */
+ while(size > 0) {
+ int chn;
+ snd_pcm_sframes_t iframes = size;
+ err = alsamm_get_channels(in, (unsigned long *)&iframes, (unsigned long *)&ioffset,ichannels,dev->a_addr);
+ if (err < 0){
+ if ((err = xrun_recovery(in, err)) < 0) {
+ check_error(err,"MMAP begins avail error");
+ return SENDDACS_NO;
+ }
+ }
+ if(debug && dac_send < WATCH_PERIODS){
+ in_avail[dac_send] = iavail;
+ in_offset[dac_send] = ioffset;
+ inaddr[dac_send] = dev->a_addr[0];
+ }
+ /* transfer into memory */
+ for (chn = 0; chn < ichannels; chn++) {
+ t_alsa_sample32 *buf = (t_alsa_sample32 *) dev->a_addr[chn];
+ for (i = 0, fp2 = fp1 + chn*sys_dacblocksize; i < iframes; i++,fp2++) {
+ /* mask the lowest bits, since subchannels info can make zero samples nonzero */
+ *fp2 = (float) ((t_alsa_sample32) (buf[i] & 0xFFFFFF00))
+ * (1.0 / (float) INT32_MAX);
+ }
+ }
+ commitres = snd_pcm_mmap_commit(in, ioffset, iframes);
+ if (commitres < 0 || commitres != iframes) {
+ post("please never");
+ if ((err = xrun_recovery(in, commitres >= 0 ? -EPIPE : commitres)) < 0) {
+ check_error(err,"MMAP synced in commit error");
+ return SENDDACS_NO;
+ }
+ }
+ fp1 += iframes;
+ size -= iframes;
+ }
+ fpi += ichannels*sys_dacblocksize;
+ } /* for out devno < alsamm_outcards*/
+ if ((timenow = sys_getrealtime()) > (timelast + sleep_time)) {
+ if(debug && dac_send < 10 && sys_verbose)
+ post("slept %f > %f + %f (=%f)", timenow,timelast,sleep_time,(timelast + sleep_time));
+ return (SENDDACS_SLEPT);
+ }
+ return SENDDACS_YES;
+}
+
+/* extra debug info */
+void alsamm_showstat(snd_pcm_t *handle) {
+ int err;
+ snd_pcm_status_t *status;
+ snd_pcm_status_alloca(&status);
+ if ((err = snd_pcm_status(handle, status)) < 0) {
+ check_error(err, "Get Stream status error");
+ return;
+ }
+ snd_pcm_status_dump(status, alsa_stdout);
+}
diff --git a/desiredata/src/s_audio_asio.cpp b/desiredata/src/s_audio_asio.cpp
new file mode 100644
index 00000000..fde2891d
--- /dev/null
+++ b/desiredata/src/s_audio_asio.cpp
@@ -0,0 +1,1014 @@
+/* Copyright (c) 2004, Tim Blechmann and others
+ * supported by vibrez.net
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt" in this distribution. */
+
+/* native ASIO interface for windows
+ * adapted from hostsample.cpp (ASIO SDK)
+ */
+
+#ifdef MSW
+#include "windows.h" /* for application window handle */
+#define IEEE754_64FLOAT 1
+#else
+#error This is for MS Windows (Intel CPU architecture) only!!
+#endif
+
+#ifdef _MSC_VER
+#pragma warning( disable : 4091 )
+#endif
+
+#include "m_pd.h"
+extern "C" {
+#include "s_stuff.h"
+#include "m_simd.h"
+}
+
+#include "asio.h" /* steinberg's header file */
+#include "asiodrivers.h" /* ASIODrivers class */
+#include "asiosys.h"
+#include "pthread.h"
+#include "stdio.h" /* for sprintf */
+
+#include <time.h>
+#include <sys/timeb.h>
+
+#include "assert.h"
+#define ASSERT assert
+
+
+/* fast float to integer conversion adapted from Erik de Castro Lopo */
+#define _ISOC9X_SOURCE 1
+#define _ISOC99_SOURCE 1
+#define __USE_ISOC9X 1
+#define __USE_ISOC99 1
+#include "math.h"
+
+// seconds to wait for driver to respond
+#define DRIVERWAIT 1
+
+#define ASIODEBUG
+
+/* public function prototypes */
+// extern "C" void asio_open_audio(int naudioindev, int *audioindev, int nchindev,
+// int *chindev, int naudiooutdev, int *audiooutdev, int nchoutdev, int *choutdev, int srate, int scheduler);
+extern "C" void asio_close_audio();
+extern "C" void asio_getdevs(char *indevlist, int *nindevs, char *outdevlist, int *noutdevs, int *canmulti, int maxndev, int devdescsize);
+extern "C" int asio_send_dacs();
+
+/* asio callback prototypes for traditional scheduling*/
+static void asio_bufferSwitch(long db_idx, ASIOBool directprocess);
+static void asio_sampleRateDidChange(ASIOSampleRate srate);
+static long asio_messages(long selector, long value, void* message, double* opt);
+static ASIOTime *asio_bufferSwitchTimeInfo(ASIOTime *params, long db_idx, ASIOBool directprocess);
+
+/* asio callback prototypes for callback-based scheduling*/
+static void asio_bufferSwitch_cb(long db_idx, ASIOBool directprocess);
+static void asio_sampleRateDidChange_cb(ASIOSampleRate srate);
+static long asio_messages_cb(long selector, long value, void* message, double* opt);
+static ASIOTime *asio_bufferSwitchTimeInfo_cb(ASIOTime *params, long db_idx, ASIOBool directprocess);
+
+static void float32tofloat32(void* inbuffer, void* outbuffer, long frames);
+static void float32tofloat32_S(void* inbuffer, void* outbuffer, long frames);
+static void float32tofloat64(void* inbuffer, void* outbuffer, long frames);
+static void float64tofloat32(void* inbuffer, void* outbuffer, long frames);
+static void float32toInt16(void* inbuffer, void* outbuffer, long frames);
+static void Int16tofloat32(void* inbuffer, void* outbuffer, long frames);
+static void float32toInt24(void* inbuffer, void* outbuffer, long frames);
+static void Int24tofloat32(void* inbuffer, void* outbuffer, long frames);
+static void float32toInt32(void* inbuffer, void* outbuffer, long frames);
+static void Int32tofloat32(void* inbuffer, void* outbuffer, long frames);
+static void float32toInt16_S(void* inbuffer, void* outbuffer, long frames);
+static void Int16tofloat32_S(void* inbuffer, void* outbuffer, long frames);
+static void float32toInt24_S(void* inbuffer, void* outbuffer, long frames);
+static void Int24tofloat32_S(void* inbuffer, void* outbuffer, long frames);
+static void float32toInt32_S(void* inbuffer, void* outbuffer, long frames);
+static void Int32tofloat32_S(void* inbuffer, void* outbuffer, long frames);
+void asio_close_audio(void);
+
+typedef void converter_t(void* inbuffer, void* outbuffer, long frames);
+
+/* sample converting helper functions:
+ * - global send / receive functions
+ * - sample conversion functions (adapted from ASIOConvertSamples.cpp */
+static converter_t *asio_converter_send (ASIOSampleType format);
+static converter_t *asio_converter_receive (ASIOSampleType format);
+
+/* pointers to the converter functions of each channel are stored here */
+static converter_t **asio_converter = NULL;
+
+/* function to get sample width of data according to ASIOSampleType */
+static int asio_get_samplewidth(ASIOSampleType format);
+
+/* that's the sample width in bytes (per output channel) -
+ * it's only for silence when stopping the driver.... (please find a better solution) */
+static int *asio_samplewidth = NULL;
+
+
+/* some local helper functions */
+static void prepare_asio_drivernames();
+
+/* system dependent helper functions */
+static unsigned long get_sys_reference_time();
+
+/* global storage */
+static ASIODriverInfo * asio_driver = NULL;
+static ASIOBufferInfo * asio_bufferinfo = NULL;
+static ASIOChannelInfo* asio_channelinfo = NULL;
+static AsioTimeInfo * asio_timerinfo = NULL;
+static ASIOCallbacks asio_callbacks;
+extern AsioDrivers * asioDrivers; /* declared in asiodrivers.cpp */
+
+static char ** asio_drivernames = NULL;
+
+static ASIOSampleRate asio_srate;
+static long asio_inchannels;
+static long asio_outchannels;
+
+static long asio_minbufsize;
+static long asio_maxbufsize;
+static long asio_prefbufsize;
+static long asio_granularity;
+static unsigned char asio_useoutputready;
+static long asio_inputlatency;
+static long asio_outputlatency;
+
+static long asio_bufsize; /* hardware buffer size */
+static long asio_ticks_per_callback;
+
+unsigned long sys_reftime;
+
+/* ringbuffer stuff */
+static t_sample ** asio_ringbuffer = NULL; /* ringbuffers */
+static int asio_ringbuffer_inoffset; /* ringbuffer(in) pointer offset for dac */
+static int asio_ringbuffer_outoffset; /* ringbuffer(out) pointer offset */
+static int asio_ringbuffer_length; /* latency - hardware latency in samples*/
+
+/* i hope we can remove this to use callback based dsp scheduling */
+static pthread_mutex_t asio_ringbuf_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t asio_ringbuf_cond = PTHREAD_COND_INITIALIZER;
+
+/* some global definitions: */
+#define ASIOVERSION 2 /* i hope we are compatible with asio 2 */
+
+/* definitions from s_audio.c ... it should be save to use them */
+#define DEVDESCSIZE 80
+#define MAXNDEV 20
+
+/* from m_sched.c: */
+extern "C" double sys_time_per_dsp_tick;
+extern "C" double sys_time;
+
+
+/**************************************************************************/
+/* some function pointers for eventual fast copying when SIMD is possible */
+
+static void (*copyblock)(t_sample *dst,t_sample *src,int n);
+static void (*zeroblock)(t_sample *dst,int n);
+static t_int *(*clipblock)(t_int *w);
+
+static void copyvec_nrm(t_sample *dst,t_sample *src,int n) { memcpy(dst,src,n*sizeof(t_sample)); }
+static void zerovec_nrm(t_sample *dst,int n) { memset(dst,0,n*sizeof(t_sample)); }
+
+/*************************************************************************/
+
+
+/* open asio interface */
+/* todo: some more error messages */
+void asio_open_audio(int naudioindev, int *audioindev, int nchindev,
+int *chindev, int naudiooutdev, int *audiooutdev, int nchoutdev, int *choutdev, int srate, int scheduler) {
+ ASIOError status = ASE_OK;
+ ASIOBufferInfo * buffers = NULL;
+ int i;
+ int channels;
+
+#ifdef IEEE754_64FLOAT
+ asio_srate=(ASIOSampleRate)srate;
+#else
+ sprintf(asio_srate,"%8d",srate);
+#endif
+ /* check, if the driver is still running */
+ if(asio_driver) asio_close_audio();
+ /* check, if we use the first asio device */
+ prepare_asio_drivernames();
+ asioDrivers->getDriverNames(asio_drivernames,MAXNDEV);
+
+ try {
+ asioDrivers->loadDriver(asio_drivernames[*audioindev]);
+ }
+ catch(...) {
+ error("ASIO: Error loading driver");
+ goto bailout;
+ }
+ /* initialize ASIO */
+ asio_driver = (ASIODriverInfo*) getbytes (sizeof(ASIODriverInfo));
+ asio_driver->asioVersion = ASIOVERSION;
+ asio_driver->sysRef = GetDesktopWindow();
+ status = ASIOInit(asio_driver);
+#ifdef ASIODEBUG
+ post("sysRef: %x", asio_driver->sysRef);
+ post("asioversion: %d", asio_driver->asioVersion);
+ post("driverversion: %d", asio_driver->driverVersion);
+ post("name: %s", asio_driver->name);
+#endif
+
+ switch (status) {
+ if(status) post("error: %s", asio_driver->errorMessage);
+ case ASE_NotPresent: error("ASIO: ASE_NotPresent"); goto bailout;
+ case ASE_NoMemory: error("ASIO: ASE_NoMemory"); goto bailout;
+ case ASE_HWMalfunction: error("ASIO: ASE_HWMalfunction"); goto bailout;
+ }
+#ifdef ASIODEBUG
+ post("ASIO initialized successfully");
+#endif
+
+
+ /* query driver */
+ status = ASIOGetChannels(&asio_inchannels, &asio_outchannels);
+ if(status != ASE_OK) {
+ error("ASIO: Couldn't get channel count");
+ goto bailout;
+ }
+
+#ifdef ASIODEBUG
+ post ("ASIOGetChannels\tinputs: %d, outputs: %d", asio_inchannels,
+ asio_outchannels);
+#endif
+
+ sys_inchannels = *chindev <= asio_inchannels ? *chindev : asio_inchannels;
+ sys_outchannels = *choutdev <= asio_outchannels ? *choutdev : asio_outchannels;
+ channels = sys_inchannels + sys_outchannels;
+ status = ASIOGetBufferSize(&asio_minbufsize, &asio_maxbufsize, &asio_prefbufsize, &asio_granularity);
+ if(status != ASE_OK) {
+ error("ASIO: Couldn't get buffer size");
+ goto bailout;
+ }
+#ifdef ASIODEBUG
+ post ("ASIOGetBufferSize\tmin: %d, max: %d, preferred: %d, granularity: "
+ "%d", asio_minbufsize, asio_maxbufsize, asio_prefbufsize,
+ asio_granularity);
+#endif
+
+ /* todo: buffer size hardcoded to asio hardware */
+ asio_bufsize = asio_prefbufsize;
+ if (scheduler) {
+ if ( asio_bufsize % sys_dacblocksize == 0 ) {
+ /* use callback scheduler */
+ sys_setscheduler(1);
+ asio_ticks_per_callback = asio_bufsize / sys_dacblocksize;
+ post("ASIO: using callback-based scheduler");
+ }
+ } else post("ASIO: using traditional scheduler");
+ /* try to set sample rate */
+ if(ASIOCanSampleRate( asio_srate ) != ASE_OK) {
+ error ("Samplerate not supported, using default");
+#ifdef IEEE754_64FLOAT
+ asio_srate = (ASIOSampleRate)44100.0;
+#else
+ sprintf(&asio_srate,"%8d",44100);
+#endif
+ srate=44100;
+ }
+
+ status = ASIOSetSampleRate( asio_srate );
+ if(status != ASE_OK)
+#ifdef IEEE754_64FLOAT
+ post("Setting ASIO sample rate to %lg failed... is the device in slave sync mode?", (double)asio_srate);
+#else
+ post("Setting ASIO sample rate to %s failed... is the device in slave sync mode?", asio_srate);
+#endif
+
+ if(ASIOOutputReady() == ASE_OK)
+ asio_useoutputready = 1;
+ else
+ asio_useoutputready = 0;
+
+
+ /* set callbacks */
+ if(sys_callbackscheduler) {
+ asio_callbacks.bufferSwitch = &asio_bufferSwitch_cb;
+ asio_callbacks.sampleRateDidChange = &asio_sampleRateDidChange_cb;
+ asio_callbacks.asioMessage = &asio_messages_cb;
+ asio_callbacks.bufferSwitchTimeInfo = &asio_bufferSwitchTimeInfo_cb;
+ } else {
+ asio_callbacks.bufferSwitch = &asio_bufferSwitch;
+ asio_callbacks.sampleRateDidChange = &asio_sampleRateDidChange;
+ asio_callbacks.asioMessage = &asio_messages;
+ asio_callbacks.bufferSwitchTimeInfo = &asio_bufferSwitchTimeInfo;
+ }
+ /* prepare, create and set up buffers */
+ asio_bufferinfo = (ASIOBufferInfo*) getbytes (channels*sizeof(ASIOBufferInfo));
+ asio_channelinfo = (ASIOChannelInfo*) getbytes(channels*sizeof(ASIOChannelInfo));
+ if (!(asio_bufferinfo && asio_channelinfo)) {
+ error("ASIO: couldn't allocate buffer or channel info");
+ goto bailout;
+ }
+
+ for (i = 0; i != sys_inchannels + sys_outchannels; ++i) {
+ if (i < sys_outchannels) {
+ asio_bufferinfo[i].isInput = ASIOFalse;
+ asio_bufferinfo[i].channelNum = i;
+ asio_bufferinfo[i].buffers[0] = asio_bufferinfo[i].buffers[1] = 0;
+ } else {
+ asio_bufferinfo[i].isInput = ASIOTrue;
+ asio_bufferinfo[i].channelNum = i - sys_outchannels;
+ asio_bufferinfo[i].buffers[0] = asio_bufferinfo[i].buffers[1] = 0;
+ }
+ }
+ status = ASIOCreateBuffers(asio_bufferinfo, sys_inchannels + sys_outchannels, asio_bufsize, &asio_callbacks);
+ if(status != ASE_OK) {
+ error("ASIO: couldn't allocate buffers");
+ goto bailout;
+ }
+#ifdef ASIODEBUG
+ post("ASIO: buffers allocated");
+#endif
+
+ asio_converter = (converter_t **)getbytes(channels * sizeof (converter_t *));
+ asio_samplewidth = (int *)getbytes((sys_outchannels + sys_inchannels) * sizeof (int));
+ for (i = 0; i != sys_outchannels + sys_inchannels; ++i) {
+ asio_channelinfo[i].channel = asio_bufferinfo[i].channelNum;
+ asio_channelinfo[i].isInput = asio_bufferinfo[i].isInput;
+ ASIOGetChannelInfo(&asio_channelinfo[i]);
+
+#ifdef ASIODEBUG
+ post("ASIO: channel %d type %d", i, asio_channelinfo[i].type);
+#endif
+ asio_samplewidth[i] = asio_get_samplewidth(asio_channelinfo[i].type);
+ if (i < sys_outchannels) asio_converter[i] = asio_converter_send( asio_channelinfo[i].type);
+ else asio_converter[i] = asio_converter_receive(asio_channelinfo[i].type);
+ }
+
+ /* get latencies */
+ ASIOGetLatencies(&asio_inputlatency, &asio_outputlatency);
+#ifdef ASIODEBUG
+ post("ASIO: input latency: %d, output latency: %d",asio_inputlatency, asio_outputlatency);
+#endif
+
+
+ /* we need a ringbuffer if we use the traditional scheduler */
+ if (!sys_callbackscheduler) {
+ /* a strange way to find the least common multiple, but works, since sys_dacblocksize (expt 2 x) */
+ asio_ringbuffer_length = asio_bufsize * sys_dacblocksize;
+ while ( !(asio_ringbuffer_length % sys_dacblocksize) && !(asio_ringbuffer_length % asio_bufsize)) {
+ asio_ringbuffer_length /= 2;
+ }
+ asio_ringbuffer_length *= 2;
+#ifdef ASIODEBUG
+ post("ASIO: ringbuffer size: %d",asio_ringbuffer_length);
+#endif
+ /* allocate ringbuffer */
+ asio_ringbuffer = (t_sample**) getbytes (channels * sizeof (t_sample*));
+ for (i = 0; i != channels; ++i) {
+ asio_ringbuffer[i] = (t_sample*)getalignedbytes(asio_ringbuffer_length * sizeof (t_sample));
+ if (!asio_ringbuffer[i])
+ error("ASIO: couldn't allocate ASIO ringbuffer");
+ memset(asio_ringbuffer[i], 0, asio_ringbuffer_length * sizeof (t_sample));
+ }
+ /* initialize ringbuffer pointers */
+ asio_ringbuffer_inoffset = asio_ringbuffer_outoffset = 0;
+ }
+ if(ASIOStart() != ASE_OK) goto bailout;
+ /* set block copy/zero/clip functions */
+ if(SIMD_CHKCNT(sys_dacblocksize) && simd_runtime_check()) {
+ // urgh... ugly cast
+ copyblock = (void (*)(t_sample *,t_sample *,int))&copyvec_simd;
+ zeroblock = &zerovec_simd;
+ clipblock = &clip_perf_simd;
+ } else {
+ copyblock = &copyvec_nrm;
+ zeroblock = &zerovec_nrm;
+ clipblock = &clip_perform;
+ }
+
+ post("ASIO: started");
+ return;
+
+bailout:
+ if(status) post("error: %s", asio_driver->errorMessage);
+ post("ASIO: couldn't start");
+ asio_close_audio();
+ return;
+}
+
+
+
+/* stop asio, free buffers and close asio interface */
+void asio_close_audio() {
+ if (asio_driver) {
+ pthread_cond_broadcast(&asio_ringbuf_cond);
+
+ ASIOError status;
+ int channels = sys_inchannels + sys_outchannels;
+ int i;
+
+ if(asio_useoutputready) {
+ // the DMA buffers would be played past ASIOStop
+ // -> clear output buffers and notify driver
+#if 0
+ if(asio_ringbuffer) {
+ // slow, blocking method
+ for(i = 0; i != sys_outchannels; ++i)
+ zerovec_simd(asio_ringbuffer[i], asio_ringbuffer_length);
+ // wait for bufferswitch to process silence (twice)
+ pthread_cond_wait(&asio_ringbuf_cond, &asio_ringbuf_mutex);
+ for(i = 0; i != sys_outchannels; ++i) memset(asio_ringbuffer[i], 0, asio_ringbuffer_length * sizeof (t_sample));
+ pthread_cond_wait(&asio_ringbuf_cond, &asio_ringbuf_mutex);
+ }
+#else
+ // direct method - clear both hardware buffers
+ if(asio_bufferinfo && asio_samplewidth) {
+ for(i = 0; i < sys_outchannels; ++i) {
+ long bytes = asio_bufsize*asio_samplewidth[i];
+ memset(asio_bufferinfo[i].buffers[0],0,bytes);
+ memset(asio_bufferinfo[i].buffers[1],0,bytes);
+ }
+ }
+ // notify driver
+ status = ASIOOutputReady();
+#endif
+ }
+
+ status = ASIOStop();
+ if(status == ASE_OK) post("ASIO: stopped");
+ status = ASIODisposeBuffers();
+ try {
+ // ASIOExit can crash if driver not really running
+ status = ASIOExit();
+ } catch(...) {}
+ // deallocate all memory
+ if(asio_ringbuffer) {
+ for(i = 0; i < channels; i++)
+ if(asio_ringbuffer[i]) freealignedbytes(asio_ringbuffer[i],asio_ringbuffer_length * sizeof (t_sample));
+ freebytes(asio_ringbuffer, channels * sizeof (t_sample *));
+ asio_ringbuffer = NULL;
+ }
+
+ if(asio_bufferinfo) {
+ freebytes(asio_bufferinfo, channels * sizeof (ASIOBufferInfo));
+ asio_bufferinfo = NULL;
+ }
+ if(asio_channelinfo) {
+ freebytes(asio_channelinfo, channels * sizeof (ASIOChannelInfo));
+ asio_channelinfo = NULL;
+ }
+ if(asio_converter) {
+ freebytes(asio_converter, channels * sizeof (converter_t *));
+ asio_converter = NULL;
+ }
+ if(asio_samplewidth) {
+ freebytes(asio_samplewidth, (sys_outchannels + sys_inchannels) * sizeof (int));
+ asio_samplewidth = NULL;
+ }
+ freebytes(asio_driver, sizeof (ASIODriverInfo));
+ asio_driver = NULL;
+ /* leave the scheduler and return to traditional mode */
+ if (sys_callbackscheduler) sys_setscheduler(0);
+ }
+}
+
+void asio_getdevs(char *indevlist, int *nindevs, char *outdevlist, int *noutdevs, int *canmulti, int maxndev, int devdescsize) {
+ prepare_asio_drivernames();
+ *canmulti = 0; /* we will only support one asio device */
+ *nindevs = *noutdevs = (int)asioDrivers->getDriverNames(asio_drivernames, maxndev);
+ for(int i = 0; i!= *nindevs; ++i) {
+ sprintf(indevlist + i * devdescsize, "%s", asio_drivernames[i]);
+ sprintf(outdevlist + i * devdescsize, "%s", asio_drivernames[i]);
+ }
+}
+
+/* called on every dac~ send */
+int asio_send_dacs() {
+ t_sample * sp; /* sample pointer */
+ int i, j;
+ double timenow;
+ double timeref = sys_getrealtime();
+#ifdef ASIODEBUG
+ if (!asio_driver) {
+ static int written = 0;
+ if(written%100 == 0) error("ASIO not running");
+ written++;
+ return SENDDACS_NO;
+ }
+
+#endif
+
+ /* send sound to ringbuffer */
+ sp = sys_soundout;
+ for (i = 0; i < sys_outchannels; i++) {
+ t_float lo = -1.f;
+ t_float hi = 1.f;
+ t_int clipargs[6];
+ clipargs[1] = (t_int)sp;
+ clipargs[2] = (t_int)(asio_ringbuffer[i] + asio_ringbuffer_inoffset);
+ clipargs[3] = (t_int)&lo;
+ clipargs[4] = (t_int)&hi;
+ clipargs[5] = (t_int)sys_dacblocksize;
+ clipblock(clipargs);
+ zeroblock(sp,sys_dacblocksize);
+ sp+=sys_dacblocksize;
+ }
+ /* get sound from ringbuffer */
+ sp = sys_soundin;
+ for (j = 0; j < sys_inchannels; j++) {
+#if 0
+ /* we should be able to read from the ringbuffer on a different position
+ * to reduce latency for asio buffer sizes that aren't multiples of 64... */
+ int offset = asio_bufsize + sys_dacblocksize;
+ offset += sys_dacblocksize - offset % sys_dacblocksize;
+ if (asio_ringbuffer_inoffset < offset) {
+ memcpy(sp, asio_ringbuffer[i+j] + asio_ringbuffer_length +
+ asio_ringbuffer_inoffset - offset, 64 *sizeof(t_sample));
+ } else memcpy(sp, asio_ringbuffer[i+j] + asio_ringbuffer_inoffset - offset, 64*sizeof(t_sample));
+#else
+ /* working but higher latency */
+ copyblock(sp, asio_ringbuffer[i+j] + asio_ringbuffer_inoffset,sys_dacblocksize);
+#endif
+ sp+=sys_dacblocksize;
+ }
+ asio_ringbuffer_inoffset += sys_dacblocksize;
+#if 1
+ // blocking method
+ if (asio_ringbuffer_inoffset >= asio_ringbuffer_outoffset + asio_bufsize) {
+ struct timespec tm;
+ _timeb tmb;
+ _ftime(&tmb);
+ tm.tv_nsec = tmb.millitm*1000000;
+ tm.tv_sec = tmb.time+DRIVERWAIT; // delay
+ if(pthread_cond_timedwait(&asio_ringbuf_cond, &asio_ringbuf_mutex, &tm) == ETIMEDOUT) {
+ error("ASIO: ASIO driver non-responsive! - closing");
+ asio_close_audio();
+ return SENDDACS_SLEPT;
+ }
+ if (asio_ringbuffer_inoffset == asio_ringbuffer_length) {
+ asio_ringbuffer_outoffset = 0;
+ asio_ringbuffer_inoffset = 0;
+ } else asio_ringbuffer_outoffset += asio_bufsize;
+ }
+ if ((timenow = sys_getrealtime()) - timeref > 0.002) {
+ return SENDDACS_SLEPT;
+ }
+#else
+ // non-blocking... let PD wait -> doesn't work!
+ if (asio_ringbuffer_inoffset >= asio_ringbuffer_outoffset + asio_bufsize) return SENDDACS_NO;
+ if (asio_ringbuffer_inoffset == asio_ringbuffer_length) {
+ asio_ringbuffer_outoffset = 0;
+ asio_ringbuffer_inoffset = 0;
+ } else asio_ringbuffer_outoffset += asio_bufsize;
+#endif
+ return SENDDACS_YES;
+}
+
+/* buffer switch callback */
+static void asio_bufferSwitch(long db_idx, ASIOBool directprocess) {
+ ASIOTime time;
+#ifdef ASIODEBUG
+ static int written = 0;
+ if(written == 0) {
+ post("ASIO: asio_bufferSwitch_cb");
+ written = 1;
+ }
+#endif
+ memset (&time, 0, sizeof (time));
+ /* todo: do we need to syncronize with other media ??? */
+ asio_bufferSwitchTimeInfo(&time, db_idx, directprocess);
+}
+
+/* sample rate change callback */
+static void asio_sampleRateDidChange(ASIOSampleRate srate) {
+ asio_srate = srate;
+#ifdef ASIODEBUG
+ post("sample rate changed");
+#endif
+}
+
+/* asio messaging callback */
+static long asio_messages(long selector, long value, void* message, double* opt) {
+ switch (selector) {
+ case kAsioSelectorSupported:
+ if (value == kAsioResetRequest || value == kAsioSupportsTimeInfo) return 1L;
+ return 0L;
+ case kAsioEngineVersion:
+ return ASIOVERSION;
+ case kAsioResetRequest:
+ /* how to handle this without changing the dsp scheduler? */
+ post("ASIO: Reset request");
+ return 1L;
+ case kAsioBufferSizeChange:
+ /* todo */
+ post("ASIO: Buffer size changed");
+ sys_reopen_audio();
+ return 1L;
+ case kAsioResyncRequest:
+ post("ASIO: Resync request");
+ return 0L;
+ case kAsioLatenciesChanged:
+ /* we are not handling the latencies atm */
+ return 0L;
+ case kAsioSupportsTimeInfo:
+ return 1L;
+ case kAsioSupportsTimeCode:
+ /* we don't support that atm */
+ return 0L;
+ }
+ return 0L;
+}
+
+static ASIOTime *asio_bufferSwitchTimeInfo(ASIOTime *params, long db_idx, ASIOBool directprocess) {
+ /* todo: i'm not sure if we'll have to synchronize with other media ... probably yes ... */
+ /* sys_reftime = get_sys_reference_time(); */
+ /* perform the processing */
+ int timeout = sys_dacblocksize * (float)asio_ticks_per_callback / (float) sys_dacsr * 1e6;
+ if (sys_timedlock(timeout) == ETIMEDOUT) /* we're late */ {
+ post("timeout %d", timeout);
+ sys_log_error(ERR_SYSLOCK);
+ return 0;
+ }
+ for (long i = 0; i < sys_outchannels + sys_inchannels; i++) {
+ if(asio_converter[i])
+ if (asio_bufferinfo[i].isInput != ASIOTrue) {
+ asio_converter[i](asio_ringbuffer[i]+asio_ringbuffer_outoffset,
+ asio_bufferinfo[i].buffers[db_idx], asio_bufsize);
+ }
+ else /* these are the input channels */ {
+ asio_converter[i](asio_bufferinfo[i].buffers[db_idx],
+ asio_ringbuffer[i]+asio_ringbuffer_outoffset, asio_bufsize);
+ }
+ }
+ pthread_cond_broadcast(&asio_ringbuf_cond);
+ sys_unlock();
+ if(asio_useoutputready) ASIOOutputReady();
+ return 0L; /* time info!!! */
+}
+
+/* get system reference time on both platforms */
+static unsigned long get_sys_reference_time() {
+#if WINDOWS
+ return timeGetTime();
+#elif MAC
+ static const double twoRaisedTo32 = 4294967296.;
+ UnsignedWide ys;
+ Microseconds(&ys);
+ double r = ((double)ys.hi * twoRaisedTo32 + (double)ys.lo);
+ return (unsigned long)(r / 1000.);
+#endif
+}
+
+/* sample converting helper functions */
+static converter_t *asio_converter_send(ASIOSampleType format) {
+#ifdef ASIODEBUG
+ /* post("ASIO: Sample Type %d", format); */
+#endif
+ switch (format) {
+ case ASIOSTInt16LSB: return float32toInt16;
+ case ASIOSTInt24LSB: return float32toInt24; // used for 20 bits as well
+ case ASIOSTInt32LSB: return float32toInt32;
+ case ASIOSTInt16MSB: return float32toInt16_S;
+ case ASIOSTInt24MSB: return float32toInt24_S; // used for 20 bits as well
+ case ASIOSTInt32MSB: return float32toInt32_S;
+ case ASIOSTFloat32LSB:return float32tofloat32; // IEEE 754 32 bit float, as found on Intel x86 architecture
+ case ASIOSTFloat32MSB:return float32tofloat32_S;
+ case ASIOSTFloat64LSB:return float32tofloat64; // IEEE 754 64 bit double float, as found on Intel x86 architecture
+ case ASIOSTFloat64MSB:
+ // these are used for 32 bit data buffer, with different alignment of the data inside
+ // 32 bit PCI bus systems can more easily used with these
+ case ASIOSTInt32LSB16: // 32 bit data with 16 bit alignment
+ case ASIOSTInt32LSB18: // 32 bit data with 18 bit alignment
+ case ASIOSTInt32LSB20: // 32 bit data with 20 bit alignment
+ case ASIOSTInt32LSB24: // 32 bit data with 24 bit alignment
+ // these are used for 32 bit data buffer, with different alignment of the data inside
+ // 32 bit PCI bus systems can more easily used with these
+ case ASIOSTInt32MSB16: // 32 bit data with 18 bit alignment
+ case ASIOSTInt32MSB18: // 32 bit data with 18 bit alignment
+ case ASIOSTInt32MSB20: // 32 bit data with 20 bit alignment
+ case ASIOSTInt32MSB24: // 32 bit data with 24 bit alignment
+ default:
+ post("Output sample Type %d not supported, yet!!!",format);
+ return NULL;
+ }
+}
+
+static converter_t *asio_converter_receive (ASIOSampleType format) {
+#ifdef ASIODEBUG
+ /* post("ASIO: Sample Type %d", format); */
+#endif
+ switch (format) {
+ case ASIOSTInt16LSB: return Int16tofloat32;
+ case ASIOSTInt24LSB: return Int24tofloat32; // used for 20 bits as well
+ case ASIOSTInt32LSB: return Int32tofloat32;
+ case ASIOSTInt16MSB: return Int16tofloat32_S;
+ case ASIOSTInt24MSB: return Int24tofloat32_S; // used for 20 bits as well
+ case ASIOSTInt32MSB: return Int32tofloat32_S;
+ case ASIOSTFloat32MSB:return float32tofloat32_S; // IEEE 754 32 bit float, as found on Intel x86 architecture
+ case ASIOSTFloat32LSB:return float32tofloat32; // IEEE 754 32 bit float, as found on Intel x86 architecture
+ case ASIOSTFloat64LSB:return float64tofloat32; // IEEE 754 64 bit double float, as found on Intel x86 architecture
+ case ASIOSTFloat64MSB:
+ // these are used for 32 bit data buffer, with different alignment of the data inside
+ // 32 bit PCI bus systems can more easily used with these
+ case ASIOSTInt32LSB16: // 32 bit data with 18 bit alignment
+ case ASIOSTInt32LSB18: // 32 bit data with 18 bit alignment
+ case ASIOSTInt32LSB20: // 32 bit data with 20 bit alignment
+ case ASIOSTInt32LSB24: // 32 bit data with 24 bit alignment
+ // these are used for 32 bit data buffer, with different alignment of the data inside
+ // 32 bit PCI bus systems can more easily used with these
+ case ASIOSTInt32MSB16: // 32 bit data with 18 bit alignment
+ case ASIOSTInt32MSB18: // 32 bit data with 18 bit alignment
+ case ASIOSTInt32MSB20: // 32 bit data with 20 bit alignment
+ case ASIOSTInt32MSB24: // 32 bit data with 24 bit alignment
+ default:
+ post("Input sample Type %d not supported, yet!!!",format);
+ return NULL;
+ }
+}
+
+static int asio_get_samplewidth(ASIOSampleType format) {
+ switch (format) {
+ case ASIOSTInt16LSB: case ASIOSTInt16MSB: return 2;
+ case ASIOSTInt24LSB: case ASIOSTInt24MSB: return 3;
+ case ASIOSTFloat32LSB:case ASIOSTFloat32MSB:
+ case ASIOSTInt32LSB: case ASIOSTInt32MSB:
+ // these are used for 32 bit data buffer, with different alignment of the data inside
+ // 32 bit PCI bus systems can more easily used with these
+ case ASIOSTInt32LSB16:
+ case ASIOSTInt32LSB18:
+ case ASIOSTInt32LSB20:
+ case ASIOSTInt32LSB24:
+ // these are used for 32 bit data buffer, with different alignment of the data inside
+ // 32 bit PCI bus systems can more easily used with these
+ case ASIOSTInt32MSB16:
+ case ASIOSTInt32MSB18:
+ case ASIOSTInt32MSB20:
+ case ASIOSTInt32MSB24:
+ return 4;
+ case ASIOSTFloat64MSB:
+ case ASIOSTFloat64LSB:
+ return 8;
+ default:
+ post("Input sample Type %d not supported, yet!!!",format);
+ return 0;
+ }
+}
+
+/* dithering algo taken from Portaudio ASIO implementation */
+/*************************************************************
+** Calculate 2 LSB dither signal with a triangular distribution.
+** Ranged properly for adding to a 32 bit integer prior to >>15.
+*/
+#define DITHER_BITS (15)
+#define DITHER_SCALE (1.0f / ((1<<DITHER_BITS)-1))
+inline static long triangulardither() {
+ static unsigned long previous = 0;
+ static unsigned long randSeed1 = 22222;
+ static unsigned long randSeed2 = 5555555;
+ long current, highPass;
+/* Generate two random numbers. */
+ randSeed1 = (randSeed1 * 196314165) + 907633515;
+ randSeed2 = (randSeed2 * 196314165) + 907633515;
+/* Generate triangular distribution about 0. */
+ current = (((long)randSeed1)>>(32-DITHER_BITS)) + (((long)randSeed2)>>(32-DITHER_BITS));
+ /* High pass filter to reduce audibility. */
+ highPass = current - previous;
+ previous = current;
+ return highPass;
+}
+
+/* sample conversion functions */
+
+#define SCALE_INT16 32767.f /* (- (expt 2 15) 1) */
+#define SCALE_INT24 8388607.f /* (- (expt 2 23) 1) */
+#define SCALE_INT32 2147483647.f /* (- (expt 2 31) 1) */
+
+/* Swap LSB to MSB and vice versa */
+inline __int32 swaplong(__int32 v) {
+ return ((v>>24)&0xFF)|((v>>8)&0xFF00)|((v&0xFF00)<<8)|((v&0xFF)<<24);
+}
+
+inline __int16 swapshort(__int16 v) {
+ return ((v>>8)&0xFF)|((v&0xFF)<<8);
+}
+
+/* todo: check dithering */
+
+static void float32tofloat32(void* inbuffer, void* outbuffer, long frames) {
+ if(SIMD_CHECK2(frames,inbuffer,outbuffer)) copyvec_simd((float *)outbuffer,(float *)inbuffer,frames);
+ else memcpy (outbuffer, inbuffer, frames* sizeof (float));
+}
+
+static void float32tofloat32_S(void* inbuffer, void* outbuffer, long frames) {
+ __int32 *in = (__int32 *)inbuffer;
+ __int32* out = (__int32*)outbuffer;
+ while (frames--) *out++ = swaplong(*(in++));
+}
+
+static void float32tofloat64(void* inbuffer, void* outbuffer, long frames) {
+ const float *in = (const float *)inbuffer;
+ double* out = (double*)outbuffer;
+ while (frames--) *(out++) = *(in++);
+}
+
+static void float64tofloat32(void* inbuffer, void* outbuffer, long frames) {
+ const double *in = (const double *)inbuffer;
+ float *out = (float *)outbuffer;
+ while (frames--) *(out++) = *(in++);
+}
+
+static void float32toInt16(void* inbuffer, void* outbuffer, long frames) {
+ const float *in = (const float *)inbuffer;
+ __int16* out = (__int16*)outbuffer;
+ while (frames--) {
+ float o = *(in++) * SCALE_INT16 + triangulardither() * DITHER_SCALE;
+ __int16 lng = lrintf(o);
+ *out++ = lng ;
+ }
+}
+
+static void Int16tofloat32(void* inbuffer, void* outbuffer, long frames) {
+ const __int16* in = (const __int16*)inbuffer;
+ float *out = (float *)outbuffer;
+ while (frames--) *(out++) = (float)*(in++) * (1.f / SCALE_INT16);
+}
+
+static void float32toInt24(void* inbuffer, void* outbuffer, long frames) {
+ const float *in = (const float *)inbuffer;
+ __int32* out = (__int32*)outbuffer;
+ while (frames--) {
+ float o = *(in++) * SCALE_INT24;
+ __int32 intg = (__int32)lrintf(o);
+ *(out++) = intg;
+ }
+}
+
+static void Int24tofloat32(void* inbuffer, void* outbuffer, long frames) {
+ const __int32* in = (const __int32*)inbuffer;
+ float *out = (float *)outbuffer;
+ while (frames--) *(out++) = (float)*(in++) * (1.f / SCALE_INT24);
+}
+
+static void float32toInt32(void* inbuffer, void* outbuffer, long frames) {
+ const float *in = (const float *)inbuffer;
+ __int32* out = (__int32*)outbuffer;
+ while (frames--) {
+ float o = (float)*(in++) * SCALE_INT32 + triangulardither() * DITHER_SCALE;
+ *out++ = lrintf(o);
+ }
+}
+
+static void Int32tofloat32(void* inbuffer, void* outbuffer, long frames) {
+ const __int32* in = (const __int32*)inbuffer;
+ float *out = (float *)outbuffer;
+ while (frames--) *(out++) = (float)*(in++) * (1.f / SCALE_INT32);
+}
+
+static void float32toInt16_S(void* inbuffer, void* outbuffer, long frames) {
+ const float *in = (const float *)inbuffer;
+ __int16* out = (__int16*)outbuffer;
+ while (frames--) {
+ float o = (float)*(in++) * SCALE_INT16 + triangulardither() * DITHER_SCALE;
+ __int16 reverse = (__int16)lrintf(o);
+ *out++ = swapshort(reverse);
+ }
+}
+
+static void Int16tofloat32_S(void* inbuffer, void* outbuffer, long frames) {
+ const __int16* in = (const __int16*)inbuffer;
+ float *out = (float *)outbuffer;
+ while (frames--) *(out++) = (float)swapshort(*(in++)) * (1.f / SCALE_INT16);
+}
+
+static void float32toInt24_S(void* inbuffer, void* outbuffer, long frames) {
+ const float *in = (const float *)inbuffer;
+ char* out = (char*)outbuffer;
+ while (frames--) {
+ float o = (float)*(in++) * SCALE_INT24;
+ __int32 reverse = (__int32)lrintf(o);
+ out[2] = ((char *)&reverse)[0];
+ out[1] = ((char *)&reverse)[1];
+ out[0] = ((char *)&reverse)[2];
+ out += 3;
+ }
+}
+
+static void Int24tofloat32_S(void* inbuffer, void* outbuffer, long frames) {
+ const char* in = (const char*)inbuffer;
+ float *out = (float *)outbuffer;
+ __int32 d = 0;
+ while (frames--) {
+ ((char *)&d)[1] = in[2];
+ ((char *)&d)[2] = in[1];
+ ((char *)&d)[3] = in[0];
+ *(out++) = (float)d * (1.f / SCALE_INT24);
+ in += 3;
+ }
+}
+
+static void float32toInt32_S(void* inbuffer, void* outbuffer, long frames) {
+ const float *in = (const float *)inbuffer;
+ __int32* out = (__int32*)outbuffer;
+ while (frames--) {
+ float o = (float)*(in++) * SCALE_INT32 + triangulardither() * DITHER_SCALE;
+ __int32 reverse = (__int32)lrintf(o);
+ *out++ = swaplong(reverse);
+ }
+}
+
+static void Int32tofloat32_S(void* inbuffer, void* outbuffer, long frames) {
+ const __int32* in = (const __int32*)inbuffer;
+ float *out = (float *)outbuffer;
+ while (frames--) *(out++) = (float)swaplong(*(in++)) * (1.f / SCALE_INT32);
+}
+
+
+/* some local helper functions */
+static void prepare_asio_drivernames() {
+ if (!asio_drivernames) {
+ asio_drivernames = (char**)getbytes(MAXNDEV * sizeof(char*));
+ for (int i = 0; i!= MAXNDEV; ++i) {
+ asio_drivernames[i] = (char*)getbytes (32 * sizeof(char));
+ }
+ }
+ /* load the driver */
+ if (!asioDrivers) asioDrivers = new AsioDrivers();
+ return;
+}
+
+/* callback-based scheduling callbacks: */
+
+/* buffer switch callback */
+static void asio_bufferSwitch_cb(long db_idx, ASIOBool directprocess) {
+ ASIOTime time;
+#ifdef ASIODEBUG
+ static int written = 0;
+ if(written == 0) {
+ post("ASIO: asio_bufferSwitch_cb");
+ written = 1;
+ }
+#endif
+ memset (&time, 0, sizeof (time));
+ /* todo: do we need to syncronize with other media ??? */
+ asio_bufferSwitchTimeInfo_cb(&time, db_idx, directprocess);
+}
+
+/* sample rate change callback */
+static void asio_sampleRateDidChange_cb(ASIOSampleRate srate) {
+ asio_sampleRateDidChange(srate);
+}
+
+/* asio messaging callback */
+static long asio_messages_cb(long selector, long value, void* message, double* opt) {
+ return asio_messages(selector, value, message, opt);
+}
+
+static ASIOTime *asio_bufferSwitchTimeInfo_cb(ASIOTime *params, long db_idx, ASIOBool directprocess) {
+ /* todo: i'm not sure if we'll have to synchronize with other media ... probably yes ... */
+ /* perform the processing */
+ int timeout = sys_dacblocksize * (float)asio_ticks_per_callback / (float) sys_dacsr * 1e6;
+ if (sys_timedlock(timeout) == ETIMEDOUT)
+ /* we're late ... lets hope that jack doesn't kick us out */
+ return 0;
+
+ for (int j = 0; j != asio_ticks_per_callback; j++) {
+ t_sample * sp = sys_soundin;
+ /* get sounds from input channels */
+ for (long i = 0; i < sys_outchannels + sys_inchannels; i++) {
+ if(asio_converter[i])
+ if (asio_bufferinfo[i].isInput == ASIOTrue) {
+ asio_converter[i]((char*)asio_bufferinfo[i].buffers[db_idx] +
+ asio_samplewidth[i] * j *sys_dacblocksize, sp, sys_dacblocksize);
+ sp += sys_dacblocksize;
+ }
+ }
+ /* run dsp */
+ sched_tick(sys_time + sys_time_per_dsp_tick);
+ sp = sys_soundout;
+ /* send sound to hardware */
+ for (long i = 0; i < sys_outchannels + sys_inchannels; i++) {
+ if (asio_bufferinfo[i].isInput != ASIOTrue) {
+ /* clip */
+ t_float lo = -1.f;
+ t_float hi = 1.f;
+ t_int clipargs[6];
+ clipargs[1] = clipargs[2] = (t_int)sp;
+ clipargs[3] = (t_int)&lo;
+ clipargs[4] = (t_int)&hi;
+ clipargs[5] = (t_int)sys_dacblocksize;
+ clipblock(clipargs);
+ /* send */
+ if(asio_converter[i])
+ asio_converter[i](sp, (char*)asio_bufferinfo[i].buffers[db_idx]
+ + asio_samplewidth[i] * j *sys_dacblocksize, sys_dacblocksize);
+ zeroblock(sp,sys_dacblocksize);
+ sp += sys_dacblocksize;
+ }
+ }
+ }
+ if(asio_useoutputready) ASIOOutputReady();
+ sys_unlock();
+ return 0L; /* time info!!! */
+}
+
+t_audioapi asio_api = {
+ asio_open_audio,
+ asio_close_audio,
+ asio_send_dacs,
+ asio_getdevs,
+};
diff --git a/desiredata/src/s_audio_jack.c b/desiredata/src/s_audio_jack.c
new file mode 100644
index 00000000..ed37829b
--- /dev/null
+++ b/desiredata/src/s_audio_jack.c
@@ -0,0 +1,381 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#define PD_PLUSPLUS_FACE
+#include "desire.h"
+#include "m_simd.h"
+#include <jack/jack.h>
+#include <regex.h>
+#include <errno.h>
+#define MAX_CLIENTS 100
+#define NUM_JACK_PORTS 32
+#define BUF_JACK 4096
+static jack_nframes_t jack_out_max;
+#define JACK_OUT_MAX 64
+static jack_nframes_t jack_filled = 0;
+static float jack_outbuf[NUM_JACK_PORTS*BUF_JACK];
+static float jack_inbuf[NUM_JACK_PORTS*BUF_JACK];
+static int jack_started = 0;
+static jack_port_t * input_port[NUM_JACK_PORTS];
+static jack_port_t *output_port[NUM_JACK_PORTS];
+static int outport_count = 0;
+static jack_client_t *jack_client = 0;
+char *jack_client_names[MAX_CLIENTS];
+static int jack_dio_error;
+static int jack_scheduler;
+pthread_mutex_t jack_mutex;
+pthread_cond_t jack_sem;
+t_int jack_save_connection_state(t_int* dummy);
+static void jack_restore_connection_state();
+void run_all_idle_callbacks();
+
+static int process (jack_nframes_t nframes, void *arg) {
+ jack_out_max = max(int(nframes),JACK_OUT_MAX);
+ if (jack_filled >= nframes) {
+ if (jack_filled != nframes) post("Partial read");
+ for (int j = 0; j < sys_outchannels; j++) {
+ float *out = (float *)jack_port_get_buffer(output_port[j], nframes);
+ memcpy(out, jack_outbuf + (j * BUF_JACK), sizeof(float)*nframes);
+ }
+ for (int j = 0; j < sys_inchannels; j++) {
+ float *in = (float *)jack_port_get_buffer( input_port[j], nframes);
+ memcpy(jack_inbuf + (j * BUF_JACK), in, sizeof(float)*nframes);
+ }
+ jack_filled -= nframes;
+ } else { /* PD could not keep up ! */
+ if (jack_started) jack_dio_error = 1;
+ for (int j = 0; j < outport_count; j++) {
+ float *out = (float *)jack_port_get_buffer (output_port[j], nframes);
+ memset(out, 0, sizeof (float) * nframes);
+ }
+ memset(jack_outbuf,0,sizeof(jack_outbuf));
+ jack_filled = 0;
+ }
+ /* tb: wait in the scheduler */
+ /* pthread_cond_broadcast(&jack_sem); */
+ return 0;
+}
+
+void sys_peakmeters();
+extern int sys_meters; /* true if we're metering */
+static int dspticks_per_jacktick;
+static void (*copyblock)(t_sample *dst,t_sample *src,int n);
+static void (*zeroblock)(t_sample *dst,int n);
+extern int canvas_dspstate;
+
+static int cb_process (jack_nframes_t nframes, void *arg) {
+ int timeout = int(nframes * 1e6 / sys_dacsr);
+ if (canvas_dspstate == 0) {
+ /* dsp is switched off, the audio is open ... */
+ for (int j=0; j<sys_outchannels; j++) {
+ t_sample *out = (t_sample *)jack_port_get_buffer (output_port[j], nframes);
+ zeroblock(out, dspticks_per_jacktick * sys_dacblocksize);
+ }
+ return 0;
+ }
+ int status = sys_timedlock(timeout);
+ if (status)
+ if (status == ETIMEDOUT) {
+ /* we're late ... lets hope that jack doesn't kick us out */
+ error("timeout %d", (timeout));
+ sys_log_error(ERR_SYSLOCK);
+ return 0;
+ } else {
+ post("sys_timedlock returned %d", status);
+ return 0;
+ }
+ for (int i = 0; i != dspticks_per_jacktick; ++i) {
+ for (int j=0; j<sys_inchannels; j++) {
+ t_sample *in = (t_sample *)jack_port_get_buffer(input_port[j], nframes);
+ copyblock(sys_soundin + j * sys_dacblocksize, in + i * sys_dacblocksize, sys_dacblocksize);
+ }
+ sched_tick(sys_time + sys_time_per_dsp_tick);
+ for (int j=0; j<sys_outchannels; j++) {
+ t_sample *out = (t_sample *)jack_port_get_buffer (output_port[j], nframes);
+ copyblock(out + i * sys_dacblocksize, sys_soundout + j * sys_dacblocksize, sys_dacblocksize);
+ }
+ if (sys_meters) sys_peakmeters();
+ zeroblock(sys_soundout, sys_outchannels * sys_dacblocksize);
+ }
+ run_all_idle_callbacks();
+ sys_unlock();
+ return 0;
+}
+
+static int jack_srate (jack_nframes_t srate, void *arg) {
+ sys_dacsr = srate;
+ return 0;
+}
+
+void jack_close_audio(void);
+static int jack_ignore_graph_callback = 0;
+static t_int jack_shutdown_handler(t_int* none) {
+ error("jack kicked us out ... trying to reconnect");
+ jack_ignore_graph_callback = 1;
+ /* clean up */
+ jack_close_audio();
+ /* try to reconnect to jack server */
+ jack_open_audio(sys_inchannels, sys_outchannels, int(sys_dacsr), jack_scheduler);
+ /* restore last connection state */
+ jack_restore_connection_state();
+ jack_ignore_graph_callback = 0;
+ return 0;
+}
+
+/* register idle callback in scheduler */
+static void jack_shutdown (void *arg) {sys_callback(jack_shutdown_handler,0,0);}
+static int jack_graph_order_callback(void* arg) {sys_callback(jack_save_connection_state,0,0); return 0;}
+
+static char** jack_get_clients() {
+ int num_clients = 0;
+ regex_t port_regex;
+ const char **jack_ports = jack_get_ports(jack_client, "", "", 0);
+ regcomp(&port_regex, "^[^:]*", REG_EXTENDED);
+ jack_client_names[0] = 0;
+ /* Build a list of clients from the list of ports */
+ for (int i=0; jack_ports[i] != 0; i++) {
+ regmatch_t match_info;
+ char tmp_client_name[100];
+ /* extract the client name from the port name, using a regex that parses the clientname:portname syntax */
+ regexec(&port_regex, jack_ports[i], 1, &match_info, 0);
+ memcpy(tmp_client_name, &jack_ports[i][match_info.rm_so], match_info.rm_eo-match_info.rm_so);
+ tmp_client_name[ match_info.rm_eo - match_info.rm_so ] = '\0';
+ /* do we know about this port's client yet? */
+ int client_seen = 0;
+ for (int j=0; j<num_clients; j++) if (strcmp(tmp_client_name, jack_client_names[j])==0) client_seen = 1;
+ if (!client_seen) {
+ jack_client_names[num_clients] = (char*)getbytes(strlen(tmp_client_name) + 1);
+ /* The alsa_pcm client should go in spot 0. If this is the alsa_pcm client AND we are NOT about to put
+ it in spot 0 put it in spot 0 and move whatever was already in spot 0 to the end. */
+ if (strcmp("alsa_pcm",tmp_client_name)==0 && num_clients>0) {
+ /* alsa_pcm goes in spot 0 */
+ char* tmp = jack_client_names[ num_clients ];
+ jack_client_names[num_clients] = jack_client_names[0];
+ jack_client_names[0] = tmp;
+ strcpy(jack_client_names[0], tmp_client_name);
+ } else {
+ /* put the new client at the end of the client list */
+ strcpy(jack_client_names[num_clients], tmp_client_name);
+ }
+ num_clients++;
+ }
+ }
+ /* for (int i=0; i<num_clients; i++) post("client: %s",jack_client_names[i]); */
+ free(jack_ports);
+ return jack_client_names;
+}
+
+/* Wire up all the ports of one client. */
+static int jack_connect_ports(char *client) {
+ char regex_pattern[100];
+ static int entered = 0;
+ if (entered) return 0;
+ entered = 1;
+ if (strlen(client) > 96) return -1;
+ sprintf(regex_pattern, "%s:.*", client);
+ const char **jack_ports = jack_get_ports(jack_client, regex_pattern, 0, JackPortIsOutput);
+ if (jack_ports)
+ for (int i=0;jack_ports[i] != 0 && i < sys_inchannels;i++)
+ if (jack_connect (jack_client, jack_ports[i], jack_port_name (input_port[i])))
+ error("cannot connect input ports %s -> %s", jack_ports[i],jack_port_name(input_port[i]));
+ free(jack_ports);
+ jack_ports = jack_get_ports(jack_client, regex_pattern, 0, JackPortIsInput);
+ if (jack_ports)
+ for (int i=0;jack_ports[i] != 0 && i < sys_outchannels;i++)
+ if (jack_connect (jack_client, jack_port_name (output_port[i]), jack_ports[i]))
+ error("cannot connect output ports %s -> %s",jack_port_name(output_port[i]),jack_ports[i]);
+ free(jack_ports);
+ return 0;
+}
+
+static void jack_error(const char *desc) {}
+
+int jack_open_audio_2(int inchans, int outchans, int rate, int scheduler);
+int jack_open_audio(int inchans, int outchans, int rate, int scheduler) {
+ jack_dio_error = 0;
+ if (inchans==0 && outchans==0) return 0;
+ int ret = jack_open_audio_2(inchans,outchans,rate,scheduler);
+ if (ret) sys_setscheduler(0);
+ return ret;
+}
+
+int jack_open_audio_2(int inchans, int outchans, int rate, int scheduler) {
+ char port_name[80] = "";
+ int new_jack = 0;
+ if (outchans > NUM_JACK_PORTS) {post("%d output ports not supported, setting to %d",outchans, NUM_JACK_PORTS); outchans = NUM_JACK_PORTS;}
+ if ( inchans > NUM_JACK_PORTS) {post( "%d input ports not supported, setting to %d", inchans, NUM_JACK_PORTS); inchans = NUM_JACK_PORTS;}
+ if (jack_client && scheduler != sys_getscheduler()) {
+ jack_client_close(jack_client);
+ jack_client = 0;
+ }
+ sys_setscheduler(scheduler);
+ jack_scheduler = scheduler;
+ /* set block copy/zero functions */
+ if(SIMD_CHKCNT(sys_dacblocksize) && simd_runtime_check()) {
+ copyblock = (void (*)(t_sample *,t_sample *,int))&copyvec_simd;
+ zeroblock = &zerovec_simd;
+ } else {
+ copyblock = (void (*)(t_sample *,t_sample *,int))&copyvec;
+ zeroblock = &zerovec;
+ }
+ /* try to become a client of the JACK server (we allow two pd's)*/
+ if (!jack_client) {
+ int client_iterator = 0;
+ do {
+ sprintf(port_name,"pure_data_%d",client_iterator);
+ client_iterator++;
+ } while (((jack_client = jack_client_new (port_name)) == 0) && client_iterator < 2);
+ // jack spits out enough messages already, do not warn
+ if (!jack_client) {sys_inchannels = sys_outchannels = 0; return 1;}
+ jack_get_clients();
+ /* tell the JACK server to call `process()' whenever there is work to be done.
+ tb: adapted for callback based scheduling */
+ if (scheduler == 1) {
+ dspticks_per_jacktick = jack_get_buffer_size(jack_client) / sys_schedblocksize;
+ jack_set_process_callback (jack_client, cb_process, 0);
+ } else jack_set_process_callback (jack_client, process, 0);
+ jack_set_error_function (jack_error);
+#ifdef JACK_XRUN
+ jack_set_xrun_callback (jack_client, jack_xrun, 0);
+#endif
+ jack_set_graph_order_callback(jack_client, jack_graph_order_callback, 0);
+ /* tell the JACK server to call `srate()' whenever the sample rate of the system changes. */
+ jack_set_sample_rate_callback (jack_client, jack_srate, 0);
+ /* tell the JACK server to call `jack_shutdown()' if
+ it ever shuts down, either entirely, or if it just decides to stop calling us. */
+ jack_on_shutdown (jack_client, jack_shutdown, 0);
+ for (int j=0;j<NUM_JACK_PORTS;j++) {
+ input_port[j]=0;
+ output_port[j]=0;
+ }
+ new_jack = 1;
+ }
+ /* display the current sample rate. once the client is activated
+ (see below), you should rely on your own sample rate callback (see above) for this value. */
+ int srate = jack_get_sample_rate (jack_client);
+ sys_dacsr = srate;
+ /* create the ports */
+ for (int j = 0; j < inchans; j++) {
+ sprintf(port_name, "input%d", j);
+ if (!input_port[j]) input_port[j] = jack_port_register(jack_client, port_name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0);
+ }
+ for (int j = 0; j < outchans; j++) {
+ sprintf(port_name, "output%d", j);
+ if (!output_port[j]) output_port[j] = jack_port_register(jack_client, port_name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
+ }
+ outport_count = outchans;
+ /* tell the JACK server that we are ready to roll */
+ if (new_jack) {
+ if (jack_activate (jack_client)) {error("cannot activate client"); sys_inchannels = sys_outchannels = 0; return 1;}
+ memset(jack_outbuf,0,sizeof(jack_outbuf));
+ if (jack_client_names[0]) jack_connect_ports(jack_client_names[0]);
+ pthread_mutex_init(&jack_mutex,0);
+ pthread_cond_init(&jack_sem,0);
+ }
+ /* tb: get advance from jack server */
+ sys_schedadvance = int((float)jack_port_get_total_latency(jack_client,output_port[0]) * 1000. / sys_dacsr * 1000);
+ return 0;
+}
+
+void jack_close_audio() {
+ if (!jack_client) return;
+ jack_deactivate(jack_client);
+ jack_started = 0;
+ jack_client_close(jack_client);
+ jack_client = 0;
+ for (int i=0; i<NUM_JACK_PORTS; i++) {
+ input_port[i] = 0;
+ output_port[i] = 0;
+ }
+}
+
+int jack_send_dacs() {
+ int rtnval = SENDDACS_YES;
+ int timeref = int(sys_getrealtime());
+ if (!jack_client) return SENDDACS_NO;
+ if (!sys_inchannels && !sys_outchannels) return SENDDACS_NO;
+ if (jack_dio_error) {
+ sys_log_error(ERR_RESYNC);
+ jack_dio_error = 0;
+ }
+ if (jack_filled >= jack_out_max) return SENDDACS_NO;
+ /* tb: wait in the scheduler */
+/* pthread_cond_wait(&jack_sem,&jack_mutex); */
+ jack_started = 1;
+ float *fp = sys_soundout;
+ for (int j=0; j<sys_outchannels; j++) {
+ memcpy(jack_outbuf + j*BUF_JACK + jack_filled, fp, sys_dacblocksize*sizeof(float));
+ fp += sys_dacblocksize;
+ }
+ fp = sys_soundin;
+ for (int j=0; j<sys_inchannels; j++) {
+ memcpy(fp, jack_inbuf + j*BUF_JACK + jack_filled, sys_dacblocksize*sizeof(float));
+ fp += sys_dacblocksize;
+ }
+ int timenow = int(sys_getrealtime());
+ if (timenow-timeref > sys_sleepgrain*1e-6) rtnval = SENDDACS_SLEPT;
+ memset(sys_soundout,0,sys_dacblocksize*sizeof(float)*sys_outchannels);
+ jack_filled += sys_dacblocksize;
+ return rtnval;
+}
+
+void jack_getdevs(char *indevlist, int *nindevs, char *outdevlist, int *noutdevs, int *canmulti, int maxndev, int devdescsize) {
+ *canmulti = 0; /* supports multiple devices */
+ int ndev = 1;
+ for (int i=0; i<ndev; i++) {
+ sprintf( indevlist + i * devdescsize, "JACK");
+ sprintf(outdevlist + i * devdescsize, "JACK");
+ }
+ *nindevs = *noutdevs = ndev;
+}
+
+void jack_listdevs () {error("device listing not implemented for jack yet");}
+
+static const char ** jack_in_connections[NUM_JACK_PORTS]; /* ports connected to the inputs */
+static const char **jack_out_connections[NUM_JACK_PORTS]; /* ports connected to the outputs */
+
+/* tb: save the current state of pd's jack connections */
+t_int jack_save_connection_state(t_int* dummy) {
+ if (jack_ignore_graph_callback) return 0;
+ for (int i=0; i<NUM_JACK_PORTS; i++) {
+ /* saving the inputs connections */
+ if ( jack_in_connections[i]) free( jack_in_connections[i]);
+ jack_in_connections[i] = i< sys_inchannels ? jack_port_get_all_connections(jack_client, input_port[i]) : 0;
+ /* saving the outputs connections */
+ if (jack_out_connections[i]) free(jack_out_connections[i]);
+ jack_out_connections[i]= i<sys_outchannels ? jack_port_get_all_connections(jack_client, output_port[i]) : 0;
+ }
+ return 0;
+}
+
+/* todo: don't try to connect twice if we're both input and output host */
+static void jack_restore_connection_state() {
+ post("restoring connections");
+ for (int i=0; i<NUM_JACK_PORTS; i++) {
+ /* restoring the inputs connections */
+ if (jack_in_connections[i]) {
+ for (int j=0;;j++) {
+ const char *port = jack_in_connections[i][j];
+ if (!port) break; /* we've connected all incoming ports */
+ int status = jack_connect(jack_client, port, jack_port_name(input_port[i]));
+ if (status) error("cannot connect input ports %s -> %s", port, jack_port_name (input_port[i]));
+ }
+ }
+ /* restoring the output connections */
+ if (jack_out_connections[i]) {
+ for (int j=0;;j++) {
+ const char *port = jack_out_connections[i][j];
+ if (!port) break; /* we've connected all outgoing ports */
+ int status = jack_connect(jack_client, jack_port_name(output_port[i]), port);
+ if (status) error("cannot connect output ports %s -> %s", jack_port_name(output_port[i]), port);
+ }
+ }
+ }
+}
+
+struct t_audioapi jack_api = {
+ 0 /*jack_open_audio*/,
+ jack_close_audio,
+ jack_send_dacs,
+ jack_getdevs,
+};
diff --git a/desiredata/src/s_audio_mmio.c b/desiredata/src/s_audio_mmio.c
new file mode 100644
index 00000000..9165ee93
--- /dev/null
+++ b/desiredata/src/s_audio_mmio.c
@@ -0,0 +1,571 @@
+/* Copyright (c) 1997-1999 Miller Puckette.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* modified 2/98 by Winfried Ritsch to deal with up to 4 synchronized
+"wave" devices, which is how ADAT boards appear to the WAVE API. */
+
+#include "m_pd.h"
+#include "s_stuff.h"
+#include <stdio.h>
+#include <windows.h>
+#include <MMSYSTEM.H>
+
+/* ------------------------- audio -------------------------- */
+
+static void nt_close_midiin();
+static void nt_noresync();
+static void postflags();
+
+#define NAPORTS 16 /* wini hack for multiple ADDA devices */
+#define CHANNELS_PER_DEVICE 2
+#define DEFAULTCHANS 2
+#define DEFAULTSRATE 44100
+#define SAMPSIZE 2
+
+int nt_realdacblksize;
+#define DEFREALDACBLKSIZE (4 * sys_dacblocksize) /* larger underlying bufsize */
+
+#define MAXBUFFER 100 /* number of buffers in use at maximum advance */
+#define DEFBUFFER 30 /* default is about 30x6 = 180 msec! */
+static int nt_naudiobuffer = DEFBUFFER;
+float sys_dacsr = DEFAULTSRATE;
+
+static int nt_whichapi = API_MMIO;
+static int nt_meters; /* true if we're metering */
+static float nt_inmax; /* max input amplitude */
+static float nt_outmax; /* max output amplitude */
+static int nt_nwavein, nt_nwaveout; /* number of WAVE devices in and out */
+
+typedef struct _sbuf {
+ HANDLE hData;
+ HPSTR lpData; // pointer to waveform data memory
+ HANDLE hWaveHdr;
+ WAVEHDR *lpWaveHdr; // pointer to header structure
+} t_sbuf;
+
+t_sbuf ntsnd_outvec[NAPORTS][MAXBUFFER]; /* circular buffer array */
+HWAVEOUT ntsnd_outdev[NAPORTS]; /* output device */
+static int ntsnd_outphase[NAPORTS]; /* index of next buffer to send */
+
+t_sbuf ntsnd_invec[NAPORTS][MAXBUFFER]; /* circular buffer array */
+HWAVEIN ntsnd_indev[NAPORTS]; /* input device */
+static int ntsnd_inphase[NAPORTS]; /* index of next buffer to read */
+
+static void nt_waveinerror(const char *s, int err) {
+ char t[256];
+ waveInGetErrorText(err, t, 256);
+ error(s,t);
+}
+
+static void nt_waveouterror(const char *s, int err) {
+ char t[256];
+ waveOutGetErrorText(err, t, 256);
+ error(s,t);
+}
+
+static void wave_prep(t_sbuf *bp, int setdone) {
+ WAVEHDR *wh;
+ short *sp;
+ int i;
+ /* Allocate and lock memory for the waveform data. The memory for waveform data must be globally allocated with
+ * GMEM_MOVEABLE and GMEM_SHARE flags. */
+ if (!(bp->hData = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, (DWORD) (CHANNELS_PER_DEVICE * SAMPSIZE * nt_realdacblksize))))
+ printf("alloc 1 failed\n");
+ if (!(bp->lpData = (HPSTR) GlobalLock(bp->hData)))
+ printf("lock 1 failed\n");
+ /* Allocate and lock memory for the header. */
+ if (!(bp->hWaveHdr = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, (DWORD) sizeof(WAVEHDR))))
+ printf("alloc 2 failed\n");
+ if (!(wh = bp->lpWaveHdr = (WAVEHDR *) GlobalLock(bp->hWaveHdr)))
+ printf("lock 2 failed\n");
+ for (i = CHANNELS_PER_DEVICE * nt_realdacblksize, sp = (short *)bp->lpData; i--; ) *sp++ = 0;
+ wh->lpData = bp->lpData;
+ wh->dwBufferLength = (CHANNELS_PER_DEVICE * SAMPSIZE * nt_realdacblksize);
+ wh->dwFlags = 0;
+ wh->dwLoops = 0L;
+ wh->lpNext = 0;
+ wh->reserved = 0;
+ /* optionally (for writing) set DONE flag as if we had queued them */
+ if (setdone) wh->dwFlags = WHDR_DONE;
+}
+
+static UINT nt_whichdac = WAVE_MAPPER, nt_whichadc = WAVE_MAPPER;
+
+int mmio_do_open_audio() {
+ PCMWAVEFORMAT form;
+ int i, j;
+ UINT mmresult;
+ int nad, nda;
+ static int naudioprepped = 0, nindevsprepped = 0, noutdevsprepped = 0;
+ if (sys_verbose) post("%d devices in, %d devices out", nt_nwavein, nt_nwaveout);
+ form.wf.wFormatTag = WAVE_FORMAT_PCM;
+ form.wf.nChannels = CHANNELS_PER_DEVICE;
+ form.wf.nSamplesPerSec = sys_dacsr;
+ form.wf.nAvgBytesPerSec = sys_dacsr * (CHANNELS_PER_DEVICE * SAMPSIZE);
+ form.wf.nBlockAlign = CHANNELS_PER_DEVICE * SAMPSIZE;
+ form.wBitsPerSample = 8 * SAMPSIZE;
+ if (nt_nwavein <= 1 && nt_nwaveout <= 1) nt_noresync();
+ if (nindevsprepped < nt_nwavein) {
+ for (i = nindevsprepped; i < nt_nwavein; i++)
+ for (j = 0; j < naudioprepped; j++)
+ wave_prep(&ntsnd_invec[i][j], 0);
+ nindevsprepped = nt_nwavein;
+ }
+ if (noutdevsprepped < nt_nwaveout) {
+ for (i = noutdevsprepped; i < nt_nwaveout; i++)
+ for (j = 0; j < naudioprepped; j++)
+ wave_prep(&ntsnd_outvec[i][j], 1);
+ noutdevsprepped = nt_nwaveout;
+ }
+ if (naudioprepped < nt_naudiobuffer) {
+ for (j = naudioprepped; j < nt_naudiobuffer; j++) {
+ for (i = 0; i < nt_nwavein; i++) wave_prep(&ntsnd_invec [i][j], 0);
+ for (i = 0; i < nt_nwaveout; i++) wave_prep(&ntsnd_outvec[i][j], 1);
+ }
+ naudioprepped = nt_naudiobuffer;
+ }
+ for (nad=0; nad < nt_nwavein; nad++) {
+ /* Open waveform device(s), sucessively numbered, for input */
+ mmresult = waveInOpen(&ntsnd_indev[nad], nt_whichadc+nad, (WAVEFORMATEX *)(&form), 0L, 0L, CALLBACK_NULL);
+ if (sys_verbose) printf("opened adc device %d with return %d\n", nt_whichadc+nad,mmresult);
+ if (mmresult != MMSYSERR_NOERROR) {
+ nt_waveinerror("waveInOpen: %s", mmresult);
+ nt_nwavein = nad; /* nt_nwavein = 0 wini */
+ } else {
+ for (i = 0; i < nt_naudiobuffer; i++) {
+ mmresult = waveInPrepareHeader(ntsnd_indev[nad], ntsnd_invec[nad][i].lpWaveHdr, sizeof(WAVEHDR));
+ if (mmresult != MMSYSERR_NOERROR) nt_waveinerror("waveinprepareheader: %s", mmresult);
+ mmresult = waveInAddBuffer( ntsnd_indev[nad], ntsnd_invec[nad][i].lpWaveHdr, sizeof(WAVEHDR));
+ if (mmresult != MMSYSERR_NOERROR) nt_waveinerror("waveInAddBuffer: %s", mmresult);
+ }
+ }
+ }
+ /* quickly start them all together */
+ for (nad = 0; nad < nt_nwavein; nad++) waveInStart(ntsnd_indev[nad]);
+ for (nda = 0; nda < nt_nwaveout; nda++) {
+ /* Open a waveform device for output in sucessiv device numbering*/
+ mmresult = waveOutOpen(&ntsnd_outdev[nda], nt_whichdac + nda, (WAVEFORMATEX *)(&form), 0L, 0L, CALLBACK_NULL);
+ if (sys_verbose) post("opened dac device %d, with return %d", nt_whichdac +nda, mmresult);
+ if (mmresult != MMSYSERR_NOERROR) {
+ post("Wave out open device %d + %d",nt_whichdac,nda);
+ nt_waveouterror("waveOutOpen device: %s", mmresult);
+ nt_nwaveout = nda;
+ }
+ }
+ return 0;
+}
+
+void mmio_close_audio() {
+ int errcode;
+ int nda, nad;
+ if (sys_verbose) post("closing audio...");
+ for (nda=0; nda < nt_nwaveout; nda++) /*if (nt_nwaveout) wini */ {
+ errcode = waveOutReset(ntsnd_outdev[nda]);
+ if (errcode != MMSYSERR_NOERROR) printf("error resetting output %d: %d", nda, errcode);
+ errcode = waveOutClose(ntsnd_outdev[nda]);
+ if (errcode != MMSYSERR_NOERROR) printf("error closing output %d: %d",nda , errcode);
+ }
+ nt_nwaveout = 0;
+ for(nad=0; nad < nt_nwavein;nad++) /* if (nt_nwavein) wini */ {
+ errcode = waveInReset(ntsnd_indev[nad]);
+ if (errcode != MMSYSERR_NOERROR) printf("error resetting input: %d", errcode);
+ errcode = waveInClose(ntsnd_indev[nad]);
+ if (errcode != MMSYSERR_NOERROR) printf("error closing input: %d", errcode);
+ }
+ nt_nwavein = 0;
+}
+
+#define ADCJITTER 10 /* We tolerate X buffers of jitter by default */
+#define DACJITTER 10
+
+static int nt_adcjitterbufsallowed = ADCJITTER;
+static int nt_dacjitterbufsallowed = DACJITTER;
+
+/* ------------- MIDI time stamping from audio clock ------------ */
+
+#ifdef MIDI_TIMESTAMP
+
+static double nt_hibuftime;
+static double initsystime = -1;
+
+/* call this whenever we reset audio */
+static void nt_resetmidisync() {
+ initsystime = clock_getsystime();
+ nt_hibuftime = sys_getrealtime();
+}
+
+/* call this whenever we're idled waiting for audio to be ready.
+ The routine maintains a high and low water point for the difference between real and DAC time. */
+
+static void nt_midisync() {
+ double jittersec, diff;
+ if (initsystime == -1) nt_resetmidisync();
+ jittersec = (nt_dacjitterbufsallowed > nt_adcjitterbufsallowed ?
+ nt_dacjitterbufsallowed : nt_adcjitterbufsallowed)
+ * nt_realdacblksize / sys_getsr();
+ diff = sys_getrealtime() - 0.001 * clock_gettimesince(initsystime);
+ if (diff > nt_hibuftime) nt_hibuftime = diff;
+ if (diff < nt_hibuftime - jittersec) {
+ post("jitter excess %d %f", dac, diff);
+ nt_resetmidisync();
+ }
+}
+
+static double nt_midigettimefor(LARGE_INTEGER timestamp) {
+ /* this is broken now... used to work when "timestamp" was derived from
+ QueryPerformanceCounter() instead of the gates approved timeGetSystemTime() call in the MIDI callback routine below. */
+ return nt_tixtotime(timestamp) - nt_hibuftime;
+}
+#endif /* MIDI_TIMESTAMP */
+
+static int nt_fill = 0;
+#define WRAPFWD(x) ((x) >= nt_naudiobuffer ? (x) - nt_naudiobuffer: (x))
+#define WRAPBACK(x) ((x) < 0 ? (x) + nt_naudiobuffer: (x))
+#define MAXRESYNC 500
+
+#if 0 /* this is used for debugging */
+static void nt_printaudiostatus() {
+ int nad, nda;
+ for (nad = 0; nad < nt_nwavein; nad++) {
+ int phase = ntsnd_inphase[nad];
+ int phase2 = phase, phase3 = WRAPFWD(phase2), count, ntrans = 0;
+ int firstphasedone = -1, firstphasebusy = -1;
+ for (count = 0; count < nt_naudiobuffer; count++) {
+ int donethis = (ntsnd_invec[nad][phase2].lpWaveHdr->dwFlags & WHDR_DONE);
+ int donenext = (ntsnd_invec[nad][phase3].lpWaveHdr->dwFlags & WHDR_DONE);
+ if (donethis && !donenext) {
+ if (firstphasebusy >= 0) goto multipleadc;
+ firstphasebusy = count;
+ }
+ if (!donethis && donenext) {
+ if (firstphasedone >= 0) goto multipleadc;
+ firstphasedone = count;
+ }
+ phase2 = phase3;
+ phase3 = WRAPFWD(phase2 + 1);
+ }
+ post("nad %d phase %d busy %d done %d", nad, phase, firstphasebusy, firstphasedone);
+ continue;
+ multipleadc:
+ startpost("nad %d phase %d: oops:", nad, phase);
+ for (count = 0; count < nt_naudiobuffer; count++) {
+ char buf[80];
+ sprintf(buf, " %d", (ntsnd_invec[nad][count].lpWaveHdr->dwFlags & WHDR_DONE));
+ poststring(buf);
+ }
+ endpost();
+ }
+ for (nda = 0; nda < nt_nwaveout; nda++) {
+ int phase = ntsnd_outphase[nad];
+ int phase2 = phase, phase3 = WRAPFWD(phase2), count, ntrans = 0;
+ int firstphasedone = -1, firstphasebusy = -1;
+ for (count = 0; count < nt_naudiobuffer; count++) {
+ int donethis = (ntsnd_outvec[nda][phase2].lpWaveHdr->dwFlags & WHDR_DONE);
+ int donenext = (ntsnd_outvec[nda][phase3].lpWaveHdr->dwFlags & WHDR_DONE);
+ if (donethis && !donenext) {
+ if (firstphasebusy >= 0) goto multipledac;
+ firstphasebusy = count;
+ }
+ if (!donethis && donenext) {
+ if (firstphasedone >= 0) goto multipledac;
+ firstphasedone = count;
+ }
+ phase2 = phase3;
+ phase3 = WRAPFWD(phase2 + 1);
+ }
+ if (firstphasebusy < 0) post("nda %d phase %d all %d", nda, phase, (ntsnd_outvec[nad][0].lpWaveHdr->dwFlags & WHDR_DONE));
+ else post("nda %d phase %d busy %d done %d", nda, phase, firstphasebusy, firstphasedone);
+ continue;
+ multipledac:
+ startpost("nda %d phase %d: oops:", nda, phase);
+ for (count = 0; count < nt_naudiobuffer; count++) {
+ char buf[80];
+ sprintf(buf, " %d", (ntsnd_outvec[nad][count].lpWaveHdr->dwFlags & WHDR_DONE));
+ poststring(buf);
+ }
+ endpost();
+ }
+}
+#endif /* 0 */
+
+/* this is a hack to avoid ever resyncing audio pointers in case for whatever
+reason the sync testing below gives false positives. */
+
+static int nt_resync_cancelled;
+
+static void nt_noresync() {
+ nt_resync_cancelled = 1;
+}
+
+static void nt_resyncaudio() {
+ UINT mmresult;
+ int nad, nda, count;
+ if (nt_resync_cancelled) return;
+ /* for each open input device, eat all buffers which are marked ready. The next one will thus be "busy". */
+ post("resyncing audio");
+ for (nad = 0; nad < nt_nwavein; nad++) {
+ int phase = ntsnd_inphase[nad];
+ for (count = 0; count < MAXRESYNC; count++) {
+ WAVEHDR *inwavehdr = ntsnd_invec[nad][phase].lpWaveHdr;
+ if (!(inwavehdr->dwFlags & WHDR_DONE)) break;
+ if (inwavehdr->dwFlags & WHDR_PREPARED) waveInUnprepareHeader(ntsnd_indev[nad], inwavehdr, sizeof(WAVEHDR));
+ inwavehdr->dwFlags = 0L;
+ waveInPrepareHeader(ntsnd_indev[nad], inwavehdr, sizeof(WAVEHDR));
+ mmresult = waveInAddBuffer(ntsnd_indev[nad], inwavehdr, sizeof(WAVEHDR));
+ if (mmresult != MMSYSERR_NOERROR) nt_waveinerror("waveInAddBuffer: %s", mmresult);
+ ntsnd_inphase[nad] = phase = WRAPFWD(phase + 1);
+ }
+ if (count == MAXRESYNC) post("resync error 1");
+ }
+ /* Each output buffer which is "ready" is filled with zeros and queued. */
+ for (nda = 0; nda < nt_nwaveout; nda++) {
+ int phase = ntsnd_outphase[nda];
+ for (count = 0; count < MAXRESYNC; count++) {
+ WAVEHDR *outwavehdr = ntsnd_outvec[nda][phase].lpWaveHdr;
+ if (!(outwavehdr->dwFlags & WHDR_DONE)) break;
+ if (outwavehdr->dwFlags & WHDR_PREPARED) waveOutUnprepareHeader(ntsnd_outdev[nda], outwavehdr, sizeof(WAVEHDR));
+ outwavehdr->dwFlags = 0L;
+ memset((char *)(ntsnd_outvec[nda][phase].lpData), 0, (CHANNELS_PER_DEVICE * SAMPSIZE * nt_realdacblksize));
+ waveOutPrepareHeader( ntsnd_outdev[nda], outwavehdr, sizeof(WAVEHDR));
+ mmresult = waveOutWrite(ntsnd_outdev[nda], outwavehdr, sizeof(WAVEHDR));
+ if (mmresult != MMSYSERR_NOERROR) nt_waveouterror("waveOutAddBuffer: %s", mmresult);
+ ntsnd_outphase[nda] = phase = WRAPFWD(phase + 1);
+ }
+ if (count == MAXRESYNC) post("resync error 2");
+ }
+#ifdef MIDI_TIMESTAMP
+ nt_resetmidisync();
+#endif
+}
+
+#define LATE 0
+#define RESYNC 1
+#define NOTHING 2
+static int nt_errorcount;
+static int nt_resynccount;
+static double nt_nextreporttime = -1;
+
+void nt_logerror(int which) {
+#if 0
+ post("error %d %d", count, which);
+ if (which < NOTHING) nt_errorcount++;
+ if (which == RESYNC) nt_resynccount++;
+ if (sys_getrealtime() > nt_nextreporttime) {
+ post("%d audio I/O error%s", nt_errorcount, (nt_errorcount > 1 ? "s" : ""));
+ if (nt_resynccount) post("DAC/ADC sync error");
+ nt_errorcount = nt_resynccount = 0;
+ nt_nextreporttime = sys_getrealtime() - 5;
+ }
+#endif
+}
+
+/* system buffer with t_sample types for one tick */
+t_sample *sys_soundout;
+t_sample *sys_soundin;
+float sys_dacsr;
+
+int mmio_send_dacs() {
+ HMMIO hmmio;
+ UINT mmresult;
+ HANDLE hFormat;
+ int i, j;
+ short *sp1, *sp2;
+ float *fp1, *fp2;
+ int nextfill, doxfer = 0;
+ if (!nt_nwavein && !nt_nwaveout) return 0;
+ if (nt_meters) {
+ int i, n;
+ float maxsamp;
+ for (i = 0, n = 2 * nt_nwavein * sys_dacblocksize, maxsamp = nt_inmax; i < n; i++) {
+ float f = sys_soundin[i];
+ if (f > maxsamp) maxsamp = f;
+ else if (-f > maxsamp) maxsamp = -f;
+ }
+ nt_inmax = maxsamp;
+ for (i = 0, n = 2 * nt_nwaveout * sys_dacblocksize, maxsamp = nt_outmax; i < n; i++) {
+ float f = sys_soundout[i];
+ if (f > maxsamp) maxsamp = f;
+ else if (-f > maxsamp) maxsamp = -f;
+ }
+ nt_outmax = maxsamp;
+ }
+ /* the "fill pointer" nt_fill controls where in the next I/O buffers we will write and/or read. If it's zero, we
+ first check whether the buffers are marked "done". */
+ if (!nt_fill) {
+ for (int nad=0; nad<nt_nwavein; nad++) {
+ int phase = ntsnd_inphase[nad];
+ WAVEHDR *inwavehdr = ntsnd_invec[nad][phase].lpWaveHdr;
+ if (!(inwavehdr->dwFlags & WHDR_DONE)) goto idle;
+ }
+ for (int nda=0; nda<nt_nwaveout; nda++) {
+ int phase = ntsnd_outphase[nda];
+ WAVEHDR *outwavehdr = ntsnd_outvec[nda][phase].lpWaveHdr;
+ if (!(outwavehdr->dwFlags & WHDR_DONE)) goto idle;
+ }
+ for (int nad=0; nad<nt_nwavein; nad++) {
+ int phase = ntsnd_inphase[nad];
+ WAVEHDR *inwavehdr = ntsnd_invec[nad][phase].lpWaveHdr;
+ if (inwavehdr->dwFlags & WHDR_PREPARED) waveInUnprepareHeader(ntsnd_indev[nad], inwavehdr, sizeof(WAVEHDR));
+ }
+ for (int nda=0; nda<nt_nwaveout; nda++) {
+ int phase = ntsnd_outphase[nda];
+ WAVEHDR *outwavehdr = ntsnd_outvec[nda][phase].lpWaveHdr;
+ if (outwavehdr->dwFlags & WHDR_PREPARED) waveOutUnprepareHeader(ntsnd_outdev[nda], outwavehdr, sizeof(WAVEHDR));
+ }
+ }
+ /* Convert audio output to fixed-point and put it in the output buffer. */
+ fp1 = sys_soundout;
+ for (int nda=0; nda<nt_nwaveout; nda++) {
+ int phase = ntsnd_outphase[nda];
+ for (i=0, sp1=(short *)(ntsnd_outvec[nda][phase].lpData)+CHANNELS_PER_DEVICE*nt_fill; i<2; i++, fp1 += sys_dacblocksize, sp1++) {
+ for (j = 0, fp2 = fp1, sp2 = sp1; j < sys_dacblocksize; j++, fp2++, sp2 += CHANNELS_PER_DEVICE) {
+ int x1 = 32767.f * *fp2;
+ if (x1 > 32767) x1 = 32767;
+ else if (x1 < -32767) x1 = -32767;
+ *sp2 = x1;
+ }
+ }
+ }
+ memset(sys_soundout, 0, (sys_dacblocksize *sizeof(t_sample)*CHANNELS_PER_DEVICE)*nt_nwaveout);
+ /* vice versa for the input buffer */
+ fp1 = sys_soundin;
+ for (int nad=0; nad<nt_nwavein; nad++) {
+ int phase = ntsnd_inphase[nad];
+ for (i=0, sp1=(short *)(ntsnd_invec[nad][phase].lpData)+CHANNELS_PER_DEVICE*nt_fill; i < 2; i++, fp1 += sys_dacblocksize, sp1++) {
+ for (j = 0, fp2 = fp1, sp2 = sp1; j < sys_dacblocksize; j++, fp2++, sp2 += CHANNELS_PER_DEVICE) {
+ *fp2 = ((float)(1./32767.)) * (float)(*sp2);
+ }
+ }
+ }
+ nt_fill = nt_fill + sys_dacblocksize;
+ if (nt_fill == nt_realdacblksize) {
+ nt_fill = 0;
+ for (int nad=0; nad<nt_nwavein; nad++) {
+ int phase = ntsnd_inphase[nad];
+ HWAVEIN device = ntsnd_indev[nad];
+ WAVEHDR *inwavehdr = ntsnd_invec[nad][phase].lpWaveHdr;
+ waveInPrepareHeader(device, inwavehdr, sizeof(WAVEHDR));
+ mmresult = waveInAddBuffer(device, inwavehdr, sizeof(WAVEHDR));
+ if (mmresult != MMSYSERR_NOERROR) nt_waveinerror("waveInAddBuffer: %s", mmresult);
+ ntsnd_inphase[nad] = WRAPFWD(phase + 1);
+ }
+ for (int nda=0; nda<nt_nwaveout; nda++) {
+ int phase = ntsnd_outphase[nda];
+ HWAVEOUT device = ntsnd_outdev[nda];
+ WAVEHDR *outwavehdr = ntsnd_outvec[nda][phase].lpWaveHdr;
+ waveOutPrepareHeader(device, outwavehdr, sizeof(WAVEHDR));
+ mmresult = waveOutWrite(device, outwavehdr, sizeof(WAVEHDR));
+ if (mmresult != MMSYSERR_NOERROR) nt_waveouterror("waveOutWrite: %s", mmresult);
+ ntsnd_outphase[nda] = WRAPFWD(phase + 1);
+ }
+ /* check for DAC underflow or ADC overflow. */
+ for (int nad=0; nad<nt_nwavein; nad++) {
+ int phase = WRAPBACK(ntsnd_inphase[nad] - 2);
+ WAVEHDR *inwavehdr = ntsnd_invec[nad][phase].lpWaveHdr;
+ if (inwavehdr->dwFlags & WHDR_DONE) goto late;
+ }
+ for (int nda=0; nda<nt_nwaveout; nda++) {
+ int phase = WRAPBACK(ntsnd_outphase[nda] - 2);
+ WAVEHDR *outwavehdr = ntsnd_outvec[nda][phase].lpWaveHdr;
+ if (outwavehdr->dwFlags & WHDR_DONE) goto late;
+ }
+ }
+ return 1;
+late:
+ nt_logerror(LATE);
+ nt_resyncaudio();
+ return 1;
+idle:
+ /* If more than nt_adcjitterbufsallowed ADC buffers are ready on any input device, resynchronize */
+ for (int nad=0; nad<nt_nwavein; nad++) {
+ int phase = ntsnd_inphase[nad];
+ WAVEHDR *inwavehdr = ntsnd_invec[nad][WRAPFWD(phase + nt_adcjitterbufsallowed)].lpWaveHdr;
+ if ( inwavehdr->dwFlags & WHDR_DONE) {nt_resyncaudio(); return 0;}
+ }
+ /* test dac sync the same way */
+ for (int nda=0; nda<nt_nwaveout; nda++) {
+ int phase = ntsnd_outphase[nda];
+ WAVEHDR *outwavehdr = ntsnd_outvec[nda][WRAPFWD(phase + nt_dacjitterbufsallowed)].lpWaveHdr;
+ if (outwavehdr->dwFlags & WHDR_DONE) {nt_resyncaudio(); return 0;}
+ }
+#ifdef MIDI_TIMESTAMP
+ nt_midisync();
+#endif
+ return 0;
+}
+
+/* ------------------- public routines -------------------------- */
+
+void mmio_open_audio(int naudioindev, int *audioindev,
+int nchindev, int *chindev, int naudiooutdev, int *audiooutdev,
+int nchoutdev, int *choutdev, int rate) /* IOhannes */ {
+ int nbuf;
+ nt_realdacblksize = (sys_blocksize ? sys_blocksize : DEFREALDACBLKSIZE);
+ nbuf = sys_advance_samples/nt_realdacblksize;
+ if (nbuf >= MAXBUFFER) {
+ post("pd: audio buffering maxed out to %d", (int)(MAXBUFFER * ((nt_realdacblksize * 1000.)/44100.)));
+ nbuf = MAXBUFFER;
+ }
+ else if (nbuf < 4) nbuf = 4;
+ post("%d audio buffers", nbuf);
+ nt_naudiobuffer = nbuf;
+ if (nt_adcjitterbufsallowed > nbuf - 2) nt_adcjitterbufsallowed = nbuf - 2;
+ if (nt_dacjitterbufsallowed > nbuf - 2) nt_dacjitterbufsallowed = nbuf - 2;
+ nt_nwavein = sys_inchannels / 2;
+ nt_nwaveout = sys_outchannels / 2;
+ nt_whichadc = (naudioindev < 1 ? (nt_nwavein > 1 ? WAVE_MAPPER : -1) : audioindev[0]);
+ nt_whichdac = (naudiooutdev < 1 ? (nt_nwaveout > 1 ? WAVE_MAPPER : -1) : audiooutdev[0]);
+ if (naudiooutdev > 1 || naudioindev > 1) post("separate audio device choice not supported; using sequential devices.");
+ mmio_do_open_audio();
+}
+
+#if 0
+/* list the audio and MIDI device names */
+void mmio_listdevs() {
+ UINT wRtn, ndevices;
+ unsigned int i;
+ ndevices = waveInGetNumDevs();
+ for (i = 0; i < ndevices; i++) {
+ WAVEINCAPS wicap;
+ wRtn = waveInGetDevCaps(i, (LPWAVEINCAPS) &wicap, sizeof(wicap));
+ if (wRtn) nt_waveinerror("waveInGetDevCaps: %s", wRtn);
+ else post("audio input device #%d: %s", i+1, wicap.szPname);
+ }
+ ndevices = waveOutGetNumDevs();
+ for (i = 0; i < ndevices; i++) {
+ WAVEOUTCAPS wocap;
+ wRtn = waveOutGetDevCaps(i, (LPWAVEOUTCAPS) &wocap, sizeof(wocap));
+ if (wRtn) nt_waveouterror("waveOutGetDevCaps: %s", wRtn);
+ else post("audio output device #%d: %s", i+1, wocap.szPname);
+ }
+}
+#endif
+
+void mmio_getdevs(char *indevlist, int *nindevs, char *outdevlist, int *noutdevs, int *canmulti, int maxndev, int devdescsize) {
+ int wRtn, ndev, i;
+ *canmulti = 2; /* supports multiple devices */
+ ndev = waveInGetNumDevs();
+ if (ndev > maxndev) ndev = maxndev;
+ *nindevs = ndev;
+ for (i = 0; i < ndev; i++) {
+ WAVEINCAPS wicap;
+ wRtn = waveInGetDevCaps(i, (LPWAVEINCAPS) &wicap, sizeof(wicap));
+ sprintf(indevlist + i * devdescsize, (wRtn ? "???" : wicap.szPname));
+ }
+ ndev = waveOutGetNumDevs();
+ if (ndev > maxndev) ndev = maxndev;
+ *noutdevs = ndev;
+ for (i = 0; i < ndev; i++) {
+ WAVEOUTCAPS wocap;
+ wRtn = waveOutGetDevCaps(i, (LPWAVEOUTCAPS) &wocap, sizeof(wocap));
+ sprintf(outdevlist + i * devdescsize, (wRtn ? "???" : wocap.szPname));
+ }
+}
+
+struct t_audioapi api_mmio = {
+ mmio_open_audio,
+ mmio_close_audio,
+ mmio_send_dacs,
+ mmio_getdevs,
+};
diff --git a/desiredata/src/s_audio_oss.c b/desiredata/src/s_audio_oss.c
new file mode 100644
index 00000000..d38051b7
--- /dev/null
+++ b/desiredata/src/s_audio_oss.c
@@ -0,0 +1,532 @@
+/* Copyright (c) 1997-2003 Guenter Geiger, Miller Puckette, Larry Troxler,
+* Winfried Ritsch, Karl MacMillan, and others.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* this file inputs and outputs audio using the OSS API available on linux. */
+#include <linux/soundcard.h>
+
+#define PD_PLUSPLUS_FACE
+#include "desire.h"
+#include "s_stuff.h"
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <sched.h>
+#include <sys/mman.h>
+
+/* Defines */
+#define DEBUG(x) x
+#define DEBUG2(x) {x;}
+
+#define OSS_MAXCHPERDEV 32 /* max channels per OSS device */
+#define OSS_MAXDEV 4 /* maximum number of input or output devices */
+#define OSS_DEFFRAGSIZE 256 /* default log fragment size (frames) */
+#define OSS_DEFAUDIOBUF 40000 /* default audiobuffer, microseconds */
+#define OSS_DEFAULTCH 2
+#define RME_DEFAULTCH 8 /* need this even if RME undefined */
+typedef int16_t t_oss_int16;
+typedef int32_t t_oss_int32;
+#define OSS_MAXSAMPLEWIDTH sizeof(t_oss_int32)
+#define OSS_BYTESPERCHAN(width) (sys_dacblocksize * (width))
+#define OSS_XFERSAMPS(chans) (sys_dacblocksize* (chans))
+#define OSS_XFERSIZE(chans, width) (sys_dacblocksize * (chans) * (width))
+
+static int linux_fragsize = 0; /* for block mode; block size (sample frames) */
+
+/* our device handles */
+struct t_oss_dev {
+ int fd;
+ unsigned int space; /* bytes available for writing/reading */
+ int bufsize; /* total buffer size in blocks for this device */
+ int dropcount; /* # of buffers to drop for resync (output only) */
+ unsigned int nchannels; /* number of channels for this device */
+ unsigned int bytespersamp; /* bytes per sample (2 for 16 bit, 4 for 32) */
+};
+
+static t_oss_dev linux_dacs[OSS_MAXDEV];
+static t_oss_dev linux_adcs[OSS_MAXDEV];
+static int linux_noutdevs = 0;
+static int linux_nindevs = 0;
+
+/* OSS-specific private variables */
+static int oss_blockmode = 0; /* flag to use "blockmode" */
+static int oss_32bit = 0; /* allow 23 bit transfers in OSS */
+
+/* don't assume we can turn all 31 bits when doing float-to-fix;
+ otherwise some audio drivers (e.g. Midiman/ALSA) wrap around. */
+#define FMAX 0x7ffff000
+#define CLIP32(x) (((x)>FMAX)?FMAX:((x) < -FMAX)?-FMAX:(x))
+
+/* ---------------- public routines ----------------------- */
+static int oss_ndev = 0;
+
+/* find out how many OSS devices we have. Since this has to
+ open the devices to find out if they're there, we have
+ to be called before audio is actually started up. So we
+ cache the results, which in effect are the number of available devices. */
+void oss_init() {
+ static int countedthem = 0;
+ if (countedthem) return;
+ for (int i=0; i<10; i++) {
+ char devname[100];
+ if (i == 0) strcpy(devname, "/dev/dsp"); else sprintf(devname, "/dev/dsp%d", i);
+ int fd = open(devname, O_WRONLY|O_NONBLOCK);
+ if (fd<0) break;
+ oss_ndev++;
+ close(fd);
+ }
+ countedthem = 1;
+}
+
+void oss_set32bit() {oss_32bit=1;}
+
+typedef struct _multidev {
+ int fd;
+ int channels;
+ int format;
+} t_multidev;
+
+int oss_reset(int fd) {
+ int err = ioctl(fd,SNDCTL_DSP_RESET);
+ if (err<0) error("OSS: Could not reset");
+ return err;
+}
+
+/* The AFMT_S32_BLOCKED format is not defined in standard linux kernels
+ but is proposed by Guenter Geiger to support extending OSS to handle
+ 32 bit sample. This is user in Geiger's OSS driver for RME Hammerfall.
+ I'm not clear why this isn't called AFMT_S32_[SLN]E... */
+
+#ifndef AFMT_S32_BLOCKED
+#define AFMT_S32_BLOCKED 0x0000400
+#endif
+
+void oss_configure(t_oss_dev *dev, int srate, int dac, int skipblocksize) {
+ /* IOhannes */
+ int orig, param, fd = dev->fd, wantformat;
+ int nchannels = dev->nchannels;
+ audio_buf_info ainfo;
+ /* IOhannes : pd is very likely to crash if different formats are used on multiple soundcards */
+ /* set resolution - first try 4 byte samples */
+ if (oss_32bit && (ioctl(fd,SNDCTL_DSP_GETFMTS,&param) >= 0) && (param & AFMT_S32_BLOCKED)) {
+ wantformat = AFMT_S32_BLOCKED;
+ dev->bytespersamp = 4;
+ } else {
+ wantformat = AFMT_S16_NE;
+ dev->bytespersamp = 2;
+ }
+ param = wantformat;
+
+ if (sys_verbose) post("bytes per sample = %d", dev->bytespersamp);
+ if (ioctl(fd, SNDCTL_DSP_SETFMT, &param) == -1) error("OSS: Could not set DSP format");
+ else if (wantformat != param) error("OSS: DSP format: wanted %d, got %d", wantformat, param);
+ /* sample rate */
+ orig = param = srate;
+ if (ioctl(fd, SNDCTL_DSP_SPEED, &param) == -1) error("OSS: Could not set sampling rate for device");
+ else if (orig != param) error("OSS: sampling rate: wanted %d, got %d", orig, param );
+
+ if (oss_blockmode && !skipblocksize) {
+ int fragbytes, logfragsize, nfragment;
+ /* setting fragment count and size. */
+ linux_fragsize = sys_blocksize;
+ if (!linux_fragsize) {
+ linux_fragsize = OSS_DEFFRAGSIZE;
+ while (linux_fragsize > sys_dacblocksize && linux_fragsize * 6 > sys_advance_samples)
+ linux_fragsize = linux_fragsize/2;
+ }
+ /* post("adv_samples %d", sys_advance_samples); */
+ nfragment = int(sys_schedadvance * 44100.e-6 / linux_fragsize);
+ fragbytes = linux_fragsize * (dev->bytespersamp * nchannels);
+ logfragsize = ilog2(fragbytes);
+ if (fragbytes != (1 << logfragsize))
+ post("warning: OSS takes only power of 2 blocksize; using %d",
+ (1 << logfragsize)/(dev->bytespersamp * nchannels));
+ if (sys_verbose) post("setting nfrags = %d, fragsize %d", nfragment, fragbytes);
+
+ param = orig = (nfragment<<16) + logfragsize;
+ if (ioctl(fd,SNDCTL_DSP_SETFRAGMENT, &param) == -1)
+ error("OSS: Could not set or read fragment size");
+ if (param != orig) {
+ nfragment = ((param >> 16) & 0xffff);
+ logfragsize = (param & 0xffff);
+ post("warning: actual fragments %d, blocksize %d", nfragment, 1<<logfragsize);
+ }
+ if (sys_verbose) post("audiobuffer set to %d msec", (int)(0.001 * sys_schedadvance));
+ }
+
+ if (dac) {
+ /* use "free space" to learn the buffer size. Normally you
+ should set this to your own desired value; but this seems not
+ to be implemented uniformly across different sound cards. LATER
+ we should figure out what to do if the requested scheduler advance
+ is greater than this buffer size; for now, we just print something
+ out. */
+ int defect;
+ if (ioctl(fd, SOUND_PCM_GETOSPACE,&ainfo) < 0) error("OSS: ioctl on output device failed");
+ dev->bufsize = ainfo.bytes;
+ defect = sys_advance_samples * (dev->bytespersamp * nchannels)
+ - dev->bufsize - OSS_XFERSIZE(nchannels, dev->bytespersamp);
+ if (defect > 0) {
+ if (sys_verbose || defect > (dev->bufsize >> 2))
+ error("OSS: requested audio buffer size %d limited to %d",
+ sys_advance_samples * (dev->bytespersamp * nchannels), dev->bufsize);
+ sys_advance_samples = (dev->bufsize-OSS_XFERSAMPS(nchannels)) / (dev->bytespersamp*nchannels);
+ }
+ }
+}
+
+static int oss_setchannels(int fd, int wantchannels, char *devname) {
+ /* IOhannes */
+ int param = wantchannels;
+ while (param > 1) {
+ int save = param;
+ if (ioctl(fd, SNDCTL_DSP_CHANNELS, &param) == -1) error("OSS: SNDCTL_DSP_CHANNELS failed %s",devname);
+ else if (param == save) return param;
+ param = save - 1;
+ }
+ return 0;
+}
+
+#define O_AUDIOFLAG O_NDELAY
+/* what's the deal with (!O_NDELAY) ? does it make sense to you? */
+
+int oss_open_audio(int nindev, int *indev, int nchin, int *chin,
+ int noutdev, int *outdev, int nchout, int *chout, int rate, int bogus)
+{ /* IOhannes */
+ int capabilities = 0;
+ int inchannels = 0, outchannels = 0;
+ char devname[20];
+ int n, i, fd, flags;
+ char buf[OSS_MAXSAMPLEWIDTH * sys_dacblocksize * OSS_MAXCHPERDEV];
+ int wantmore=0;
+
+ linux_nindevs = linux_noutdevs = 0;
+ /* mark devices unopened */
+ for (int i=0; i<OSS_MAXDEV; i++) linux_adcs[i].fd = linux_dacs[i].fd = -1;
+
+ /* open output devices */
+ wantmore=0;
+ if (noutdev < 0 || nindev < 0) bug("linux_open_audio");
+ for (int n=0; n<noutdev; n++) {
+ int gotchans, j, inindex = -1;
+ int thisdevice = (outdev[n] >= 0 ? outdev[n] : 0);
+ int wantchannels = (nchout>n) ? chout[n] : wantmore;
+ fd = -1;
+ if (!wantchannels) goto end_out_loop;
+ if (thisdevice > 0) sprintf(devname, "/dev/dsp%d", thisdevice); else sprintf(devname, "/dev/dsp");
+ /* search for input request for same device. Succeed only if the number of channels matches. */
+ for (j = 0; j < nindev; j++) if (indev[j] == thisdevice && chin[j] == wantchannels) inindex = j;
+ /* if the same device is requested for input and output, try to open it read/write */
+ if (inindex >= 0) {
+ sys_setalarm(1000000);
+ if ((fd = open(devname, O_RDWR | O_AUDIOFLAG)) == -1) {
+ post("%s (read/write): %s", devname, strerror(errno));
+ post("(now will try write-only...)");
+ } else {
+ if (fcntl(fd, F_SETFD, 1) < 0) post("couldn't set close-on-exec flag on audio");
+ if ((flags = fcntl(fd, F_GETFL)) < 0) post("couldn't get audio device flags");
+ else if (fcntl(fd, F_SETFL, flags & (!O_NDELAY)) < 0) post("couldn't set audio device flags");
+ if (sys_verbose) post("opened %s for reading and writing", devname);
+ linux_adcs[inindex].fd = fd;
+ }
+ }
+ /* if that didn't happen or if it failed, try write-only */
+ if (fd == -1) {
+ sys_setalarm(1000000);
+ if ((fd = open(devname, O_WRONLY | O_AUDIOFLAG)) == -1) {
+ post("%s (writeonly): %s", devname, strerror(errno));
+ break;
+ }
+ if (fcntl(fd, F_SETFD, 1) < 0) post("couldn't set close-on-exec flag on audio");
+ if ((flags = fcntl(fd, F_GETFL)) < 0) post("couldn't get audio device flags");
+ else if (fcntl(fd, F_SETFL, flags & (!O_NDELAY)) < 0) post("couldn't set audio device flags");
+ if (sys_verbose) post("opened %s for writing only", devname);
+ }
+ if (ioctl(fd, SNDCTL_DSP_GETCAPS, &capabilities) == -1) error("OSS: SNDCTL_DSP_GETCAPS failed %s", devname);
+ gotchans = oss_setchannels(fd, (wantchannels>OSS_MAXCHPERDEV)?OSS_MAXCHPERDEV:wantchannels, devname);
+ if (sys_verbose) post("opened audio output on %s; got %d channels", devname, gotchans);
+ if (gotchans < 2) {
+ close(fd); /* can't even do stereo? just give up. */
+ } else {
+ linux_dacs[linux_noutdevs].nchannels = gotchans;
+ linux_dacs[linux_noutdevs].fd = fd;
+ oss_configure(&linux_dacs[linux_noutdevs], rate, 1, 0);
+ linux_noutdevs++;
+ outchannels += gotchans;
+ if (inindex >= 0) {
+ linux_adcs[inindex].nchannels = gotchans;
+ chin[inindex] = gotchans;
+ }
+ }
+ /* LATER think about spreading large numbers of channels over
+ various dsp's and vice-versa */
+ wantmore = wantchannels - gotchans;
+ end_out_loop: ;
+ }
+
+ /* open input devices */
+ wantmore = 0;
+ for (n = 0; n < nindev; n++) {
+ int gotchans=0;
+ int thisdevice = (indev[n] >= 0 ? indev[n] : 0);
+ int wantchannels = (nchin>n)?chin[n]:wantmore;
+ int alreadyopened = 0;
+ if (!wantchannels) goto end_in_loop;
+ if (thisdevice > 0) sprintf(devname, "/dev/dsp%d", thisdevice); else sprintf(devname, "/dev/dsp");
+ sys_setalarm(1000000);
+ /* perhaps it's already open from the above? */
+ if (linux_dacs[n].fd >= 0) {
+ fd = linux_adcs[n].fd;
+ alreadyopened = 1;
+ } else {
+ /* otherwise try to open it here. */
+ if ((fd = open(devname, O_RDONLY | O_AUDIOFLAG)) == -1) {
+ post("%s (readonly): %s", devname, strerror(errno));
+ goto end_in_loop;
+ }
+ if (fcntl(fd, F_SETFD, 1) < 0) post("couldn't set close-on-exec flag on audio");
+ if ((flags = fcntl(fd, F_GETFL)) < 0) post("couldn't get audio device flags");
+ else if (fcntl(fd, F_SETFL, flags & (!O_NDELAY)) < 0) post("couldn't set audio device flags");
+ if (sys_verbose) post("opened %s for reading only", devname);
+ }
+ linux_adcs[linux_nindevs].fd = fd;
+ gotchans = oss_setchannels(fd, (wantchannels>OSS_MAXCHPERDEV)?OSS_MAXCHPERDEV:wantchannels, devname);
+ if (sys_verbose) post("opened audio input device %s; got %d channels", devname, gotchans);
+ if (gotchans < 1) {
+ close(fd);
+ goto end_in_loop;
+ }
+ linux_adcs[linux_nindevs].nchannels = gotchans;
+ oss_configure(linux_adcs+linux_nindevs, rate, 0, alreadyopened);
+ inchannels += gotchans;
+ linux_nindevs++;
+ wantmore = wantchannels-gotchans;
+ /* LATER think about spreading large numbers of channels over various dsp's and vice-versa */
+ end_in_loop: ;
+ }
+ /* We have to do a read to start the engine. This is necessary because sys_send_dacs waits until the input
+ buffer is filled and only reads on a filled buffer. This is good, because it's a way to make sure that we
+ will not block. But I wonder why we only have to read from one of the devices and not all of them??? */
+ if (linux_nindevs) {
+ if (sys_verbose) post("OSS: issuing first ADC 'read'...");
+ read(linux_adcs[0].fd, buf, linux_adcs[0].bytespersamp * linux_adcs[0].nchannels * sys_dacblocksize);
+ if (sys_verbose) post("...done.");
+ }
+ /* now go and fill all the output buffers. */
+ for (i = 0; i < linux_noutdevs; i++) {
+ t_oss_dev &d = linux_dacs[i];
+ memset(buf, 0, d.bytespersamp * d.nchannels * sys_dacblocksize);
+ for (int j = 0; j < sys_advance_samples/sys_dacblocksize; j++)
+ write(d.fd, buf, d.bytespersamp * d.nchannels * sys_dacblocksize);
+ }
+ sys_setalarm(0);
+ sys_inchannels = inchannels;
+ sys_outchannels = outchannels;
+ return 0;
+}
+
+void oss_close_audio() {
+ for (int i=0;i<linux_nindevs ;i++) close(linux_adcs[i].fd);
+ for (int i=0;i<linux_noutdevs;i++) close(linux_dacs[i].fd);
+ linux_nindevs = linux_noutdevs = 0;
+}
+
+static int linux_dacs_write(int fd,void *buf,long bytes) {return write(fd, buf, bytes);}
+static int linux_adcs_read (int fd,void *buf,long bytes) {return read(fd, buf, bytes);}
+
+ /* query audio devices for "available" data size. */
+static void oss_calcspace() {
+ audio_buf_info ainfo;
+ for (int dev=0; dev<linux_noutdevs; dev++) {
+ if (ioctl(linux_dacs[dev].fd, SOUND_PCM_GETOSPACE,&ainfo) < 0)
+ error("OSS: ioctl on output device %d failed",dev);
+ linux_dacs[dev].space = ainfo.bytes;
+ }
+ for (int dev=0; dev<linux_nindevs; dev++) {
+ if (ioctl(linux_adcs[dev].fd, SOUND_PCM_GETISPACE,&ainfo) < 0)
+ error("OSS: ioctl on input device %d, fd %d failed", dev, linux_adcs[dev].fd);
+ linux_adcs[dev].space = ainfo.bytes;
+ }
+}
+
+void linux_audiostatus() {
+ if (!oss_blockmode) {
+ oss_calcspace();
+ for (int dev=0; dev < linux_noutdevs; dev++) post("dac %d space %d", dev, linux_dacs[dev].space);
+ for (int dev=0; dev < linux_nindevs; dev++) post("adc %d space %d", dev, linux_adcs[dev].space);
+ }
+}
+
+/* this call resyncs audio output and input which will cause discontinuities
+in audio output and/or input. */
+
+static void oss_doresync() {
+ int zeroed = 0;
+ char buf[OSS_MAXSAMPLEWIDTH * sys_dacblocksize * OSS_MAXCHPERDEV];
+ audio_buf_info ainfo;
+ /* 1. if any input devices are ahead (have more than 1 buffer stored), drop one or more buffers worth */
+ for (int dev=0; dev<linux_nindevs; dev++) {
+ t_oss_dev d = linux_adcs[dev];
+ if (d.space == 0) {
+ linux_adcs_read(d.fd, buf, OSS_XFERSIZE(d.nchannels, d.bytespersamp));
+ } else while (d.space > OSS_XFERSIZE(d.nchannels, d.bytespersamp)) {
+ linux_adcs_read(d.fd, buf, OSS_XFERSIZE(d.nchannels, d.bytespersamp));
+ if (ioctl(d.fd, SOUND_PCM_GETISPACE, &ainfo) < 0) { error("OSS: ioctl on input device %d, fd %d failed",dev,d.fd); break;}
+ d.space = ainfo.bytes;
+ }
+ }
+ /* 2. if any output devices are behind, feed them zeros to catch them up */
+ for (int dev=0; dev<linux_noutdevs; dev++) {
+ t_oss_dev d = linux_dacs[dev];
+ while (d.space > d.bufsize - sys_advance_samples*d.nchannels*d.bytespersamp) {
+ if (!zeroed) {
+ for (unsigned int i = 0; i < OSS_XFERSAMPS(d.nchannels); i++) buf[i] = 0;
+ zeroed = 1;
+ }
+ linux_dacs_write(d.fd, buf, OSS_XFERSIZE(d.nchannels, d.bytespersamp));
+ if (ioctl(d.fd, SOUND_PCM_GETOSPACE, &ainfo) < 0) {error("OSS: ioctl on output device %d, fd %d failed",dev,d.fd); break;}
+ d.space = ainfo.bytes;
+ }
+ }
+ /* 3. if any DAC devices are too far ahead, plan to drop the number of frames which will let the others catch up. */
+ for (int dev=0; dev<linux_noutdevs; dev++) {
+ t_oss_dev d = linux_dacs[dev];
+ if (d.space > d.bufsize - (sys_advance_samples - 1) * d.nchannels * d.bytespersamp) {
+ d.dropcount = sys_advance_samples - 1 - (d.space - d.bufsize) / (d.nchannels * d.bytespersamp);
+ } else d.dropcount = 0;
+ }
+}
+
+int oss_send_dacs() {
+ float *fp1, *fp2;
+ int i, j, rtnval = SENDDACS_YES;
+ char buf[OSS_MAXSAMPLEWIDTH * sys_dacblocksize * OSS_MAXCHPERDEV];
+ t_oss_int16 *sp;
+ t_oss_int32 *lp;
+ /* the maximum number of samples we should have in the ADC buffer */
+ int idle = 0;
+ double timeref, timenow;
+ if (!linux_nindevs && !linux_noutdevs) return SENDDACS_NO;
+ if (!oss_blockmode) {
+ /* determine whether we're idle. This is true if either (1)
+ some input device has less than one buffer to read or (2) some
+ output device has fewer than (sys_advance_samples) blocks buffered already. */
+ oss_calcspace();
+ for (int dev=0; dev<linux_noutdevs; dev++) {
+ t_oss_dev d = linux_dacs[dev];
+ if (d.dropcount || (d.bufsize - d.space > sys_advance_samples * d.bytespersamp * d.nchannels)) idle = 1;
+ }
+ for (int dev=0; dev<linux_nindevs; dev++) {
+ t_oss_dev d = linux_adcs[dev];
+ if (d.space < OSS_XFERSIZE(d.nchannels, d.bytespersamp)) idle = 1;
+ }
+ }
+ if (idle && !oss_blockmode) {
+ /* sometimes---rarely---when the ADC available-byte-count is
+ zero, it's genuine, but usually it's because we're so
+ late that the ADC has overrun its entire kernel buffer. We
+ distinguish between the two by waiting 2 msec and asking again.
+ There should be an error flag we could check instead; look for this someday... */
+ for (int dev=0; dev<linux_nindevs; dev++) if (linux_adcs[dev].space == 0) {
+ sys_microsleep(sys_sleepgrain); /* tb: changed to sys_sleepgrain */
+ oss_calcspace();
+ if (linux_adcs[dev].space != 0) continue;
+ /* here's the bad case. Give up and resync. */
+ sys_log_error(ERR_DATALATE);
+ oss_doresync();
+ return SENDDACS_NO;
+ }
+ /* check for slippage between devices, either because
+ data got lost in the driver from a previous late condition, or
+ because the devices aren't synced. When we're idle, no
+ input device should have more than one buffer readable and
+ no output device should have less than sys_advance_samples-1 */
+ for (int dev=0; dev<linux_noutdevs; dev++) {
+ t_oss_dev d = linux_dacs[dev];
+ if (!d.dropcount && (d.bufsize - d.space < (sys_advance_samples - 2)*d.bytespersamp*d.nchannels))
+ goto badsync;
+ }
+ for (int dev=0; dev<linux_nindevs; dev++)
+ if (linux_adcs[dev].space > 3 * OSS_XFERSIZE(linux_adcs[dev].nchannels, linux_adcs[dev].bytespersamp)) goto badsync;
+ /* return zero to tell the scheduler we're idle. */
+ return SENDDACS_NO;
+ badsync:
+ sys_log_error(ERR_RESYNC);
+ oss_doresync();
+ return SENDDACS_NO;
+ }
+ /* do output */
+ timeref = sys_getrealtime();
+ for (int dev=0, thischan = 0; dev < linux_noutdevs; dev++) {
+ t_oss_dev d = linux_dacs[dev];
+ int nchannels = d.nchannels;
+ if (d.dropcount) d.dropcount--;
+ else {
+ fp1 = sys_soundout + sys_dacblocksize*thischan;
+ if (d.bytespersamp == 4) {
+ for (i = sys_dacblocksize * nchannels, lp = (t_oss_int32 *)buf; i--; fp1++, lp++) {
+ float f = *fp1 * 2147483648.;
+ *lp = int(f >= 2147483647. ? 2147483647. : (f < -2147483648. ? -2147483648. : f));
+ }
+ } else {
+ for (i = sys_dacblocksize, sp = (t_oss_int16 *)buf; i--; fp1++, sp += nchannels) {
+ for (j=0, fp2 = fp1; j<nchannels; j++, fp2 += sys_dacblocksize) {
+ int s = int(*fp2 * 32767.);
+ if (s > 32767) s = 32767; else if (s < -32767) s = -32767;
+ sp[j] = s;
+ }
+ }
+ }
+ linux_dacs_write(d.fd, buf, OSS_XFERSIZE(nchannels, d.bytespersamp));
+ if ((timenow = sys_getrealtime()) - timeref > 0.002) {
+ if (!oss_blockmode) sys_log_error(ERR_DACSLEPT); else rtnval = SENDDACS_SLEPT;
+ }
+ timeref = timenow;
+ }
+ thischan += nchannels;
+ }
+ memset(sys_soundout, 0, sys_outchannels * (sizeof(float) * sys_dacblocksize));
+ for (int dev=0, thischan = 0; dev < linux_nindevs; dev++) {
+ int nchannels = linux_adcs[dev].nchannels;
+ linux_adcs_read(linux_adcs[dev].fd, buf, OSS_XFERSIZE(nchannels, linux_adcs[dev].bytespersamp));
+ if ((timenow = sys_getrealtime()) - timeref > 0.002) {
+ if (!oss_blockmode) sys_log_error(ERR_ADCSLEPT); else rtnval = SENDDACS_SLEPT;
+ }
+ timeref = timenow;
+ fp1 = sys_soundin + thischan*sys_dacblocksize;
+ if (linux_adcs[dev].bytespersamp == 4) {
+ for (i = sys_dacblocksize*nchannels, lp = (t_oss_int32 *)buf; i--; fp1++, lp++)
+ *fp1 = float(*lp)*float(1./2147483648.);
+ } else {
+ for (i = sys_dacblocksize, sp = (t_oss_int16 *)buf; i--; fp1++, sp += nchannels)
+ for (j=0; j<nchannels; j++) fp1[j*sys_dacblocksize] = (float)sp[j]*(float)3.051850e-05;
+ }
+ thischan += nchannels;
+ }
+ return rtnval;
+}
+
+void oss_getdevs(char *indevlist, int *nindevs, char *outdevlist, int *noutdevs, int *canmulti, int maxndev, int devdescsize) {
+ int ndev = min(oss_ndev,maxndev);
+ *canmulti = 2; /* supports multiple devices */
+ for (int i=0; i<ndev; i++) {
+ sprintf(indevlist + i*devdescsize, "OSS device #%d", i+1);
+ sprintf(outdevlist + i*devdescsize, "OSS device #%d", i+1);
+ }
+ *nindevs = *noutdevs = ndev;
+}
+
+struct t_audioapi oss_api = {
+ oss_open_audio,
+ oss_close_audio,
+ oss_send_dacs,
+ oss_getdevs,
+};
diff --git a/desiredata/src/s_audio_pa.c b/desiredata/src/s_audio_pa.c
new file mode 100644
index 00000000..d1641501
--- /dev/null
+++ b/desiredata/src/s_audio_pa.c
@@ -0,0 +1,332 @@
+/* Copyright (c) 2001 Miller Puckette and others.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* this file calls Ross Bencina's and Phil Burk's Portaudio package. It's
+ the main way in for Mac OS and, with Michael Casey's help, also into
+ ASIO in Windows. */
+
+/* tb: requires portaudio >= V19 */
+
+#include "m_pd.h"
+#include "s_stuff.h"
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <portaudio.h>
+#include <errno.h>
+
+#ifdef MSW
+/* jmz thinks that we have to include:
+ * on Windows: <malloc.h> (probably this is already included?)
+ * on linux: <alloca.h> (might be true for osX too, no way to check right now...)
+ */
+#zinclude <malloc.h>
+#else
+# include <alloca.h>
+#endif
+
+#ifdef MSW
+#include "pthread.h" /* for ETIMEDOUT */
+#endif
+
+#define MAX_PA_CHANS 32
+
+/* portaudio's blocking api is not working, yet: */
+/* #define PABLOCKING */
+
+//#ifndef PABLOCKING
+#include "s_audio_pablio.h"
+//#endif
+
+static int pa_inchans, pa_outchans;
+
+static PaStream *pa_stream;
+static PABLIO_Stream *pablio_stream;
+static PaStreamCallback *pa_callback = NULL;
+
+int process (const void *input, void *output, unsigned long frameCount, const PaStreamCallbackTimeInfo* timeInfo,
+PaStreamCallbackFlags statusFlags, void *userData);
+
+int pa_open_audio(int inchans, int outchans, int rate, int advance, int indeviceno, int outdeviceno, int schedmode) {
+ PaError err;
+ int j, devno, pa_indev = -1, pa_outdev = -1;
+ pa_callback = schedmode==1 ? process : NULL;
+ sys_setscheduler(schedmode);
+ /* Initialize PortAudio */
+ err = Pa_Initialize();
+ if (err != paNoError) {
+ error("Error number %d occured initializing portaudio: %s", err, Pa_GetErrorText(err));
+ return 1;
+ }
+ /* post("in %d out %d rate %d device %d", inchans, outchans, rate, deviceno); */
+ if ( inchans > MAX_PA_CHANS) {post( "input channels reduced to maximum %d", MAX_PA_CHANS); inchans = MAX_PA_CHANS;}
+ if (outchans > MAX_PA_CHANS) {post("output channels reduced to maximum %d", MAX_PA_CHANS); outchans = MAX_PA_CHANS;}
+ if (inchans > 0) {
+ for (j = 0, devno = 0; j < Pa_GetDeviceCount(); j++) {
+ const PaDeviceInfo *info = Pa_GetDeviceInfo(j);
+ int maxchans = info->maxInputChannels;
+ if (maxchans > 0) {
+ if (devno == indeviceno) {
+ if (maxchans < inchans) inchans = maxchans;
+ pa_indev = j;
+ break;
+ }
+ devno++;
+ }
+ }
+ }
+ if (outchans > 0) {
+ for (j = 0, devno = 0; j < Pa_GetDeviceCount(); j++) {
+ const PaDeviceInfo *info = Pa_GetDeviceInfo(j);
+ int maxchans = info->maxOutputChannels;
+ if (maxchans > 0) {
+ if (devno == outdeviceno) {
+ if (maxchans < outchans) outchans = maxchans;
+ pa_outdev = j;
+ break;
+ }
+ devno++;
+ }
+ }
+ }
+ if (sys_verbose) {
+ post( "input device %d, channels %d", pa_indev, inchans);
+ post("output device %d, channels %d", pa_outdev, outchans);
+ post("latency advance %d", advance);
+ }
+ if (inchans || outchans) {
+#ifndef PABLOCKING
+ if (schedmode == 1) {
+#endif
+ PaStreamParameters inputParameters, outputParameters;
+ /* initialize input */
+ inputParameters.device = pa_indev ;
+ inputParameters.channelCount = inchans;
+ inputParameters.sampleFormat = paFloat32 | paNonInterleaved;
+ inputParameters.suggestedLatency = advance * 0.001;
+ inputParameters.hostApiSpecificStreamInfo = NULL;
+ /* initialize output */
+ outputParameters.device = pa_outdev;
+ outputParameters.channelCount = outchans;
+ outputParameters.sampleFormat = paFloat32 | paNonInterleaved;
+ outputParameters.suggestedLatency = advance * 0.001;
+ outputParameters.hostApiSpecificStreamInfo = NULL;
+ /* report to portaudio */
+ err = Pa_OpenStream(&pa_stream,
+ ( pa_indev!=-1 ? &inputParameters : 0),
+ (pa_outdev!=-1 ? &outputParameters : 0),
+ rate, sys_dacblocksize, paClipOff, /* tb: we should be faster ;-) */ pa_callback, NULL);
+ if (err == paNoError) {
+ const PaStreamInfo * streaminfo = Pa_GetStreamInfo (pa_stream);
+ sys_schedadvance = 1e6 * streaminfo->outputLatency;
+ }
+#ifndef PABLOCKING
+ } else {
+ int nbuffers = sys_advance_samples / sys_dacblocksize;
+ err = PD_OpenAudioStream( &pablio_stream, rate, paFloat32,
+ inchans, outchans, sys_dacblocksize, nbuffers, pa_indev, pa_outdev);
+ }
+#endif
+ } else err = 0;
+ if (err != paNoError) {
+ post("Error number %d occured opening portaudio stream", err);
+ post("Error message: %s", Pa_GetErrorText(err));
+ Pa_Terminate();
+ sys_inchannels = sys_outchannels = 0;
+ return 1;
+ } else if (sys_verbose) post("... opened OK.");
+ pa_inchans = inchans;
+ pa_outchans = outchans;
+#ifndef PABLOCKING
+ if (schedmode)
+#endif
+ err = Pa_StartStream(pa_stream);
+ if (err != paNoError) {
+ post("Error number %d occured starting portaudio stream", err);
+ post("Error message: %s", Pa_GetErrorText(err));
+ Pa_Terminate();
+ sys_inchannels = sys_outchannels = 0;
+ return 1;
+ }
+ post("successfully started");
+ return 0;
+}
+
+void sys_peakmeters(void);
+extern int sys_meters; /* true if we're metering */
+
+int process (const void *input, void *output, unsigned long frameCount,
+const PaStreamCallbackTimeInfo* timeInfo, PaStreamCallbackFlags statusFlags, void *userData) {
+ int i,j;
+ int timeout = (float)frameCount / (float) sys_dacsr * 1e6;
+ if (sys_timedlock(timeout) == ETIMEDOUT) /* we're late */ {
+ post("timeout %d", timeout);
+ sys_log_error(ERR_SYSLOCK);
+ return 0;
+ }
+ for (j = 0; j < sys_inchannels; j++) {
+ t_sample * in = ((t_sample**)input)[j];
+ copyvec(sys_soundin + j * sys_dacblocksize,in,sys_dacblocksize);
+ }
+ sched_tick(sys_time + sys_time_per_dsp_tick);
+ for (j = 0; j < sys_outchannels; j++) {
+ t_sample * out = ((t_sample**)output)[j];
+ copyvec(out,sys_soundout + j * sys_dacblocksize,sys_dacblocksize);
+ }
+ /* update peak meters */
+ if (sys_meters) sys_peakmeters();
+ /* clear the output buffer */
+ zerovec(sys_soundout, pa_outchans * sys_dacblocksize);
+ sys_unlock();
+ return 0;
+}
+
+void pa_close_audio() {
+ post("closing portaudio");
+ if (pa_inchans || pa_outchans) {
+ if (pa_stream) {
+ Pa_StopStream(pa_stream);
+ Pa_CloseStream(pa_stream);
+ pa_stream = NULL;
+ }
+ if (pablio_stream) {
+ PD_CloseAudioStream(pablio_stream);
+ pablio_stream = NULL;
+ }
+ }
+ post("portaudio closed");
+ pa_inchans = pa_outchans = 0;
+}
+
+/* for blocked IO */
+int pa_send_dacs() {
+#ifdef PABLOCKING /* tb: blocking IO isn't really working for v19 yet */
+ double timenow, timebefore;
+ if (( pa_inchans && Pa_GetStreamReadAvailable(pa_stream) < sys_dacblocksize*0.8) &&
+ (pa_outchans && Pa_GetStreamWriteAvailable(pa_stream) < sys_dacblocksize*0.8)) {
+ /* we can't transfer data ... wait in the scheduler */
+ return SENDDACS_NO;
+ }
+ timebefore = sys_getrealtime();
+ if (pa_outchans) Pa_WriteStream(pa_stream, &sys_soundout, sys_dacblocksize);
+ if ( pa_inchans) Pa_ReadStream(pa_stream, &sys_soundin, sys_dacblocksize);
+ zerovec(sys_soundout, pa_inchans * sys_dacblocksize);
+ while (( pa_inchans && Pa_GetStreamReadAvailable(pa_stream) < sys_dacblocksize*0.8) &&
+ (pa_outchans && Pa_GetStreamWriteAvailable(pa_stream) < sys_dacblocksize*0.8)) {
+ if (pa_outchans) Pa_WriteStream(pa_stream, &sys_soundout, sys_dacblocksize);
+ if ( pa_inchans) Pa_ReadStream(pa_stream, &sys_soundin, sys_dacblocksize);
+ zerovec(sys_soundout, pa_inchans * sys_dacblocksize);
+ sched_tick(sys_time + sys_time_per_dsp_tick);
+ }
+ if (sys_getrealtime() > timebefore + sys_sleepgrain * 1e-6) {
+ return SENDDACS_SLEPT;
+ } else return SENDDACS_YES;
+#else /* for now we're using pablio */
+ float *samples, *fp1, *fp2;
+ int i, j;
+ double timebefore;
+ samples=(float*)alloca(sizeof(float) * MAX_PA_CHANS * sys_dacblocksize);
+ timebefore = sys_getrealtime();
+ if ((pa_inchans && PD_GetAudioStreamReadable(pablio_stream) < sys_dacblocksize) ||
+ (pa_outchans && PD_GetAudioStreamWriteable(pablio_stream) < sys_dacblocksize)) {
+ if (pa_inchans && pa_outchans) {
+ int synced = 0;
+ while (PD_GetAudioStreamWriteable(pablio_stream) > 2*sys_dacblocksize) {
+ for (j = 0; j < pa_outchans; j++)
+ for (i = 0, fp2 = samples + j; i < sys_dacblocksize; i++, fp2 += pa_outchans)
+ *fp2 = 0;
+ synced = 1;
+ PD_WriteAudioStream(pablio_stream, samples, sys_dacblocksize);
+ }
+ while (PD_GetAudioStreamReadable(pablio_stream) > 2*sys_dacblocksize) {
+ synced = 1;
+ PD_ReadAudioStream(pablio_stream, samples, sys_dacblocksize);
+ }
+/* if (synced) post("sync"); */
+ }
+ return SENDDACS_NO;
+ }
+ if (pa_inchans) {
+ PD_ReadAudioStream(pablio_stream, samples, sys_dacblocksize);
+ for (j = 0, fp1 = sys_soundin; j < pa_inchans; j++, fp1 += sys_dacblocksize)
+ for (i = 0, fp2 = samples + j; i < sys_dacblocksize; i++, fp2 += pa_inchans)
+ fp1[i] = *fp2;
+ }
+ if (pa_outchans) {
+ for (j = 0, fp1 = sys_soundout; j < pa_outchans; j++, fp1 += sys_dacblocksize)
+ for (i = 0, fp2 = samples + j; i < sys_dacblocksize; i++, fp2 += pa_outchans) {
+ *fp2 = fp1[i];
+ fp1[i] = 0;
+ }
+ PD_WriteAudioStream(pablio_stream, samples, sys_dacblocksize);
+ }
+ if (sys_getrealtime() > timebefore + sys_sleepgrain * 1e-6) {
+ /* post("slept"); */
+ return SENDDACS_SLEPT;
+ } else return SENDDACS_YES;
+#endif
+}
+
+void pa_listdevs() /* lifted from pa_devs.c in portaudio */ {
+ int j, numDevices;
+ const PaDeviceInfo *pdi;
+ PaError err;
+ Pa_Initialize();
+ numDevices = Pa_GetDeviceCount();
+ if (numDevices<0) {
+ error("ERROR: Pa_GetDeviceCount returned %d", numDevices);
+ err = numDevices;
+ goto error;
+ }
+ post("Audio Devices:");
+ for (int i=0; i<numDevices; i++) {
+ const PaDeviceInfo *pdi = Pa_GetDeviceInfo(i);
+ post("device %s", pdi->name);
+ post("device %d:", i+1);
+ post(" %s;", pdi->name);
+ post("%d inputs, ", pdi->maxInputChannels);
+ post("%d outputs", pdi->maxOutputChannels);
+#ifdef PA19
+ if (i == Pa_GetDefaultInputDevice ()) post(" (Default Input)");
+ if (i == Pa_GetDefaultOutputDevice()) post(" (Default Output)");
+#else
+ if (i == Pa_GetDefaultInputDeviceID ()) post(" (Default Input)");
+ if (i == Pa_GetDefaultOutputDeviceID()) post(" (Default Output)");
+#endif
+ post("");
+ }
+ post("");
+ return;
+error:
+ error("An error occured while using the portaudio stream: #%d: %s",err,Pa_GetErrorText(err));
+}
+/* scanning for devices */
+void pa_getdevs(char *indevlist, int *nindevs, char *outdevlist, int *noutdevs, int *canmulti, int maxndev, int devdescsize) {
+ int i, nin = 0, nout = 0, ndev;
+ *canmulti = 1; /* one dev each for input and output */
+ Pa_Initialize();
+ ndev = Pa_GetDeviceCount();
+ for (i = 0; i < ndev; i++) {
+ const PaDeviceInfo *pdi = Pa_GetDeviceInfo(i);
+ if (pdi->maxInputChannels > 0 && nin < maxndev) {
+ sprintf(indevlist + nin * devdescsize, "(%d)%s", pdi->hostApi,pdi->name);
+ /* strcpy(indevlist + nin * devdescsize, pdi->name); */
+ nin++;
+ }
+ if (pdi->maxOutputChannels > 0 && nout < maxndev) {
+ sprintf(outdevlist + nout * devdescsize, "(%d)%s", pdi->hostApi,pdi->name);
+ /* strcpy(outdevlist + nout * devdescsize, pdi->name); */
+ nout++;
+ }
+ }
+ *nindevs = nin;
+ *noutdevs = nout;
+}
+
+t_audioapi pa_api = {
+ pa_open_audio,
+ pa_close_audio,
+ pa_send_dacs,
+ pa_getdevs,
+};
diff --git a/desiredata/src/s_audio_pablio.c b/desiredata/src/s_audio_pablio.c
new file mode 100644
index 00000000..5915250b
--- /dev/null
+++ b/desiredata/src/s_audio_pablio.c
@@ -0,0 +1,304 @@
+/*
+ * $Id: s_audio_pablio.c,v 1.1.4.2.2.4.2.2 2007-07-30 22:19:11 matju Exp $
+ * pablio.c
+ * Portable Audio Blocking Input/Output utility.
+ *
+ * Author: Phil Burk, http://www.softsynth.com
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.audiomulch.com/portaudio/
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+ /* changes by Miller Puckette to support Pd: device selection,
+ settable audio buffer size, and settable number of channels.
+ LATER also fix it to poll for input and output fifo fill points. */
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include "portaudio.h"
+#include "s_audio_paring.h"
+#include "s_audio_pablio.h" /* MSP */
+#include <string.h>
+
+ /* MSP -- FRAMES_PER_BUFFER constant removed */
+static void NPa_Sleep(int n) { /* MSP wrapper to check we never stall... */
+#if 0
+ post("sleep");
+#endif
+ Pa_Sleep(n);
+}
+
+/************************************************************************/
+/******** Prototypes ****************************************************/
+/************************************************************************/
+
+#ifdef PA19
+static int blockingIOCallback( const void *inputBuffer, void *outputBuffer, /*MSP */
+ unsigned long framesPerBuffer,
+ const PaStreamCallbackTimeInfo *outTime,
+ PaStreamCallbackFlags myflags,
+ void *userData );
+#else
+static int blockingIOCallback( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData );
+#endif
+static PaError PABLIO_InitFIFO( RingBuffer *rbuf, long numFrames, long bytesPerFrame );
+static PaError PABLIO_TermFIFO( RingBuffer *rbuf );
+
+/************************************************************************/
+/******** Functions *****************************************************/
+/************************************************************************/
+
+/* Called from PortAudio.
+ * Read and write data only if there is room in FIFOs.
+ */
+#ifdef PA19
+static int blockingIOCallback(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer,
+const PaStreamCallbackTimeInfo *outTime, PaStreamCallbackFlags myflags, void *userData)
+#else
+static int blockingIOCallback(void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer,
+PaTimestamp outTime, void *userData )
+#endif
+{
+ PABLIO_Stream *data = (PABLIO_Stream*)userData;
+// (void) outTime;
+ /* This may get called with NULL inputBuffer during initial setup. */
+ if (inputBuffer) PD_RingBuffer_Write( &data->inFIFO, inputBuffer, data->inbytesPerFrame * framesPerBuffer );
+ if (outputBuffer) {
+ int numBytes = data->outbytesPerFrame * framesPerBuffer;
+ int numRead = PD_RingBuffer_Read( &data->outFIFO, outputBuffer, numBytes);
+ /* Zero out remainder of buffer if we run out of data. */
+ for (int i=numRead; i<numBytes; i++) ((char *)outputBuffer)[i] = 0;
+ }
+ return 0;
+}
+
+/* Allocate buffer. */
+static PaError PABLIO_InitFIFO(RingBuffer *rbuf, long numFrames, long bytesPerFrame) {
+ long numBytes = numFrames * bytesPerFrame;
+ char *buffer = (char *)malloc(numBytes);
+ if (!buffer) return paInsufficientMemory;
+ memset(buffer, 0, numBytes);
+ return (PaError) PD_RingBuffer_Init(rbuf, numBytes, buffer);
+}
+
+/* Free buffer. */
+static PaError PABLIO_TermFIFO(RingBuffer *rbuf) {
+ if (rbuf->buffer) free(rbuf->buffer);
+ rbuf->buffer = NULL;
+ return paNoError;
+}
+
+/************************************************************
+ * Write data to ring buffer.
+ * Will not return until all the data has been written.
+ */
+long PD_WriteAudioStream(PABLIO_Stream *aStream, void *data, long numFrames) {
+ long bytesWritten;
+ char *p = (char *) data;
+ long numBytes = aStream->outbytesPerFrame * numFrames;
+ while (numBytes > 0) {
+ bytesWritten = PD_RingBuffer_Write(&aStream->outFIFO, p, numBytes);
+ numBytes -= bytesWritten;
+ p += bytesWritten;
+ if (numBytes>0) NPa_Sleep(10); /* MSP */
+ }
+ return numFrames;
+}
+
+/************************************************************
+ * Read data from ring buffer.
+ * Will not return until all the data has been read.
+ */
+long PD_ReadAudioStream(PABLIO_Stream *aStream, void *data, long numFrames) {
+ char *p = (char *)data;
+ long numBytes = aStream->inbytesPerFrame * numFrames;
+ while (numBytes > 0) {
+ long bytesRead = PD_RingBuffer_Read(&aStream->inFIFO, p, numBytes);
+ numBytes -= bytesRead;
+ p += bytesRead;
+ if (numBytes > 0) NPa_Sleep(10); /* MSP */
+ }
+ return numFrames;
+}
+
+/* Return the number of frames that could be written to the stream without having to wait. */
+long PD_GetAudioStreamWriteable(PABLIO_Stream *aStream) {
+ int bytesEmpty = PD_RingBuffer_GetWriteAvailable(&aStream->outFIFO);
+ return bytesEmpty / aStream->outbytesPerFrame;
+}
+
+/* Return the number of frames that are available to be read from the stream without having to wait. */
+long PD_GetAudioStreamReadable(PABLIO_Stream *aStream) {
+ int bytesFull = PD_RingBuffer_GetReadAvailable(&aStream->inFIFO);
+ return bytesFull / aStream->inbytesPerFrame;
+}
+
+static unsigned long RoundUpToNextPowerOf2(unsigned long n) {
+ long numBits = 0;
+ if( ((n-1) & n) == 0) return n; /* Already Power of two. */
+ while(n > 0) {
+ n= n>>1;
+ numBits++;
+ }
+ return 1<<numBits;
+}
+
+/************************************************************
+ * Opens a PortAudio stream with default characteristics.
+ * Allocates PABLIO_Stream structure.
+ * flags parameter can be an ORed combination of:
+ * PABLIO_READ, PABLIO_WRITE, or PABLIO_READ_WRITE */
+PaError PD_OpenAudioStream(PABLIO_Stream **rwblPtr, double sampleRate, PaSampleFormat format, int inchannels,
+int outchannels, int framesperbuf, int nbuffers, int indeviceno, int outdeviceno) {
+ long bytesPerSample;
+ long doRead = 0;
+ long doWrite = 0;
+ PaError err;
+ PABLIO_Stream *aStream;
+ long minNumBuffers;
+ long numFrames;
+#ifdef PA19
+ PaStreamParameters instreamparams, outstreamparams; /* MSP */
+#endif
+ /* post("open %lf fmt %d flags %d ch: %d fperbuf: %d nbuf: %d devs: %d %d",
+ sampleRate, format, flags, nchannels, framesperbuf, nbuffers, indeviceno, outdeviceno); */
+ if (indeviceno < 0) {
+#ifdef PA19
+ indeviceno = Pa_GetDefaultInputDevice();
+#else
+ indeviceno = Pa_GetDefaultInputDeviceID();
+#endif
+ if (indeviceno == paNoDevice) inchannels = 0;
+ post("using default input device number: %d", indeviceno);
+ }
+ if (outdeviceno<0) {
+#ifdef PA19
+ outdeviceno = Pa_GetDefaultOutputDevice();
+#else
+ outdeviceno = Pa_GetDefaultOutputDeviceID();
+#endif
+ if(outdeviceno == paNoDevice) outchannels = 0;
+ post("using default output device number: %d", outdeviceno);
+ }
+ /* post("nchan %d, flags %d, bufs %d, framesperbuf %d", nchannels, flags, nbuffers, framesperbuf); */
+ /* Allocate PABLIO_Stream structure for caller. */
+ aStream = (PABLIO_Stream *) malloc(sizeof(PABLIO_Stream));
+ if( aStream == NULL ) return paInsufficientMemory;
+ memset(aStream, 0, sizeof(PABLIO_Stream));
+ /* Determine size of a sample. */
+ bytesPerSample = Pa_GetSampleSize(format);
+ if (bytesPerSample<0) {err = (PaError) bytesPerSample; goto error;}
+ aStream-> insamplesPerFrame = inchannels; aStream-> inbytesPerFrame = bytesPerSample * aStream-> insamplesPerFrame;
+ aStream->outsamplesPerFrame = outchannels; aStream->outbytesPerFrame = bytesPerSample * aStream->outsamplesPerFrame;
+ err = Pa_Initialize();
+ if (err != paNoError) goto error;
+#ifdef PA19
+ numFrames = nbuffers * framesperbuf; /* ...MSP */
+ instreamparams.device = indeviceno; /* MSP... */
+ instreamparams.channelCount = inchannels;
+ instreamparams.sampleFormat = format;
+ instreamparams.suggestedLatency = nbuffers*framesperbuf/sampleRate;
+ instreamparams.hostApiSpecificStreamInfo = 0;
+ outstreamparams.device = outdeviceno;
+ outstreamparams.channelCount = outchannels;
+ outstreamparams.sampleFormat = format;
+ outstreamparams.suggestedLatency = nbuffers*framesperbuf/sampleRate;
+ outstreamparams.hostApiSpecificStreamInfo = 0; /* ... MSP */
+#else
+/* Warning: numFrames must be larger than amount of data processed per
+ interrupt inside PA to prevent glitches. */ /* MSP */
+ minNumBuffers = Pa_GetMinNumBuffers(framesperbuf, sampleRate);
+ if (minNumBuffers > nbuffers)
+ post("warning: number of buffers %d less than recommended minimum %d", (int)nbuffers, (int)minNumBuffers);
+#endif
+ numFrames = nbuffers * framesperbuf;
+ /* post("numFrames %d", numFrames); */
+ /* Initialize Ring Buffers */
+ doRead = (inchannels != 0);
+ doWrite = (outchannels != 0);
+ if(doRead) {
+ err = PABLIO_InitFIFO(&aStream->inFIFO, numFrames, aStream->inbytesPerFrame);
+ if (err != paNoError) goto error;
+ }
+ if(doWrite) {
+ long numBytes;
+ err = PABLIO_InitFIFO(&aStream->outFIFO, numFrames, aStream->outbytesPerFrame);
+ if (err != paNoError) goto error;
+ /* Make Write FIFO appear full initially. */
+ numBytes = PD_RingBuffer_GetWriteAvailable( &aStream->outFIFO );
+ PD_RingBuffer_AdvanceWriteIndex( &aStream->outFIFO, numBytes );
+ }
+
+/* Open a PortAudio stream that we will use to communicate with the underlying audio drivers. */
+#ifdef PA19
+ err = Pa_OpenStream(&aStream->stream, (doRead ? &instreamparams : 0), (doWrite ? &outstreamparams : 0),
+ sampleRate, framesperbuf, paNoFlag, blockingIOCallback, aStream);
+#else
+ err = Pa_OpenStream(&aStream->stream,
+ (doRead ? indeviceno : paNoDevice), (doRead ? aStream->insamplesPerFrame : 0 ), format, NULL,
+ (doWrite ? outdeviceno : paNoDevice), (doWrite ? aStream->outsamplesPerFrame : 0 ), format, NULL,
+ sampleRate, framesperbuf, nbuffers, paNoFlag, blockingIOCallback, aStream);
+#endif
+ if (err != paNoError) goto error;
+ err = Pa_StartStream( aStream->stream );
+ if (err != paNoError) {
+ error("Pa_StartStream failed; closing audio stream...");
+ PD_CloseAudioStream(aStream);
+ goto error;
+ }
+ *rwblPtr = aStream;
+ return paNoError;
+error:
+ *rwblPtr = NULL;
+ return err;
+}
+
+/************************************************************/
+PaError PD_CloseAudioStream(PABLIO_Stream *aStream) {
+ PaError err;
+ int bytesEmpty;
+ int byteSize = aStream->outFIFO.bufferSize;
+ /* If we are writing data, make sure we play everything written. */
+ if (byteSize>0) {
+ bytesEmpty = PD_RingBuffer_GetWriteAvailable( &aStream->outFIFO );
+ while (bytesEmpty<byteSize) {
+ NPa_Sleep( 10 ); /* MSP */
+ bytesEmpty = PD_RingBuffer_GetWriteAvailable( &aStream->outFIFO );
+ }
+ }
+ err = Pa_StopStream(aStream->stream); if(err != paNoError) goto error;
+ err = Pa_CloseStream(aStream->stream); if(err != paNoError) goto error;
+ Pa_Terminate();
+error:
+ PABLIO_TermFIFO(&aStream->inFIFO);
+ PABLIO_TermFIFO(&aStream->outFIFO);
+ free(aStream);
+ return err;
+}
diff --git a/desiredata/src/s_audio_pablio.h b/desiredata/src/s_audio_pablio.h
new file mode 100644
index 00000000..1a1ecb8d
--- /dev/null
+++ b/desiredata/src/s_audio_pablio.h
@@ -0,0 +1,112 @@
+#ifndef _PD_PABLIO_H
+#define _PD_PABLIO_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+/*
+ * $Id: s_audio_pablio.h,v 1.1.4.1.2.3 2006-01-24 01:29:54 xovo Exp $
+ * PABLIO.h
+ * Portable Audio Blocking read/write utility.
+ *
+ * Author: Phil Burk, http://www.softsynth.com/portaudio/
+ *
+ * Include file for PABLIO, the Portable Audio Blocking I/O Library.
+ * PABLIO is built on top of PortAudio, the Portable Audio Library.
+ * For more information see: http://www.audiomulch.com/portaudio/
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <portaudio.h>
+#include "s_audio_paring.h"
+#include <string.h>
+
+typedef struct
+{
+ RingBuffer inFIFO;
+ RingBuffer outFIFO;
+ PaStream *stream;
+ int inbytesPerFrame;
+ int insamplesPerFrame;
+ int outbytesPerFrame;
+ int outsamplesPerFrame;
+}
+PABLIO_Stream;
+
+/* Values for flags for OpenAudioStream(). */
+#define PABLIO_READ (1<<0)
+#define PABLIO_WRITE (1<<1)
+#define PABLIO_READ_WRITE (PABLIO_READ|PABLIO_WRITE)
+#define PABLIO_MONO (1<<2)
+#define PABLIO_STEREO (1<<3)
+
+/************************************************************
+ * Write data to ring buffer.
+ * Will not return until all the data has been written.
+ */
+long PD_WriteAudioStream( PABLIO_Stream *aStream, void *data, long numFrames );
+
+/************************************************************
+ * Read data from ring buffer.
+ * Will not return until all the data has been read.
+ */
+long PD_ReadAudioStream( PABLIO_Stream *aStream, void *data, long numFrames );
+
+/************************************************************
+ * Return the number of frames that could be written to the stream without
+ * having to wait.
+ */
+long PD_GetAudioStreamWriteable( PABLIO_Stream *aStream );
+
+/************************************************************
+ * Return the number of frames that are available to be read from the
+ * stream without having to wait.
+ */
+long PD_GetAudioStreamReadable( PABLIO_Stream *aStream );
+
+/************************************************************
+ * Opens a PortAudio stream with default characteristics.
+ * Allocates PABLIO_Stream structure.
+ *
+ * flags parameter can be an ORed combination of:
+ * PABLIO_READ, PABLIO_WRITE, or PABLIO_READ_WRITE,
+ */
+PaError PD_OpenAudioStream( PABLIO_Stream **rwblPtr, double sampleRate,
+ PaSampleFormat format, int inchannels,
+ int outchannels, int framesperbuf, int nbuffers,
+ int indeviceno, int outdeviceno); /* MSP */
+
+PaError PD_CloseAudioStream( PABLIO_Stream *aStream );
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* _PD_PABLIO_H */
diff --git a/desiredata/src/s_audio_paring.c b/desiredata/src/s_audio_paring.c
new file mode 100644
index 00000000..dcdcce0e
--- /dev/null
+++ b/desiredata/src/s_audio_paring.c
@@ -0,0 +1,172 @@
+/*
+ * $Id: s_audio_paring.c,v 1.1.4.1.2.1.2.1 2007-07-31 00:10:37 matju Exp $
+ * ringbuffer.c
+ * Ring Buffer utility..
+ *
+ * Author: Phil Burk, http://www.softsynth.com
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.audiomulch.com/portaudio/
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+/*
+ * modified 2002/07/13 by olaf.matthes@gmx.de to allow any number if channels
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include "s_audio_paring.h"
+#include <string.h>
+
+/* Initialize FIFO. */
+long PD_RingBuffer_Init(RingBuffer *rbuf, long numBytes, void *dataPtr) {
+ rbuf->bufferSize = numBytes;
+ rbuf->buffer = (char *)dataPtr;
+ PD_RingBuffer_Flush( rbuf );
+ return 0;
+}
+/***************************************************************************
+** Return number of bytes available for reading. */
+long PD_RingBuffer_GetReadAvailable(RingBuffer *rbuf) {
+ long ret = rbuf->writeIndex - rbuf->readIndex;
+ if (ret < 0) ret += 2 * rbuf->bufferSize;
+ if (ret < 0 || ret > rbuf->bufferSize) error("consistency check failed: PD_RingBuffer_GetReadAvailable");
+ return ret;
+}
+/* Return number of bytes available for writing. */
+long PD_RingBuffer_GetWriteAvailable(RingBuffer *rbuf) {
+ return rbuf->bufferSize - PD_RingBuffer_GetReadAvailable(rbuf);
+}
+
+/* Clear buffer. Should only be called when buffer is NOT being read. */
+void PD_RingBuffer_Flush(RingBuffer *rbuf) {
+ rbuf->writeIndex = rbuf->readIndex = 0;
+}
+
+/* Get address of region(s) to which we can write data. If the region is contiguous, size2 will be zero.
+ If non-contiguous, size2 will be the size of second region.
+ Returns room available to be written or numBytes, whichever is smaller. */
+long PD_RingBuffer_GetWriteRegions(RingBuffer *rbuf, long numBytes,
+void **dataPtr1, long *sizePtr1, void **dataPtr2, long *sizePtr2) {
+ long index;
+ long available = PD_RingBuffer_GetWriteAvailable(rbuf);
+ if (numBytes > available) numBytes = available;
+ /* Check to see if write is not contiguous. */
+ index = rbuf->writeIndex;
+ while (index >= rbuf->bufferSize) index -= rbuf->bufferSize;
+ if ((index + numBytes) > rbuf->bufferSize) {
+ /* Write data in two blocks that wrap the buffer. */
+ long firstHalf = rbuf->bufferSize - index;
+ *dataPtr1 = &rbuf->buffer[index];
+ *sizePtr1 = firstHalf;
+ *dataPtr2 = &rbuf->buffer[0];
+ *sizePtr2 = numBytes - firstHalf;
+ } else {
+ *dataPtr1 = &rbuf->buffer[index];
+ *sizePtr1 = numBytes;
+ *dataPtr2 = NULL;
+ *sizePtr2 = 0;
+ }
+ return numBytes;
+}
+
+
+/***************************************************************************
+*/
+long PD_RingBuffer_AdvanceWriteIndex(RingBuffer *rbuf, long numBytes) {
+ long ret = rbuf->writeIndex + numBytes;
+ if (ret >= 2 * rbuf->bufferSize) ret -= 2 * rbuf->bufferSize; /* check for end of buffer */
+ return rbuf->writeIndex = ret;
+}
+
+/***************************************************************************
+** Get address of region(s) from which we can read data.
+** If the region is contiguous, size2 will be zero.
+** If non-contiguous, size2 will be the size of second region.
+** Returns room available to be written or numBytes, whichever is smaller.
+*/
+long PD_RingBuffer_GetReadRegions(RingBuffer *rbuf, long numBytes,
+void **dataPtr1, long *sizePtr1, void **dataPtr2, long *sizePtr2) {
+ long index;
+ long available = PD_RingBuffer_GetReadAvailable(rbuf);
+ if (numBytes > available) numBytes = available;
+ /* Check to see if read is not contiguous. */
+ index = rbuf->readIndex;
+ while (index >= rbuf->bufferSize) index -= rbuf->bufferSize;
+ if ((index + numBytes) > rbuf->bufferSize) {
+ /* Write data in two blocks that wrap the buffer. */
+ long firstHalf = rbuf->bufferSize - index;
+ *dataPtr1 = &rbuf->buffer[index];
+ *sizePtr1 = firstHalf;
+ *dataPtr2 = &rbuf->buffer[0];
+ *sizePtr2 = numBytes - firstHalf;
+ } else {
+ *dataPtr1 = &rbuf->buffer[index];
+ *sizePtr1 = numBytes;
+ *dataPtr2 = NULL;
+ *sizePtr2 = 0;
+ }
+ return numBytes;
+}
+
+long PD_RingBuffer_AdvanceReadIndex( RingBuffer *rbuf, long numBytes ) {
+ long ret = (rbuf->readIndex + numBytes);
+ if( ret >= 2 * rbuf->bufferSize) ret -= 2 * rbuf->bufferSize;
+ return rbuf->readIndex = ret;
+}
+
+/* Return bytes written. */
+long PD_RingBuffer_Write(RingBuffer *rbuf, const void *data, long numBytes) {
+ long size1, size2, numWritten;
+ void *data1, *data2;
+ numWritten = PD_RingBuffer_GetWriteRegions( rbuf, numBytes, &data1, &size1, &data2, &size2 );
+ if (size2 > 0) {
+ memcpy(data1, data, size1);
+ data = ((char *)data) + size1;
+ memcpy(data2, data, size2);
+ } else {
+ memcpy(data1, data, size1);
+ }
+ PD_RingBuffer_AdvanceWriteIndex( rbuf, numWritten );
+ return numWritten;
+}
+
+/* Return bytes read. */
+long PD_RingBuffer_Read(RingBuffer *rbuf, void *data, long numBytes) {
+ long size1, size2, numRead;
+ void *data1, *data2;
+ numRead = PD_RingBuffer_GetReadRegions( rbuf, numBytes, &data1, &size1, &data2, &size2 );
+ if (size2 > 0) {
+ memcpy(data, data1, size1);
+ data = ((char *)data) + size1;
+ memcpy(data, data2, size2);
+ } else {
+ memcpy(data, data1, size1);
+ }
+ PD_RingBuffer_AdvanceReadIndex( rbuf, numRead );
+ return numRead;
+}
diff --git a/desiredata/src/s_audio_paring.h b/desiredata/src/s_audio_paring.h
new file mode 100644
index 00000000..5415f64a
--- /dev/null
+++ b/desiredata/src/s_audio_paring.h
@@ -0,0 +1,101 @@
+#ifndef _PD_RINGBUFFER_H
+#define _PD_RINGBUFFER_H
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+/*
+ * $Id: s_audio_paring.h,v 1.1.4.1.2.3 2006-01-24 01:29:54 xovo Exp $
+ * ringbuffer.h
+ * Ring Buffer utility..
+ *
+ * Author: Phil Burk, http://www.softsynth.com
+ *
+ * This program is distributed with the PortAudio Portable Audio Library.
+ * For more information see: http://www.audiomulch.com/portaudio/
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+
+typedef struct
+{
+ long bufferSize; /* Number of bytes in FIFO. Power of 2. Set by RingBuffer_Init. */
+/* These are declared volatile because they are written by a different thread than the reader. */
+ volatile long writeIndex; /* Index of next writable byte. Set by RingBuffer_AdvanceWriteIndex. */
+ volatile long readIndex; /* Index of next readable byte. Set by RingBuffer_AdvanceReadIndex. */
+ long bigMask; /* Used for wrapping indices with extra bit to distinguish full/empty. */
+ long smallMask; /* Used for fitting indices to buffer. */
+ char *buffer;
+}
+RingBuffer;
+/*
+ * Initialize Ring Buffer.
+ * numBytes must be power of 2, returns -1 if not.
+ */
+long PD_RingBuffer_Init( RingBuffer *rbuf, long numBytes, void *dataPtr );
+
+/* Clear buffer. Should only be called when buffer is NOT being read. */
+void PD_RingBuffer_Flush( RingBuffer *rbuf );
+
+/* Return number of bytes available for writing. */
+long PD_RingBuffer_GetWriteAvailable( RingBuffer *rbuf );
+/* Return number of bytes available for read. */
+long PD_RingBuffer_GetReadAvailable( RingBuffer *rbuf );
+/* Return bytes written. */
+long PD_RingBuffer_Write( RingBuffer *rbuf, const void *data, long numBytes );
+/* Return bytes read. */
+long PD_RingBuffer_Read( RingBuffer *rbuf, void *data, long numBytes );
+
+/* Get address of region(s) to which we can write data.
+** If the region is contiguous, size2 will be zero.
+** If non-contiguous, size2 will be the size of second region.
+** Returns room available to be written or numBytes, whichever is smaller.
+*/
+long PD_RingBuffer_GetWriteRegions( RingBuffer *rbuf, long numBytes,
+ void **dataPtr1, long *sizePtr1,
+ void **dataPtr2, long *sizePtr2 );
+long PD_RingBuffer_AdvanceWriteIndex( RingBuffer *rbuf, long numBytes );
+
+/* Get address of region(s) from which we can read data.
+** If the region is contiguous, size2 will be zero.
+** If non-contiguous, size2 will be the size of second region.
+** Returns room available to be read or numBytes, whichever is smaller.
+*/
+long PD_RingBuffer_GetReadRegions( RingBuffer *rbuf, long numBytes,
+ void **dataPtr1, long *sizePtr1,
+ void **dataPtr2, long *sizePtr2 );
+
+long PD_RingBuffer_AdvanceReadIndex( RingBuffer *rbuf, long numBytes );
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* _PD_RINGBUFFER_H */
diff --git a/desiredata/src/s_audio_portaudio.c b/desiredata/src/s_audio_portaudio.c
new file mode 100755
index 00000000..05b11643
--- /dev/null
+++ b/desiredata/src/s_audio_portaudio.c
@@ -0,0 +1,416 @@
+/* Copyright (c) 2001 Miller Puckette and others.
+ * Copyright (c) 2005-2006 Tim Blechmann
+ * supported by vibrez.net
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* this file calls Ross Bencina's and Phil Burk's Portaudio package. It's
+ the main way in for Mac OS and, with Michael Casey's help, also into
+ ASIO in Windows. */
+
+/* tb: requires portaudio >= V19 */
+
+#include "m_pd.h"
+#include "s_stuff.h"
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <portaudio.h>
+#include <errno.h>
+#include "assert.h"
+#ifdef MSW
+# include <malloc.h>
+# include <pa_asio.h>
+#else
+# include <alloca.h>
+#endif
+#include "pthread.h"
+/* for M_PI */
+#if defined(_MSC_VER) && !defined(_USE_MATH_DEFINES)
+#define _USE_MATH_DEFINES
+#endif
+#include <math.h>
+#define MAX_PA_CHANS 32
+
+static int pa_inchans, pa_outchans;
+static int pa_blocksize;
+
+static PaStream *pa_stream;
+/* Initialize PortAudio */
+PaError pa_status = -1;
+int pa_initialized = 0;
+
+void pa_initialize() {
+// if (pa_initialized) return;
+ pa_status = Pa_Initialize();
+ if (pa_status!=paNoError) {
+ error("Error number %d occured initializing portaudio: %s", pa_status, Pa_GetErrorText(pa_status));
+ return;
+ }
+ pa_initialized = 1;
+}
+
+static float* pa_inbuffer[MAX_PA_CHANS];
+static float* pa_outbuffer[MAX_PA_CHANS];
+static int pa_bufferpos;
+static int pddev2padev(int pdindev,int isinput);
+static int padev2pddev(int padev,int isinput);
+int process (const void *input, void *output, unsigned long frameCount, const PaStreamCallbackTimeInfo* timeInfo,
+ PaStreamCallbackFlags statusFlags, void *userData);
+
+static int pa_indev = -1, pa_outdev = -1;
+
+int pa_open_audio(int inchans, int outchans, int rate, int advance,
+int indeviceno, int outdeviceno, int schedmode) {
+ PaError err;
+ const PaDeviceInfo *pdi,*pdo;
+ schedmode = 1; /* we don't support blocking io */
+ pa_initialize();
+ sys_setscheduler(schedmode);
+ /* post("in %d out %d rate %d device %d", inchans, outchans, rate, deviceno); */
+ if ( inchans > MAX_PA_CHANS) {post( "input channels reduced to maximum %d", MAX_PA_CHANS); inchans = MAX_PA_CHANS;}
+ if (outchans > MAX_PA_CHANS) {post("output channels reduced to maximum %d", MAX_PA_CHANS); outchans = MAX_PA_CHANS;}
+ pdi = NULL;
+ if (inchans > 0) {
+ pa_indev = pddev2padev(indeviceno,1);
+ if(pa_indev >= 0) {
+ pdi = Pa_GetDeviceInfo(pa_indev);
+ if(pdi->maxInputChannels < inchans) inchans = pdi->maxInputChannels;
+ }
+ }
+ pdo = NULL;
+ if (outchans > 0) {
+ pa_outdev = pddev2padev(outdeviceno,0);
+ if(pa_outdev >= 0) {
+ pdo = Pa_GetDeviceInfo(pa_outdev);
+ if(pdo->maxOutputChannels < outchans) outchans = pdo->maxOutputChannels;
+ }
+ }
+ if (sys_verbose) {
+ post("input device %d, channels %d", pa_indev, inchans);
+ post("output device %d, channels %d", pa_outdev, outchans);
+ post("latency advance %d", advance);
+ }
+ if (inchans || outchans) {
+ int blocksize;
+ PaStreamParameters iparam,oparam;
+ /* initialize input */
+ iparam.device = pa_indev;
+ iparam.channelCount = inchans;
+ iparam.sampleFormat = paFloat32 | paNonInterleaved;
+ iparam.suggestedLatency = advance * 0.001;
+ iparam.hostApiSpecificStreamInfo = NULL;
+ /* initialize output */
+ oparam.device = pa_outdev;
+ oparam.channelCount = outchans;
+ oparam.sampleFormat = paFloat32 | paNonInterleaved;
+ oparam.suggestedLatency = advance * 0.001;
+ oparam.hostApiSpecificStreamInfo = NULL;
+ /* set block size */
+ blocksize=64;
+ while ((float)blocksize/(float)rate*1000*2 < advance && blocksize==1024) blocksize *= 2;
+ pa_blocksize = blocksize;
+ /* initialize io buffer */
+ for (int j=0; j != MAX_PA_CHANS;++j) {
+ if (pa_inbuffer[j]) freealignedbytes(pa_inbuffer[j], 0);
+ if (pa_outbuffer[j]) freealignedbytes(pa_outbuffer[j], 0);
+ pa_inbuffer[j] = (float *)getalignedbytes((blocksize + sys_dacblocksize)*sizeof(float));
+ pa_outbuffer[j] = (float *)getalignedbytes((blocksize + sys_dacblocksize)*sizeof(float));
+ }
+ pa_bufferpos = 0;
+ /* report to portaudio */
+ err = Pa_OpenStream(&pa_stream,
+ (( pa_indev!=-1) ? &iparam : 0),
+ ((pa_outdev!=-1) ? &oparam : 0),
+ rate, pa_blocksize, paClipOff, /* tb: we should be faster ;-) */ process /* patestCallback */, NULL);
+ if (err == paNoError) {
+ const PaStreamInfo *streaminfo = Pa_GetStreamInfo(pa_stream);
+ t_atom atoms[4];
+ t_symbol *pd = gensym("pd");
+ t_symbol *selector1 = gensym("audiocurrentininfo");
+ t_symbol *selector2 = gensym("audiocurrentoutinfo");
+ sys_schedadvance = int(1e-6 * streaminfo->outputLatency);
+
+ SETFLOAT(atoms, (float)indeviceno);
+ SETFLOAT(atoms+1, (float)inchans);
+ SETFLOAT(atoms+2, (float)rate);
+ SETFLOAT(atoms+3, (float)streaminfo->inputLatency * 1000.f);
+ typedmess(pd->s_thing, selector1, 4, atoms);
+
+ SETFLOAT(atoms, (float)outdeviceno);
+ SETFLOAT(atoms+1, (float)outchans);
+ SETFLOAT(atoms+2, (float)rate);
+ SETFLOAT(atoms+3, (float)streaminfo->outputLatency * 1000.f);
+ typedmess(pd->s_thing, selector2, 4, atoms);
+ }
+ } else err = 0;
+
+ if (err != paNoError) {
+ error("Error number %d occured opening portaudio stream: %s", err, Pa_GetErrorText(err));
+ sys_inchannels = sys_outchannels = 0;
+ pa_indev = pa_outdev = -1;
+ pa_inchans = pa_outchans = 0;
+ return 1;
+ } else if (sys_verbose) post("... opened OK.");
+ pa_inchans = inchans;
+ pa_outchans = outchans;
+
+ /* we might have adapted the channel count */
+ sys_setchsr(inchans, outchans, rate, sys_dacblocksize);
+ err = Pa_StartStream(pa_stream);
+ if (err!=paNoError) {
+ post("Error number %d occured starting portaudio stream: %s", err, Pa_GetErrorText(err));
+ sys_inchannels = sys_outchannels = 0;
+ return 1;
+ }
+ if(sys_verbose) post("successfully started");
+ return 0;
+}
+
+void sys_peakmeters();
+extern int sys_meters; /* true if we're metering */
+
+void run_all_idle_callbacks();
+void sys_xrun_notification(); /* in m_sched.c */
+void sys_lock_timeout_notification();
+
+int process (const void *input, void *output, unsigned long frameCount, const PaStreamCallbackTimeInfo* timeInfo,
+PaStreamCallbackFlags statusFlags, void *userData) {
+ int timeout = int((float)frameCount / (float) sys_dacsr * 1e6);
+ if (statusFlags) sys_xrun_notification();
+ if (sys_timedlock(timeout) == ETIMEDOUT) /* we're late */ {
+ sys_lock_timeout_notification();
+ return 0;
+ }
+ for (int i=0; (unsigned)i < frameCount / sys_dacblocksize; ++i) {
+ for (int j=0; j < sys_inchannels; j++) {
+ t_sample *in = ((t_sample**)input)[j] + i * sys_dacblocksize;
+ copyvec(sys_soundin + j * sys_dacblocksize, in, sys_dacblocksize);
+ }
+ sched_tick(sys_time + sys_time_per_dsp_tick);
+ for (int j=0; j < sys_outchannels; j++) {
+ t_sample *out = ((t_sample**)output)[j] + i * sys_dacblocksize;
+ copyvec(out, sys_soundout + j * sys_dacblocksize, sys_dacblocksize);
+ }
+ if (sys_meters) sys_peakmeters();
+ zerovec(sys_soundout, pa_outchans * sys_dacblocksize);
+ }
+ run_all_idle_callbacks();
+ sys_unlock();
+ return 0;
+}
+
+void pa_close_audio() {
+ if(sys_verbose) post("closing portaudio");
+ if (pa_inchans || pa_outchans) {
+ if (pa_stream) {
+ int status = Pa_StopStream(pa_stream);
+ if (status) post("error closing audio: %d", status);
+ Pa_CloseStream(pa_stream);
+ pa_stream = NULL;
+ }
+ }
+ sys_setscheduler(0);
+ if(sys_verbose) post("portaudio closed");
+ pa_inchans = pa_outchans = 0;
+ pa_indev = pa_outdev = -1;
+}
+
+/* for blocked IO */
+int pa_send_dacs() {
+ /* we don't support blocking i/o */
+ return SENDDACS_NO;
+}
+
+/* lifted from pa_devs.c in portaudio */
+void pa_listdevs() {
+ PaError err;
+ pa_initialize();
+ int numDevices = Pa_GetDeviceCount();
+ if(numDevices < 0) {
+ error("ERROR: Pa_GetDeviceCount returned %d", numDevices);
+ err = numDevices;
+ goto error;
+ }
+ post("Audio Devices:");
+ for(int i=0; i<numDevices; i++) {
+ const PaDeviceInfo *pdi = Pa_GetDeviceInfo(i);
+ post ("device %s", pdi->name);
+ post("device %d:", i+1);
+ post(" %s;", pdi->name);
+ post("%d inputs, ", pdi->maxInputChannels);
+ post("%d outputs ", pdi->maxOutputChannels);
+ if (i == Pa_GetDefaultInputDevice()) post(" (Default Input)");
+ if (i == Pa_GetDefaultOutputDevice()) post(" (Default Output)");
+ post("");
+ }
+ post("");
+ return;
+ error:
+ error("Error #%d occurred while using the portaudio stream: %s\n", err, Pa_GetErrorText(err));
+}
+
+/* scanning for devices */
+void pa_getdevs(char *indevlist, int *nindevs, char *outdevlist, int *noutdevs, int *canmulti, int maxndev, int devdescsize) {
+ int nin = 0, nout = 0, ndev;
+ *canmulti = 1; /* one dev each for input and output */
+ pa_initialize();
+ ndev = Pa_GetDeviceCount();
+ for (int i=0; i<ndev; i++) {
+ const PaDeviceInfo *pdi = Pa_GetDeviceInfo(i);
+ if (pdi->maxInputChannels > 0 && nin < maxndev) {
+ PaHostApiIndex api = pdi->hostApi;
+ const PaHostApiInfo *info = Pa_GetHostApiInfo(api);
+ const char *apiName = info->name;
+ unsigned int apiNameLen = strlen(apiName);
+ strcpy(indevlist + nin * devdescsize, apiName);
+ indevlist[nin * devdescsize + apiNameLen] = '/';
+ strcpy(indevlist + nin * devdescsize + apiNameLen + 1, pdi->name);
+ nin++;
+ }
+ if (pdi->maxOutputChannels > 0 && nout < maxndev) {
+ PaHostApiIndex api = pdi->hostApi;
+ const PaHostApiInfo *info = Pa_GetHostApiInfo(api);
+ const char *apiName = info->name;
+ unsigned int apiNameLen = strlen(apiName);
+ strcpy(outdevlist + nout * devdescsize, apiName);
+ outdevlist[nout * devdescsize + apiNameLen] = '/';
+ strcpy(outdevlist + nout * devdescsize + apiNameLen + 1, pdi->name);
+ nout++;
+ }
+ }
+ *nindevs = nin;
+ *noutdevs = nout;
+}
+
+void pa_getaudioininfo(t_float f) {
+ int i = pddev2padev((int)f,1);
+ const PaDeviceInfo *pdi;
+ pa_initialize();
+ pdi = Pa_GetDeviceInfo(i);
+ if (pdi) {
+ t_symbol *selector = gensym("audioininfo");
+ t_symbol *pd = gensym("pd");
+ t_atom argv[4];
+ SETFLOAT(argv, pdi->maxInputChannels);
+ SETFLOAT(argv+1, pdi->defaultSampleRate);
+ SETFLOAT(argv+2, pdi->defaultLowInputLatency*1000.f);
+ SETFLOAT(argv+3, pdi->defaultHighInputLatency*1000.f);
+ typedmess(pd->s_thing, selector, 4, argv);
+ }
+}
+
+void pa_getaudiooutinfo(t_float f) {
+ int i = pddev2padev((int)f,0);
+ const PaDeviceInfo *pdi;
+ pa_initialize();
+ pdi = Pa_GetDeviceInfo(i);
+ if (pdi) {
+ t_symbol *selector = gensym("audiooutinfo");
+ t_symbol *pd = gensym("pd");
+ t_atom argv[4];
+ SETFLOAT(argv, pdi->maxOutputChannels);
+ SETFLOAT(argv+1, pdi->defaultSampleRate);
+ SETFLOAT(argv+2, pdi->defaultLowOutputLatency*1000.f);
+ SETFLOAT(argv+3, pdi->defaultHighOutputLatency*1000.f);
+ typedmess(pd->s_thing, selector, 4, argv);
+ }
+}
+
+void pa_getcurrent_devices() {
+ t_symbol *pd = gensym("pd");
+ t_symbol *selector = gensym("audiodevice");
+ t_atom argv[2];
+ SETFLOAT(argv, padev2pddev(pa_indev,1));
+ SETFLOAT(argv+1, padev2pddev(pa_outdev,0));
+ typedmess(pd->s_thing, selector, 2, argv);
+}
+
+void pa_test_setting (int ac, t_atom *av) {
+ int indev = atom_getintarg(0, ac, av);
+ int outdev = atom_getintarg(1, ac, av);
+ int samplerate = atom_getintarg(2, ac, av);
+ int inchans = atom_getintarg(3, ac, av);
+ int outchans = atom_getintarg(4, ac, av);
+ int advance = atom_getintarg(5, ac, av);
+ t_symbol *pd = gensym("pd");
+ t_symbol *selector = gensym("testaudiosettingresult");
+ t_atom argv[1];
+ pa_initialize();
+ indev = pddev2padev(indev,1);
+ outdev = pddev2padev(outdev,0);
+ if (pa_indev==-1 && pa_outdev==-1) {
+ int ret;
+ PaStreamParameters iparam, oparam;
+ iparam.device = indev;
+ iparam.channelCount = inchans;
+ iparam.sampleFormat = paFloat32 | paNonInterleaved;
+ iparam.suggestedLatency = advance * 0.001;
+ iparam.hostApiSpecificStreamInfo = NULL;
+ oparam.device = outdev;
+ oparam.channelCount = outchans;
+ oparam.sampleFormat = paFloat32 | paNonInterleaved;
+ oparam.suggestedLatency = advance * 0.001;
+ oparam.hostApiSpecificStreamInfo = NULL;
+ ret = Pa_IsFormatSupported(&iparam, &oparam, samplerate);
+ SETFLOAT(argv, ret == paNoError?1:0);
+ typedmess(pd->s_thing, selector, 1, argv);
+ }
+}
+
+static int pddev2padev(int pddev,int input) {
+ pa_initialize();
+ for (int j=0, devno=0; j < Pa_GetDeviceCount(); j++) {
+ const PaDeviceInfo *info = Pa_GetDeviceInfo(j);
+ int maxchans = input?info->maxInputChannels:info->maxOutputChannels;
+ if (maxchans > 0) {
+ if (devno == pddev) return j;
+ devno++;
+ }
+ }
+ return -1;
+}
+
+static int padev2pddev(int padev,int input) {
+ int count = Pa_GetDeviceCount();
+ for (int j=0, devno=0; j < count; j++) {
+ const PaDeviceInfo *info = Pa_GetDeviceInfo(j);
+ int chans = input?info->maxInputChannels:info->maxOutputChannels;
+ if (chans > 0) {
+ if(j == padev) return devno;
+ devno++;
+ }
+ }
+ return -1; // no found
+}
+
+void pa_get_asio_latencies(t_float f) {
+ int index = pddev2padev((int)f,0);
+ const PaDeviceInfo *pdi = Pa_GetDeviceInfo(index);
+ const PaHostApiInfo *phi = Pa_GetHostApiInfo(pdi->hostApi);
+ if (phi->type != paASIO) {
+ post("device not an asio device");
+ return;
+ }
+#ifdef WIN32
+ else {
+ long minlat, maxlat, preflat, gran;
+ t_atom argv[4];
+ t_symbol *selector = gensym("asiolatency");
+ t_symbol *pd = gensym("pd");
+ PaAsio_GetAvailableLatencyValues(index, &minlat, &maxlat, &preflat, &gran);
+ SETFLOAT(argv, (float) minlat);
+ SETFLOAT(argv + 1, (float) maxlat);
+ SETFLOAT(argv + 2, (float) preflat);
+ SETFLOAT(argv + 3, (float) gran);
+ typedmess(pd->s_thing, selector, 4, argv);
+ }
+#endif
+}
+
+t_audioapi pa_api = {
+ 0 /* pa_open_audio */,
+ pa_close_audio,
+ pa_send_dacs,
+ pa_getdevs,
+};
diff --git a/desiredata/src/s_audio_sgi.c b/desiredata/src/s_audio_sgi.c
new file mode 100644
index 00000000..878cf255
--- /dev/null
+++ b/desiredata/src/s_audio_sgi.c
@@ -0,0 +1,313 @@
+/* ----------------------- Experimental routines for SGI -------------- */
+/* written by Olaf Matthes <olaf.matthes@gmx.de> */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <m_pd.h>
+#include <s_stuff.h>
+
+#include <dmedia/audio.h>
+#include <dmedia/midi.h>
+#include <sys/fpu.h>
+#include <errno.h>
+
+#define SGI_MAXDEV 4 /* it's just 3, but default counts as well... */
+#define SGI_MAXCH 12 /* max. number of channels - is this enough? */
+
+static ALport sgi_iport[SGI_MAXDEV];
+static ALport sgi_oport[SGI_MAXDEV];
+static ALconfig sgi_inconfig;
+static ALconfig sgi_outconfig;
+static int sgi_nindevs, sgi_noutdevs;
+static int sgi_inchannels, sgi_outchannels;
+static int sgi_ninchans[SGI_MAXDEV], sgi_noutchans[SGI_MAXDEV];
+
+/* set the special "flush zero" but (FS, bit 24) in the Control Status Register of the FPU of R4k and beyond
+ so that the result of any underflowing operation will be clamped to zero, and no exception of any kind will
+ be generated on the CPU. thanks to cpirazzi@cp.esd.sgi.com (Chris Pirazzi). */
+static void sgi_flush_all_underflows_to_zero () {
+ union fpc_csr f;
+ f.fc_word = get_fpc_csr();
+ f.fc_struct.flush = 1;
+ set_fpc_csr(f.fc_word);
+}
+
+/* convert the most common errors into readable strings */
+static char *sgi_get_error_message(int err) {
+ switch (err) {
+ case AL_BAD_CONFIG: return "Invalid config";
+ case AL_BAD_DIRECTION: return "Invalid direction (neither \"r\" nor \"w\")";
+ case AL_BAD_OUT_OF_MEM: return "Not enough memory";
+ case AL_BAD_DEVICE_ACCESS: return "Audio hardware is not available or is improperly configured";
+ case AL_BAD_DEVICE: return "Invalid device";
+ case AL_BAD_NO_PORTS: return "No audio ports available";
+ case AL_BAD_QSIZE: return "Invalid fifo size";
+ case AL_BAD_SAMPFMT: return "Invalid sample format";
+ case AL_BAD_FLOATMAX: return "Invalid float maximum";
+ case AL_BAD_WIDTH: return "Invalid sample width";
+ default: return "Unknown error";
+ }
+}
+
+int sgi_open_audio(int nindev, int *indev, int nchin, int *chin,
+int noutdev, int *outdev, int nchout, int *chout, int rate/*, int dummy*/) {
+ ALpv pvbuf[2];
+ int num_devs = 0;
+ int in_dev = 0;
+ int out_dev = 0;
+ int inchans = 0;
+ int outchans = 0;
+ int err, n, gotchannels;
+ char *indevnames[4] = {"DefaultIn", "AnalogIn", "AESIn", "ADATIn"};
+ char *outdevnames[4] = {"DefaultOut", "AnalogOut", "AESOut", "ADATOut"};
+ sgi_flush_all_underflows_to_zero();
+ if (sys_verbose) post("opening sound input...");
+ for (n = 0; n < nindev; n++) {
+ int gotchannels = 0;
+ if (indev[n] >= 0 && indev[n] < SGI_MAXDEV) {
+ if (sys_verbose) post("opening %s", indevnames[indev[n]]);
+ in_dev = alGetResourceByName(AL_SYSTEM, indevnames[indev[n]], AL_DEVICE_TYPE);
+ } else {
+ if(sys_verbose)post("opening %s", indevnames[0]);
+ in_dev = AL_DEFAULT_INPUT;
+ }
+ if (!in_dev) {
+ error("%s", sgi_get_error_message(in_dev));
+ continue; /* try next device, if any */
+ }
+ sgi_inconfig = alNewConfig();
+ alSetSampFmt(sgi_inconfig, AL_SAMPFMT_FLOAT);
+ alSetFloatMax(sgi_outconfig, 1.1f);
+ alSetChannels(sgi_outconfig, chin[n]);
+ alSetQueueSize(sgi_inconfig, sys_advance_samples * chin[n]);
+ alSetDevice(sgi_inconfig, in_dev);
+ sgi_iport[n] = alOpenPort("Pd input port", "r", sgi_inconfig);
+ if (!sgi_iport[n]) error("failed to open audio read port");
+ /* try to set samplerate */
+ pvbuf[0].param = AL_RATE;
+ pvbuf[0].value.ll = alDoubleToFixed(rate);
+ if ((err = alSetParams(in_dev, pvbuf, 1)) < 0) {
+ post("could not set specified sample rate for input (%s)", sgi_get_error_message(err));
+ if(pvbuf[0].sizeOut < 0) post("rate was invalid");
+ }
+ /* check how many channels we actually got */
+ pvbuf[0].param = AL_CHANNELS;
+ if (alGetParams(in_dev, pvbuf, 1) < 0) {
+ post("could not figure out how many input channels we got");
+ gotchannels = chin[n]; /* assume we got them all */
+ } else {
+ gotchannels = pvbuf[0].value.i;
+ }
+ inchans += gotchannels; /* count total number of channels */
+ sgi_ninchans[n] = gotchannels; /* remember channels for this device */
+ }
+ if (sys_verbose) post("opening sound output...");
+ for (n = 0; n < noutdev; n++) {
+ if (outdev[n] >= 0 && outdev[n] < SGI_MAXDEV) {
+ if(sys_verbose)post("opening %s", outdevnames[outdev[n]]);
+ out_dev = alGetResourceByName(AL_SYSTEM, outdevnames[outdev[n]], AL_DEVICE_TYPE);
+ } else {
+ if (sys_verbose) post("opening %s", outdevnames[0]);
+ out_dev = AL_DEFAULT_OUTPUT;
+ }
+ if (!out_dev) {
+ error("%s", sgi_get_error_message(out_dev));
+ continue; /* try next device, if any */
+ }
+ /* configure the port before opening it */
+ sgi_outconfig = alNewConfig();
+ alSetSampFmt(sgi_outconfig, AL_SAMPFMT_FLOAT);
+ alSetFloatMax(sgi_outconfig, 1.1f);
+ alSetChannels(sgi_outconfig, chout[n]);
+ alSetQueueSize(sgi_outconfig, sys_advance_samples * chout[n]);
+ alSetDevice(sgi_outconfig, out_dev);
+ /* open the port */
+ sgi_oport[n] = alOpenPort("Pd ouput port", "w", sgi_outconfig);
+ if (!sgi_oport[n]) error("failed to open audio write port");
+ /* now try to set sample rate */
+ pvbuf[0].param = AL_RATE;
+ pvbuf[0].value.ll = alDoubleToFixed(rate);
+ if ((err = alSetParams(out_dev, pvbuf, 1)) < 0) {
+ post("could not set specified sample rate for output (%s)", sgi_get_error_message(err));
+ if(pvbuf[0].sizeOut < 0) post("rate was invalid");
+ }
+ /* check how many channels we actually got */
+ pvbuf[0].param = AL_CHANNELS;
+ if (alGetParams(out_dev, pvbuf, 1) < 0) {
+ post("could not figure out how many output channels we got");
+ gotchannels = chout[n];
+ } else {
+ gotchannels = pvbuf[0].value.i;
+ }
+ outchans += gotchannels;
+ sgi_noutchans[n] = gotchannels;
+ }
+ sgi_noutdevs = noutdev;
+ sgi_nindevs = nindev;
+ sgi_inchannels = inchans;
+ sgi_outchannels = outchans;
+ return !(inchans || outchans);
+}
+
+void sgi_close_audio() {
+ int err, n;
+ for (n = 0; n < sgi_nindevs; n++) {
+ if (sgi_iport[n]) {
+ err = alClosePort(sgi_iport[n]);
+ if (err < 0) error("closing input %d: %s (%d)", n + 1, alGetErrorString(oserror()), err);
+ }
+ }
+ for (n = 0; n < sgi_noutdevs; n++) {
+ if (sgi_oport[n]) {
+ err = alClosePort(sgi_oport[n]);
+ if (err < 0) error("closing output %d: %s (%d)", n + 1, alGetErrorString(oserror()), err);
+ }
+ }
+}
+
+/* call this only if both input and output are open */
+static void sgi_checkiosync() {
+// int i, result, checkit = 1, giveup = 1000, alreadylogged = 0;
+// long indelay, outdelay, defect;
+// if (!(sgi_outchannels && sgi_inchannels)) return;
+}
+
+int sgi_send_dacs() {
+ float buf[SGI_MAXCH * sys_dacblocksize], *fp1, *fp2, *fp3, *fp4;
+ static int xferno = 0;
+ static int callno = 0;
+ static double timenow;
+ double timelast;
+ int inchannels = min(sys_inchannels, sgi_inchannels);
+ int outchannels = min(sys_outchannels,sgi_outchannels);
+ long outfill[SGI_MAXDEV], infill[SGI_MAXDEV];
+ int outdevchannels, indevchannels;
+ int i, n, channel;
+ int result;
+ unsigned int outtransfersize = sys_dacblocksize;
+ unsigned int intransfersize = sys_dacblocksize;
+ /* no audio channels open, return */
+ if (!inchannels && !outchannels) return SENDDACS_NO;
+ timelast = timenow;
+ timenow = sys_getrealtime();
+#ifdef DEBUG_SGI_XFER
+ if (timenow - timelast > 0.050) post("(%d)", (int)(1000 * (timenow - timelast)));
+#endif
+ callno++;
+ sgi_checkiosync(); /* check I/O are in sync and data not late */
+ /* check whether there is enough space in buffers */
+ if (sgi_nindevs) {
+ for (n = 0; n < sgi_nindevs; n++) {
+ if (alGetFilled(sgi_iport[n]) < intransfersize)
+ return SENDDACS_NO;
+ }
+ }
+ if (sgi_noutdevs) {
+ for(n = 0; n < sgi_noutdevs; n++) {
+ if (alGetFillable(sgi_oport[n]) < outtransfersize)
+ return SENDDACS_NO;
+ }
+ }
+ /* output audio data, if we use audio out */
+ if (sgi_noutdevs) {
+ fp2 = sys_soundout; /* point to current output position in buffer */
+ for(n = 0; n < sgi_noutdevs; n++) {
+ outdevchannels = sgi_noutchans[n]; /* channels supported by this device */
+ for (channel = 0, fp1 = buf; channel < outdevchannels; channel++, fp1++, fp2 += sys_dacblocksize) {
+ for (i = 0, fp3 = fp1, fp4 = fp2; i < sys_dacblocksize; i++, fp3 += outdevchannels, fp4++) *fp3 = *fp4, *fp4 = 0;
+ }
+ alWriteFrames(sgi_oport[n], buf, sys_dacblocksize);
+ }
+ }
+ /* zero out the output buffer */
+ memset(sys_soundout, 0, sys_dacblocksize * sizeof(*sys_soundout) * sys_outchannels);
+ if (sys_getrealtime() - timenow > 0.002) {
+ #ifdef DEBUG_SGI_XFER
+ post("output %d took %d msec", callno, (int)(1000 * (timenow - timelast)));
+ #endif
+ timenow = sys_getrealtime();
+ sys_log_error(ERR_DACSLEPT);
+ }
+ /* get audio data from input, if we use audio in */
+ if (sgi_nindevs) {
+ fp2 = sys_soundin; /* point to current input position in buffer */
+ for (n = 0; n < sgi_nindevs; n++) {
+ indevchannels = sgi_ninchans[n]; /* channels supported by this device */
+ if (alGetFilled(sgi_iport[n]) > sys_dacblocksize) {
+ alReadFrames(sgi_iport[n], buf, sys_dacblocksize);
+ } else /* have to read but nothing's there... */ {
+ // if (sys_verbose) post("extra ADC buf");
+ /* set buffer to silence */
+ memset(buf, 0, intransfersize * sizeof(*sys_soundout) * sgi_ninchans[n]);
+ }
+ for (channel = 0, fp1 = buf; channel < indevchannels; channel++, fp1++, fp2 += sys_dacblocksize) {
+ for (i = 0, fp3 = fp1, fp4 = fp2; i < sys_dacblocksize; i++, fp3 += indevchannels, fp4++) *fp4 = *fp3;
+ }
+ }
+ }
+ xferno++;
+ if (sys_getrealtime() - timenow > 0.002) {
+#ifdef DEBUG_SGI_XFER
+ post("routine took %d msec", int(1000 * (sys_getrealtime() - timenow)));
+#endif
+ sys_log_error(ERR_ADCSLEPT);
+ }
+ return SENDDACS_YES;
+}
+
+void sgi_getdevs(char *indevlist, int *nindevs, char *outdevlist, int *noutdevs, int *canmulti, int maxndev, int devdescsize) {
+#if 0
+ ALpv pvs[1];
+ char name[32];
+ int i, ndev, err;
+ *canmulti = 3; /* supports multiple devices */
+ /* get max. number of audio ports from system */
+ pvs[0].param = AL_DEVICES;
+ err = alGetParams(AL_SYSTEM, pvs, 1);
+ if (err < 0) {
+ sprintf("alGetParams failed: %s\n", alGetErrorString(oserror()));
+ }
+ ndev = pvs[0].value.i;
+ for (i = 0; i < ndev; i++) {
+ pvs[0].param = AL_NAME; /* a string parameter */
+ pvs[0].value.ptr = name; /* the string we've allocated */
+ pvs[0].sizeIn = 32; /* the array size, in characters, including space for NULL */
+ if (alGetParams(i, pvs, 1) < 0) {
+ sprintf("alGetParams failed: %s\n", alGetErrorString(oserror()));
+ }
+ sprintf(indevlist + i * devdescsize, "%d: %s", i + 1, name);
+ sprintf(outdevlist + i * devdescsize, "%d: %s", i + 1, name);
+ }
+ *nindevs = ndev;
+ *noutdevs = ndev;
+#else
+ sprintf( indevlist + 0 * devdescsize, "Default In");
+ sprintf(outdevlist + 0 * devdescsize, "Default Out");
+ sprintf( indevlist + 1 * devdescsize, "Analog In");
+ sprintf(outdevlist + 1 * devdescsize, "Analog Out");
+ sprintf( indevlist + 2 * devdescsize, "AES In");
+ sprintf(outdevlist + 2 * devdescsize, "AES Out");
+ sprintf( indevlist + 3 * devdescsize, "ADAT In");
+ sprintf(outdevlist + 3 * devdescsize, "ADAT Out");
+ *nindevs = 4;
+ *noutdevs = 4;
+ *canmulti = 3; /* supports multiple devices */
+#endif
+}
+
+/* list devices: only reflect the most common setup (Octane) */
+void sgi_listaudiodevs() {
+ post("common devices on SGI machines:");
+ post("#-1 - Default In/Out selected in Audio Panel");
+ post("#1 - Analog In/Out");
+ post("#2 - AES In/Out");
+ post("#3 - ADAT I/O");
+}
+
+struct t_audioapi sgi_api = {
+ sgi_open_audio,
+ sgi_close_audio,
+ sgi_send_dacs,
+ sgi_getdevs,
+};
diff --git a/desiredata/src/s_inter.c b/desiredata/src/s_inter.c
new file mode 100644
index 00000000..ad19ceb1
--- /dev/null
+++ b/desiredata/src/s_inter.c
@@ -0,0 +1,732 @@
+/* Copyright (c) 1997-1999 Miller Puckette.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* Pd side of the Pd/Pd-gui interface. Also, some system interface routines
+that didn't really belong anywhere. */
+
+#define WATCHDOGTHREAD
+
+#define PD_PLUSPLUS_FACE
+#include "desire.h"
+#include "pthread.h"
+#include <sstream>
+#ifdef UNISTD
+#include <unistd.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <netdb.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include <sys/mman.h>
+#include <sys/resource.h>
+#endif
+#ifdef HAVE_BSTRING_H
+#include <bstring.h>
+#endif
+#if defined(_WIN32) && !defined(__CYGWIN__)
+#include <io.h>
+#include <fcntl.h>
+#include <process.h>
+#include <winsock.h>
+#include <windows.h>
+#ifdef _MSC_VER
+typedef int pid_t;
+#endif
+typedef int socklen_t;
+#define EADDRINUSE WSAEADDRINUSE
+#endif
+
+#include <stdarg.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+
+#ifndef SIGIOT
+#define SIGIOT SIGABRT
+#endif
+
+#ifdef __APPLE__
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <pthread.h>
+#else
+#include <stdlib.h>
+#endif
+
+#define DEBUG_MESSUP 1 /* messages up from pd to pd-gui */
+#define DEBUG_MESSDOWN 2 /* messages down from pd-gui to pd */
+
+/* T.Grill - make it a _little_ more adaptable... */
+#ifndef PDBINDIR
+#define PDBINDIR "bin/"
+#endif
+
+#ifndef WISHAPP
+#define WISHAPP "wish84.exe"
+#endif
+
+#ifdef __linux__
+#define LOCALHOST "127.0.0.1"
+#else
+#define LOCALHOST "localhost"
+#endif
+
+struct t_fdpoll {
+ int fdp_fd;
+ t_fdpollfn fdp_fn;
+ void *fdp_ptr;
+};
+
+#define INBUFSIZE 16384
+
+extern int sys_guisetportnumber;
+static int sys_nfdpoll;
+static t_fdpoll *sys_fdpoll;
+static int sys_maxfd;
+t_text *sys_netreceive;
+static t_binbuf *inbinbuf;
+t_socketreceiver *sys_socketreceiver;
+extern int sys_addhist(int phase);
+
+/* ----------- functions for timing, signals, priorities, etc --------- */
+
+#ifdef _WIN32
+static LARGE_INTEGER nt_inittime;
+static double nt_freq = 0;
+
+static void sys_initntclock() {
+ LARGE_INTEGER f1;
+ LARGE_INTEGER now;
+ QueryPerformanceCounter(&now);
+ if (!QueryPerformanceFrequency(&f1)) {
+ fprintf(stderr, "pd: QueryPerformanceFrequency failed\n");
+ f1.QuadPart = 1;
+ }
+ nt_freq = f1.QuadPart;
+ nt_inittime = now;
+}
+
+#if 0
+/* this is a version you can call if you did the QueryPerformanceCounter
+ call yourself. Necessary for time tagging incoming MIDI at interrupt
+ level, for instance; but we're not doing that just now. */
+
+double nt_tixtotime(LARGE_INTEGER *dumbass) {
+ if (nt_freq == 0) sys_initntclock();
+ return (((double)(dumbass->QuadPart - nt_inittime.QuadPart)) / nt_freq);
+}
+#endif
+#endif /* _WIN32 */
+
+ /* get "real time" in seconds; take the
+ first time we get called as a reference time of zero. */
+double sys_getrealtime() {
+#ifndef _WIN32
+ static struct timeval then;
+ struct timeval now;
+ gettimeofday(&now, 0);
+ if (then.tv_sec == 0 && then.tv_usec == 0) then = now;
+ return (now.tv_sec - then.tv_sec) + (1./1000000.) * (now.tv_usec - then.tv_usec);
+#else
+ LARGE_INTEGER now;
+ QueryPerformanceCounter(&now);
+ if (nt_freq == 0) sys_initntclock();
+ return double(now.QuadPart - nt_inittime.QuadPart) / nt_freq;
+#endif
+}
+
+int sys_pollsockets () {
+ struct timeval timout;
+ int didsomething = 0;
+ fd_set readset, writeset, exceptset;
+ timout.tv_sec = 0;
+ timout.tv_usec = 0;
+ FD_ZERO(&writeset);
+ FD_ZERO(&readset);
+ FD_ZERO(&exceptset);
+ t_fdpoll *fp = sys_fdpoll;
+ for (int i=sys_nfdpoll; i--; fp++) FD_SET(fp->fdp_fd, &readset);
+ select(sys_maxfd+1, &readset, &writeset, &exceptset, &timout);
+ for (int i=0; i<sys_nfdpoll; i++) if (FD_ISSET(sys_fdpoll[i].fdp_fd, &readset)) {
+ sys_fdpoll[i].fdp_fn(sys_fdpoll[i].fdp_ptr, sys_fdpoll[i].fdp_fd);
+ didsomething = 1;
+ }
+ return didsomething;
+}
+
+void sys_microsleep(int microsec) {
+ /* Tim says: sleep granularity on "modern" operating systems is only 1ms???
+ - linux: we might be better with the high precision posix timer kernel patches ...
+ - windows: win9x doesn't implement a SwitchToThread function, so we can't sleep for small timeslices
+ - osx: ???
+ */
+ if (!sys_callbackscheduler && microsec < 1000) {
+ if (500 < microsec) microsec = 1000; else return;
+ }
+#ifndef MSW
+ struct timeval timeout;
+ timeout.tv_sec = 0;
+ timeout.tv_usec = microsec;
+ select(0,0,0,0,&timeout);
+
+#else
+ Sleep(microsec/1000);
+#endif
+ /* a solution for lower timeslices might be a busysleep but this might
+ block a low-priority thread and won't work for win9x
+#define _WIN32_WINNT 0x0400
+ double end = sys_getrealtime() + (double)microsec * 1e-6;
+ do {
+#ifdef MSW
+ SwitchToThread();
+#else
+ sched_yield();
+#endif
+ }
+ while(sys_getrealtime() < end);
+ */
+}
+
+#ifdef UNISTD
+typedef void (*sighandler_t)(int);
+
+static void sys_signal(int signo, sighandler_t sigfun) {
+ struct sigaction action;
+ action.sa_flags = 0;
+ action.sa_handler = sigfun;
+ memset(&action.sa_mask, 0, sizeof(action.sa_mask));
+#if 0 /* GG says: don't use that */
+ action.sa_restorer = 0;
+#endif
+ if (sigaction(signo, &action, 0) < 0) perror("sigaction");
+
+}
+
+static void sys_exithandler(int n) {
+ static int trouble = 0;
+ if (!trouble) {
+ trouble = 1;
+ fprintf(stderr, "Pd: signal %d\n", n);
+ sys_bail(1);
+ } else sys_bail(0);
+}
+
+static void sys_alarmhandler(int n) {
+ fprintf(stderr, "Pd: system call timed out\n");
+}
+
+/* what is this for?? */
+static void sys_huphandler(int n) {
+ struct timeval timout;
+ timout.tv_sec = 0;
+ timout.tv_usec = 30000;
+ select(1, 0, 0, 0, &timout);
+}
+
+void sys_setalarm(int microsec) {
+ struct itimerval it;
+ it.it_interval.tv_sec = 0;
+ it.it_interval.tv_usec = 0;
+ it.it_value.tv_sec = microsec/1000000;
+ it.it_value.tv_usec = microsec%1000000;
+ sys_signal(SIGALRM, microsec ? sys_alarmhandler : SIG_IGN);
+ setitimer(ITIMER_REAL, &it, 0);
+}
+
+#endif
+
+#if defined(__linux) || defined(__APPLE__)
+#if (_POSIX_PRIORITY_SCHEDULING - 0) >= 200112L || (_POSIX_MEMLOCK - 0) >= 200112L
+#include <sched.h>
+#endif
+#if (_POSIX_MEMLOCK - 0) >= 200112L
+#include <sys/resource.h>
+#endif
+void sys_set_priority(int higher) {
+#if (_POSIX_PRIORITY_SCHEDULING - 0) >= 200112L
+ struct sched_param par;
+#ifdef USEAPI_JACK
+ int p1 = sched_get_priority_min(SCHED_FIFO);
+ int p3 = (higher ? p1 + 7 : p1 + 5);
+#else
+ int p2 = sched_get_priority_max(SCHED_FIFO);
+ int p3 = (higher ? p2 - 1 : p2 - 3);
+#endif
+ par.sched_priority = p3;
+ if (sched_setscheduler(0,SCHED_FIFO,&par) != -1)
+ fprintf(stderr, "priority %d scheduling enabled.\n", p3);
+#endif
+#if (_POSIX_MEMLOCK - 0) >= 200112L
+ /* tb: force memlock to physical memory { */
+ struct rlimit mlock_limit;
+ mlock_limit.rlim_cur=0;
+ /* tb: only if we are really root we can set the hard limit */
+ mlock_limit.rlim_max = getuid() ? 100 : 0;
+ setrlimit(RLIMIT_MEMLOCK,&mlock_limit);
+ /* } tb */
+ if (mlockall(MCL_FUTURE) != -1) fprintf(stderr, "memory locking enabled.\n");
+#endif
+}
+#endif /* __linux__ */
+
+#ifdef IRIX /* hack by <olaf.matthes@gmx.de> at 2003/09/21 */
+
+#if (_POSIX_PRIORITY_SCHEDULING - 0) >= 200112L || (_POSIX_MEMLOCK - 0) >= 200112L
+#include <sched.h>
+#endif
+
+void sys_set_priority(int higher) {
+#if (_POSIX_PRIORITY_SCHEDULING - 0) >= 200112L
+ struct sched_param par;
+ /* Bearing the table found in 'man realtime' in mind, I found it a */
+ /* good idea to use 192 as the priority setting for Pd. Any thoughts? */
+ if (higher) par.sched_priority = 250; /* priority for watchdog */
+ else par.sched_priority = 192; /* priority for pd (DSP) */
+ if (sched_setscheduler(0, SCHED_FIFO, &par) != -1)
+ fprintf(stderr, "priority %d scheduling enabled.\n", par.sched_priority);
+#endif
+
+#if (_POSIX_MEMLOCK - 0) >= 200112L
+ if (mlockall(MCL_FUTURE) != -1) fprintf(stderr, "memory locking enabled.\n");
+#endif
+}
+/* end of hack */
+#endif /* IRIX */
+
+/* ------------------ receiving incoming messages over sockets ------------- */
+
+void sys_sockerror(char *s) {
+#ifdef _WIN32
+ int err = WSAGetLastError();
+ if (err == 10054) return;
+ else if (err == 10044) {
+ fprintf(stderr, "Warning: you might not have TCP/IP \"networking\" turned on\n");
+ fprintf(stderr, "which is needed for Pd to talk to its GUI layer.\n");
+ }
+#else
+ int err = errno;
+#endif /* _WIN32 */
+ fprintf(stderr, "%s: %s (%d)\n", s, strerror(err), err);
+}
+
+void sys_addpollfn(int fd, t_fdpollfn fn, void *ptr) {
+ int nfd = sys_nfdpoll;
+ int size = nfd * sizeof(t_fdpoll);
+ sys_fdpoll = (t_fdpoll *)t_resizebytes(sys_fdpoll, size, size + sizeof(t_fdpoll));
+ t_fdpoll *fp = sys_fdpoll + nfd;
+ fp->fdp_fd = fd;
+ fp->fdp_fn = fn;
+ fp->fdp_ptr = ptr;
+ sys_nfdpoll = nfd + 1;
+ if (fd >= sys_maxfd) sys_maxfd = fd + 1;
+}
+
+void sys_rmpollfn(int fd) {
+ int nfd = sys_nfdpoll;
+ int size = nfd * sizeof(t_fdpoll);
+ t_fdpoll *fp = sys_fdpoll;
+ for (int i=nfd; i--; fp++) {
+ if (fp->fdp_fd == fd) {
+ while (i--) {
+ fp[0] = fp[1];
+ fp++;
+ }
+ sys_fdpoll = (t_fdpoll *)t_resizebytes(sys_fdpoll, size, size - sizeof(t_fdpoll));
+ sys_nfdpoll = nfd - 1;
+ return;
+ }
+ }
+ post("warning: %d removed from poll list but not found", fd);
+}
+
+t_socketreceiver *socketreceiver_new(t_pd *owner, int fd, t_socketnotifier notifier,
+t_socketreceivefn socketreceivefn, int udp) {
+ t_socketreceiver *x = (t_socketreceiver *)getbytes(sizeof(*x));
+ x->inhead = x->intail = 0;
+ x->owner = owner;
+ x->notifier = notifier;
+ x->socketreceivefn = socketreceivefn;
+ x->udp = udp;
+ x->fd = fd;
+ x->obuf = 0;
+ x->next = 0;
+ x->inbuf = (char *)malloc(INBUFSIZE);
+ if (!x->inbuf) bug("t_socketreceiver");
+ return x;
+}
+
+void socketreceiver_free(t_socketreceiver *x) {free(x->inbuf); free(x);}
+
+/* this is in a separately called subroutine so that the buffer isn't
+ sitting on the stack while the messages are getting passed. */
+static int socketreceiver_doread(t_socketreceiver *x) {
+ char messbuf[INBUFSIZE], *bp = messbuf;
+ int inhead = x->inhead;
+ int intail = x->intail;
+ char *inbuf = x->inbuf;
+ if (intail == inhead) return 0;
+ for (int i=intail; i!=inhead; i=(i+1)&(INBUFSIZE-1)) {
+ /* ";" not preceded by "\" is a message boundary in current syntax.
+ in future syntax it might become more complex. */
+ char c = *bp++ = inbuf[i];
+ if (c == ';' && (!i || inbuf[i-1] != '\\')) {
+ intail = (i+1)&(INBUFSIZE-1);
+ binbuf_text(inbinbuf, messbuf, bp - messbuf);
+ x->inhead = inhead;
+ x->intail = intail;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static void socketreceiver_getudp(t_socketreceiver *x, int fd) {
+ char buf[INBUFSIZE+1];
+ int ret = recv(fd, buf, INBUFSIZE, 0);
+ if (ret < 0) {
+ sys_sockerror("recv");
+ sys_rmpollfn(fd);
+ sys_closesocket(fd);
+ } else if (ret > 0) {
+ buf[ret] = 0;
+ if (buf[ret-1] == '\n') {
+ char *semi = strchr(buf, ';');
+ if (semi) *semi = 0;
+ binbuf_text(inbinbuf, buf, strlen(buf));
+ outlet_setstacklim();
+ x->socketreceivefn(x->owner, inbinbuf);
+ } else {/*bad buffer ignored */}
+ }
+}
+
+void sys_exit();
+
+void socketreceiver_read(t_socketreceiver *x, int fd) {
+ if (x->udp) {socketreceiver_getudp(x, fd); return;}
+ /* else TCP */
+ int readto = x->inhead >= x->intail ? INBUFSIZE : x->intail-1;
+ /* the input buffer might be full. If so, drop the whole thing */
+ if (readto == x->inhead) {
+ fprintf(stderr, "pd: dropped message from gui\n");
+ x->inhead = x->intail = 0;
+ readto = INBUFSIZE;
+ } else {
+ int ret = recv(fd, x->inbuf+x->inhead, readto-x->inhead, 0);
+ if (ret<=0) {
+ if (ret<0) sys_sockerror("recv"); else post("EOF on socket %d", fd);
+ if (x->notifier) x->notifier(x->owner);
+ sys_rmpollfn(fd);
+ sys_closesocket(fd);
+ return;
+ }
+ x->inhead += ret;
+ if (x->inhead >= INBUFSIZE) x->inhead = 0;
+ while (socketreceiver_doread(x)) {
+ outlet_setstacklim();
+ x->socketreceivefn(x->owner, inbinbuf);
+ }
+ }
+}
+
+void sys_closesocket(int fd) {
+#ifdef UNISTD
+ close(fd);
+#endif
+#ifdef _WIN32
+ closesocket(fd);
+#endif /* _WIN32 */
+}
+
+/* ---------------------- sending messages to the GUI ------------------ */
+#define GUI_ALLOCCHUNK 8192
+#define GUI_UPDATESLICE 512 /* how much we try to do in one idle period */
+#define GUI_BYTESPERPING 1024 /* how much we send up per ping */
+
+static void sys_trytogetmoreguibuf(t_socketreceiver *self, int newsize) {
+ self->osize = newsize;
+ self->obuf = (char *)realloc(self->obuf, newsize);
+}
+
+#undef max /* for msys compat */
+int max(int a, int b) { return ((a)>(b)?(a):(b)); }
+
+std::ostringstream lost_posts;
+
+void sys_vgui(char *fmt, ...) {
+ t_socketreceiver *self = sys_socketreceiver;
+ va_list ap;
+ va_start(ap, fmt);
+ if (!self) {voprintf(lost_posts,fmt,ap); va_end(ap); return;}
+ if (!self->obuf) {
+ self->obuf = (char *)malloc(GUI_ALLOCCHUNK);
+ self->osize = GUI_ALLOCCHUNK;
+ self->ohead = self->otail = 0;
+ }
+ if (self->ohead > self->osize - GUI_ALLOCCHUNK/2)
+ sys_trytogetmoreguibuf(self,self->osize + GUI_ALLOCCHUNK);
+ int msglen = vsnprintf(self->obuf+self->ohead, self->osize-self->ohead, fmt, ap);
+ va_end(ap);
+ if(msglen < 0) {fprintf(stderr, "Pd: buffer space wasn't sufficient for long GUI string\n"); return;}
+ if (msglen >= self->osize - self->ohead) {
+ int msglen2, newsize = self->osize+1+max(msglen,GUI_ALLOCCHUNK);
+ sys_trytogetmoreguibuf(self,newsize);
+ va_start(ap, fmt);
+ msglen2 = vsnprintf(self->obuf+self->ohead, self->osize-self->ohead, fmt, ap);
+ va_end(ap);
+ if (msglen2 != msglen) bug("sys_vgui");
+ if (msglen >= self->osize-self->ohead) msglen = self->osize-self->ohead;
+ }
+ self->ohead += msglen;
+ self->bytessincelastping += msglen;
+}
+
+void sys_gui(char *s) {sys_vgui("%s", s);}
+
+static int sys_flushtogui(t_socketreceiver *self) {
+ int writesize = self->ohead-self->otail;
+ if (!writesize) return 0;
+ int nwrote = send(self->fd, self->obuf+self->otail, writesize, 0);
+ if (nwrote < 0) {
+ perror("pd-to-gui socket");
+ sys_bail(1);
+ } else if (!nwrote) {
+ return 0;
+ } else if (nwrote >= self->ohead-self->otail) {
+ self->ohead = self->otail = 0;
+ } else if (nwrote) {
+ self->otail += nwrote;
+ if (self->otail > self->osize>>2) {
+ memmove(self->obuf, self->obuf+self->otail, self->ohead-self->otail);
+ self->ohead -= self->otail;
+ self->otail = 0;
+ }
+ }
+ return 1;
+}
+
+void glob_ping(t_pd *dummy) {t_socketreceiver *self = sys_socketreceiver; self->waitingforping = 0;}
+
+int sys_pollgui() {
+ if (sys_socketreceiver) sys_flushtogui(sys_socketreceiver);
+ return sys_pollsockets();
+}
+
+/* --------------------- starting up the GUI connection ------------- */
+
+#ifdef __linux__
+void glob_watchdog(t_pd *dummy) {
+#ifndef WATCHDOGTHREAD
+ if (write(sys_watchfd, "\n", 1) < 1) {
+ fprintf(stderr, "pd: watchdog process died\n");
+ sys_bail(1);
+ }
+#endif
+}
+#endif
+
+static void sys_setsignals() {
+#ifdef UNISTD
+ signal(SIGHUP, sys_huphandler);
+ signal(SIGINT, sys_exithandler);
+ signal(SIGQUIT, sys_exithandler);
+ signal(SIGILL, sys_exithandler);
+ signal(SIGIOT, sys_exithandler);
+ signal(SIGFPE, SIG_IGN);
+/* signal(SIGILL, sys_exithandler);
+ signal(SIGBUS, sys_exithandler);
+ signal(SIGSEGV, sys_exithandler); */
+ signal(SIGPIPE, SIG_IGN);
+ signal(SIGALRM, SIG_IGN);
+/* GG says: don't set SIGSTKFLT */
+#endif
+}
+
+//t_pd *pd_new3(const char *s);
+
+extern "C" t_text *netreceive_new(t_symbol *compatflag, t_floatarg fportno, t_floatarg udpflag);
+static int sys_start_watchdog_thread();
+static void sys_setpriority();
+extern t_text *manager;
+
+int sys_startgui() {
+#ifdef _WIN32
+ short version = MAKEWORD(2, 0);
+ WSADATA nobby;
+ if (WSAStartup(version, &nobby)) sys_sockerror("WSAstartup");
+#endif /* _WIN32 */
+ /* create an empty FD poll list */
+ sys_fdpoll = (t_fdpoll *)t_getbytes(0);
+ sys_nfdpoll = 0;
+ inbinbuf = binbuf_new();
+ sys_setsignals();
+ sys_netreceive = netreceive_new(&s_,sys_guisetportnumber,0);
+// fprintf(stderr,"sys_netreceive=%p\n",sys_netreceive);
+ if (!sys_netreceive) return 0;
+// obj_connect(sys_netreceive,0,(t_text *)pd_new3("print left"),0);
+// obj_connect(sys_netreceive,1,(t_text *)pd_new3("print right"),0);
+ obj_connect(sys_netreceive,0,manager,0);
+#if defined(__linux__) || defined(IRIX)
+/* now that we've spun off the child process we can promote our process's
+ priority, if we can and want to. If not specfied (-1), we check root
+ status. This misses the case where we might have permission from a
+ "security module" (linux 2.6) -- I don't know how to test for that.
+ The "-rt" flag must be set in that case. */
+ if (sys_hipriority == -1) sys_hipriority = !getuid() || !geteuid();
+#endif
+ if (sys_hipriority) sys_setpriority();
+ setuid(getuid());
+ return 0;
+}
+
+/* To prevent lockup, we fork off a watchdog process with higher real-time
+ priority than ours. The GUI has to send a stream of ping messages to the
+ watchdog THROUGH the Pd process which has to pick them up from the GUI
+ and forward them. If any of these things aren't happening the watchdog
+ starts sending "stop" and "cont" signals to the Pd process to make it
+ timeshare with the rest of the system. (Version 0.33P2 : if there's no
+ GUI, the watchdog pinging is done from the scheduler idle routine in this
+ process instead.) */
+void sys_setpriority() {
+#if defined(__linux__) || defined(IRIX)
+#ifndef WATCHDOGTHREAD
+ int pipe9[2];
+ if (pipe(pipe9) < 0) {
+ setuid(getuid());
+ sys_sockerror("pipe");
+ return 1;
+ }
+ int watchpid = fork();
+ if (watchpid < 0) {
+ setuid(getuid());
+ if (errno) perror("sys_startgui"); else fprintf(stderr, "sys_startgui failed\n");
+ return 1;
+ } else if (!watchpid) { /* we're the child */
+ sys_set_priority(1);
+ setuid(getuid());
+ if (pipe9[1]) {
+ dup2(pipe9[0], 0);
+ close(pipe9[0]);
+ }
+ close(pipe9[1]);
+ sprintf(cmdbuf, "%s/pd-watchdog\n", guidir);
+ if (sys_verbose) fprintf(stderr, "%s", cmdbuf);
+ execl("/bin/sh", "sh", "-c", cmdbuf, (char*)0);
+ perror("pd: exec");
+ _exit(1);
+ } else { /* we're the parent */
+ sys_set_priority(0);
+ setuid(getuid());
+ close(pipe9[0]);
+ sys_watchfd = pipe9[1];
+ /* We also have to start the ping loop in the GUI; this is done later when the socket is open. */
+ }
+#else
+ sys_start_watchdog_thread();
+ sys_set_priority(0);
+#endif
+#endif /* __linux__ */
+#ifdef MSW
+ if (!SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS))
+ fprintf(stderr, "pd: couldn't set high priority class\n");
+#endif
+#ifdef __APPLE__
+ if (sys_hipriority) {
+ struct sched_param param;
+ int policy = SCHED_RR;
+ param.sched_priority = 80; /* adjust 0 : 100 */
+ int err = pthread_setschedparam(pthread_self(), policy, &param);
+ if (err) post("warning: high priority scheduling failed");
+ }
+#endif /* __APPLE__ */
+ if (!sys_nogui) {
+ /* here is where we start the pinging. */
+#if defined(__linux__) || defined(IRIX)
+#ifndef WATCHDOGTHREAD
+ if (sys_hipriority) sys_gui("pdtk_watchdog\n");
+#endif
+#endif
+ }
+}
+
+/* This is called when something bad has happened, like a segfault.
+Call glob_quit() below to exit cleanly.
+LATER try to save dirty documents even in the bad case. */
+void sys_bail(int n) {
+ static int reentered = 0;
+ if (reentered) _exit(1);
+ reentered = 1;
+ fprintf(stderr, "closing audio...\n");
+ sys_close_audio();
+ fprintf(stderr, "closing MIDI...\n");
+ sys_close_midi();
+ fprintf(stderr, "... done.\n");
+ exit(n);
+}
+
+extern "C" void glob_closeall(void *dummy, t_floatarg fforce);
+
+void glob_quit(void *dummy) {
+ glob_closeall(0, 1);
+ sys_bail(0);
+}
+
+static pthread_t watchdog_id;
+static pthread_t main_pd_thread;
+static pthread_mutex_t watchdog_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t watchdog_cond = PTHREAD_COND_INITIALIZER;
+static void *watchdog_thread(void *);
+
+/* start a high priority watchdog thread */
+static int sys_start_watchdog_thread() {
+ pthread_attr_t w_attr;
+ main_pd_thread = pthread_self();
+ pthread_attr_init(&w_attr);
+ pthread_attr_setschedpolicy(&w_attr, SCHED_FIFO); /* use rt scheduling */
+ int status = pthread_create(&watchdog_id, &w_attr, (void*(*)(void*)) watchdog_thread, NULL);
+ return status; /* what is this function supposed to return anyway? it tried returning void though declared as int */
+}
+
+#ifdef MSW
+int gettimeofday (struct timeval *tv, void *tz);
+#endif
+
+static t_int* watchdog_callback(t_int *dummy) {
+ /* signal the condition */
+ pthread_cond_signal(&watchdog_cond);
+ return 0;
+}
+
+/* this watchdog thread registers an idle callback once a minute
+ if the idle callback isn't excecuted within one minute, we're probably
+ blocking the system.
+ kill the whole process!
+*/
+
+static void *watchdog_thread(void *dummy) {
+ sys_set_priority(1);
+ post("watchdog thread started");
+ sys_microsleep(60*1000*1000); /* wait 60 seconds ... hoping that everything is set up */
+ post("watchdog thread active");
+ while (1) {
+ struct timespec timeout;
+ struct timeval now;
+ int status;
+ gettimeofday(&now,0);
+ timeout.tv_sec = now.tv_sec + 15; /* timeout: 15 seconds */
+ timeout.tv_nsec = now.tv_usec * 1000;
+ sys_callback((t_int(*)(t_int*))watchdog_callback, 0, 0);
+ status = pthread_cond_timedwait(&watchdog_cond, &watchdog_mutex, &timeout);
+ if (status) {
+#if defined(__linux__) || defined(IRIX)
+ fprintf(stderr, "watchdog killing");
+ kill(0,9); /* kill parent thread */
+#endif
+ }
+ sys_microsleep(15*1000*1000); /* and sleep for another 15 seconds */
+ }
+ return 0; /* avoid warning */
+}
diff --git a/desiredata/src/s_loader.c b/desiredata/src/s_loader.c
new file mode 100644
index 00000000..aa4d81a0
--- /dev/null
+++ b/desiredata/src/s_loader.c
@@ -0,0 +1,196 @@
+/* Copyright (c) 1997-1999 Miller Puckette.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#ifdef DL_OPEN
+#include <dlfcn.h>
+#endif
+#ifdef UNISTD
+#include <stdlib.h>
+#include <unistd.h>
+#endif
+#ifdef MSW
+#include <io.h>
+#include <windows.h>
+#endif
+#ifdef __APPLE__
+#include <mach-o/dyld.h>
+#endif
+#include <string.h>
+#define PD_PLUSPLUS_FACE
+#include "desire.h"
+#include "s_stuff.h"
+#include <stdio.h>
+#include <sstream>
+using namespace std;
+
+typedef void (*t_xxx)();
+
+/* naming convention for externs. The names are kept distinct for those
+who wich to make "fat" externs compiled for many platforms. Less specific
+fallbacks are provided, primarily for back-compatibility; these suffice if
+you are building a package which will run with a single set of compiled
+objects. The specific name is the letter b, l, d, or m for BSD, linux,
+darwin, or microsoft, followed by a more specific string, either "fat" for
+a fat binary or an indication of the instruction set. */
+
+#ifdef __FreeBSD__
+static char sys_dllextent[] = ".b_i386", sys_dllextent2[] = ".pd_freebsd";
+#endif
+#ifdef __linux__
+#ifdef __ia64__
+static char sys_dllextent[] = ".l_ia64", sys_dllextent2[] = ".pd_linux";
+#else
+static char sys_dllextent[] = ".l_i386", sys_dllextent2[] = ".pd_linux";
+#endif
+#endif
+#ifdef __APPLE__
+#ifndef MACOSX3
+static char sys_dllextent[] = ".d_fat", sys_dllextent2[] = ".pd_darwin";
+#else
+static char sys_dllextent[] = ".d_ppc", sys_dllextent2[] = ".pd_darwin";
+#endif
+#endif
+#ifdef MSW
+static char sys_dllextent[] = ".m_i386", sys_dllextent2[] = ".dll";
+#endif
+
+/* maintain list of loaded modules to avoid repeating loads */
+struct t_loadlist {
+ t_loadlist *ll_next;
+ t_symbol *ll_name;
+};
+
+static t_loadlist *sys_loaded;
+/* return true if already loaded */
+int sys_onloadlist(char *classname) {
+ t_symbol *s = gensym(classname);
+ t_loadlist *ll;
+ for (ll = sys_loaded; ll; ll = ll->ll_next)
+ if (ll->ll_name == s)
+ return 1;
+ return 0;
+}
+
+/* add to list of loaded modules */
+void sys_putonloadlist(char *classname) {
+ t_loadlist *ll = (t_loadlist *)getbytes(sizeof(*ll));
+ ll->ll_name = gensym(classname);
+ ll->ll_next = sys_loaded;
+ sys_loaded = ll;
+ /* post("put on list %s", classname); */
+}
+
+static char *make_setup_name(const char *s) {
+ bool hexmunge=0;
+ ostringstream buf;
+ for (; *s; s++) {
+ char c = *s;
+ if ((c>='0' && c<='9') || (c>='A' && c<='Z') || (c>='a' && c<='z' )|| c == '_') {
+ buf << c;
+ } else if (c=='~' && s[1]==0) { /* trailing tilde becomes "_tilde" */
+ buf << "_tilde";
+ } else { /* anything you can't put in a C symbol is sprintf'ed in hex */
+ // load_object: symbol "setup_0xbf861ee4" not found
+ oprintf(buf,"0x%02x",c);
+ hexmunge = 1;
+ }
+ }
+ char *r;
+ if (hexmunge) asprintf(&r,"setup_%s",buf.str().data());
+ else asprintf(&r,"%s_setup",buf.str().data());
+ return r;
+}
+
+static int sys_do_load_lib(t_canvas *canvas, char *objectname) {
+ char *filename=0, *dirbuf, *classname, *nameptr;
+ t_xxx makeout = NULL;
+ int fd;
+ if ((classname = strrchr(objectname, '/'))) classname++;
+ else classname = objectname;
+ if (sys_onloadlist(objectname)) {
+ post("%s: already loaded", objectname);
+ return 1;
+ }
+ char *symname = make_setup_name(classname);
+ /* try looking in the path for (objectname).(sys_dllextent) ... */
+ if ((fd = canvas_open2(canvas, objectname, sys_dllextent , &dirbuf, &nameptr, 1)) >= 0) goto gotone;
+ /* same, with the more generic sys_dllextent2 */
+ if ((fd = canvas_open2(canvas, objectname, sys_dllextent2, &dirbuf, &nameptr, 1)) >= 0) goto gotone;
+ /* next try (objectname)/(classname).(sys_dllextent) ... */
+ asprintf(&filename,"%s/%s",objectname,classname);
+ if ((fd = canvas_open2(canvas, filename, sys_dllextent , &dirbuf, &nameptr, 1)) >= 0) goto gotone;
+ if ((fd = canvas_open2(canvas, filename, sys_dllextent2, &dirbuf, &nameptr, 1)) >= 0) goto gotone;
+ return 0;
+gotone:
+ close(fd);
+ class_set_extern_dir(gensym(dirbuf));
+ /* rebuild the absolute pathname */
+ free(filename);
+ /* extra nulls are a workaround for a dlopen bug */
+ asprintf(&filename,"%s/%s%c%c%c%c",dirbuf,nameptr,0,0,0,0);
+// filename = realloc(filename,);
+#ifdef DL_OPEN
+ void *dlobj = dlopen(filename, RTLD_NOW | RTLD_GLOBAL);
+ if (!dlobj) {
+ post("%s: %s", filename, dlerror());
+ goto forgetit;
+ }
+ makeout = (t_xxx)dlsym(dlobj, symname);
+#endif
+#ifdef MSW
+ sys_bashfilename(filename, filename);
+ HINSTANCE ntdll = LoadLibrary(filename);
+ if (!ntdll) {
+ post("%s: couldn't load", filename);
+ goto forgetit;
+ }
+ makeout = (t_xxx)GetProcAddress(ntdll);
+#endif
+ if (!makeout) {
+ post("%s: can't find symbol '%s' in library", filename, symname);
+ goto forgetit;
+ }
+ makeout();
+ class_set_extern_dir(&s_);
+ sys_putonloadlist(objectname);
+ free(filename); free(symname);
+ return 1;
+forgetit:
+ class_set_extern_dir(&s_);
+ free(filename); free(symname); free(dirbuf);
+ return 0;
+}
+
+/* callback type definition */
+typedef int (*t_loader)(t_canvas *canvas, char *classname);
+
+/* linked list of loaders */
+typedef struct t_loader_queue {
+ t_loader loader;
+ t_loader_queue *next;
+};
+
+static t_loader_queue loaders = {sys_do_load_lib, NULL};
+
+/* register class loader function */
+void sys_register_loader(t_loader loader) {
+ t_loader_queue *q = &loaders;
+ while (1) {
+ if (q->next) q = q->next;
+ else {
+ q->next = (t_loader_queue *)getbytes(sizeof(t_loader_queue));
+ q->next->loader = loader;
+ q->next->next = NULL;
+ break;
+ }
+ }
+}
+
+int sys_load_lib(t_canvas *canvas, char *classname) {
+ int dspstate = canvas_suspend_dsp();
+ int ok = 0;
+ for(t_loader_queue *q = &loaders; q; q = q->next) if ((ok = q->loader(canvas, classname))) break;
+ canvas_resume_dsp(dspstate);
+ return ok;
+}
diff --git a/desiredata/src/s_main.c b/desiredata/src/s_main.c
new file mode 100644
index 00000000..70cc7a9b
--- /dev/null
+++ b/desiredata/src/s_main.c
@@ -0,0 +1,632 @@
+/* Copyright (c) 1997-1999 Miller Puckette and others.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* Zmlnig added advanced multidevice-support (2001) */
+
+#include "desire.h"
+#include "s_stuff.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <limits.h>
+#include <string.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <sstream>
+
+#ifdef __CYGWIN__
+#define UNISTD
+#endif
+#ifdef UNISTD
+#include <unistd.h>
+#endif
+#ifdef MSW
+#include <io.h>
+#include <windows.h>
+#include <winbase.h>
+#endif
+
+#ifdef DAZ
+#define _MM_DENORM_ZERO_ON 0x0040
+#include <xmmintrin.h>
+#endif
+
+extern "C" void pd_init();
+extern "C" int sys_argparse(int argc, char **argv);
+void sys_findprogdir(char *progname);
+int sys_startgui();
+void sys_init_idle_callbacks();
+extern "C" int sys_rcfile();
+extern int m_scheduler();
+void sys_addhelppath(char *p);
+void alsa_adddev(char *name);
+extern "C" int sys_parsercfile(char*filename);
+
+#ifdef THREADED_SF
+void sys_start_sfthread();
+#endif /* THREDED_SF */
+
+char pd_version[] = "DesireData 2007.08.22";
+char pd_compiletime[] = __TIME__;
+char pd_compiledate[] = __DATE__;
+
+int sys_verbose;
+int sys_noloadbang;
+int sys_hipriority = -1; /* -1 = don't care; 0 = no; 1 = yes */
+int sys_guisetportnumber = 5400;
+
+int sys_defeatrt;
+t_symbol *sys_flags;
+
+char *sys_guicmd;
+t_symbol *sys_libdir;
+t_namelist *sys_externlist =0;
+t_namelist *sys_openlist =0;
+t_namelist *sys_messagelist=0;
+static int sys_version;
+
+int sys_nmidiout = 1;
+#ifdef MSW
+int sys_nmidiin = 0;
+#else
+int sys_nmidiin = 1;
+#endif
+int sys_midiindevlist[MAXMIDIINDEV] = {1};
+int sys_midioutdevlist[MAXMIDIOUTDEV] = {1};
+
+static int sys_main_srate;
+static int sys_main_dacblocksize = DEFDACBLKSIZE;
+static int sys_main_advance;
+static int sys_listplease;
+
+/* jsarlo { */
+int sys_externalschedlib;
+char *sys_externalschedlibname;
+int sys_extraflags;
+char *sys_extraflagsstring;
+/* } jsarlo */
+
+/* IOhannes { */
+/* here the "-1" counts signify that the corresponding vector hasn't been
+ specified in command line arguments; sys_open_audio will detect this and fill things in. */
+static int sys_nsoundin = -1;
+static int sys_nsoundout = -1;
+static int sys_soundindevlist[MAXAUDIOINDEV];
+static int sys_soundoutdevlist[MAXAUDIOOUTDEV];
+static int sys_nchin = -1;
+static int sys_nchout = -1;
+static int sys_chinlist[MAXAUDIOINDEV];
+static int sys_choutlist[MAXAUDIOOUTDEV];
+/* } IOhannes */
+
+/* jsarlo { */
+t_sample* get_sys_soundout() { return sys_soundout; }
+t_sample* get_sys_soundin() { return sys_soundin; }
+int* get_sys_main_advance() { return &sys_main_advance; }
+double* get_sys_time_per_dsp_tick() { return &sys_time_per_dsp_tick; }
+int* get_sys_schedblocksize() { return &sys_schedblocksize; }
+double* get_sys_time() { return &sys_time; }
+float* get_sys_dacsr() { return &sys_dacsr; }
+int* get_sys_sleepgrain() { return &sys_sleepgrain; }
+int* get_sys_schedadvance() { return &sys_schedadvance; }
+/* } jsarlo */
+
+static void sys_afterargparse();
+
+/* this is called from main() in s_entry.c */
+extern "C" int sys_main(int argc, char **argv) {
+ int noprefs = 0;
+ class_table = new t_hash<t_symbol*,t_class*>(127);
+ /* jsarlo { */
+ sys_externalschedlib = 0;
+ sys_extraflags = 0;
+ /* } jsarlo */
+#ifdef DEBUG
+ fprintf(stderr, "Pd: COMPILED FOR DEBUGGING\n");
+#endif
+ pd_init(); /* start the message system */
+ sys_findprogdir(argv[0]); /* set sys_progname, guipath */
+ /* tb: command line flag to defeat preset loading */
+ for (int i=0; i<argc; i++) if (!strcmp(argv[i],"-noprefs") || !strcmp(argv[i],"-rcfile")) noprefs = 1;
+ if (!noprefs) sys_rcfile(); /* parse the startup file */
+ /* initalize idle callbacks before starting the gui */
+ sys_init_idle_callbacks();
+ /* } tb */
+ if (sys_argparse(argc-1, argv+1)) return 1; /* parse cmd line */
+ sys_afterargparse(); /* post-argparse settings */
+ if (sys_verbose || sys_version) fprintf(stderr, "%s, compiled %s %s\n", pd_version, pd_compiletime, pd_compiledate);
+ if (sys_version) return 0; /* if we were just asked our version, exit here. */
+ if (sys_startgui()) return 1; /* start the gui */
+ /* tb: { start the soundfiler helper thread */
+#ifdef THREADED_SF
+ sys_start_sfthread();
+#endif /* THREDED_SF */
+ /* try to set ftz and daz */
+#ifdef DAZ
+ _mm_setcsr(_MM_FLUSH_ZERO_ON | _MM_MASK_UNDERFLOW | _mm_getcsr());
+ _mm_setcsr(_MM_DENORM_ZERO_ON | _mm_getcsr());
+#endif /* DAZ */
+ /* } tb */
+ /* jsarlo { */
+ if (sys_externalschedlib) {
+#ifdef MSW
+ typedef int (*t_externalschedlibmain)(char *);
+ t_externalschedlibmain externalmainfunc;
+ HINSTANCE ntdll;
+ char *filename;
+ asprintf(&filename,"%s.dll", sys_externalschedlibname);
+ sys_bashfilename(filename, filename);
+ ntdll = LoadLibrary(filename);
+ if (!ntdll) {
+ post("%s: couldn't load external scheduler lib ", filename);
+ free(filename);
+ return 0;
+ }
+ free(filename);
+ externalmainfunc = (t_externalschedlibmain)GetProcAddress(ntdll,"main");
+ return externalmainfunc(sys_extraflagsstring);
+#else
+ return 0;
+#endif
+ }
+ /* open audio and MIDI */
+ sys_reopen_midi();
+ sys_reopen_audio();
+ /* run scheduler until it quits */
+ int r = m_scheduler();
+ fprintf(stderr,"%s",lost_posts.str().data()); // this could be useful if anyone ever called sys_exit
+ return r;
+}
+
+static char *(usagemessage[]) = {
+"usage: pd [-flags] [file]...","",
+"audio configuration flags:",
+"-r <n> -- specify sample rate",
+"-audioindev ... -- audio in devices; e.g., \"1,3\" for first and third",
+"-audiooutdev ... -- audio out devices (same)",
+"-audiodev ... -- specify input and output together",
+"-inchannels ... -- audio input channels (by device, like \"2\" or \"16,8\")",
+"-outchannels ... -- number of audio out channels (same)",
+"-channels ... -- specify both input and output channels",
+"-audiobuf <n> -- specify size of audio buffer in msec",
+"-blocksize <n> -- specify audio I/O block size in sample frames",
+"-dacblocksize <n>-- specify audio dac~block size in samples",
+"-sleepgrain <n> -- specify number of milliseconds to sleep when idle",
+"-cb_scheduler -- use callback-based scheduler (jack and native asio only)",
+"-nodac -- suppress audio output",
+"-noadc -- suppress audio input",
+"-noaudio -- suppress audio input and output (-nosound is synonym)",
+"-listdev -- list audio and MIDI devices",
+
+#define NOT_HERE "(support not compiled in)"
+
+#ifdef USEAPI_OSS
+"-oss -- use OSS audio API",
+"-32bit ---- allow 32 bit OSS audio (for RME Hammerfall)",
+#else
+"-oss -- OSS "NOT_HERE,
+"-32bit ---- allow 32 bit OSS audio "NOT_HERE,
+#endif
+
+#ifdef USEAPI_ALSA
+"-alsa -- use ALSA audio API",
+"-alsaadd <name> -- add an ALSA device name to list",
+#else
+"-alsa -- use ALSA audio API "NOT_HERE,
+"-alsaadd <name> -- add an ALSA device name to list "NOT_HERE,
+#endif
+
+#ifdef USEAPI_JACK
+"-jack -- use JACK audio API",
+#else
+"-jack -- use JACK audio API "NOT_HERE,
+#endif
+
+#ifdef USEAPI_ASIO
+ "-asio_native -- use native ASIO API",
+#else
+ "-asio_native -- use native ASIO API "NOT_HERE,
+#endif
+
+#ifdef USEAPI_PORTAUDIO
+"-pa -- use Portaudio API",
+"-asio -- synonym for -pa - use ASIO via Portaudio",
+#else
+"-pa -- use Portaudio API "NOT_HERE,
+"-asio -- synonym for -pa - use ASIO via Portaudio "NOT_HERE,
+#endif
+
+#ifdef USEAPI_MMIO
+"-mmio -- use MMIO audio API",
+#else
+"-mmio -- use MMIO audio API "NOT_HERE,
+#endif
+#ifdef API_DEFSTRING
+" (default audio API for this platform: "API_DEFSTRING")","",
+#endif
+
+"MIDI configuration flags:",
+"-midiindev ... -- midi in device list; e.g., \"1,3\" for first and third",
+"-midioutdev ... -- midi out device list, same format",
+"-mididev ... -- specify -midioutdev and -midiindev together",
+"-nomidiin -- suppress MIDI input",
+"-nomidiout -- suppress MIDI output",
+"-nomidi -- suppress MIDI input and output",
+#ifdef USEAPI_ALSA
+"-alsamidi -- use ALSA midi API",
+#else
+"-alsamidi -- use ALSA midi API "NOT_HERE,
+#endif
+
+"","other flags:",
+"-rcfile <file> -- read this rcfile instead of default",
+"-noprefs -- suppress loading preferences on startup",
+"-path <path> -- add to file search path",
+"-nostdpath -- don't search standard (\"extra\") directory",
+"-stdpath -- search standard directory (true by default)",
+"-helppath <path> -- add to help file search path",
+"-open <file> -- open file(s) on startup",
+"-lib <file> -- load object library(s)",
+"-verbose -- extra printout on startup and when searching for files",
+"-version -- don't run Pd; just print out which version it is",
+"-d <n> -- specify debug level",
+"-noloadbang -- suppress all loadbangs",
+"-stderr -- send printout to standard error instead of GUI",
+"-guiport <n> -- set port that the GUI should connect to",
+"-send \"msg...\" -- send a message at startup, after patches are loaded",
+#ifdef UNISTD
+"-rt or -realtime -- use real-time priority",
+"-nrt -- don't use real-time priority",
+#else
+"-rt or -realtime -- use real-time priority "NOT_HERE,
+"-nrt -- don't use real-time priority "NOT_HERE,
+#endif
+};
+
+static void sys_parsedevlist(int *np, int *vecp, int max, char *str) {
+ int n = 0;
+ while (n < max) {
+ if (!*str) break;
+ else {
+ char *endp;
+ vecp[n] = strtol(str, &endp, 10);
+ if (endp == str) break;
+ n++;
+ if (!endp) break;
+ str = endp + 1;
+ }
+ }
+ *np = n;
+}
+
+#ifndef INSTALL_PREFIX
+#define INSTALL_PREFIX "."
+#endif
+
+/* this routine tries to figure out where to find the auxilliary files Pd will need to run.
+ This is either done by looking at the command line invokation for Pd, or if that fails,
+ by consulting the variable INSTALL_PREFIX. In MSW, we don't try to use INSTALL_PREFIX. */
+void sys_findprogdir(char *progname) {
+ char *lastslash;
+#ifdef UNISTD
+ struct stat statbuf;
+#endif
+ /* find out by what string Pd was invoked; put answer in "sbuf". */
+ char *sbuf;
+#ifdef MSW
+ int len = GetModuleFileName(NULL, sbuf, 0);
+ sbuf = malloc(len+1);
+ GetModuleFileName(NULL, sbuf, len);
+ sbuf[len] = 0;
+ sys_unbashfilename(sbuf,sbuf);
+#endif /* MSW */
+#ifdef UNISTD
+ sbuf = strdup(progname);
+#endif
+ lastslash = strrchr(sbuf, '/');
+ char *sbuf2;
+ if (lastslash) {
+ /* bash last slash to zero so that sbuf is directory pd was in, e.g., ~/pd/bin */
+ *lastslash = 0;
+ /* go back to the parent from there, e.g., ~/pd */
+ lastslash = strrchr(sbuf, '/');
+ if (lastslash) {
+ asprintf(&sbuf2, "%.*s", lastslash-sbuf, sbuf);
+ } else sbuf2 = strdup("..");
+ } else { /* no slashes found. Try INSTALL_PREFIX. */
+ sbuf2 = strdup(INSTALL_PREFIX);
+ }
+#ifdef MSW
+ sys_libdir = gensym(sbuf2);
+#else
+ sys_libdir = stat(sbuf, &statbuf)>=0 ? symprintf("%s/lib/pd",sbuf2) : gensym(sbuf2);
+#endif
+ free(sbuf);
+ post("sys_libdir = %s",sys_libdir->name);
+}
+
+#ifdef MSW
+static int sys_mmio = 1;
+#else
+static int sys_mmio = 0;
+#endif
+
+#undef NOT_HERE
+#define NOT_HERE fprintf(stderr,"option %s not compiled into this pd\n", *argv)
+
+#define ARG(name,count) (!strcmp(*argv,(name)) && argc>=(count))
+#define NEXT(count) argc -= (count), argv += (count); continue;
+
+int sys_argparse(int argc, char **argv) {
+ while ((argc > 0) && **argv == '-') {
+ if (ARG("-r",2)) {
+ if (sscanf(argv[1], "%d", &sys_main_srate)<1) goto usage;
+ NEXT(2);
+ }
+ if (ARG("-inchannels",2)) { /* IOhannes */
+ sys_parsedevlist(&sys_nchin, sys_chinlist, MAXAUDIOINDEV, argv[1]);
+ if (!sys_nchin) goto usage;
+ NEXT(2);
+ }
+ if (ARG("-outchannels",2)) { /* IOhannes */
+ sys_parsedevlist(&sys_nchout, sys_choutlist, MAXAUDIOOUTDEV, argv[1]);
+ if (!sys_nchout) goto usage;
+ NEXT(2);
+ }
+ if (ARG("-channels",2)) {
+ sys_parsedevlist(&sys_nchin, sys_chinlist,MAXAUDIOINDEV, argv[1]);
+ sys_parsedevlist(&sys_nchout, sys_choutlist,MAXAUDIOOUTDEV, argv[1]);
+ if (!sys_nchout) goto usage;
+ NEXT(2);
+ }
+ if (ARG("-soundbuf",2) || ARG("-audiobuf",2)) {
+ sys_main_advance = atoi(argv[1]);
+ NEXT(2);
+ }
+ if (ARG("-blocksize",2)) {sys_setblocksize(atoi(argv[1])); NEXT(2);}
+ if (ARG("-dacblocksize",2)) {
+ if (sscanf(argv[1], "%d", &sys_main_dacblocksize)<1) goto usage;
+ NEXT(2);
+ }
+ if (ARG("-sleepgrain",2)) {sys_sleepgrain = int(1000 * atof(argv[1])); NEXT(2);}
+
+ /* from tim */
+ if (ARG("-cb_scheduler",1)) {sys_setscheduler(1); NEXT(1);}
+
+ /* IOhannes */
+ if (ARG("-nodac",1)) {sys_nsoundout= sys_nchout = 0; NEXT(1);}
+ if (ARG("-noadc",1)) {sys_nsoundin = sys_nchin = 0; NEXT(1);}
+ if (ARG("-nosound",1) || ARG("-noaudio",1)) {
+ sys_nsoundin=sys_nsoundout = 0;
+ sys_nchin = sys_nchout = 0;
+ NEXT(1);
+ }
+
+ /* many options for selecting audio api */
+ if (ARG("-oss",1)) {
+#ifdef USEAPI_OSS
+ sys_set_audio_api(API_OSS);
+#else
+ NOT_HERE;
+#endif
+ NEXT(1);
+ }
+ if (ARG("-32bit",1)) {
+#ifdef USEAPI_OSS
+ sys_set_audio_api(API_OSS);
+ oss_set32bit();
+#else
+ NOT_HERE;
+#endif
+ NEXT(1);
+ }
+ if (ARG("-alsa",1)) {
+#ifdef USEAPI_ALSA
+ sys_set_audio_api(API_ALSA);
+#else
+ NOT_HERE;
+#endif
+ NEXT(1);
+ }
+ if (ARG("-alsaadd",2)) {
+#ifdef USEAPI_ALSA
+ if (argc > 1)
+ alsa_adddev(argv[1]);
+ else goto usage;
+#else
+ NOT_HERE;
+#endif
+ NEXT(2);
+ }
+ if (ARG("-alsamidi",1)) {
+#ifdef USEAPI_ALSA
+ sys_set_midi_api(API_ALSA);
+#else
+ NOT_HERE;
+#endif
+ NEXT(1);
+ }
+ if (ARG("-jack",1)) {
+#ifdef USEAPI_JACK
+ sys_set_audio_api(API_JACK);
+#else
+ NOT_HERE;
+#endif
+ NEXT(1);
+ }
+ if (ARG("-pa",1) || ARG("-portaudio",1) || ARG("-asio",1)) {
+#ifdef USEAPI_PORTAUDIO
+ sys_set_audio_api(API_PORTAUDIO);
+#else
+ NOT_HERE;
+#endif
+ sys_mmio = 0;
+ argc--; argv++;
+ }
+ if (ARG("-asio_native",1)) {
+#ifdef USEAPI_ASIO
+ sys_set_audio_api(API_ASIO);
+#else
+ NOT_HERE;
+#endif
+ sys_mmio = 0;
+ argc--; argv++;
+ }
+ if (ARG("-mmio",1)) {
+#ifdef USEAPI_MMIO
+ sys_set_audio_api(API_MMIO);
+#else
+ NOT_HERE;
+#endif
+ sys_mmio = 1;
+ NEXT(1);
+ }
+
+ if (ARG("-nomidiin", 1)) {sys_nmidiin = 0; NEXT(1);}
+ if (ARG("-nomidiout",1)) {sys_nmidiout = 0; NEXT(1);}
+ if (ARG("-nomidi",1)) {sys_nmidiin = sys_nmidiout = 0; NEXT(1);}
+ if (ARG("-midiindev",2)) {
+ sys_parsedevlist(&sys_nmidiin, sys_midiindevlist, MAXMIDIINDEV, argv[1]);
+ if (!sys_nmidiin) goto usage;
+ NEXT(2);
+ }
+ if (ARG("-midioutdev",2)) {
+ sys_parsedevlist(&sys_nmidiout, sys_midioutdevlist, MAXMIDIOUTDEV, argv[1]);
+ if (!sys_nmidiout) goto usage;
+ NEXT(2);
+ }
+ if (ARG("-mididev",2)) {
+ sys_parsedevlist(&sys_nmidiin, sys_midiindevlist, MAXMIDIINDEV, argv[1]);
+ sys_parsedevlist(&sys_nmidiout, sys_midioutdevlist, MAXMIDIOUTDEV, argv[1]);
+ if (!sys_nmidiout) goto usage;
+ NEXT(2);
+ }
+ if (ARG("-nostdpath",1)) {sys_usestdpath = 0; NEXT(1);}
+ if (ARG("-stdpath",1)) {sys_usestdpath = 1; NEXT(1);}
+ if (ARG("-path",2)) {sys_searchpath = namelist_append_files(sys_searchpath,argv[1]); NEXT(2);}
+ if (ARG("-helppath",2)) {sys_helppath = namelist_append_files(sys_helppath, argv[1]); NEXT(2);}
+ if (ARG("-open",2)) {sys_openlist = namelist_append_files(sys_openlist, argv[1]); NEXT(2);}
+ if (ARG("-lib",2)) {sys_externlist = namelist_append_files(sys_externlist,argv[1]); NEXT(2);}
+ if (ARG("-font",2)) {
+ fprintf(stderr,"Warning: -font ignored by DesireData; use .ddrc instead\n");
+ //sys_defaultfont = sys_nearestfontsize(atoi(argv[1]));
+ NEXT(2);
+ }
+ if (ARG("-typeface",2)) { /* tim */
+ fprintf(stderr,"Warning: -typeface ignored by DesireData; use .ddrc instead\n");
+ NEXT(2);
+ }
+ if (ARG("-noprefs",1)) {NEXT(1);} /* tim: skip flag, we already parsed it */
+ /* jmz: read an alternative rcfile { */
+ if (ARG("-rcfile",2)) {sys_parsercfile(argv[1]); NEXT(2);} /* recursively */
+ /* } jmz */
+ if (ARG("-verbose",1)) {sys_verbose++; NEXT(1);}
+ if (ARG("-version",1)) {sys_version = 1; NEXT(1);}
+ if (ARG("-noloadbang",1)) {sys_noloadbang = 1; NEXT(1);}
+ if (ARG("-nogui",1)) {
+ sys_printtostderr = 1;
+ fprintf(stderr,"Warning: -nogui is obsolete: nowadays it does just like -stderr instead\n");
+ NEXT(1);
+ }
+ if (ARG("-guiport",2)) {
+ if (sscanf(argv[1], "%d", &sys_guisetportnumber)<1) goto usage;
+ NEXT(2);
+ }
+ if (ARG("-stderr",1)) {sys_printtostderr = 1; NEXT(1);}
+ if (ARG("-guicmd",2)) {
+ fprintf(stderr,"Warning: -guicmd ignored");
+ NEXT(2);
+ }
+ if (ARG("-send",2)) {
+ sys_messagelist = namelist_append(sys_messagelist, argv[1], 1);
+ NEXT(2);
+ }
+ if (ARG("-listdev",1)) {sys_listplease=1; NEXT(1);}
+ /* jsarlo { */
+ if (ARG("-schedlib",2)) {
+ sys_externalschedlib = 1;
+ sys_externalschedlibname = strdup(argv[1]);
+ NEXT(2);
+ }
+ if (ARG("-extraflags",2)) {
+ sys_extraflags = 1;
+ sys_extraflagsstring = strdup(argv[1]);
+ NEXT(2);
+ }
+ /* } jsarlo */
+#ifdef UNISTD
+ if (ARG("-rt",1) || ARG("-realtime",1)) {sys_hipriority = 1; NEXT(1);}
+ if (ARG("-nrt",1)) {sys_hipriority = 0; NEXT(1);}
+#endif
+ if (ARG("-soundindev",2) || ARG("-audioindev",2)) { /* IOhannes */
+ sys_parsedevlist(&sys_nsoundin, sys_soundindevlist, MAXAUDIOINDEV, argv[1]);
+ if (!sys_nsoundin) goto usage;
+ NEXT(2);
+ }
+ if (ARG("-soundoutdev",2) || ARG("-audiooutdev",2)) { /* IOhannes */
+ sys_parsedevlist(&sys_nsoundout, sys_soundoutdevlist, MAXAUDIOOUTDEV, argv[1]);
+ if (!sys_nsoundout) goto usage;
+ NEXT(2);
+ }
+ if (ARG("-sounddev",2) || ARG("-audiodev",2)) {
+ sys_parsedevlist(&sys_nsoundin, sys_soundindevlist, MAXAUDIOINDEV, argv[1]);
+ sys_parsedevlist(&sys_nsoundout, sys_soundoutdevlist, MAXAUDIOOUTDEV, argv[1]);
+ if (!sys_nsoundout) goto usage;
+ NEXT(2);
+ }
+ usage:
+ if (argc) fprintf(stderr, "Can't handle option '%s'.\n",*argv);
+ for (size_t i=0; i < sizeof(usagemessage)/sizeof(*usagemessage); i++)
+ fprintf(stderr, "%s\n", usagemessage[i]);
+ return 1;
+ }
+ for (; argc > 0; argc--, argv++) sys_openlist = namelist_append_files(sys_openlist, *argv);
+ return 0;
+}
+
+int sys_getblksize() {return sys_dacblocksize;}
+
+/* stuff to do, once, after calling sys_argparse() -- which may itself
+ be called more than once (first from "settings, second from .pdrc, then
+ from command-line arguments */
+static void sys_afterargparse() {
+ char *sbuf;
+ t_audiodevs audio_in, audio_out;
+ int nchindev, nchoutdev, rate, dacblksize, advance, scheduler;
+ int nmidiindev = 0, midiindev[MAXMIDIINDEV];
+ int nmidioutdev = 0, midioutdev[MAXMIDIOUTDEV];
+ /* add "extra" library to path */
+ asprintf(&sbuf,"%s/extra",sys_libdir->name);
+ sys_setextrapath(sbuf);
+ free(sbuf);
+ asprintf(&sbuf,"%s/doc/5.reference",sys_libdir->name);
+ sys_helppath = namelist_append_files(sys_helppath, sbuf);
+ free(sbuf);
+ /* correct to make audio and MIDI device lists zero based. On MMIO, however, "1" really means the second device
+ the first one is "mapper" which is was not included when the command args were set up, so we leave it that way for compatibility. */
+ if (!sys_mmio) {
+ for (int i=0; i<sys_nsoundin ; i++) sys_soundindevlist[i]--;
+ for (int i=0; i<sys_nsoundout; i++) sys_soundoutdevlist[i]--;
+ }
+ for (int i=0; i<sys_nmidiin; i++) sys_midiindevlist[i]--;
+ for (int i=0; i<sys_nmidiout; i++) sys_midioutdevlist[i]--;
+ if (sys_listplease) sys_listdevs();
+ /* get the current audio parameters. These are set by the preferences mechanism (sys_loadpreferences()) or
+ else are the default. Overwrite them with any results of argument parsing, and store them again. */
+ sys_get_audio_params(&audio_in, &audio_out, &rate, &dacblksize, &advance, &scheduler);
+ nchindev = sys_nchin>=0 ? sys_nchin : audio_in.ndev;
+ nchoutdev = sys_nchout>=0 ? sys_nchout : audio_out.ndev;
+ if (sys_nchin >=0) {for (int i=0; i< nchindev; i++) audio_in.chdev[i] = sys_chinlist[i];}
+ if (sys_nchout>=0) {for (int i=0; i<nchoutdev; i++) audio_out.chdev[i] = sys_choutlist[i];}
+ if (sys_nsoundin>=0) {audio_in.ndev = sys_nsoundin; for (int i=0; i< audio_in.ndev; i++) audio_in.dev[i] = sys_soundindevlist[i];}
+ if (sys_nsoundout>=0) {audio_out.ndev = sys_nsoundout;for (int i=0; i<audio_out.ndev; i++) audio_out.dev[i] = sys_soundoutdevlist[i];}
+ if (sys_nmidiin >=0) {nmidiindev = sys_nmidiin; for (int i=0; i< nmidiindev; i++) midiindev[i] = sys_midiindevlist[i];}
+ if (sys_nmidiout>=0) {nmidioutdev = sys_nmidiout; for (int i=0; i< nmidioutdev; i++) midioutdev[i] = sys_midioutdevlist[i];}
+ if (sys_main_advance) advance = sys_main_advance;
+ if (sys_main_srate) rate = sys_main_srate;
+ if (sys_main_dacblocksize) dacblksize = sys_main_dacblocksize;
+ sys_open_audio(audio_in.ndev, audio_in.dev, nchindev, audio_in.chdev,
+ audio_out.ndev, audio_out.dev, nchoutdev, audio_out.chdev, rate, dacblksize, advance, scheduler, 0);
+ sys_open_midi(nmidiindev, midiindev, nmidioutdev, midioutdev, 0);
+}
diff --git a/desiredata/src/s_midi.c b/desiredata/src/s_midi.c
new file mode 100644
index 00000000..f8ee0fd9
--- /dev/null
+++ b/desiredata/src/s_midi.c
@@ -0,0 +1,619 @@
+/* Copyright (c) 1997-1999 Miller Puckette and others.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* Clock functions (which should move, but where?) and MIDI queueing */
+
+#define PD_PLUSPLUS_FACE
+#include "desire.h"
+#include "s_stuff.h"
+#ifdef UNISTD
+#include <unistd.h>
+#include <sys/time.h>
+#ifdef HAVE_BSTRING_H
+#include <bstring.h>
+#endif
+#endif
+#ifdef MSW
+#include <winsock.h>
+#include <sys/types.h>
+#include <sys/timeb.h>
+#include <wtypes.h>
+#endif
+#include <string.h>
+#include <stdio.h>
+#include <signal.h>
+
+struct t_midiqelem {
+ double time;
+ int portno;
+ unsigned char onebyte;
+ unsigned char byte1;
+ unsigned char byte2;
+ unsigned char byte3;
+};
+
+#define MIDIQSIZE 1024
+
+t_midiqelem midi_outqueue[MIDIQSIZE];
+int midi_outhead, midi_outtail;
+t_midiqelem midi_inqueue[MIDIQSIZE];
+int midi_inhead, midi_intail;
+static double sys_midiinittime;
+
+#ifndef API_DEFAULT
+#define API_DEFAULT 0
+#endif
+int sys_midiapi = API_DEFAULT;
+
+/* this is our current estimate for at what "system" real time the
+ current logical time's output should occur. */
+static double sys_dactimeminusrealtime;
+/* same for input, should be schduler advance earlier. */
+static double sys_adctimeminusrealtime;
+
+static double sys_newdactimeminusrealtime = -1e20;
+static double sys_newadctimeminusrealtime = -1e20;
+static double sys_whenupdate;
+
+void sys_initmidiqueue() {
+ sys_midiinittime = clock_getlogicaltime();
+ sys_dactimeminusrealtime = sys_adctimeminusrealtime = 0;
+}
+
+/* this is called from the OS dependent code from time to time when we
+ think we know the delay (outbuftime) in seconds, at which the last-output
+ audio sample will go out the door. */
+void sys_setmiditimediff(double inbuftime, double outbuftime) {
+ double dactimeminusrealtime = .001 * clock_gettimesince(sys_midiinittime) - outbuftime - sys_getrealtime();
+ double adctimeminusrealtime = .001 * clock_gettimesince(sys_midiinittime) + inbuftime - sys_getrealtime();
+ if (dactimeminusrealtime > sys_newdactimeminusrealtime) sys_newdactimeminusrealtime = dactimeminusrealtime;
+ if (adctimeminusrealtime > sys_newadctimeminusrealtime) sys_newadctimeminusrealtime = adctimeminusrealtime;
+ if (sys_getrealtime() > sys_whenupdate) {
+ sys_dactimeminusrealtime = sys_newdactimeminusrealtime;
+ sys_adctimeminusrealtime = sys_newadctimeminusrealtime;
+ sys_newdactimeminusrealtime = -1e20;
+ sys_newadctimeminusrealtime = -1e20;
+ sys_whenupdate = sys_getrealtime() + 1;
+ }
+}
+
+/* return the logical time of the DAC sample we believe is currently going out, based on how much "system time"
+ has elapsed since the last time sys_setmiditimediff got called. */
+static double sys_getmidioutrealtime() {return sys_getrealtime() + sys_dactimeminusrealtime;}
+static double sys_getmidiinrealtime () {return sys_getrealtime() + sys_adctimeminusrealtime;}
+
+static void sys_putnext () {
+ t_midiqelem &m = midi_outqueue[midi_outtail];
+ int portno = m.portno;
+#ifdef USEAPI_ALSA
+ if (sys_midiapi == API_ALSA) {
+ if (m.onebyte) sys_alsa_putmidibyte(portno, m.byte1);
+ else sys_alsa_putmidimess(portno, m.byte1, m.byte2, m.byte3);
+ } else
+#endif /* ALSA */
+ {
+ if (m.onebyte) sys_putmidibyte(portno, m.byte1);
+ else sys_putmidimess(portno, m.byte1, m.byte2, m.byte3);
+ }
+ midi_outtail = (midi_outtail + 1 == MIDIQSIZE ? 0 : midi_outtail + 1);
+}
+
+/* #define TEST_DEJITTER */
+
+void sys_pollmidioutqueue() {
+#ifdef TEST_DEJITTER
+ static int db = 0;
+#endif
+ double midirealtime = sys_getmidioutrealtime();
+#ifdef TEST_DEJITTER
+ if (midi_outhead == midi_outtail) db = 0;
+#endif
+ while (midi_outhead != midi_outtail) {
+#ifdef TEST_DEJITTER
+ if (!db) {
+ post("out: del %f, midiRT %f logicaltime %f, RT %f dacminusRT %f",
+ (midi_outqueue[midi_outtail].time - midirealtime),
+ midirealtime, .001 * clock_gettimesince(sys_midiinittime),
+ sys_getrealtime(), sys_dactimeminusrealtime);
+ db = 1;
+ }
+#endif
+ if (midi_outqueue[midi_outtail].time <= midirealtime)
+ sys_putnext();
+ else break;
+ }
+}
+
+static void sys_queuemidimess(int portno, int onebyte, int a, int b, int c) {
+ int newhead = midi_outhead +1;
+ if (newhead == MIDIQSIZE) newhead = 0;
+ /* if FIFO is full flush an element to make room */
+ if (newhead == midi_outtail) sys_putnext();
+ t_midiqelem m = midi_outqueue[midi_outhead];
+ m.portno = portno;
+ m.onebyte = onebyte;
+ m.byte1 = a;
+ m.byte2 = b;
+ m.byte3 = c;
+ m.time = .001 * clock_gettimesince(sys_midiinittime);
+ midi_outhead = newhead;
+ sys_pollmidioutqueue();
+}
+
+#define MIDI_NOTEON 144
+#define MIDI_POLYAFTERTOUCH 160
+#define MIDI_CONTROLCHANGE 176
+#define MIDI_PROGRAMCHANGE 192
+#define MIDI_AFTERTOUCH 208
+#define MIDI_PITCHBEND 224
+
+void outmidi_noteon(int portno, int channel, int pitch, int velo) {
+ if (pitch < 0) pitch = 0; else if (pitch > 127) pitch = 127;
+ if (velo < 0) velo = 0; else if (velo > 127) velo = 127;
+ sys_queuemidimess(portno, 0, MIDI_NOTEON + (channel & 0xf), pitch, velo);
+}
+
+void outmidi_controlchange(int portno, int channel, int ctl, int value) {
+ if (ctl < 0) ctl = 0; else if (ctl > 127) ctl = 127;
+ if (value < 0) value = 0; else if (value > 127) value = 127;
+ sys_queuemidimess(portno, 0, MIDI_CONTROLCHANGE + (channel & 0xf),
+ ctl, value);
+}
+
+void outmidi_programchange(int portno, int channel, int value) {
+ if (value < 0) value = 0; else if (value > 127) value = 127;
+ sys_queuemidimess(portno, 0, MIDI_PROGRAMCHANGE + (channel & 0xf), value, 0);
+}
+
+void outmidi_pitchbend(int portno, int channel, int value) {
+ if (value < 0) value = 0; else if (value > 16383) value = 16383;
+ sys_queuemidimess(portno, 0, MIDI_PITCHBEND + (channel & 0xf), (value & 127), ((value>>7) & 127));
+}
+
+void outmidi_aftertouch(int portno, int channel, int value) {
+ if (value < 0) value = 0; else if (value > 127) value = 127;
+ sys_queuemidimess(portno, 0, MIDI_AFTERTOUCH + (channel & 0xf), value, 0);
+}
+
+void outmidi_polyaftertouch(int portno, int channel, int pitch, int value) {
+ if (pitch < 0) pitch = 0; else if (pitch > 127) pitch = 127;
+ if (value < 0) value = 0; else if (value > 127) value = 127;
+ sys_queuemidimess(portno, 0, MIDI_POLYAFTERTOUCH + (channel & 0xf), pitch, value);
+}
+
+void outmidi_byte(int portno, int value) {
+#ifdef USEAPI_ALSA
+ if (sys_midiapi == API_ALSA) sys_alsa_putmidibyte(portno, value); else
+#endif
+ sys_putmidibyte(portno, value);
+}
+
+void outmidi_mclk(int portno) {sys_queuemidimess(portno, 1, 0xf8, 0,0);}
+
+/* ------------------------- MIDI input queue handling ------------------ */
+typedef struct midiparser {
+ int mp_status;
+ int mp_gotbyte1;
+ int mp_byte1;
+} t_midiparser;
+
+#define MIDINOTEOFF 0x80 /* 2 following 'data bytes' */
+#define MIDINOTEON 0x90 /* 2 */
+#define MIDIPOLYTOUCH 0xa0 /* 2 */
+#define MIDICONTROLCHANGE 0xb0 /* 2 */
+#define MIDIPROGRAMCHANGE 0xc0 /* 1 */
+#define MIDICHANNELTOUCH 0xd0 /* 1 */
+#define MIDIPITCHBEND 0xe0 /* 2 */
+#define MIDISTARTSYSEX 0xf0 /* (until F7) */
+#define MIDITIMECODE 0xf1 /* 1 */
+#define MIDISONGPOS 0xf2 /* 2 */
+#define MIDISONGSELECT 0xf3 /* 1 */
+#define MIDIRESERVED1 0xf4 /* ? */
+#define MIDIRESERVED2 0xf5 /* ? */
+#define MIDITUNEREQUEST 0xf6 /* 0 */
+#define MIDIENDSYSEX 0xf7 /* 0 */
+#define MIDICLOCK 0xf8 /* 0 */
+#define MIDITICK 0xf9 /* 0 */
+#define MIDISTART 0xfa /* 0 */
+#define MIDICONT 0xfb /* 0 */
+#define MIDISTOP 0xfc /* 0 */
+#define MIDIACTIVESENSE 0xfe /* 0 */
+#define MIDIRESET 0xff /* 0 */
+
+static void sys_dispatchnextmidiin() {
+ static t_midiparser parser[MAXMIDIINDEV], *parserp;
+ int portno = midi_inqueue[midi_intail].portno, byte = midi_inqueue[midi_intail].byte1;
+ if (!midi_inqueue[midi_intail].onebyte) bug("sys_dispatchnextmidiin");
+ if (portno < 0 || portno >= MAXMIDIINDEV) bug("sys_dispatchnextmidiin 2");
+ parserp = parser + portno;
+ outlet_setstacklim();
+ if (byte >= 0xf8) {
+ inmidi_realtimein(portno, byte);
+ } else {
+ inmidi_byte(portno, byte);
+ if (byte & 0x80) {
+ if (byte == MIDITUNEREQUEST || byte == MIDIRESERVED1 || byte == MIDIRESERVED2) {
+ parserp->mp_status = 0;
+ } else if (byte == MIDISTARTSYSEX) {
+ inmidi_sysex(portno, byte);
+ parserp->mp_status = byte;
+ } else if (byte == MIDIENDSYSEX) {
+ inmidi_sysex(portno, byte);
+ parserp->mp_status = 0;
+ } else {
+ parserp->mp_status = byte;
+ }
+ parserp->mp_gotbyte1 = 0;
+ } else {
+ int cmd = (parserp->mp_status >= 0xf0 ? parserp->mp_status :
+ (parserp->mp_status & 0xf0));
+ int chan = (parserp->mp_status & 0xf);
+ int byte1 = parserp->mp_byte1, gotbyte1 = parserp->mp_gotbyte1;
+ switch (cmd) {
+ case MIDINOTEOFF:
+ if (gotbyte1) inmidi_noteon(portno, chan, byte1, 0), parserp->mp_gotbyte1 = 0;
+ else parserp->mp_byte1 = byte, parserp->mp_gotbyte1 = 1;
+ break;
+ case MIDINOTEON:
+ if (gotbyte1) inmidi_noteon(portno, chan, byte1, byte), parserp->mp_gotbyte1 = 0;
+ else parserp->mp_byte1 = byte, parserp->mp_gotbyte1 = 1;
+ break;
+ case MIDIPOLYTOUCH:
+ if (gotbyte1) inmidi_polyaftertouch(portno, chan, byte1, byte), parserp->mp_gotbyte1 = 0;
+ else parserp->mp_byte1 = byte, parserp->mp_gotbyte1 = 1;
+ break;
+ case MIDICONTROLCHANGE:
+ if (gotbyte1) inmidi_controlchange(portno, chan, byte1, byte), parserp->mp_gotbyte1 = 0;
+ else parserp->mp_byte1 = byte, parserp->mp_gotbyte1 = 1;
+ break;
+ case MIDIPROGRAMCHANGE:
+ inmidi_programchange(portno, chan, byte);
+ break;
+ case MIDICHANNELTOUCH:
+ inmidi_aftertouch(portno, chan, byte);
+ break;
+ case MIDIPITCHBEND:
+ if (gotbyte1) inmidi_pitchbend(portno, chan, ((byte << 7) + byte1)), parserp->mp_gotbyte1 = 0;
+ else parserp->mp_byte1 = byte, parserp->mp_gotbyte1 = 1;
+ break;
+ case MIDISTARTSYSEX:
+ inmidi_sysex(portno, byte);
+ break;
+ /* other kinds of messages are just dropped here. We'll
+ need another status byte before we start letting MIDI in
+ again (no running status across "system" messages). */
+ case MIDITIMECODE: break; /* 1 data byte*/
+ case MIDISONGPOS: break; /* 2 */
+ case MIDISONGSELECT: break; /* 1 */
+ }
+ }
+ }
+ midi_intail = (midi_intail + 1 == MIDIQSIZE ? 0 : midi_intail + 1);
+}
+
+void sys_pollmidiinqueue() {
+#ifdef TEST_DEJITTER
+ static int db = 0;
+#endif
+ double logicaltime = .001 * clock_gettimesince(sys_midiinittime);
+#ifdef TEST_DEJITTER
+ if (midi_inhead == midi_intail)
+ db = 0;
+#endif
+ while (midi_inhead != midi_intail) {
+#ifdef TEST_DEJITTER
+ if (!db) {
+ post("in del %f, logicaltime %f, RT %f adcminusRT %f",
+ (midi_inqueue[midi_intail].time - logicaltime),
+ logicaltime, sys_getrealtime(), sys_adctimeminusrealtime);
+ db = 1;
+ }
+#endif
+#if 0
+ if (midi_inqueue[midi_intail].time <= logicaltime - 0.007)
+ post("late %f", 1000 * (logicaltime - midi_inqueue[midi_intail].time));
+#endif
+ if (midi_inqueue[midi_intail].time <= logicaltime) {
+#if 0
+ post("diff %f", 1000* (logicaltime - midi_inqueue[midi_intail].time));
+#endif
+ sys_dispatchnextmidiin();
+ }
+ else break;
+ }
+}
+
+ /* this should be called from the system dependent MIDI code when a byte
+ comes in, as a result of our calling sys_poll_midi. We stick it on a
+ timetag queue and dispatch it at the appropriate logical time. */
+
+
+void sys_midibytein(int portno, int byte) {
+ static int warned = 0;
+ int newhead = midi_inhead+1;
+ if (newhead == MIDIQSIZE) newhead = 0;
+ /* if FIFO is full flush an element to make room */
+ if (newhead == midi_intail) {
+ if (!warned) {
+ post("warning: MIDI timing FIFO overflowed");
+ warned = 1;
+ }
+ sys_dispatchnextmidiin();
+ }
+ midi_inqueue[midi_inhead].portno = portno;
+ midi_inqueue[midi_inhead].onebyte = 1;
+ midi_inqueue[midi_inhead].byte1 = byte;
+ midi_inqueue[midi_inhead].time = sys_getmidiinrealtime();
+ midi_inhead = newhead;
+ sys_pollmidiinqueue();
+}
+
+void sys_pollmidiqueue() {
+#if 0
+ static double lasttime;
+ double newtime = sys_getrealtime();
+ if (newtime - lasttime > 0.007)
+ post("delay %d", (int)(1000 * (newtime - lasttime)));
+ lasttime = newtime;
+#endif
+#ifdef USEAPI_ALSA
+ if (sys_midiapi == API_ALSA) sys_alsa_poll_midi();
+ else
+#endif /* ALSA */
+ sys_poll_midi(); /* OS dependent poll for MIDI input */
+ sys_pollmidioutqueue();
+ sys_pollmidiinqueue();
+}
+
+/******************** dialog window and device listing ********************/
+
+#ifdef USEAPI_ALSA
+void midi_alsa_init();
+#endif
+#ifndef USEAPI_PORTMIDI
+#ifdef USEAPI_OSS
+void midi_oss_init();
+#endif
+#endif
+
+/* last requested parameters */
+static int midi_nmidiindev;
+static int midi_midiindev[MAXMIDIINDEV];
+static int midi_nmidioutdev;
+static int midi_midioutdev[MAXMIDIOUTDEV];
+
+void sys_get_midi_apis(char *buf) {
+ int n = 0;
+ strcpy(buf, "{ ");
+ sprintf(buf + strlen(buf), "{default-MIDI %d} ", API_DEFAULT); n++;
+#ifdef USEAPI_ALSA
+ sprintf(buf + strlen(buf), "{ALSA-MIDI %d} ", API_ALSA); n++;
+#endif
+ strcat(buf, "}");
+}
+void sys_get_midi_params(int *pnmidiindev, int *pmidiindev, int *pnmidioutdev, int *pmidioutdev) {
+ *pnmidiindev = midi_nmidiindev; for (int i=0; i<MAXMIDIINDEV; i++) pmidiindev [i] = midi_midiindev[i];
+ *pnmidioutdev = midi_nmidioutdev; for (int i=0; i<MAXMIDIOUTDEV; i++) pmidioutdev[i] = midi_midioutdev[i];
+}
+
+static void sys_save_midi_params(int nmidiindev, int *midiindev, int nmidioutdev, int *midioutdev) {
+ midi_nmidiindev = nmidiindev; for (int i=0; i<MAXMIDIINDEV; i++) midi_midiindev [i] = midiindev[i];
+ midi_nmidioutdev = nmidioutdev; for (int i=0; i<MAXMIDIOUTDEV; i++) midi_midioutdev[i] = midioutdev[i];
+}
+
+void sys_open_midi(int nmidiindev, int *midiindev, int nmidioutdev, int *midioutdev, int enable) {
+#ifdef USEAPI_ALSA
+ midi_alsa_init();
+#endif
+#ifndef USEAPI_PORTMIDI
+#ifdef USEAPI_OSS
+ midi_oss_init();
+#endif
+#endif
+ if (enable)
+#ifdef USEAPI_ALSA
+ if (sys_midiapi == API_ALSA)
+ sys_alsa_do_open_midi(nmidiindev, midiindev, nmidioutdev, midioutdev);
+ else
+#endif /* ALSA */
+ sys_do_open_midi(nmidiindev, midiindev, nmidioutdev, midioutdev);
+ sys_save_midi_params(nmidiindev, midiindev, nmidioutdev, midioutdev);
+ sys_vgui("set pd_whichmidiapi %d\n", sys_midiapi);
+}
+
+/* open midi using whatever parameters were last used */
+void sys_reopen_midi() {
+ int nmidiindev, midiindev[MAXMIDIINDEV];
+ int nmidioutdev, midioutdev[MAXMIDIOUTDEV];
+ sys_get_midi_params(&nmidiindev, midiindev, &nmidioutdev, midioutdev);
+ sys_open_midi(nmidiindev, midiindev, nmidioutdev, midioutdev, 1);
+}
+
+#define MAXNDEV 50
+#define DEVDESCSIZE 80
+#define DEVONSET 1 /* To agree with command line flags, normally start at 1 */
+
+void sys_listmididevs() {
+ char indevlist[MAXNDEV*DEVDESCSIZE], outdevlist[MAXNDEV*DEVDESCSIZE];
+ int nindevs = 0, noutdevs = 0;
+#ifdef USEAPI_ALSA
+ if (sys_midiapi == API_ALSA)
+ midi_alsa_getdevs(indevlist, &nindevs, outdevlist, &noutdevs, MAXNDEV, DEVDESCSIZE);
+ else
+#endif /* ALSA */
+ midi_getdevs(indevlist, &nindevs, outdevlist, &noutdevs, MAXNDEV, DEVDESCSIZE);
+ if (!nindevs) post("no midi input devices found");
+ else {
+ post("MIDI input devices:");
+ for (int i=0; i<nindevs; i++) post("%d. %s", i+1, indevlist + i * DEVDESCSIZE);
+ }
+ if (!noutdevs) post("no midi output devices found");
+ else {
+ post("MIDI output devices:");
+ for (int i=0; i<noutdevs; i++) post("%d. %s", i+DEVONSET, outdevlist + i * DEVDESCSIZE);
+ }
+}
+
+void sys_set_midi_api(int which) {
+ sys_midiapi = which;
+ if (sys_verbose) post("sys_midiapi %d", sys_midiapi);
+}
+
+void glob_midi_properties(t_pd *dummy, t_floatarg flongform);
+
+void glob_midi_setapi(t_pd *dummy, t_floatarg f) {
+ int newapi = int(f);
+ if (newapi) {
+ if (newapi == sys_midiapi) {
+ //if (!midi_isopen()) s_reopen_midi();
+ } else {
+#ifdef USEAPI_ALSA
+ if (sys_midiapi == API_ALSA) sys_alsa_close_midi();
+ else
+#endif
+ sys_close_midi();
+ sys_midiapi = newapi;
+ /* bash device params back to default */
+ midi_nmidiindev = midi_nmidioutdev = 1;
+ //midi_midiindev[0] = midi_midioutdev[0] = DEFAULTMIDIDEV;
+ //midi_midichindev[0] = midi_midichoutdev[0] = SYS_DEFAULTCH;
+ sys_reopen_midi();
+ }
+ glob_midi_properties(0, 0);
+ } else /* if (midi_isopen()) */ {
+ sys_close_midi();
+ //midi_state = 0;
+ }
+}
+
+extern t_class *glob_pdobject;
+
+/* start an midi settings dialog window */
+void glob_midi_properties(t_pd *dummy, t_floatarg flongform) {
+ /* these are the devices you're using: */
+ int nindev, midiindev[MAXMIDIINDEV];
+ int noutdev, midioutdev[MAXMIDIOUTDEV];
+ char midiinstr[16*4+1],midioutstr[16*4+1],*strptr;
+ /* these are all the devices on your system: */
+ char indevlist[MAXNDEV*DEVDESCSIZE], outdevlist[MAXNDEV*DEVDESCSIZE];
+ int nindevs = 0, noutdevs = 0, i;
+ char indevliststring[MAXNDEV*(DEVDESCSIZE+4)+80],
+ outdevliststring[MAXNDEV*(DEVDESCSIZE+4)+80];
+ midi_getdevs(indevlist, &nindevs, outdevlist, &noutdevs, MAXNDEV, DEVDESCSIZE);
+ strcpy(indevliststring, "{");
+ for (i = 0; i < nindevs; i++) {
+ strcat(indevliststring, "\"");
+ strcat(indevliststring, indevlist + i * DEVDESCSIZE);
+ strcat(indevliststring, "\" ");
+ }
+ strcat(indevliststring, "}");
+ strcpy(outdevliststring, "{");
+ for (i = 0; i < noutdevs; i++) {
+ strcat(outdevliststring, "\"");
+ strcat(outdevliststring, outdevlist + i * DEVDESCSIZE);
+ strcat(outdevliststring, "\" ");
+ }
+ strcat(outdevliststring, "}");
+ sys_get_midi_params(&nindev, midiindev, &noutdev, midioutdev);
+ if (nindev > 1 || noutdev > 1) flongform = 1;
+ *(strptr = midiinstr) = 0;
+ for(i = 0; i < 16; ++i) {
+ sprintf(strptr,"%3d ",nindev > i && midiindev[i]>= 0 ? midiindev[i] : -1);
+ strptr += strlen(strptr);
+ }
+ *(strptr = midioutstr) = 0;
+ for(i = 0; i < 16; ++i) {
+ sprintf(strptr,"%3d ",noutdev > i && midioutdev[i]>= 0 ? midioutdev[i] : -1);
+ strptr += strlen(strptr);
+ }
+ sys_vgui("pdtk_midi_dialog %%s %s %s %s %s %d\n",
+ indevliststring,midiinstr,outdevliststring,midioutstr,!!flongform);
+}
+
+/* new values from dialog window */
+void glob_midi_dialog(t_pd *dummy, t_symbol *s, int argc, t_atom *argv) {
+ int i, nindev, noutdev;
+ int newmidiindev[16], newmidioutdev[16];
+ int alsadevin, alsadevout;
+ for (i = 0; i < 16; i++) {
+ newmidiindev[i] = atom_getintarg(i, argc, argv);
+ newmidioutdev[i] = atom_getintarg(i+16, argc, argv);
+ }
+ for (i = 0, nindev = 0; i < 16; i++) {
+ if (newmidiindev[i] >= 0) {newmidiindev[nindev] = newmidiindev[i]; nindev++;}
+ }
+ for (i = 0, noutdev = 0; i < 16; i++) {
+ if (newmidioutdev[i] >= 0) {newmidioutdev[noutdev] = newmidioutdev[i]; noutdev++;}
+ }
+ alsadevin = atom_getintarg(32, argc, argv);
+ alsadevout = atom_getintarg(33, argc, argv);
+#ifdef USEAPI_ALSA
+ if (sys_midiapi == API_ALSA) {
+ sys_alsa_close_midi();
+ sys_open_midi(alsadevin, newmidiindev, alsadevout, newmidioutdev, 1);
+ } else
+#endif
+ {
+ sys_close_midi();
+ sys_open_midi(nindev, newmidiindev, noutdev, newmidioutdev, 1);
+ }
+}
+
+/* tb { */
+
+void glob_midi_getindevs(t_pd *dummy, t_symbol *s, int ac, t_atom *av) {
+ /* these are all the devices on your system: */
+ char indevlist[MAXNDEV*DEVDESCSIZE], outdevlist[MAXNDEV*DEVDESCSIZE];
+ int nindevs = 0, noutdevs = 0;
+ t_atom argv[MAXNDEV];
+ int f = ac ? (int)atom_getfloatarg(0,ac,av) : -1;
+ t_symbol *selector = gensym("midiindev");
+ t_symbol *pd = gensym("pd");
+ midi_getdevs(indevlist, &nindevs, outdevlist, &noutdevs, MAXNDEV, DEVDESCSIZE);
+ if (f < 0) {
+ for (int i=0; i<nindevs; i++) SETSYMBOL(argv+i, gensym(indevlist + i * DEVDESCSIZE));
+ typedmess(pd->s_thing, selector, nindevs, argv);
+ } else if (f < nindevs) {
+ SETSYMBOL(argv, gensym(indevlist + f * DEVDESCSIZE));
+ typedmess(pd->s_thing, selector, 1, argv);
+ }
+}
+
+void glob_midi_getoutdevs(t_pd *dummy, t_symbol *s, int ac, t_atom *av) {
+ /* these are all the devices on your system: */
+ char indevlist[MAXNDEV*DEVDESCSIZE], outdevlist[MAXNDEV*DEVDESCSIZE];
+ int nindevs = 0, noutdevs = 0;
+ t_atom argv[MAXNDEV];
+ int f = ac ? (int)atom_getfloatarg(0,ac,av) : -1;
+ t_symbol *selector = gensym("midioutdev");
+ t_symbol *pd = gensym("pd");
+ midi_getdevs(indevlist, &nindevs, outdevlist, &noutdevs, MAXNDEV, DEVDESCSIZE);
+ if (f < 0) {
+ for (int i=0; i<noutdevs; i++) SETSYMBOL(argv+i, gensym(outdevlist + i*DEVDESCSIZE));
+ typedmess(pd->s_thing, selector, noutdevs, argv);
+ } else if (f < noutdevs) {
+ SETSYMBOL(argv, gensym(outdevlist + f*DEVDESCSIZE));
+ typedmess(pd->s_thing, selector, 1, argv);
+ }
+}
+
+void glob_midi_getcurrentindevs(t_pd *dummy) {
+ /* these are the devices you're using: */
+ int nindev, midiindev[MAXMIDIINDEV];
+ int noutdev, midioutdev[MAXMIDIOUTDEV];
+ t_atom argv[MAXNDEV];
+ sys_get_midi_params(&nindev, midiindev, &noutdev, midioutdev);
+ for (int i=0; i<nindev; i++) SETFLOAT(argv+i, midiindev[i]);
+ typedmess(gensym("pd")->s_thing, gensym("midicurrentindev"), nindev, argv);
+}
+
+void glob_midi_getcurrentoutdevs(t_pd *dummy) {
+ /* these are the devices you're using: */
+ int nindev, midiindev[MAXMIDIINDEV];
+ int noutdev, midioutdev[MAXMIDIOUTDEV];
+ t_atom argv[MAXNDEV];
+ sys_get_midi_params(&nindev, midiindev, &noutdev, midioutdev);
+ for (int i=0; i<noutdev; i++) SETFLOAT(argv+i, midioutdev[i]);
+ typedmess(gensym("pd")->s_thing, gensym("midicurrentoutdev"), noutdev, argv);
+}
diff --git a/desiredata/src/s_midi_alsa.c b/desiredata/src/s_midi_alsa.c
new file mode 100644
index 00000000..894d7200
--- /dev/null
+++ b/desiredata/src/s_midi_alsa.c
@@ -0,0 +1,209 @@
+/* Copyright (c) 1997-1999 Guenter Geiger, Miller Puckette, Larry Troxler,
+* Winfried Ritsch, Karl MacMillan, and others.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* MIDI I/O for Linux using ALSA */
+
+#include <stdio.h>
+#ifdef UNISTD
+#include <unistd.h>
+#endif
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <alsa/asoundlib.h>
+#include "desire.h"
+//#include "s_stuff.h"
+
+#define MAX_EVENT_SIZE 256
+
+static int alsa_nmidiin;
+static int alsa_midiinfd[MAXMIDIINDEV];
+static int alsa_nmidiout;
+static int alsa_midioutfd[MAXMIDIOUTDEV];
+static snd_seq_t *midi_handle;
+static snd_midi_event_t *midiev;
+
+static unsigned short CombineBytes(unsigned char First, unsigned char Second) {
+ return ((unsigned short)Second << 7) | (unsigned short)First;
+}
+
+void sys_alsa_do_open_midi(int nmidiin, int *midiinvec, int nmidiout, int *midioutvec) {
+ char portname[50];
+ int err = 0;
+ snd_seq_client_info_t *alsainfo;
+ /* do we want to connect pd automatically with other devices ?; see below! */
+ /* LATER: think about a flag to enable/disable automatic connection (sometimes it could be a pain) */
+ int autoconnect = 1;
+ alsa_nmidiin = 0;
+ alsa_nmidiout = 0;
+ if (nmidiout == 0 && nmidiin == 0) return;
+ if (nmidiin>MAXMIDIINDEV) {post( "midi input ports reduced to maximum %d", MAXMIDIINDEV); nmidiin =MAXMIDIINDEV;}
+ if (nmidiout>MAXMIDIOUTDEV) {post("midi output ports reduced to maximum %d", MAXMIDIOUTDEV); nmidiout=MAXMIDIOUTDEV;}
+ if (nmidiin>0 && nmidiout>0) err = snd_seq_open(&midi_handle,"default",SND_SEQ_OPEN_DUPLEX,0);
+ else if (nmidiin > 0) err = snd_seq_open(&midi_handle,"default",SND_SEQ_OPEN_INPUT,0);
+ else if (nmidiout > 0) err = snd_seq_open(&midi_handle,"default",SND_SEQ_OPEN_OUTPUT,0);
+ if (err!=0) {
+ sys_setalarm(1000000);
+ post("couldn't open alsa sequencer");
+ return;
+ }
+ int client;
+ for (int i=0; i<nmidiin; i++) {
+ sprintf(portname,"Pure Data Midi-In %d",i+1);
+ int port = snd_seq_create_simple_port(midi_handle,portname,
+ SND_SEQ_PORT_CAP_WRITE |SND_SEQ_PORT_CAP_SUBS_WRITE, SND_SEQ_PORT_TYPE_APPLICATION);
+ if (port < 0) goto error;
+ alsa_midiinfd[i] = port;
+ }
+ for (int i=0; i<nmidiout; i++) {
+ sprintf(portname,"Pure Data Midi-Out %d",i+1);
+ int port = snd_seq_create_simple_port(midi_handle,portname,
+ SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ, SND_SEQ_PORT_TYPE_APPLICATION);
+ if (port < 0) goto error;
+ alsa_midioutfd[i] = port;
+ }
+ snd_seq_client_info_malloc(&alsainfo);
+ snd_seq_get_client_info(midi_handle,alsainfo);
+ snd_seq_client_info_set_name(alsainfo,"Pure Data");
+ client = snd_seq_client_info_get_client(alsainfo);
+ snd_seq_set_client_info(midi_handle,alsainfo);
+ snd_seq_client_info_free(alsainfo);
+ post("Opened Alsa Client %d in:%d out:%d",client,nmidiin,nmidiout);
+ sys_setalarm(0);
+ snd_midi_event_new(MAX_EVENT_SIZE,&midiev);
+ alsa_nmidiout = nmidiout;
+ alsa_nmidiin = nmidiin;
+ /* JMZ: connect all available devices to pd */
+ if (autoconnect) {
+ snd_seq_client_info_t *cinfo;
+ snd_seq_port_info_t *pinfo;
+ snd_seq_port_subscribe_t *subs;
+ snd_seq_addr_t other, topd, frompd;
+ /* since i don't know how to connect multiple ports (connect everything to each port, modulo,...),
+ * i only fully connect where we have only one single port */
+ if(alsa_nmidiin ) { topd.client = client; topd.port = alsa_midiinfd [0];}
+ if(alsa_nmidiout) {frompd.client = client; frompd.port = alsa_midioutfd[0];}
+ snd_seq_port_subscribe_alloca(&subs);
+ snd_seq_client_info_alloca(&cinfo);
+ snd_seq_port_info_alloca(&pinfo);
+ snd_seq_client_info_set_client(cinfo, -1);
+ while (snd_seq_query_next_client(midi_handle, cinfo) >= 0) {
+ /* reset query info */
+ int client_id=snd_seq_client_info_get_client(cinfo);
+ if((SND_SEQ_CLIENT_SYSTEM != client_id)&&(client != client_id)) { /* skipping port 0 and ourself */
+ snd_seq_port_info_set_client(pinfo, client_id);
+ snd_seq_port_info_set_port(pinfo, -1);
+ while (snd_seq_query_next_port(midi_handle, pinfo) >= 0) {
+ other.client=client_id;
+ other.port =snd_seq_port_info_get_port(pinfo);
+ if(1==alsa_nmidiin) /* only autoconnect 1st port */ {
+ snd_seq_port_subscribe_set_sender(subs, &other);
+ snd_seq_port_subscribe_set_dest(subs, &topd);
+ snd_seq_subscribe_port(midi_handle, subs);
+ }
+ if(1==alsa_nmidiout) /* only autoconnect 1st port */ {
+ snd_seq_port_subscribe_set_sender(subs, &frompd);
+ snd_seq_port_subscribe_set_dest(subs, &other);
+ snd_seq_subscribe_port(midi_handle, subs);
+ }
+ }
+ }
+ }
+ }
+ return;
+ error:
+ sys_setalarm(1000000);
+ post("couldn't open alsa MIDI output device");
+ return;
+}
+
+#define md_msglen(x) (((x)<0xC0)?2:((x)<0xE0)?1:((x)<0xF0)?2:\
+ ((x)==0xF2)?2:((x)<0xF4)?1:0)
+
+void sys_alsa_putmidimess(int portno, int a, int b, int c) {
+ int channel = a&15;
+ snd_seq_event_t ev;
+ snd_seq_ev_clear(&ev);
+ if (portno >= 0 && portno < alsa_nmidiout) {
+ if (a >= 224) { // pitchbend
+ snd_seq_ev_set_pitchbend(&ev,channel,CombineBytes(b,c));
+ } else if (a >= 208) { // touch
+ snd_seq_ev_set_chanpress(&ev,channel,b);
+ } else if (a >= 192) { // program
+ snd_seq_ev_set_pgmchange(&ev,channel,b);
+ } else if (a >= 176) { // controller
+ snd_seq_ev_set_controller(&ev,channel,b,c);
+ } else if (a >= 160) { // polytouch
+ snd_seq_ev_set_keypress(&ev,channel,b,c);
+ } else if (a >= 144) { // note
+ channel = a-144;
+ if (c) snd_seq_ev_set_noteon(&ev,channel,b,c);
+ else snd_seq_ev_set_noteoff(&ev,channel,b,c);
+ }
+ snd_seq_ev_set_direct(&ev);
+ snd_seq_ev_set_subs(&ev);
+ snd_seq_ev_set_source(&ev,alsa_midioutfd[portno]);
+ snd_seq_event_output_direct(midi_handle,&ev);
+ }
+}
+
+void sys_alsa_putmidibyte(int portno, int byte) {
+ snd_seq_event_t ev;
+ snd_seq_ev_clear(&ev);
+ if (portno >= 0 && portno < alsa_nmidiout) {
+ // repack into 1 byte char and put somewhere to point at
+ unsigned char data = (unsigned char)byte;
+ snd_seq_ev_set_sysex(&ev,1,&data); //...set_variable *should* have worked but didn't
+ snd_seq_ev_set_direct(&ev);
+ snd_seq_ev_set_subs(&ev);
+ snd_seq_ev_set_source(&ev,alsa_midioutfd[portno]);
+ snd_seq_event_output_direct(midi_handle,&ev);
+ }
+}
+
+/* this version uses the asynchronous "read()" ... */
+void sys_alsa_poll_midi() {
+ unsigned char buf[MAX_EVENT_SIZE];
+ int count, alsa_source;
+ snd_seq_event_t *midievent = NULL;
+ if (alsa_nmidiout == 0 && alsa_nmidiin == 0) return;
+ snd_midi_event_init(midiev);
+ if (!alsa_nmidiout && !alsa_nmidiin) return;
+ count = snd_seq_event_input_pending(midi_handle,1);
+ if (count != 0) count = snd_seq_event_input(midi_handle,&midievent);
+ if (midievent != NULL) {
+ count = snd_midi_event_decode(midiev,buf,sizeof(buf),midievent);
+ alsa_source = midievent->dest.port;
+ for(int i=0; i<count; i++) sys_midibytein(alsa_source, (buf[i] & 0xff));
+ //post("received %d midi bytes",count);
+ }
+}
+
+void sys_alsa_close_midi() {
+ alsa_nmidiin = alsa_nmidiout = 0;
+ if(midi_handle) {
+ snd_seq_close(midi_handle);
+ if(midiev) snd_midi_event_free(midiev);
+ }
+}
+
+#define NSEARCH 10
+static int alsa_nmidiindevs, alsa_nmidioutdevs, alsa_initted;
+
+void midi_alsa_init() {
+ if (alsa_initted) return;
+ alsa_initted = 1;
+}
+
+void midi_alsa_getdevs(char *indevlist, int *nindevs, char *outdevlist, int *noutdevs, int maxndev, int devdescsize) {
+ int ndev = min(maxndev,alsa_nmidiindevs);
+ for (int i=0; i<ndev; i++) sprintf(indevlist + i * devdescsize, "ALSA MIDI device #%d", i+1);
+ *nindevs = ndev;
+ ndev = min(maxndev,alsa_nmidioutdevs);
+ for (int i=0; i<ndev; i++) sprintf(outdevlist + i * devdescsize, "ALSA MIDI device #%d", i+1);
+ *noutdevs = ndev;
+}
diff --git a/desiredata/src/s_midi_mmio.c b/desiredata/src/s_midi_mmio.c
new file mode 100644
index 00000000..95c95d76
--- /dev/null
+++ b/desiredata/src/s_midi_mmio.c
@@ -0,0 +1,505 @@
+/* Copyright (c) 1997-1999 Miller Puckette.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include "m_pd.h"
+#include "s_stuff.h"
+#include <stdio.h>
+#include <windows.h>
+#include <MMSYSTEM.H>
+
+/* ------------- MIDI time stamping from audio clock ------------ */
+#ifdef MIDI_TIMESTAMP
+
+static double msw_hibuftime;
+static double initsystime = -1;
+
+/* call this whenever we reset audio */
+static void msw_resetmidisync() {
+ initsystime = clock_getsystime();
+ msw_hibuftime = sys_getrealtime();
+}
+
+/* call this whenever we're idled waiting for audio to be ready. The routine maintains a high and low water point
+ for the difference between real and DAC time. */
+static void msw_midisync() {
+ if (initsystime == -1) msw_resetmidisync();
+ double jittersec = max(msw_dacjitterbufsallowed,msw_adcjitterbufsallowed) * REALDACBLKSIZE / sys_getsr();
+ double diff = sys_getrealtime() - 0.001 * clock_gettimesince(initsystime);
+ if (diff > msw_hibuftime) msw_hibuftime = diff;
+ if (diff < msw_hibuftime - jittersec) {
+ post("jitter excess %d %f", dac, diff);
+ msw_resetmidisync();
+ }
+}
+
+static double msw_midigettimefor(LARGE_INTEGER timestamp) {
+ /* this is broken now... used to work when "timestamp" was derived from QueryPerformanceCounter() instead of
+ the MS-approved timeGetSystemTime() call in the MIDI callback routine below. */
+ return msw_tixtotime(timestamp) - msw_hibuftime;
+}
+#endif /* MIDI_TIMESTAMP */
+
+/* ------------------------- MIDI output -------------------------- */
+static void msw_midiouterror(char *s, int err) {
+ char t[256];
+ midiOutGetErrorText(err, t, 256);
+ error(s,t);
+}
+
+static HMIDIOUT hMidiOut[MAXMIDIOUTDEV]; /* output device */
+static int msw_nmidiout; /* number of devices */
+
+static void msw_open_midiout(int nmidiout, int *midioutvec) {
+ UINT result, wRtn;
+ MIDIOUTCAPS midioutcaps;
+ if (nmidiout > MAXMIDIOUTDEV) nmidiout = MAXMIDIOUTDEV;
+ int dev = 0;
+ for (int i=0; i<nmidiout; i++) {
+ MIDIOUTCAPS mocap;
+ int devno = midioutvec[i];
+ result = midiOutOpen(&hMidiOut[dev], devno, 0, 0, CALLBACK_NULL);
+ wRtn = midiOutGetDevCaps(i, (LPMIDIOUTCAPS) &mocap, sizeof(mocap));
+ if (result != MMSYSERR_NOERROR) {
+ error("midiOutOpen: %s",midioutcaps.szPname);
+ msw_midiouterror("midiOutOpen: %s", result);
+ } else {
+ if (sys_verbose) error("midiOutOpen: Open %s as Port %d", midioutcaps.szPname, dev);
+ dev++;
+ }
+ }
+ msw_nmidiout = dev;
+}
+
+static void msw_close_midiout() {
+ for (int i=0; i<msw_nmidiout; i++) {
+ midiOutReset(hMidiOut[i]);
+ midiOutClose(hMidiOut[i]);
+ }
+ msw_nmidiout = 0;
+}
+
+/* -------------------------- MIDI input ---------------------------- */
+
+#define INPUT_BUFFER_SIZE 1000 // size of input buffer in events
+
+static void msw_midiinerror(char *s, int err) {
+ char t[256];
+ midiInGetErrorText(err, t, 256);
+ error(s,t);
+}
+
+/* Structure to represent a single MIDI event. */
+#define EVNT_F_ERROR 0x00000001L
+typedef struct evemsw_tag {
+ DWORD fdwEvent;
+ DWORD dwDevice;
+ LARGE_INTEGER timestamp;
+ DWORD data;
+} EVENT;
+typedef EVENT FAR *LPEVENT;
+
+/* Structure to manage the circular input buffer. */
+typedef struct circularBuffer_tag {
+ HANDLE hSelf; /* handle to this structure */
+ HANDLE hBuffer; /* buffer handle */
+ WORD wError; /* error flags */
+ DWORD dwSize; /* buffer size (in EVENTS) */
+ DWORD dwCount; /* byte count (in EVENTS) */
+ LPEVENT lpStart; /* ptr to start of buffer */
+ LPEVENT lpEnd; /* ptr to end of buffer (last byte + 1) */
+ LPEVENT lpHead; /* ptr to head (next location to fill) */
+ LPEVENT lpTail; /* ptr to tail (next location to empty) */
+} CIRCULARBUFFER;
+typedef CIRCULARBUFFER FAR *LPCIRCULARBUFFER;
+
+/* Structure to pass instance data from the application to the low-level callback function. */
+typedef struct callbackInstance_tag {
+ HANDLE hSelf;
+ DWORD dwDevice;
+ LPCIRCULARBUFFER lpBuf;
+} CALLBACKINSTANCEDATA;
+typedef CALLBACKINSTANCEDATA FAR *LPCALLBACKINSTANCEDATA;
+
+/* Function prototypes */
+LPCALLBACKINSTANCEDATA FAR PASCAL AllocCallbackInstanceData();
+void FAR PASCAL FreeCallbackInstanceData(LPCALLBACKINSTANCEDATA lpBuf);
+LPCIRCULARBUFFER AllocCircularBuffer(DWORD dwSize);
+void FreeCircularBuffer(LPCIRCULARBUFFER lpBuf);
+WORD FAR PASCAL GetEvent(LPCIRCULARBUFFER lpBuf, LPEVENT lpEvent);
+
+// Callback instance data pointers
+LPCALLBACKINSTANCEDATA lpCallbackInstanceData[MAXMIDIINDEV];
+
+UINT wNumDevices = 0; // Number of MIDI input devices opened
+BOOL bRecordingEnabled = 1; // Enable/disable recording flag
+int nNumBufferLines = 0; // Number of lines in display buffer
+RECT rectScrollClip; // Clipping rectangle for scrolling
+LPCIRCULARBUFFER lpInputBuffer; // Input buffer structure
+EVENT incomingEvent; // Incoming MIDI event structure
+MIDIINCAPS midiInCaps[MAXMIDIINDEV]; // Device capabilities structures
+HMIDIIN hMidiIn[MAXMIDIINDEV]; // MIDI input device handles
+
+/* AllocCallbackInstanceData - Allocates a CALLBACKINSTANCEDATA structure. This structure is used to pass information
+ to the low-level callback function, each time it receives a message. Because this structure is accessed by the
+ low-level callback function, it must be allocated using GlobalAlloc() with the GMEM_SHARE and GMEM_MOVEABLE flags
+ and page-locked with GlobalPageLock().
+ Return: A pointer to the allocated CALLBACKINSTANCE data structure. */
+LPCALLBACKINSTANCEDATA FAR PASCAL AllocCallbackInstanceData() {
+ HANDLE hMem;
+ LPCALLBACKINSTANCEDATA lpBuf;
+ /* Allocate and lock global memory. */
+ hMem = GlobalAlloc(GMEM_SHARE | GMEM_MOVEABLE, (DWORD)sizeof(CALLBACKINSTANCEDATA));
+ if(!hMem) return 0;
+ lpBuf = (LPCALLBACKINSTANCEDATA)GlobalLock(hMem);
+ if(!lpBuf) {GlobalFree(hMem); return 0;}
+ /* Page lock the memory. */
+ //GlobalPageLock((HGLOBAL)HIWORD(lpBuf));
+ /* Save the handle. */
+ lpBuf->hSelf = hMem;
+ return lpBuf;
+}
+
+/* FreeCallbackInstanceData - Frees the given CALLBACKINSTANCEDATA structure.
+ * Params: lpBuf - Points to the CALLBACKINSTANCEDATA structure to be freed. */
+void FAR PASCAL FreeCallbackInstanceData(LPCALLBACKINSTANCEDATA lpBuf) {
+ HANDLE hMem;
+ /* Save the handle until we're through here. */
+ hMem = lpBuf->hSelf;
+ /* Free the structure. */
+ //GlobalPageUnlock((HGLOBAL)HIWORD(lpBuf));
+ GlobalUnlock(hMem);
+ GlobalFree(hMem);
+}
+
+/* AllocCircularBuffer - Allocates memory for a CIRCULARBUFFER structure
+ * and a buffer of the specified size. Each memory block is allocated
+ * with GlobalAlloc() using GMEM_SHARE and GMEM_MOVEABLE flags, locked
+ * with GlobalLock(), and page-locked with GlobalPageLock().
+ * Params: dwSize - The size of the buffer, in events.
+ * Return: A pointer to a CIRCULARBUFFER structure identifying the allocated display buffer. NULL if the buffer could not be allocated. */
+
+LPCIRCULARBUFFER AllocCircularBuffer(DWORD dwSize) {
+ HANDLE hMem;
+ LPCIRCULARBUFFER lpBuf;
+ LPEVENT lpMem;
+ /* Allocate and lock a CIRCULARBUFFER structure. */
+ hMem = GlobalAlloc(GMEM_SHARE | GMEM_MOVEABLE, (DWORD)sizeof(CIRCULARBUFFER));
+ if(!hMem) return 0;
+ lpBuf = (LPCIRCULARBUFFER)GlobalLock(hMem);
+ if(!lpBuf) {GlobalFree(hMem); return 0;}
+ /* Page lock the memory. Global memory blocks accessed by low-level callback functions must be page locked. */
+#ifndef _WIN32
+ GlobalSmartPageLock((HGLOBAL)HIWORD(lpBuf));
+#endif
+ /* Save the memory handle. */
+ lpBuf->hSelf = hMem;
+ /* Allocate and lock memory for the actual buffer. */
+ hMem = GlobalAlloc(GMEM_SHARE | GMEM_MOVEABLE, dwSize * sizeof(EVENT));
+ if(!hMem) {
+#ifndef _WIN32
+ GlobalSmartPageUnlock((HGLOBAL)HIWORD(lpBuf));
+#endif
+ GlobalUnlock(lpBuf->hSelf);
+ GlobalFree(lpBuf->hSelf);
+ return 0;
+ }
+ lpMem = (LPEVENT)GlobalLock(hMem);
+ if(!lpMem) {
+ GlobalFree(hMem);
+#ifndef _WIN32
+ GlobalSmartPageUnlock((HGLOBAL)HIWORD(lpBuf));
+#endif
+ GlobalUnlock(lpBuf->hSelf);
+ GlobalFree(lpBuf->hSelf);
+ return NULL;
+ }
+ /* Page lock the memory. Global memory blocks accessed by low-level callback functions must be page locked. */
+#ifndef _WIN32
+ GlobalSmartPageLock((HGLOBAL)HIWORD(lpMem));
+#endif
+ /* Set up the CIRCULARBUFFER structure. */
+ lpBuf->hBuffer = hMem;
+ lpBuf->wError = 0;
+ lpBuf->dwSize = dwSize;
+ lpBuf->dwCount = 0L;
+ lpBuf->lpStart = lpMem;
+ lpBuf->lpEnd = lpMem + dwSize;
+ lpBuf->lpTail = lpMem;
+ lpBuf->lpHead = lpMem;
+ return lpBuf;
+}
+
+/* FreeCircularBuffer - Frees the memory for the given CIRCULARBUFFER structure and the memory for the buffer it references.
+ * Params: lpBuf - Points to the CIRCULARBUFFER to be freed. */
+void FreeCircularBuffer(LPCIRCULARBUFFER lpBuf) {
+ HANDLE hMem;
+ /* Free the buffer itself. */
+#ifndef _WIN32
+ GlobalSmartPageUnlock((HGLOBAL)HIWORD(lpBuf->lpStart));
+#endif
+ GlobalUnlock(lpBuf->hBuffer);
+ GlobalFree(lpBuf->hBuffer);
+ /* Free the CIRCULARBUFFER structure. */
+ hMem = lpBuf->hSelf;
+#ifndef _WIN32
+ GlobalSmartPageUnlock((HGLOBAL)HIWORD(lpBuf));
+#endif
+ GlobalUnlock(hMem);
+ GlobalFree(hMem);
+}
+
+/* GetEvent - Gets a MIDI event from the circular input buffer. Events
+ * are removed from the buffer. The corresponding PutEvent() function
+ * is called by the low-level callback function, so it must reside in
+ * the callback DLL. PutEvent() is defined in the CALLBACK.C module.
+ *
+ * Params: lpBuf - Points to the circular buffer.
+ * lpEvent - Points to an EVENT structure that is filled with the retrieved event.
+ * Return: Returns non-zero if successful, zero if there are no events to get. */
+WORD FAR PASCAL GetEvent(LPCIRCULARBUFFER lpBuf, LPEVENT lpEvent) {
+ /* If no event available, return */
+ if (!wNumDevices || lpBuf->dwCount <= 0) return 0;
+ /* Get the event. */
+ *lpEvent = *lpBuf->lpTail;
+ /* Decrement the byte count, bump the tail pointer. */
+ --lpBuf->dwCount;
+ ++lpBuf->lpTail;
+ /* Wrap the tail pointer, if necessary. */
+ if (lpBuf->lpTail >= lpBuf->lpEnd) lpBuf->lpTail = lpBuf->lpStart;
+ return 1;
+}
+
+/* PutEvent - Puts an EVENT in a CIRCULARBUFFER. If the buffer is full,
+ * it sets the wError element of the CIRCULARBUFFER structure
+ * to be non-zero.
+ *
+ * Params: lpBuf - Points to the CIRCULARBUFFER.
+ * lpEvent - Points to the EVENT. */
+
+void FAR PASCAL PutEvent(LPCIRCULARBUFFER lpBuf, LPEVENT lpEvent) {
+ /* If the buffer is full, set an error and return. */
+ if(lpBuf->dwCount >= lpBuf->dwSize){
+ lpBuf->wError = 1;
+ return;
+ }
+ /* Put the event in the buffer, bump the head pointer and the byte count. */
+ *lpBuf->lpHead = *lpEvent;
+ ++lpBuf->lpHead;
+ ++lpBuf->dwCount;
+ /* Wrap the head pointer, if necessary. */
+ if(lpBuf->lpHead >= lpBuf->lpEnd) lpBuf->lpHead = lpBuf->lpStart;
+}
+
+/* midiInputHandler - Low-level callback function to handle MIDI input.
+ * Installed by midiInOpen(). The input handler takes incoming
+ * MIDI events and places them in the circular input buffer. It then
+ * notifies the application by posting a MM_MIDIINPUT message.
+ *
+ * This function is accessed at interrupt time, so it should be as
+ * fast and efficient as possible. You can't make any
+ * Windows calls here, except PostMessage(). The only Multimedia
+ * Windows call you can make are timeGetSystemTime(), midiOutShortMsg().
+ *
+ * Param: hMidiIn - Handle for the associated input device.
+ * wMsg - One of the MIM_***** messages.
+ * dwInstance - Points to CALLBACKINSTANCEDATA structure.
+ * dwParam1 - MIDI data.
+ * dwParam2 - Timestamp (in milliseconds) */
+void FAR PASCAL midiInputHandler(HMIDIIN hMidiIn, WORD wMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2) {
+ EVENT event;
+ switch(wMsg) {
+ case MIM_OPEN: break;
+ /* The only error possible is invalid MIDI data, so just pass the invalid data on so we'll see it. */
+ case MIM_ERROR:
+ case MIM_DATA:
+ event.fdwEvent = (wMsg == MIM_ERROR) ? EVNT_F_ERROR : 0;
+ event.dwDevice = ((LPCALLBACKINSTANCEDATA)dwInstance)->dwDevice;
+ event.data = dwParam1;
+#ifdef MIDI_TIMESTAMP
+ event.timestamp = timeGetSystemTime();
+#endif
+ /* Put the MIDI event in the circular input buffer. */
+ PutEvent(((LPCALLBACKINSTANCEDATA)dwInstance)->lpBuf, (LPEVENT)&event);
+ break;
+ default: break;
+ }
+}
+
+void msw_open_midiin(int nmidiin, int *midiinvec) {
+ UINT wRtn;
+ char szErrorText[256];
+ unsigned int i;
+ unsigned int ndev = 0;
+ /* Allocate a circular buffer for low-level MIDI input. This buffer is filled by the low-level callback function
+ and emptied by the application. */
+ lpInputBuffer = AllocCircularBuffer((DWORD)(INPUT_BUFFER_SIZE));
+ if (!lpInputBuffer) {
+ printf("Not enough memory available for input buffer.\n");
+ return;
+ }
+ /* Open all MIDI input devices after allocating and setting up instance data for each device. The instance data is
+ used to pass buffer management information between the application and the low-level callback function. It also
+ includes a device ID, a handle to the MIDI Mapper, and a handle to the application's display window, so the callback
+ can notify the window when input data is available. A single callback function is used to service all opened input devices. */
+ for (i=0; (i<(unsigned)nmidiin) && (i<MAXMIDIINDEV); i++) {
+ if ((lpCallbackInstanceData[ndev] = AllocCallbackInstanceData()) == NULL) {
+ printf("Not enough memory available.\n");
+ FreeCircularBuffer(lpInputBuffer);
+ return;
+ }
+ lpCallbackInstanceData[i]->dwDevice = i;
+ lpCallbackInstanceData[i]->lpBuf = lpInputBuffer;
+ wRtn = midiInOpen((LPHMIDIIN)&hMidiIn[ndev], midiinvec[i], (DWORD)midiInputHandler,
+ (DWORD)lpCallbackInstanceData[ndev], CALLBACK_FUNCTION);
+ if (wRtn) {
+ FreeCallbackInstanceData(lpCallbackInstanceData[ndev]);
+ msw_midiinerror("midiInOpen: %s", wRtn);
+ } else ndev++;
+ }
+ /* Start MIDI input. */
+ for (i=0; i<ndev; i++) {
+ if (hMidiIn[i]) midiInStart(hMidiIn[i]);
+ }
+ wNumDevices = ndev;
+}
+
+static void msw_close_midiin() {
+ unsigned int i;
+ /* Stop, reset, close MIDI input. Free callback instance data. */
+ for (i=0; (i<wNumDevices) && (i<MAXMIDIINDEV); i++) {
+ if (hMidiIn[i]) {
+ if (sys_verbose) post("closing MIDI input %d...", i);
+ midiInStop(hMidiIn[i]);
+ midiInReset(hMidiIn[i]);
+ midiInClose(hMidiIn[i]);
+ FreeCallbackInstanceData(lpCallbackInstanceData[i]);
+ }
+ }
+ /* Free input buffer. */
+ if (lpInputBuffer) FreeCircularBuffer(lpInputBuffer);
+ if (sys_verbose) post("...done");
+ wNumDevices = 0;
+}
+
+/* ------------------- public routines -------------------------- */
+
+void sys_putmidimess(int portno, int a, int b, int c) {
+ DWORD foo;
+ MMRESULT res;
+ if (portno >= 0 && portno < msw_nmidiout) {
+ foo = (a & 0xff) | ((b & 0xff) << 8) | ((c & 0xff) << 16);
+ res = midiOutShortMsg(hMidiOut[portno], foo);
+ if (res != MMSYSERR_NOERROR) post("MIDI out error %d", res);
+ }
+}
+
+void sys_putmidibyte(int portno, int byte) {
+ MMRESULT res;
+ if (portno >= 0 && portno < msw_nmidiout) {
+ res = midiOutShortMsg(hMidiOut[portno], byte);
+ if (res != MMSYSERR_NOERROR) post("MIDI out error %d", res);
+ }
+}
+
+void sys_poll_midi() {
+ static EVENT msw_nextevent;
+ static int msw_isnextevent;
+ static double msw_nexteventtime;
+ while (1) {
+ if (!msw_isnextevent) {
+ if (!GetEvent(lpInputBuffer, &msw_nextevent)) break;
+ msw_isnextevent = 1;
+#ifdef MIDI_TIMESTAMP
+ msw_nexteventtime = msw_midigettimefor(&foo.timestamp);
+#endif
+ }
+#ifdef MIDI_TIMESTAMP
+ if (0.001 * clock_gettimesince(initsystime) >= msw_nexteventtime)
+#endif
+ {
+ int msgtype = ((msw_nextevent.data & 0xf0) >> 4) - 8;
+ int commandbyte = msw_nextevent.data & 0xff;
+ int byte1 = (msw_nextevent.data >> 8) & 0xff;
+ int byte2 = (msw_nextevent.data >> 16) & 0xff;
+ int portno = msw_nextevent.dwDevice;
+ switch (msgtype) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 6:
+ sys_midibytein(portno, commandbyte);
+ sys_midibytein(portno, byte1);
+ sys_midibytein(portno, byte2);
+ break;
+ case 4:
+ case 5:
+ sys_midibytein(portno, commandbyte);
+ sys_midibytein(portno, byte1);
+ break;
+ case 7:
+ sys_midibytein(portno, commandbyte);
+ break;
+ }
+ msw_isnextevent = 0;
+ }
+ }
+}
+
+void sys_do_open_midi(int nmidiin, int *midiinvec, int nmidiout, int *midioutvec) {
+ if (nmidiout) msw_open_midiout(nmidiout, midioutvec);
+ if (nmidiin) {
+ post("Warning: midi input is dangerous in Microsoft Windows; see Pd manual)");
+ msw_open_midiin(nmidiin, midiinvec);
+ }
+}
+
+void sys_close_midi() {
+ msw_close_midiin();
+ msw_close_midiout();
+}
+
+#if 0
+/* list the audio and MIDI device names */
+void sys_listmididevs() {
+ UINT wRtn, ndevices;
+ unsigned int i;
+ /* for MIDI and audio in and out, get the number of devices. Then get the capabilities of each device and print its description. */
+ ndevices = midiInGetNumDevs();
+ for (i = 0; i < ndevices; i++) {
+ MIDIINCAPS micap;
+ wRtn = midiInGetDevCaps(i, (LPMIDIINCAPS) &micap, sizeof(micap));
+ if (wRtn) msw_midiinerror("midiInGetDevCaps: %s", wRtn);
+ else error("MIDI input device #%d: %s", i+1, micap.szPname);
+ }
+ ndevices = midiOutGetNumDevs();
+ for (i = 0; i < ndevices; i++) {
+ MIDIOUTCAPS mocap;
+ wRtn = midiOutGetDevCaps(i, (LPMIDIOUTCAPS) &mocap, sizeof(mocap));
+ if (wRtn) msw_midiouterror("midiOutGetDevCaps: %s", wRtn);
+ else error("MIDI output device #%d: %s", i+1, mocap.szPname);
+ }
+}
+#endif
+
+void midi_getdevs(char *indevlist, int *nindevs, char *outdevlist, int *noutdevs, int maxndev, int devdescsize) {
+ int i, nin = midiInGetNumDevs(), nout = midiOutGetNumDevs();
+ UINT wRtn;
+ if (nin > maxndev) nin = maxndev;
+ for (i = 0; i < nin; i++) {
+ MIDIINCAPS micap;
+ wRtn = midiInGetDevCaps(i, (LPMIDIINCAPS) &micap, sizeof(micap));
+ strncpy(indevlist + i * devdescsize, (wRtn ? "???" : micap.szPname), devdescsize);
+ indevlist[(i+1) * devdescsize - 1] = 0;
+ }
+ if (nout > maxndev) nout = maxndev;
+ for (i = 0; i < nout; i++) {
+ MIDIOUTCAPS mocap;
+ wRtn = midiOutGetDevCaps(i, (LPMIDIOUTCAPS) &mocap, sizeof(mocap));
+ strncpy(outdevlist + i * devdescsize, (wRtn ? "???" : mocap.szPname), devdescsize);
+ outdevlist[(i+1) * devdescsize - 1] = 0;
+ }
+ *nindevs = nin;
+ *noutdevs = nout;
+}
diff --git a/desiredata/src/s_midi_none.c b/desiredata/src/s_midi_none.c
new file mode 100644
index 00000000..9d83545e
--- /dev/null
+++ b/desiredata/src/s_midi_none.c
@@ -0,0 +1,16 @@
+/* This is for compiling pd without any midi support. by matju, 2006.11.21 */
+
+#include "m_pd.h"
+#include "s_stuff.h"
+
+void sys_do_open_midi(int nmidiin, int *midiinvec, int nmidiout, int *midioutvec) {}
+void sys_close_midi(void) {}
+void sys_putmidimess(int portno, int a, int b, int c) {}
+void sys_putmidibyte(int portno, int byte) {}
+void sys_poll_midi(void) {}
+void midi_getdevs(char *indevlist, int *nindevs,
+ char *outdevlist, int *noutdevs, int maxndev, int devdescsize)
+{
+ *nindevs = 0;
+ *noutdevs = 0;
+}
diff --git a/desiredata/src/s_midi_oss.c b/desiredata/src/s_midi_oss.c
new file mode 100644
index 00000000..1cfeae7c
--- /dev/null
+++ b/desiredata/src/s_midi_oss.c
@@ -0,0 +1,234 @@
+/* Copyright (c) 1997-1999 Guenter Geiger, Miller Puckette, Larry Troxler,
+* Winfried Ritsch, Karl MacMillan, and others.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* MIDI I/O for Linux using OSS */
+
+#include <stdio.h>
+#ifdef UNISTD
+#include <unistd.h>
+#endif
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include "m_pd.h"
+#include "s_stuff.h"
+
+static int oss_nmidiin;
+static int oss_midiinfd[MAXMIDIINDEV];
+static int oss_nmidiout;
+static int oss_midioutfd[MAXMIDIOUTDEV];
+
+static void oss_midiout(int fd, int n) {
+ char b = n;
+ if ((write(fd, (char *) &b, 1)) != 1) perror("midi write");
+}
+
+#define O_MIDIFLAG O_NDELAY
+
+void sys_do_open_midi(int nmidiin, int *midiinvec, int nmidiout, int *midioutvec) {
+ int i;
+ for (i = 0; i < nmidiout; i++) oss_midioutfd[i] = -1;
+ for (i = 0, oss_nmidiin = 0; i < nmidiin; i++) {
+ int fd = -1, j, outdevindex = -1;
+ char namebuf[80];
+ int devno = midiinvec[i];
+ for (j = 0; j < nmidiout; j++) if (midioutvec[j] == midiinvec[i]) outdevindex = j;
+ /* try to open the device for read/write. */
+ if (devno == 0 && fd < 0 && outdevindex >= 0) {
+ sys_setalarm(1000000); fd = open("/dev/midi", O_RDWR | O_MIDIFLAG);
+ if (sys_verbose) error("device 1: tried /dev/midi READ/WRITE; returned %d", fd);
+ if (outdevindex >= 0 && fd >= 0) oss_midioutfd[outdevindex] = fd;
+ }
+ if (fd < 0 && outdevindex >= 0) {
+ sprintf(namebuf, "/dev/midi%2.2d", devno);
+ sys_setalarm(1000000); fd = open(namebuf, O_RDWR | O_MIDIFLAG);
+ if (sys_verbose) error("device %d: tried %s READ/WRITE; returned %d", devno, namebuf, fd);
+ if (outdevindex >= 0 && fd >= 0) oss_midioutfd[outdevindex] = fd;
+ }
+ if (fd < 0 && outdevindex >= 0) {
+ sprintf(namebuf, "/dev/midi%d", devno);
+ sys_setalarm(1000000); fd = open(namebuf, O_RDWR | O_MIDIFLAG);
+ if (sys_verbose) error("device %d: tried %s READ/WRITE; returned %d", devno, namebuf, fd);
+ if (outdevindex >= 0 && fd >= 0) oss_midioutfd[outdevindex] = fd;
+ }
+ if (devno == 1 && fd < 0) {
+ sys_setalarm(1000000); fd = open("/dev/midi", O_RDONLY | O_MIDIFLAG);
+ if (sys_verbose) error("device 1: tried /dev/midi READONLY; returned %d", fd);
+ }
+ if (fd < 0) {
+ sprintf(namebuf, "/dev/midi%2.2d", devno);
+ sys_setalarm(1000000); fd = open(namebuf, O_RDONLY | O_MIDIFLAG);
+ if (sys_verbose) error("device %d: tried %s READONLY; returned %d", devno, namebuf, fd);
+ }
+ if (fd < 0) {
+ sprintf(namebuf, "/dev/midi%d", devno);
+ sys_setalarm(1000000); fd = open(namebuf, O_RDONLY | O_MIDIFLAG);
+ if (sys_verbose) error("device %d: tried %s READONLY; returned %d", devno, namebuf, fd);
+ }
+ if (fd >= 0) oss_midiinfd[oss_nmidiin++] = fd;
+ else post("couldn't open MIDI input device %d", devno);
+ }
+ for (i = 0, oss_nmidiout = 0; i < nmidiout; i++) {
+ int fd = oss_midioutfd[i];
+ char namebuf[80];
+ int devno = midioutvec[i];
+ if (devno == 1 && fd < 0) {
+ sys_setalarm(1000000); fd = open("/dev/midi", O_WRONLY | O_MIDIFLAG);
+ if (sys_verbose) error("device 1: tried /dev/midi WRITEONLY; returned %d", fd);
+ }
+ if (fd < 0) {
+ sprintf(namebuf, "/dev/midi%2.2d", devno);
+ sys_setalarm(1000000); fd = open(namebuf, O_WRONLY | O_MIDIFLAG);
+ if (sys_verbose) error("device %d: tried %s WRITEONLY; returned %d", devno, namebuf, fd);
+ }
+ if (fd < 0) {
+ sprintf(namebuf, "/dev/midi%d", devno);
+ sys_setalarm(1000000); fd = open(namebuf, O_WRONLY | O_MIDIFLAG);
+ if (sys_verbose) error("device %d: tried %s WRITEONLY; returned %d", devno, namebuf, fd);
+ }
+ if (fd >= 0) oss_midioutfd[oss_nmidiout++] = fd;
+ else post("couldn't open MIDI output device %d", devno);
+ }
+ if (oss_nmidiin < nmidiin || oss_nmidiout < nmidiout || sys_verbose)
+ post("opened %d MIDI input device(s) and %d MIDI output device(s).", oss_nmidiin, oss_nmidiout);
+ sys_setalarm(0);
+}
+
+#define md_msglen(x) (((x)<0xC0)?2:((x)<0xE0)?1:((x)<0xF0)?2:((x)==0xF2)?2:((x)<0xF4)?1:0)
+
+void sys_putmidimess(int portno, int a, int b, int c) {
+ if (portno >= 0 && portno < oss_nmidiout) {
+ switch (md_msglen(a)) {
+ case 2:
+ oss_midiout(oss_midioutfd[portno],a);
+ oss_midiout(oss_midioutfd[portno],b);
+ oss_midiout(oss_midioutfd[portno],c);
+ return;
+ case 1:
+ oss_midiout(oss_midioutfd[portno],a);
+ oss_midiout(oss_midioutfd[portno],b);
+ return;
+ case 0:
+ oss_midiout(oss_midioutfd[portno],a);
+ return;
+ }
+ }
+}
+
+void sys_putmidibyte(int portno, int byte) {
+ if (portno >= 0 && portno < oss_nmidiout) oss_midiout(oss_midioutfd[portno], byte);
+}
+
+#if 0 /* this is the "select" version which doesn't work with OSS driver for emu10k1 (it doesn't implement select.) */
+void sys_poll_midi() {
+ int throttle = 100;
+ struct timeval timout;
+ int did = 1, maxfd = 0;
+ while (did) {
+ fd_set readset, writeset, exceptset;
+ did = 0;
+ if (throttle-- < 0) break;
+ timout.tv_sec = 0;
+ timout.tv_usec = 0;
+ FD_ZERO(&writeset);
+ FD_ZERO(&readset);
+ FD_ZERO(&exceptset);
+ for (int i=0; i<oss_nmidiin; i++) {
+ if (oss_midiinfd[i] > maxfd) maxfd = oss_midiinfd[i];
+ FD_SET(oss_midiinfd[i], &readset);
+ }
+ select(maxfd+1, &readset, &writeset, &exceptset, &timout);
+ for (int i=0; i<oss_nmidiin; i++) if (FD_ISSET(oss_midiinfd[i], &readset)) {
+ char c;
+ int ret = read(oss_midiinfd[i], &c, 1);
+ if (ret <= 0) error("Midi read error");
+ else sys_midibytein(i, (c & 0xff));
+ did = 1;
+ }
+ }
+}
+#else
+/* this version uses the asynchronous "read()" ... */
+void sys_poll_midi() {
+ int throttle = 100;
+ struct timeval timout;
+ int did = 1, maxfd = 0;
+ while (did) {
+ fd_set readset, writeset, exceptset;
+ did = 0;
+ if (throttle-- < 0) break;
+ for (int i=0; i<oss_nmidiin; i++) {
+ char c;
+ int ret = read(oss_midiinfd[i], &c, 1);
+ if (ret < 0) {
+ if (errno != EAGAIN) perror("MIDI");
+ } else if (ret != 0) {
+ sys_midibytein(i, (c & 0xff));
+ did = 1;
+ }
+ }
+ }
+}
+#endif
+
+void sys_close_midi() {
+ for (int i=0; i<oss_nmidiin ; i++) close(oss_midiinfd [i]);
+ for (int i=0; i<oss_nmidiout; i++) close(oss_midioutfd[i]);
+ oss_nmidiin = oss_nmidiout = 0;
+}
+
+#define NSEARCH 10
+static int oss_nmidiindevs, oss_nmidioutdevs, oss_initted;
+
+void midi_oss_init() {
+ if (oss_initted) return;
+ oss_initted = 1;
+ for (int i=0; i<NSEARCH; i++) {
+ int fd;
+ char namebuf[80];
+ oss_nmidiindevs = i;
+ /* try to open the device for reading */
+ if (i == 0) {
+ fd = open("/dev/midi", O_RDONLY | O_NDELAY);
+ if (fd >= 0) {close(fd); continue;}
+ }
+ sprintf(namebuf, "/dev/midi%2.2d", i);
+ fd = open(namebuf, O_RDONLY | O_NDELAY);
+ if (fd >= 0) {close(fd); continue;}
+ sprintf(namebuf, "/dev/midi%d", i);
+ fd = open(namebuf, O_RDONLY | O_NDELAY);
+ if (fd >= 0) {close(fd); continue;}
+ break;
+ }
+ for (int i=0; i<NSEARCH; i++) {
+ int fd;
+ char namebuf[80];
+ oss_nmidioutdevs = i;
+ /* try to open the device for writing */
+ if (i == 0) {
+ fd = open("/dev/midi", O_WRONLY | O_NDELAY);
+ if (fd >= 0) {close(fd); continue;}
+ }
+ sprintf(namebuf, "/dev/midi%2.2d", i);
+ fd = open(namebuf, O_WRONLY | O_NDELAY);
+ if (fd >= 0) {close(fd); continue;}
+ sprintf(namebuf, "/dev/midi%d", i);
+ fd = open(namebuf, O_WRONLY | O_NDELAY);
+ if (fd >= 0) {close(fd); continue;}
+ break;
+ }
+}
+
+void midi_getdevs(char *indevlist, int *nindevs, char *outdevlist, int *noutdevs, int maxndev, int devdescsize) {
+ int i, ndev;
+ if ((ndev = oss_nmidiindevs) > maxndev) ndev = maxndev;
+ for (i = 0; i < ndev; i++) sprintf(indevlist + i * devdescsize, "OSS MIDI device #%d", i+1);
+ *nindevs = ndev;
+ if ((ndev = oss_nmidioutdevs) > maxndev) ndev = maxndev;
+ for (i = 0; i < ndev; i++) sprintf(outdevlist + i * devdescsize, "OSS MIDI device #%d", i+1);
+ *noutdevs = ndev;
+}
diff --git a/desiredata/src/s_midi_pm.c b/desiredata/src/s_midi_pm.c
new file mode 100644
index 00000000..d51badf7
--- /dev/null
+++ b/desiredata/src/s_midi_pm.c
@@ -0,0 +1,239 @@
+/* Copyright (c) 1997-2003 Guenter Geiger, Miller Puckette, Larry Troxler,
+* Winfried Ritsch, Karl MacMillan, and others.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution.
+
+ this file calls portmidi to do MIDI I/O for MSW and Mac OSX.
+ applied sysexin/midiin patch by Nathaniel Dose, july 2007.
+
+*/
+
+
+#include "m_pd.h"
+#include "s_stuff.h"
+#include <stdio.h>
+#ifdef UNISTD
+#include <unistd.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <portaudio.h>
+#include <portmidi.h>
+#include <porttime.h>
+
+static PmStream *mac_midiindevlist[MAXMIDIINDEV];
+static PmStream *mac_midioutdevlist[MAXMIDIOUTDEV];
+static int mac_nmidiindev;
+static int mac_nmidioutdev;
+
+void sys_do_open_midi(int nmidiin, int *midiinvec, int nmidiout, int *midioutvec) {
+ PmError err;
+ Pt_Start(1, 0, 0); /* start a timer with millisecond accuracy */
+ mac_nmidiindev = 0;
+ for (int i=0; i<nmidiin; i++) {
+ int found = 0,count = Pm_CountDevices();
+ for (int j=0, devno=0; j<count && !found; j++) {
+ const PmDeviceInfo *info = Pm_GetDeviceInfo(j);
+ if (info->input) {
+ if (devno == midiinvec[i]) {
+ err = Pm_OpenInput(&mac_midiindevlist[mac_nmidiindev],j,NULL,100,NULL,NULL);
+ if (err != pmNoError) post("could not open midi input %d (%s): %s", j, info->name, Pm_GetErrorText(err));
+ else {mac_nmidiindev++; if (sys_verbose) post("Midi Input (%s) opened.", info->name);}
+ found = 1;
+ }
+ devno++;
+ }
+ }
+ if (!found) post("could not find midi device %d",midiinvec[i]);
+ }
+ mac_nmidioutdev = 0;
+ for (int i=0; i<nmidiout; i++) {
+ int found = 0,count = Pm_CountDevices();
+ for (int j=0, devno=0; j<count && !found; j++) {
+ const PmDeviceInfo *info = Pm_GetDeviceInfo(j);
+ if (info->output) {
+ if (devno == midioutvec[i]) {
+ err = Pm_OpenOutput(&mac_midioutdevlist[mac_nmidioutdev],j,NULL,0,NULL,NULL,0);
+ if (err != pmNoError) post("could not open midi output %d (%s): %s",j,info->name,Pm_GetErrorText(err));
+ else {mac_nmidioutdev++; if (sys_verbose) post("Midi Output (%s) opened.",info->name);}
+ found = 1;
+ }
+ devno++;
+ }
+ }
+ if (!found) post("could not find midi device %d",midioutvec[i]);
+ }
+}
+
+void sys_close_midi () {
+ for (int i=0; i< mac_nmidiindev; i++) Pm_Close(mac_midiindevlist[i]);
+ mac_nmidiindev = 0;
+ for (int i=0; i<mac_nmidioutdev; i++) Pm_Close(mac_midioutdevlist[i]);
+ mac_nmidioutdev = 0;
+}
+
+void sys_putmidimess(int portno, int a, int b, int c) {
+ PmEvent buffer;
+ /* post("put 1 msg %d %d", portno, mac_nmidioutdev); */
+ if (portno >= 0 && portno < mac_nmidioutdev) {
+ buffer.message = Pm_Message(a, b, c);
+ buffer.timestamp = 0;
+ /* post("put msg"); */
+ Pm_Write(mac_midioutdevlist[portno], &buffer, 1);
+ }
+}
+
+static void writemidi4(PortMidiStream* stream, int a, int b, int c, int d) {
+ PmEvent buffer;
+ buffer.timestamp = 0;
+ buffer.message = ((a & 0xff) | ((b & 0xff) << 8) | ((c & 0xff) << 16) | ((d & 0xff) << 24));
+ Pm_Write(stream, &buffer, 1);
+}
+
+void sys_putmidibyte(int portno, int byte) {
+ /* try to parse the bytes into MIDI messages so they can fit into PortMidi buffers. */
+ static int mess[4];
+ static int nbytes = 0, sysex = 0, i;
+ if (byte >= 0xf8) /* MIDI real time */
+ writemidi4(mac_midioutdevlist[portno], byte, 0, 0, 0);
+ else if (byte == 0xf0) {
+ mess[0] = 0xf0;
+ nbytes = 1;
+ sysex = 1;
+ } else if (byte == 0xf7) {
+ mess[nbytes] = byte;
+ for (i = nbytes+1; i<4; i++) mess[i] = 0;
+ writemidi4(mac_midioutdevlist[portno], mess[0], mess[1], mess[2], mess[3]);
+ sysex = 0;
+ nbytes = 0;
+ } else if (byte >= 0x80) {
+ sysex = 0;
+ if (byte == 0xf4 || byte == 0xf5 || byte == 0xf6) {
+ writemidi4(mac_midioutdevlist[portno], byte, 0, 0, 0);
+ nbytes = 0;
+ } else {
+ mess[0] = byte;
+ nbytes = 1;
+ }
+ } else if (sysex) {
+ mess[nbytes] = byte;
+ nbytes++;
+ if (nbytes == 4) {
+ writemidi4(mac_midioutdevlist[portno], mess[0], mess[1], mess[2], mess[3]);
+ nbytes = 0;
+ }
+ } else if (nbytes) {
+ int status = mess[0];
+ if (status < 0xf0) status &= 0xf0;
+ /* 2 byte messages: */
+ if (status == 0xc0 || status == 0xd0 || status == 0xf1 || status == 0xf3) {
+ writemidi4(mac_midioutdevlist[portno], mess[0], byte, 0, 0);
+ nbytes = (status < 0xf0 ? 1 : 0);
+ } else {
+ if (nbytes == 1) {
+ mess[1] = byte;
+ nbytes = 2;
+ } else {
+ writemidi4(mac_midioutdevlist[portno],
+ mess[0], mess[1], byte, 0);
+ nbytes = (status < 0xf0 ? 1 : 0);
+ }
+ }
+ }
+}
+
+/* this is non-zero if we are in the middle of transmitting sysex */
+int nd_sysex_mode=0;
+
+/* send in 4 bytes of sysex data. if one of the bytes is 0xF7 (sysex end) stop and unset nd_sysex_mode */
+void nd_sysex_inword(int midiindev, int status, int data1, int data2, int data3) {
+ if (nd_sysex_mode) {sys_midibytein(midiindev, status); if (status == 0xF7) nd_sysex_mode = 0;}
+ if (nd_sysex_mode) {sys_midibytein(midiindev, data1); if (data1 == 0xF7) nd_sysex_mode = 0;}
+ if (nd_sysex_mode) {sys_midibytein(midiindev, data2); if (data2 == 0xF7) nd_sysex_mode = 0;}
+ if (nd_sysex_mode) {sys_midibytein(midiindev, data3); if (data3 == 0xF7) nd_sysex_mode = 0;}
+}
+
+void sys_poll_midi() {
+ PmEvent buffer;
+ for (int i=0; i<mac_nmidiindev; i++) {
+ int nmess = Pm_Read(mac_midiindevlist[i], &buffer, 1);
+ if (nmess > 0) {
+ PmMessage msg = buffer.message;
+ int status = Pm_MessageStatus(msg);
+ if(status == 0xf0 || !(status&0x80)) {
+ /* sysex header or data */
+ for(int j=0; j<4; ++j,msg >>= 8) {
+ int data = msg&0xff;
+ sys_midibytein(i, data);
+ if(data == 0xf7) break; /* sysex end */
+ }
+ } else {
+ int data1 = Pm_MessageData1(msg);
+ int data2 = Pm_MessageData2(msg);
+ /* non-sysex */
+ sys_midibytein(i, status);
+ switch(status>>4) {
+ case 0x8: /* note off */
+ case 0x9: /* note on */
+ case 0xa: /* poly pressure */
+ case 0xb: /* control change */
+ case 0xe: /* pitch bend */
+ sys_midibytein(i,data1);
+ sys_midibytein(i,data2);
+ break;
+ case 0xc: /* program change */
+ case 0xd: /* channel pressure */
+ sys_midibytein(i,data1);
+ break;
+ case 0xf: /* system common/realtime messages */
+ switch(status) {
+ case 0xf1: /* time code */
+ case 0xf3: /* song select */
+ case 0xf6: /* tune request */
+ sys_midibytein(i,data1);
+ break;
+ case 0xf2: /* song position pointer */
+ sys_midibytein(i,data1);
+ sys_midibytein(i,data2);
+ break;
+ case 0xf7: // from Nathaniel; don't know whether it'll work in this context.
+ nd_sysex_mode=1;
+ nd_sysex_inword(i,status,data1,data2,((msg>>24)&0xFF));
+ break;
+ default: // from Nathaniel too.
+ if (nd_sysex_mode) nd_sysex_inword(i,status,data1,data2,((msg>>24)&0xFF));
+ break;
+ }
+ }
+ }
+ }
+ }
+}
+
+#if 0
+/* lifted from pa_devs.c in portaudio */
+void sys_listmididevs() {
+ for (int i=0; i<Pm_CountDevices(); i++) {
+ const PmDeviceInfo *info = Pm_GetDeviceInfo(i);
+ printf("%d: %s, %s", i, info->interf, info->name);
+ if (info->input) printf(" (input)");
+ if (info->output) printf(" (output)");
+ printf("\n");
+ }
+}
+#endif
+
+void midi_getdevs(char *indevlist, int *nindevs, char *outdevlist, int *noutdevs, int maxndev, int devdescsize) {
+ int nindev=0, noutdev=0;
+ for (int i=0; i<Pm_CountDevices(); i++) {
+ const PmDeviceInfo *info = Pm_GetDeviceInfo(i);
+ /* post("%d: %s, %s (%d,%d)", i, info->interf, info->name,info->input, info->output); */
+ if (info->input && nindev < maxndev) {strcpy(indevlist + nindev * devdescsize, info->name); nindev++;}
+ if (info->output && noutdev < maxndev) {strcpy(outdevlist + noutdev * devdescsize, info->name); noutdev++;}
+ }
+ *nindevs = nindev;
+ *noutdevs = noutdev;
+}
diff --git a/desiredata/src/s_midi_sgi.c b/desiredata/src/s_midi_sgi.c
new file mode 100644
index 00000000..8a0895ba
--- /dev/null
+++ b/desiredata/src/s_midi_sgi.c
@@ -0,0 +1,143 @@
+/* Copyright (c) 1997-1999 Miller Puckette.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include "m_pd.h"
+#include "s_stuff.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#ifdef HAVE_BSTRING_H
+#include <bstring.h>
+#endif
+#include <sys/types.h>
+#include <sys/time.h>
+#include <dmedia/audio.h>
+#include <sys/fpu.h>
+#include <dmedia/midi.h>
+int mdInit(); /* prototype was messed up in midi.h */
+//#include "sys/select.h"
+
+/* set the special "flush zero" but (FS, bit 24) in the Control Status Register of the FPU of R4k and beyond
+ so that the result of any underflowing operation will be clamped to zero, and no exception of any kind will
+ be generated on the CPU. thanks to cpirazzi@cp.esd.sgi.com (Chris Pirazzi). */
+
+static void sgi_flush_all_underflows_to_zero() {
+ union fpc_csr f;
+ f.fc_word = get_fpc_csr();
+ f.fc_struct.flush = 1;
+ set_fpc_csr(f.fc_word);
+}
+
+#define NPORT 2
+
+static MDport sgi_inport[NPORT];
+static MDport sgi_outport[NPORT];
+
+void sgi_open_midi(int midiin, int midiout) {
+ int i;
+ int sgi_nports = mdInit();
+ if (sgi_nports < 0) sgi_nports = 0;
+ else if (sgi_nports > NPORT) sgi_nports = NPORT;
+ if (sys_verbose) {
+ if (!sgi_nports) {
+ post("no serial ports are configured for MIDI;");
+ post("if you want to use MIDI, try exiting Pd, typing");
+ post("'startmidi -d /dev/ttyd2' to a shell, and restarting Pd.");
+ } else if (sgi_nports == 1) post("Found one MIDI port on %s", mdGetName(0));
+ else if (sgi_nports == 2) post("Found MIDI ports on %s and %s", mdGetName(0), mdGetName(1));
+ }
+ if (midiin) {
+ for (i = 0; i < sgi_nports; i++) {
+ if (!(sgi_inport[i] = mdOpenInPort(mdGetName(i)))) error("MIDI input port %d: open failed", i+1);
+ }
+ }
+ if (midiout) {
+ for (i = 0; i < sgi_nports; i++) {
+ if (!(sgi_outport[i] = mdOpenOutPort(mdGetName(i)))) error("MIDI output port %d: open failed", i+1);
+ }
+ }
+ return;
+}
+
+void sys_putmidimess(int portno, int a, int b, int c) {
+ MDevent mdv;
+ if (portno >= NPORT || portno < 0 || !sgi_outport[portno]) return;
+ mdv.msg[0] = a;
+ mdv.msg[1] = b;
+ mdv.msg[2] = c;
+ mdv.msg[3] = 0;
+ mdv.sysexmsg = 0;
+ mdv.stamp = 0;
+ mdv.msglen = 0;
+ if (mdSend(sgi_outport[portno], &mdv, 1) < 0) error("MIDI output error");
+ post("msg out %d %d %d", a, b, c);
+}
+
+void sys_putmidibyte(int portno, int foo) {
+ error("MIDI raw byte output not available on SGI");
+}
+
+void inmidi_noteon(int portno, int channel, int pitch, int velo);
+void inmidi_controlchange(int portno, int channel, int ctlnumber, int value);
+void inmidi_programchange(int portno, int channel, int value);
+void inmidi_pitchbend(int portno, int channel, int value);
+void inmidi_aftertouch(int portno, int channel, int value);
+void inmidi_polyaftertouch(int portno, int channel, int pitch, int value);
+
+void sys_poll_midi() {
+ int i;
+ MDport *mp;
+ for (i = 0, mp = sgi_inport; i < NPORT; i++, mp++) {
+ int ret, status, b1, b2, nfds;
+ MDevent mdv;
+ fd_set inports;
+ struct timeval timeout;
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 0;
+ if (!*mp) continue;
+ FD_ZERO(&inports);
+ FD_SET(mdGetFd(*mp), &inports);
+ if (select(mdGetFd(*mp)+1 , &inports, 0, 0, &timeout) < 0) perror("midi select");
+ if (FD_ISSET(mdGetFd(*mp),&inports)) {
+ if (mdReceive(*mp, &mdv, 1) < 0)
+ error("failure receiving message");
+ else if (mdv.msg[0] == MD_SYSEX) mdFree(mdv.sysexmsg);
+ else {
+ int status = mdv.msg[0];
+ int channel = (status & 0xf) + 1;
+ int b1 = mdv.msg[1];
+ int b2 = mdv.msg[2];
+ switch(status & 0xf0) {
+ case MD_NOTEOFF: inmidi_noteon(i, channel, b1, 0); break;
+ case MD_NOTEON: inmidi_noteon(i, channel, b1, b2); break;
+ case MD_POLYKEYPRESSURE: inmidi_polyaftertouch(i, channel, b1, b2); break;
+ case MD_CONTROLCHANGE: inmidi_controlchange(i, channel, b1, b2); break;
+ case MD_PITCHBENDCHANGE: inmidi_pitchbend(i, channel, ((b2 << 7) + b1)); break;
+ case MD_PROGRAMCHANGE: inmidi_programchange(i, channel, b1); break;
+ case MD_CHANNELPRESSURE: inmidi_aftertouch(i, channel, b1); break;
+ }
+ }
+ }
+ }
+}
+
+void sys_do_open_midi(int nmidiin, int *midiinvec, int nmidiout, int *midioutvec) {
+ sgi_open_midi(nmidiin!=0, nmidiout!=0);
+}
+void sys_close_midi() {/* ??? */}
+
+void midi_getdevs(char *indevlist, int *nindevs, char *outdevlist, int *noutdevs, int maxndev, int devdescsize) {
+ int i, nindev = 0, noutdev = 0;
+ for (i = 0; i < mdInit(); i++) {
+ if (nindev < maxndev) {
+ strcpy(indevlist + nindev * devdescsize, mdGetName(i));
+ nindev++;
+ strcpy(outdevlist + noutdev * devdescsize, mdGetName(i));
+ noutdev++;
+ }
+ }
+ *nindevs = nindev;
+ *noutdevs = noutdev;
+}
diff --git a/desiredata/src/s_path.c b/desiredata/src/s_path.c
new file mode 100644
index 00000000..06a37c1a
--- /dev/null
+++ b/desiredata/src/s_path.c
@@ -0,0 +1,350 @@
+/* Copyright (c) 1999 Guenter Geiger and others.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* This file implements the loader for linux, which includes a little bit of path handling.
+ * Generalized by MSP to provide an open_via_path function and lists of files for all purposes. */
+/* #define DEBUG(x) x */
+#define DEBUG(x)
+
+#include <stdlib.h>
+#ifdef UNISTD
+#include <unistd.h>
+#include <sys/stat.h>
+#endif
+#ifdef MSW
+#include <io.h>
+#endif
+
+#include <string.h>
+#include "desire.h"
+#include <stdio.h>
+#include <fcntl.h>
+#include <ctype.h>
+
+extern t_namelist *sys_externlist;
+t_namelist *sys_searchpath;
+t_namelist *sys_helppath;
+
+/* change '/' characters to the system's native file separator */
+void sys_bashfilename(const char *from, char *to) {
+ char c;
+ while ((c = *from++)) {
+#ifdef MSW
+ if (c == '/') c = '\\';
+#endif
+ *to++ = c;
+ }
+ *to = 0;
+}
+
+/* change the system's native file separator to '/' characters */
+void sys_unbashfilename(const char *from, char *to) {
+ char c;
+ while ((c = *from++)) {
+#ifdef MSW
+ if (c == '\\') c = '/';
+#endif
+ *to++ = c;
+ }
+ *to = 0;
+}
+
+/******************* Utility functions used below ******************/
+
+/* copy until delimiter and return position after delimiter in string */
+/* if it was the last substring, return NULL */
+
+static const char *strtokcpy(char *&to, const char *from, int delim) {
+ int size = 0;
+ while (from[size] != (char)delim && from[size] != '\0') size++;
+ to = (char *)malloc(size+1);
+ strncpy(to,from,size);
+ to[size] = '\0';
+ if (from[size] == '\0') return NULL;
+ return size ? from+size+1 : 0;
+}
+
+/* add a single item to a namelist. If "allowdup" is true, duplicates
+may be added; othewise they're dropped. */
+t_namelist *namelist_append(t_namelist *listwas, const char *s, int allowdup) {
+ t_namelist *nl, *nl2 = (t_namelist *)getbytes(sizeof(*nl));
+ nl2->nl_next = 0;
+ nl2->nl_string = strdup(s);
+ sys_unbashfilename(nl2->nl_string, nl2->nl_string);
+ if (!listwas) return nl2;
+ for (nl = listwas; ;) {
+ if (!allowdup && !strcmp(nl->nl_string, s)) return listwas;
+ if (!nl->nl_next) break;
+ nl = nl->nl_next;
+ }
+ nl->nl_next = nl2;
+ return listwas;
+}
+
+/* add a colon-separated list of names to a namelist */
+
+#ifdef MSW
+#define SEPARATOR ';' /* in MSW the natural separator is semicolon instead */
+#else
+#define SEPARATOR ':'
+#endif
+
+t_namelist *namelist_append_files(t_namelist *listwas, const char *s) {
+ const char *npos = s;
+ t_namelist *nl = listwas;
+ do {
+ char *temp;
+ npos = strtokcpy(temp, npos, SEPARATOR);
+ if (!*temp) continue;
+ nl = namelist_append(nl, temp, 0);
+ free(temp);
+ } while (npos);
+ return nl;
+}
+
+void namelist_free(t_namelist *listwas) {
+ t_namelist *nl2;
+ for (t_namelist *nl = listwas; nl; nl = nl2) {
+ nl2 = nl->nl_next;
+ free(nl->nl_string);
+ free(nl);
+ }
+}
+
+char *namelist_get(t_namelist *namelist, int n) {
+ int i=0;
+ for (t_namelist *nl = namelist; i < n && nl; nl = nl->nl_next) {if (i==n) return nl->nl_string; else i++;}
+ return 0;
+}
+
+static t_namelist *pd_extrapath;
+
+int sys_usestdpath = 1;
+
+void sys_setextrapath(const char *p) {
+ namelist_free(pd_extrapath);
+ pd_extrapath = namelist_append(0, p, 0);
+}
+
+#ifdef MSW
+#define MSWOPENFLAG(bin) (bin ? _O_BINARY : _O_TEXT)
+#else
+#define MSWOPENFLAG(bin) 0
+#endif
+
+/* try to open a file in the directory "dir", named "name""ext", for reading. "Name" may have slashes.
+ The directory is copied to "dirresult" which must be at least "size" bytes. "nameresult" is set
+ to point to the filename (copied elsewhere into the same buffer). The "bin" flag requests opening
+ for binary (which only makes a difference on Windows). */
+int sys_trytoopenone(const char *dir, const char *name, const char* ext, char **dirresult, char **nameresult, int bin) {
+ bool needslash = (*dir && dir[strlen(dir)-1] != '/');
+ asprintf(dirresult,"%s%s%s%s", dir, needslash ? "/" : "", name, ext);
+ sys_bashfilename(*dirresult, *dirresult);
+ DEBUG(post("looking for %s",*dirresult));
+ /* see if we can open the file for reading */
+ int fd = open(*dirresult,O_RDONLY | MSWOPENFLAG(bin));
+ if (fd<0) {
+ if (sys_verbose) post("tried %s and failed", *dirresult);
+ return -1;
+ }
+#ifdef UNISTD /* in unix, further check that it's not a directory */
+ struct stat statbuf;
+ int ok = (fstat(fd, &statbuf) >= 0) && !S_ISDIR(statbuf.st_mode);
+ if (!ok) {
+ if (sys_verbose) post("tried %s; stat failed or directory", *dirresult);
+ close (fd);
+ return -1;
+ }
+#endif
+ if (sys_verbose) post("tried %s and succeeded", *dirresult);
+ sys_unbashfilename(*dirresult, *dirresult);
+ char *slash = strrchr(*dirresult, '/');
+ if (slash) {
+ *slash = 0;
+ *nameresult = slash + 1;
+ } else *nameresult = *dirresult;
+ return fd;
+}
+
+/* check if we were given an absolute pathname, if so try to open it and return 1 to signal the caller to cancel any path searches */
+int sys_open_absolute(const char *name, const char* ext, char **dirresult, char **nameresult, int bin, int *fdp) {
+ if (name[0] == '/'
+#ifdef MSW
+ || (name[1] == ':' && name[2] == '/')
+#endif
+ ) {
+ int dirlen = strrchr(name, '/') - name;
+ char *dirbuf = new char[dirlen+1];
+ *fdp = sys_trytoopenone(name, name+dirlen+1, ext, dirresult, nameresult, bin);
+ delete[] dirbuf;
+ return 1;
+ } else return 0;
+}
+
+/* search for a file in a specified directory, then along the globally
+defined search path, using ext as filename extension. The
+fd is returned, the directory ends up in the "dirresult" which must be at
+least "size" bytes. "nameresult" is set to point to the filename, which
+ends up in the same buffer as dirresult. Exception:
+if the 'name' starts with a slash or a letter, colon, and slash in MSW,
+there is no search and instead we just try to open the file literally. */
+
+/* see also canvas_openfile() which, in addition, searches down the
+canvas-specific path. */
+
+static int do_open_via_path(
+const char *dir, const char *name, const char *ext, char **dirresult, char **nameresult, int bin, t_namelist *searchpath) {
+ int fd = -1;
+ /* first check if "name" is absolute (and if so, try to open) */
+ if (sys_open_absolute(name, ext, dirresult, nameresult, bin, &fd)) return fd;
+ /* otherwise "name" is relative; try the directory "dir" first. */
+ if ((fd = sys_trytoopenone(dir, name, ext, dirresult, nameresult, bin)) >= 0) return fd;
+ /* next go through the search path */
+ for (t_namelist *nl=searchpath; nl; nl=nl->nl_next)
+ if ((fd = sys_trytoopenone(nl->nl_string, name, ext, dirresult, nameresult, bin)) >= 0) return fd;
+ /* next look in "extra" */
+ if (sys_usestdpath && (fd = sys_trytoopenone(pd_extrapath->nl_string, name, ext, dirresult, nameresult, bin)) >= 0)
+ return fd;
+ *dirresult = 0;
+ *nameresult = *dirresult;
+ return -1;
+}
+
+extern "C" int open_via_path2(const char *dir, const char *name, const char *ext, char **dirresult, char **nameresult, int bin) {
+ return do_open_via_path(dir, name, ext, dirresult, nameresult, bin, sys_searchpath);
+}
+
+/* open via path, using the global search path. */
+extern "C" int open_via_path(const char *dir, const char *name, const char *ext,
+char *dirresult, char **nameresult, unsigned int size, int bin) {
+ char *dirr;
+ int r = do_open_via_path(dir, name, ext, &dirr, nameresult, bin, sys_searchpath);
+ if (dirr) {strncpy(dirresult,dirr,size); dirresult[size-1]=0; free(dirr);}
+ return r;
+}
+
+/* Open a help file using the help search path. We expect the ".pd" suffix here,
+ even though we have to tear it back off for one of the search attempts. */
+extern "C" void open_via_helppath(const char *name, const char *dir) {
+ char *realname=0, *dirbuf, *basename;
+ int suffixed = strlen(name) > 3 && !strcmp(name+strlen(name)-3, ".pd");
+ asprintf(&realname,"%.*s-help.pd",strlen(name)-3*suffixed,name);
+ int fd;
+ if ((fd = do_open_via_path(dir,realname,"",&dirbuf,&basename,0,sys_helppath))>=0) goto gotone;
+ free(realname);
+ asprintf(&realname,"help-%s",name);
+ if ((fd = do_open_via_path(dir,realname,"",&dirbuf,&basename,0,sys_helppath))>=0) goto gotone;
+ free(realname);
+ if ((fd = do_open_via_path(dir, name,"",&dirbuf,&basename,0,sys_helppath))>=0) goto gotone;
+ post("sorry, couldn't find help patch for \"%s\"", name);
+ return;
+gotone:
+ close(fd); if (realname) free(realname);
+ glob_evalfile(0, gensym((char*)basename), gensym(dirbuf));
+}
+
+extern "C" int sys_argparse(int argc, char **argv);
+
+#define NUMARGS 1000
+
+extern "C" int sys_parsercfile(char *filename) {
+ int rcargc;
+ char* rcargv[NUMARGS];
+ char buf[1000];
+ char c[MAXPDSTRING];
+ int retval = 1; /* that's what we will return at the end; for now, let's think it'll be an error */
+ /* initialize rc-arg-array so we can safely clean up at the end */
+ for (int i=1; i<NUMARGS-1; i++) rcargv[i]=0;
+ /* parse a startup file */
+ FILE* file = fopen(filename, "r");
+ if (!file) return 1;
+ post("reading startup file: %s", filename);
+ rcargv[0] = "."; /* this no longer matters to sys_argparse() */
+ /* tb: comments in pdrc file { */
+ int i=1;
+ while ((fgets(c,MAXPDSTRING,file)) != 0) {
+ if (c[strlen(c)-1] !='\n') {
+ //it is unlikely that this is ever the case
+ error("startup file contains a line that's too long");
+ while(fgetc(file) != '\n') {}
+ }
+ if (c[0] != '#') {
+ long n;
+ while (sscanf(c,"%999s%ln",buf,&n) != EOF) {
+ buf[999] = 0;
+ if (!(rcargv[i] = (char *)malloc(strlen(buf) + 1))) goto cleanup;
+ strcpy(rcargv[i], buf);
+ strcpy(buf,c+n);
+ strcpy(c,buf);
+ ++i;
+ }
+ }
+ }
+ /* } tb */
+ if (i >= NUMARGS-1) error("startup file too long; extra args dropped");
+ rcargv[i] = 0;
+ rcargc = i;
+ /* parse the options */
+ fclose(file);
+ if (sys_verbose) {
+ if (rcargv) {
+ post("startup args from RC file:");
+ for (i = 1; i < rcargc; i++) post("%s", rcargv[i]);
+ } else post("no RC file arguments found");
+ }
+ if (sys_argparse(rcargc-1, rcargv+1)) {
+ post("error parsing RC arguments");
+ goto cleanup;
+ }
+ retval=0; /* we made it without an error */
+ cleanup: /* prevent memleak */
+ for (i=1; i<NUMARGS-1; i++) if (rcargv[i]) free(rcargv[i]);
+ return retval;
+}
+
+#ifndef MSW
+#define STARTUPNAME ".pdrc"
+extern "C" int sys_rcfile () {
+ char *fname, *home = getenv("HOME");
+ asprintf(&fname,"%s/%s",home? home : ".",STARTUPNAME);
+ int r = sys_parsercfile(fname);
+ free(fname);
+ return r;
+}
+#endif /* MSW */
+
+void sys_doflags() {
+ int beginstring = 0, state = 0, len = strlen(sys_flags->s_name);
+ int rcargc = 0;
+ char *rcargv[MAXPDSTRING];
+ if (len > MAXPDSTRING) {post("flags: %s: too long", sys_flags->s_name); return;}
+ for (int i=0; i<len+1; i++) {
+ int c = sys_flags->s_name[i];
+ if (state == 0) {
+ if (c && !isspace(c)) {
+ beginstring = i;
+ state = 1;
+ }
+ } else {
+ if (!c || isspace(c)) {
+ char *foo = (char *)malloc(i - beginstring + 1);
+ if (!foo) return;
+ strncpy(foo, sys_flags->s_name + beginstring, i - beginstring);
+ foo[i - beginstring] = 0;
+ rcargv[rcargc] = foo;
+ rcargc++;
+ if (rcargc >= MAXPDSTRING) break;
+ state = 0;
+ }
+ }
+ }
+ if (sys_argparse(rcargc, rcargv)) post("error parsing startup arguments");
+}
+
+extern "C" void glob_update_path () {
+ t_namelist *nl;
+ sys_vgui("global pd_path; set pd_path {");
+ for (nl=sys_searchpath; nl; nl=nl->nl_next) sys_vgui("%s ",nl->nl_string);
+ sys_vgui("}\n");
+}
diff --git a/desiredata/src/s_stuff.h b/desiredata/src/s_stuff.h
new file mode 100644
index 00000000..8edf5982
--- /dev/null
+++ b/desiredata/src/s_stuff.h
@@ -0,0 +1,321 @@
+#ifndef __STUFF_H
+#define __STUFF_H
+#if defined(_LANGUAGE_C_PLUS_PLUS) || defined(__cplusplus)
+extern "C" {
+#endif
+
+/* Copyright (c) 1997-1999 Miller Puckette.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* Audio and MIDI I/O, and other scheduling and system stuff. */
+
+/* NOTE: this file describes Pd implementation details which may change
+in future releases. The public (stable) API is in m_pd.h. */
+
+/* in s_path.c */
+
+typedef struct _namelist { /* element in a linked list of stored strings */
+ struct _namelist *nl_next; /* next in list */
+ char *nl_string; /* the string */
+} t_namelist;
+
+t_namelist *namelist_append(t_namelist *listwas, const char *s, int allowdup);
+t_namelist *namelist_append_files(t_namelist *listwas, const char *s);
+void namelist_free(t_namelist *listwas);
+char *namelist_get(t_namelist *namelist, int n);
+void sys_setextrapath(const char *p);
+extern int sys_usestdpath;
+extern t_namelist *sys_externlist;
+extern t_namelist *sys_searchpath;
+extern t_namelist *sys_helppath;
+
+// IOhannes : added namespace support for libraries
+// the define QUALIFIED_NAME both turns on namespaces and sets the library-object delimiter
+#define QUALIFIED_NAME "/"
+#ifdef QUALIFIED_NAME
+void pd_set_library_name(char *libname);
+#endif
+
+int sys_open_absolute( const char *name, const char* ext, char **dirresult, char **nameresult, int bin, int *fdp);
+int sys_trytoopenone(const char *dir, const char *name, const char* ext, char **dirresult, char **nameresult, int bin);
+
+/* s_main.c */
+extern int sys_debuglevel;
+extern int sys_verbose;
+extern int sys_noloadbang;
+extern int sys_nogui;
+extern char *sys_guicmd;
+extern int sys_tooltips;
+extern int sys_defeatrt;
+extern t_symbol *sys_flags;
+extern t_symbol *sys_libdir; /* library directory for auxilliary files */
+
+/* s_loader.c */
+int sys_load_lib(t_canvas *canvas, char *filename);
+
+/* s_audio.c */
+#define SENDDACS_NO 0 /* return values for sys_send_dacs() */
+#define SENDDACS_YES 1
+#define SENDDACS_SLEPT 2
+#define DEFDACBLKSIZE 64 /* the default dac~blocksize */
+extern int sys_dacblocksize; /* the real dac~blocksize */
+extern int sys_schedblocksize; /* audio block size for scheduler */
+extern int sys_hipriority; /* real-time flag, true if priority boosted */
+extern t_sample *sys_soundout;
+extern t_sample *sys_soundin;
+extern int sys_inchannels;
+extern int sys_outchannels;
+extern int sys_advance_samples; /* scheduler advance in samples */
+extern int sys_blocksize; /* audio I/O block size in sample frames */
+extern float sys_dacsr;
+extern int sys_schedadvance;
+extern int sys_sleepgrain;
+extern int sys_callbackscheduler; /* tb: scheduler to use (0: traditional, 1: callback) */
+void sys_open_audio(
+int naudioindev, int * audioindev, int nchindev, int * chindev,
+int naudiooutdev, int *audiooutdev, int nchoutdev, int *choutdev,
+int srate, int dacblocksize, int advance, int schedmode, int enable);
+void sys_reopen_audio(void);
+void sys_close_audio(void);
+int sys_send_dacs(void);
+void sys_set_priority(int higher);
+void sys_audiobuf(int nbufs);
+void sys_getmeters(float *inmax, float *outmax);
+void sys_listdevs(void);
+void sys_setblocksize(int n);
+void sys_update_sleepgrain(void); //tb
+
+/* s_midi.c */
+#define MAXMIDIINDEV 16 /* max. number of input ports */
+#define MAXMIDIOUTDEV 16 /* max. number of output ports */
+extern int sys_nmidiin;
+extern int sys_nmidiout;
+extern int sys_midiindevlist[];
+extern int sys_midioutdevlist[];
+void sys_open_midi(int nmidiin, int *midiinvec, int nmidiout, int *midioutvec, int enable);
+void sys_get_midi_params(int *pnmidiindev, int *pmidiindev, int *pnmidioutdev, int *pmidioutdev);
+void sys_get_midi_apis(char *buf);
+void sys_reopen_midi( void);
+void sys_close_midi( void);
+EXTERN void sys_putmidimess(int portno, int a, int b, int c);
+EXTERN void sys_putmidibyte(int portno, int a);
+EXTERN void sys_poll_midi(void);
+EXTERN void sys_setmiditimediff(double inbuftime, double outbuftime);
+EXTERN void sys_midibytein(int portno, int byte);
+/* implemented in the system dependent MIDI code (s_midi_pm.c, etc.) */
+void midi_getdevs(char *indevlist, int *nindevs, char *outdevlist, int *noutdevs, int maxndev, int devdescsize);
+void sys_do_open_midi(int nmidiindev, int *midiindev, int nmidioutdev, int *midioutdev);
+
+#ifdef USEAPI_ALSA
+EXTERN void sys_alsa_putmidimess(int portno, int a, int b, int c);
+EXTERN void sys_alsa_putmidibyte(int portno, int a);
+EXTERN void sys_alsa_poll_midi(void);
+EXTERN void sys_alsa_setmiditimediff(double inbuftime, double outbuftime);
+EXTERN void sys_alsa_midibytein(int portno, int byte);
+EXTERN void sys_alsa_close_midi( void);
+/* implemented in the system dependent MIDI code (s_midi_pm.c, etc. ) */
+void midi_alsa_getdevs(char *indevlist, int *nindevs, char *outdevlist, int *noutdevs, int maxndev, int devdescsize);
+void sys_alsa_do_open_midi(int nmidiindev, int *midiindev, int nmidioutdev, int *midioutdev);
+#endif
+
+/* m_sched.c */
+EXTERN void sys_log_error(int type);
+#define ERR_NOTHING 0
+#define ERR_ADCSLEPT 1
+#define ERR_DACSLEPT 2
+#define ERR_RESYNC 3
+#define ERR_DATALATE 4
+#define ERR_XRUN 5
+#define ERR_SYSLOCK 6
+void sched_set_using_dacs(int flag);
+void sys_setscheduler(int scheduler); //tb
+int sys_getscheduler(void); //tb
+
+/* s_inter.c */
+EXTERN void sys_microsleep(int microsec);
+EXTERN void sys_bail(int exitcode);
+EXTERN int sys_pollgui(void);
+typedef void (*t_socketnotifier)(void *x);
+typedef void (*t_socketreceivefn)(void *x, t_binbuf *b);
+
+typedef struct _socketreceiver {
+ char *inbuf;
+ int inhead;
+ int intail;
+ void *owner;
+ int udp;
+ t_socketnotifier notifier;
+ t_socketreceivefn socketreceivefn;
+/* for sending only: */
+ int fd;
+ struct _socketreceiver *next;
+ char *obuf;
+ int ohead, otail, osize;
+ int waitingforping;
+ int bytessincelastping;
+} t_socketreceiver;
+
+EXTERN char pd_version[];
+EXTERN t_text *sys_netreceive;
+EXTERN t_socketreceiver *sys_socketreceiver;
+//EXTERN t_socketreceiver *netreceive_newest_receiver(t_text *x);
+
+EXTERN t_namelist *sys_externlist;
+EXTERN t_namelist *sys_openlist;
+EXTERN t_namelist *sys_messagelist;
+
+EXTERN t_socketreceiver *socketreceiver_new(t_pd *owner, int fd,
+ t_socketnotifier notifier, t_socketreceivefn socketreceivefn, int udp);
+EXTERN void socketreceiver_read(t_socketreceiver *x, int fd);
+EXTERN void sys_sockerror(char *s);
+EXTERN void sys_closesocket(int fd);
+
+typedef void (*t_fdpollfn)(void *ptr, int fd);
+EXTERN void sys_addpollfn(int fd, t_fdpollfn fn, void *ptr);
+EXTERN void sys_rmpollfn(int fd);
+#ifdef UNIX
+void sys_setalarm(int microsec);
+void sys_setvirtualalarm(void);
+#endif
+
+#define API_NONE 0
+#define API_ALSA 1
+#define API_OSS 2
+#define API_MMIO 3
+#define API_PORTAUDIO 4
+#define API_JACK 5
+#define API_SGI 6
+#define API_ASIO 7
+
+#if defined(USEAPI_OSS)
+#define API_DEFAULT API_OSS
+#define API_DEFSTRING "oss"
+#elif defined(USEAPI_ALSA)
+#define API_DEFAULT API_ALSA
+#define API_DEFSTRING "alsa"
+#elif defined(USEAPI_JACK)
+#define API_DEFAULT API_JACK
+#define API_DEFSTRING "jack"
+#elif defined(USEAPI_MMIO)
+#define API_DEFAULT API_MMIO
+#define API_DEFSTRING "mmio"
+#elif defined(USEAPI_PORTAUDIO)
+#define API_DEFAULT API_PORTAUDIO
+#define API_DEFSTRING "portaudio"
+#else
+#define API_DEFAULT 0
+#define API_DEFSTRING "none"
+#endif
+
+#define DEFAULTAUDIODEV 0
+#define MAXAUDIOINDEV 4
+#define MAXAUDIOOUTDEV 4
+#define DEFMIDIDEV 0
+#define DEFAULTSRATE 44100
+#ifdef MSW
+#define DEFAULTADVANCE 70
+#else
+#define DEFAULTADVANCE 50
+#endif
+
+struct t_audiodevs {
+ int ndev;
+ int dev[MAXAUDIOINDEV];
+ int chdev[MAXAUDIOINDEV];
+#ifdef __cplusplus
+ t_audiodevs() : ndev(-1) {}
+#endif
+};
+
+/* new audio api interface */
+typedef struct t_audioapi {
+ int (*open_audio)(
+ int naudioindev, int *audioindev, int nchindev, int *chindev,
+ int naudiooutdev, int *audiooutdev, int nchoutdev, int *choutdev,
+ int rate, int schedmode);
+ void (*close_audio)(void);
+ int (*send_dacs)(void);
+ void (*getdevs)(char *indevlist, int *nindevs, char *outdevlist, int *noutdevs, int *canmulti, int maxndev, int devdescsize);
+} t_audioapi;
+
+int pa_open_audio(int inchans, int outchans, int rate, int advance, int indeviceno, int outdeviceno, int schedmode);
+
+/* tb { */
+void pa_test_setting (int ac, t_atom *av);
+void pa_getcurrent_devices(void);
+void pa_getaudiooutdevinfo(t_float f);
+void pa_getaudioindevinfo(t_float f);
+/* } tb */
+
+int jack_open_audio(int wantinchans, int wantoutchans, int rate, int scheduler);
+void jack_listdevs(void);
+void sys_listmididevs(void);
+void sys_set_midi_api(int whichapi);
+void sys_set_audio_api(int whichapi);
+void sys_get_audio_apis(char *buf);
+extern int sys_audioapi;
+void sys_set_audio_state(int onoff);
+
+/* API dependent audio flags and settings */
+void oss_set32bit(void);
+void linux_alsa_devname(char *devname);
+
+void sys_get_audio_params(t_audiodevs *in, t_audiodevs *out, int *prate, int *dacblocksize, int *padvance, int *pscheduler);
+void sys_save_audio_params(t_audiodevs *in, t_audiodevs *out, int rate, int dacblocksize, int advance, int scheduler);
+
+/* s_file.c */
+typedef void (*t_printhook)(const char *s);
+extern t_printhook sys_printhook; /* set this to override printing */
+extern int sys_printtostderr;
+#ifdef MSW
+#define vsnprintf _vsnprintf /* jsarlo -- alias this name for msw */
+#endif
+
+/* jsarlo { */
+EXTERN double sys_time;
+EXTERN double sys_time_per_dsp_tick;
+EXTERN int sys_externalschedlib;
+
+EXTERN t_sample* get_sys_soundout(void);
+EXTERN t_sample* get_sys_soundin(void);
+EXTERN int* get_sys_main_advance(void);
+EXTERN double* get_sys_time_per_dsp_tick(void);
+EXTERN int* get_sys_schedblocksize(void);
+EXTERN double* get_sys_time(void);
+EXTERN float* get_sys_dacsr(void);
+EXTERN int* get_sys_sleepgrain(void);
+EXTERN int* get_sys_schedadvance(void);
+
+EXTERN void sys_clearhist(void);
+EXTERN void sys_initmidiqueue(void);
+EXTERN int sys_addhist(int phase);
+EXTERN void sys_setmiditimediff(double inbuftime, double outbuftime);
+EXTERN void sched_tick(double next_sys_time);
+EXTERN void sys_pollmidiqueue(void);
+EXTERN int sys_pollgui(void);
+EXTERN void sys_setchsr(int chin, int chout, int sr, int dacblocksize);
+
+EXTERN void inmidi_noteon(int portno, int channel, int pitch, int velo);
+EXTERN void inmidi_controlchange(int portno, int channel, int ctlnumber, int value);
+EXTERN void inmidi_programchange(int portno, int channel, int value);
+EXTERN void inmidi_pitchbend(int portno, int channel, int value);
+EXTERN void inmidi_aftertouch(int portno, int channel, int value);
+EXTERN void inmidi_polyaftertouch(int portno, int channel, int pitch, int value);
+/* } jsarlo */
+
+/* functions in x_midi.c */
+void inmidi_realtimein(int portno, int cmd);
+void inmidi_byte(int portno, int byte);
+void inmidi_sysex(int portno, int byte);
+void inmidi_noteon(int portno, int channel, int pitch, int velo);
+void inmidi_controlchange(int portno, int channel, int ctlnumber, int value);
+void inmidi_programchange(int portno, int channel, int value);
+void inmidi_pitchbend(int portno, int channel, int value);
+void inmidi_aftertouch(int portno, int channel, int value);
+void inmidi_polyaftertouch(int portno, int channel, int pitch, int value);
+
+#if defined(_LANGUAGE_C_PLUS_PLUS) || defined(__cplusplus)
+}
+#endif
+#endif /* __STUFF_H */
diff --git a/desiredata/src/s_watchdog.c b/desiredata/src/s_watchdog.c
new file mode 100644
index 00000000..14089eeb
--- /dev/null
+++ b/desiredata/src/s_watchdog.c
@@ -0,0 +1,40 @@
+/* Copyright (c) 1997-2000 Miller Puckette.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* This file is compiled into the separate program, "pd-watchdog," which
+tries to prevent Pd from locking up the processor if it's at realtime
+priority. Linux only. Invoked from s_inter.c. */
+
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <signal.h>
+#include <stdio.h>
+
+int main(int argc, char **argv) {
+ int happy = 1;
+ while (1) {
+ struct timeval timout;
+ fd_set readset;
+ if (happy) {
+ timout.tv_sec = 5;
+ timout.tv_usec = 0;
+ } else {
+ timout.tv_sec = 2;
+ timout.tv_usec = 0;
+ }
+ FD_ZERO(&readset);
+ FD_SET(0, &readset);
+ select(1, &readset, 0, 0, &timout);
+ if (FD_ISSET(0, &readset)) {
+ char buf[100];
+ happy = 1;
+ if (read(0, &buf, 100) <= 0) return 0;
+ continue;
+ }
+ happy = 0;
+ kill(getppid(), SIGHUP);
+ fprintf(stderr, "watchdog: signaling pd...\n");
+ }
+}
diff --git a/desiredata/src/tests/abstr-test.pd b/desiredata/src/tests/abstr-test.pd
new file mode 100644
index 00000000..dce22c6b
--- /dev/null
+++ b/desiredata/src/tests/abstr-test.pd
@@ -0,0 +1,3 @@
+#N canvas 0 0 450 300 10;
+#X obj 30 36 abstr;
+#X obj 101 36 abstr2;
diff --git a/desiredata/src/tests/abstr.pd b/desiredata/src/tests/abstr.pd
new file mode 100644
index 00000000..91250635
--- /dev/null
+++ b/desiredata/src/tests/abstr.pd
@@ -0,0 +1,11 @@
+#N canvas 0 0 450 300 10;
+#X obj 77 5 inlet;
+#X obj 189 6 inlet;
+#X obj 171 256 outlet;
+#X obj 133 6 inlet;
+#X obj 245 7 inlet;
+#X connect 0 0 2 0;
+#X connect 1 0 2 0;
+#X connect 3 0 2 0;
+#X connect 4 0 2 0;
+#X coords 0 0 1 1 0 0 0;
diff --git a/desiredata/src/tests/abstr2.pd b/desiredata/src/tests/abstr2.pd
new file mode 100644
index 00000000..c3a9639c
--- /dev/null
+++ b/desiredata/src/tests/abstr2.pd
@@ -0,0 +1,15 @@
+#N canvas 0 0 450 300 10;
+#X obj 19 29 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 39 29 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X obj 59 29 nbx 8 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 0 8 -262144
+-1 -1 0 256;
+#X obj 19 52 vsl 15 128 0 127 0 0 empty empty empty 0 -6 0 8 -262144
+-1 -1 0 1;
+#X obj 19 11 hsl 128 15 0 127 0 0 empty empty empty 0 -6 0 8 -262144
+-1 -1 0 1;
+#X obj 136 29 vradio 15 1 0 8 empty empty empty 0 -6 0 8 -262144 -1
+-1 0;
+#X obj 38 156 hradio 15 1 0 8 empty empty empty 0 -6 0 8 -262144 -1
+-1 6;
diff --git a/desiredata/src/tests/all_guis_and_gop.pd b/desiredata/src/tests/all_guis_and_gop.pd
new file mode 100644
index 00000000..2be10062
--- /dev/null
+++ b/desiredata/src/tests/all_guis_and_gop.pd
@@ -0,0 +1,116 @@
+#N canvas 339 27 590 690 10;
+#X obj 98 29 +;
+#X floatatom 99 83 5 0 0 0 - - -;
+#X symbolatom 99 108 10 0 0 0 - - -;
+#X obj 158 27 bng 42 250 50 0 empty empty button-label 50 8 0 8 -258699
+-1 -1;
+#X obj 158 87 tgl 15 0 empty empty hello? 20 8 0 9 -24198 -1 -1 0 1
+;
+#X obj 227 140 nbx 5 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 0 10
+-262144 -1 -1 0 256;
+#X obj 5 13 vsl 25 150 0 127 0 0 empty empty vslider-hello -2 -6 0
+9 -241291 -1 -1 0 0;
+#X obj 43 201 hsl 100 10 0 127 0 0 empty empty hello-hslider 10 6 0
+9 -262144 -1 -258699 0 0;
+#X obj 67 159 hradio 15 1 0 8 empty empty hello-hradio 0 -6 0 9 -261681
+-1 -1 0;
+#X obj 68 24 vradio 15 1 0 8 empty empty hello-vradio 0 -6 0 9 -262144
+-1 -1 0;
+#X obj 435 73 vu 15 120 empty vumeter-label -1 -8 0 8 -166441 -1 1
+0;
+#X obj 306 9 cnv 15 100 60 empty empty empty 20 12 0 14 -233017 -66577
+0;
+#N canvas 0 0 450 300 graph2 0;
+#X array array1 100 float 1;
+#A 0 -0.0571427 -0.0428571 -0.0857141 -0.171428 -0.185714 -0.199999
+-0.206428 -0.212856 -0.219285 -0.225714 -0.232142 -0.238571 -0.244999
+-0.251428 -0.257856 -0.264285 -0.270713 -0.277142 -0.28357 -0.289999
+-0.296427 -0.302856 -0.309285 -0.315713 -0.322142 -0.32857 -0.331427
+-0.334285 -0.337142 -0.339999 -0.342856 -0.345713 -0.34857 -0.351427
+-0.354284 -0.357141 -0.359999 -0.362856 -0.365713 -0.35857 -0.351427
+-0.329999 -0.30857 -0.279999 -0.25619 -0.23238 -0.208571 -0.18 0.162856
+0.305712 0.419998 0.448569 0.491426 0.57714 0.591425 0.605711 0.305712
+0.14857 0.105713 -0.00857189 -0.122857 -0.237142 -0.322856 -0.40857
+-0.479998 -0.50857 -0.565712 -0.594283 -0.608569 -0.608569 -0.608569
+-0.594283 -0.565712 -0.546664 -0.527617 -0.494284 -0.460951 0.0342851
+-0.0514288 -0.165714 -0.201428 -0.251428 -0.265714 -0.294285 -0.337142
+-0.337142 -0.365713 -0.365713 -0.40857 -0.437141 -0.451427 -0.451427
+-0.451427 -0.479998 -0.494284 -0.477141 -0.482855 -0.48857 -0.494284
+-0.499998;
+#X coords 0 1 99 -1 200 140 1;
+#X restore 199 178 graph;
+#X floatatom 432 22 5 0 0 0 - - -;
+#X floatatom 479 23 5 -99 42 2 floatatom-label - -;
+#X obj 225 74 nbx 5 14 -1e+37 1e+37 0 0 empty empty numbox2-label 60
+8 0 9 -260818 -62784 -1 0 256;
+#X floatatom 237 48 5 0 0 0 - - -;
+#X msg 98 57;
+#N canvas 0 0 450 300 foo 0;
+#X obj 148 99 +;
+#X floatatom 149 153 5 0 0 0 - - -;
+#X symbolatom 149 178 10 0 0 0 - - -;
+#X obj 208 97 bng 42 250 50 0 empty empty button-label 50 8 0 8 -258699
+-1 -1;
+#X obj 208 157 tgl 15 0 empty empty hello? 20 8 0 9 -24198 -1 -1 0
+1;
+#X obj 277 210 nbx 5 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 0 10
+-262144 -1 -1 0 256;
+#X obj 55 83 vsl 25 150 0 127 0 0 empty empty vslider-hello -2 -6 0
+9 -241291 -1 -1 0 0;
+#X obj 93 271 hsl 100 10 0 127 0 0 empty empty hello-hslider 10 6 0
+9 -262144 -1 -258699 0 0;
+#X obj 117 229 hradio 15 1 0 8 empty empty hello-hradio 0 -6 0 9 -261681
+-1 -1 0;
+#X obj 118 94 vradio 15 1 0 8 empty empty hello-vradio 0 -6 0 9 -262144
+-1 -1 0;
+#X obj 485 143 vu 15 120 empty vumeter-label -1 -8 0 8 -166441 -1 1
+0;
+#X obj 356 79 cnv 15 100 60 empty empty empty 20 12 0 14 -233017 -66577
+0;
+#N canvas 0 0 450 300 graph2 0;
+#X array array1 100 float 1;
+#A 0 -0.0571427 -0.0428571 -0.0857141 -0.171428 -0.185714 -0.199999
+-0.206428 -0.212856 -0.219285 -0.225714 -0.232142 -0.238571 -0.244999
+-0.251428 -0.257856 -0.264285 -0.270713 -0.277142 -0.28357 -0.289999
+-0.296427 -0.302856 -0.309285 -0.315713 -0.322142 -0.32857 -0.331427
+-0.334285 -0.337142 -0.339999 -0.342856 -0.345713 -0.34857 -0.351427
+-0.354284 -0.357141 -0.359999 -0.362856 -0.365713 -0.35857 -0.351427
+-0.329999 -0.30857 -0.279999 -0.25619 -0.23238 -0.208571 -0.18 0.162856
+0.305712 0.419998 0.448569 0.491426 0.57714 0.591425 0.605711 0.305712
+0.14857 0.105713 -0.00857189 -0.122857 -0.237142 -0.322856 -0.40857
+-0.479998 -0.50857 -0.565712 -0.594283 -0.608569 -0.608569 -0.608569
+-0.594283 -0.565712 -0.546664 -0.527617 -0.494284 -0.460951 0.0342851
+-0.0514288 -0.165714 -0.201428 -0.251428 -0.265714 -0.294285 -0.337142
+-0.337142 -0.365713 -0.365713 -0.40857 -0.437141 -0.451427 -0.451427
+-0.451427 -0.479998 -0.494284 -0.477141 -0.482855 -0.48857 -0.494284
+-0.499998;
+#X coords 0 1 99 -1 200 140 1;
+#X restore 249 248 graph;
+#X floatatom 482 92 5 0 0 0 - - -;
+#X floatatom 529 93 5 -99 42 2 floatatom-label - -;
+#X obj 275 144 nbx 5 14 -1e+37 1e+37 0 0 empty empty numbox2-label
+60 8 0 9 -260818 -62784 -1 0 256;
+#X floatatom 287 118 5 0 0 0 - - -;
+#X msg 148 127;
+#X obj 15 17 bng 15 250 50 0 empty empty i_shouldn't_be_visible_in_parent
+0 -6 0 9 -262144 -1 -1;
+#X connect 3 0 4 0;
+#X connect 4 0 5 0;
+#X connect 6 0 7 0;
+#X connect 8 0 7 0;
+#X connect 9 0 8 0;
+#X connect 13 0 10 0;
+#X connect 14 0 10 1;
+#X connect 15 0 5 0;
+#X connect 16 0 15 0;
+#X coords 0 -1 1 1 400 300 1 50 50;
+#X restore 99 336 pd foo;
+#X connect 3 0 4 0;
+#X connect 4 0 5 0;
+#X connect 6 0 7 0;
+#X connect 8 0 7 0;
+#X connect 9 0 8 0;
+#X connect 13 0 10 0;
+#X connect 14 0 10 1;
+#X connect 15 0 5 0;
+#X connect 16 0 15 0;
diff --git a/desiredata/src/tests/all_guis_and_gop.pd.gif b/desiredata/src/tests/all_guis_and_gop.pd.gif
new file mode 100644
index 00000000..288c6902
--- /dev/null
+++ b/desiredata/src/tests/all_guis_and_gop.pd.gif
Binary files differ
diff --git a/desiredata/src/tests/bof.pd b/desiredata/src/tests/bof.pd
new file mode 100644
index 00000000..706950cf
--- /dev/null
+++ b/desiredata/src/tests/bof.pd
@@ -0,0 +1,27 @@
+#N canvas 0 0 675 450 10;
+#X obj 23 28 +;
+#X obj 35 206 adc~;
+#X obj 99 124 -;
+#X obj 142 214 * 42;
+#X msg 130 47 foo;
+#X msg 280 91 0;
+#X msg 280 70 set \$1;
+#X obj 280 46 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 0
+0;
+#X obj 228 54 vsl 15 128 0 127 0 0 empty empty empty 0 -6 0 8 -262144
+-1 -1 0 0 0;
+#X obj 254 64 vradio 15 1 0 8 empty empty empty 0 -6 0 8 -262144 -1
+-1 0;
+#X floatatom 381 79 5 0 0 0 - - -;
+#X obj 372 109 nbx 5 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 0 8
+-262144 -1 -1 0 0 256;
+#X symbolatom 352 42 10 0 0 0 - - -;
+#X obj -43 -41 lop~;
+#X text 11 3 there's a [lop~] top left \, but negative coords are buggy.
+;
+#X connect 0 0 1 0;
+#X connect 0 0 2 1;
+#X connect 2 0 3 0;
+#X connect 4 0 2 0;
+#X connect 6 0 5 0;
+#X connect 7 0 6 0;
diff --git a/desiredata/src/tests/chun.pd b/desiredata/src/tests/chun.pd
new file mode 100644
index 00000000..0ee7d48a
--- /dev/null
+++ b/desiredata/src/tests/chun.pd
@@ -0,0 +1,36 @@
+#N canvas 385 550 450 300 10;
+#X obj 151 212 dac~;
+#X obj 132 139 *~ 0.02;
+#X msg 231 120 0;
+#X obj 252 95 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X msg 235 154 0.2;
+#X obj 274 140 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 45 105 delread~ down;
+#X obj 21 26 delread~ up;
+#X obj 15 132 *~ 0.8;
+#X obj 126 41 osc~ 500;
+#X obj 133 11 osc~ 40;
+#X obj 225 19 +~ 1;
+#X obj 219 46 *~ 500;
+#X floatatom 337 69 5 0 0 0 - - -;
+#X obj 46 78 delwrite~ down 20;
+#X obj 15 156 delwrite~ up 20;
+#X text 323 50 tweak me;
+#X connect 1 0 0 0;
+#X connect 1 0 0 1;
+#X connect 2 0 1 1;
+#X connect 3 0 2 0;
+#X connect 4 0 1 1;
+#X connect 5 0 4 0;
+#X connect 6 0 8 0;
+#X connect 6 0 1 0;
+#X connect 7 0 14 0;
+#X connect 8 0 15 0;
+#X connect 9 0 14 0;
+#X connect 10 0 11 0;
+#X connect 11 0 12 0;
+#X connect 12 0 9 0;
+#X connect 13 0 6 0;
+#X connect 13 0 7 0;
diff --git a/desiredata/src/tests/city.pd b/desiredata/src/tests/city.pd
new file mode 100644
index 00000000..9b30647c
--- /dev/null
+++ b/desiredata/src/tests/city.pd
@@ -0,0 +1,128 @@
+#N canvas 0 0 450 300 10;
+#X obj 23 20 +;
+#X obj 53 20 +;
+#X obj 23 50 +;
+#X obj 53 50 +;
+#X obj 83 20 +;
+#X obj 113 20 +;
+#X obj 83 50 +;
+#X obj 113 50 +;
+#X obj 23 80 +;
+#X obj 53 80 +;
+#X obj 23 110 +;
+#X obj 53 110 +;
+#X obj 83 80 +;
+#X obj 113 80 +;
+#X obj 83 110 +;
+#X obj 113 110 +;
+#X obj 143 20 +;
+#X obj 173 20 +;
+#X obj 143 50 +;
+#X obj 173 50 +;
+#X obj 203 20 +;
+#X obj 233 20 +;
+#X obj 203 50 +;
+#X obj 233 50 +;
+#X obj 143 80 +;
+#X obj 173 80 +;
+#X obj 143 110 +;
+#X obj 173 110 +;
+#X obj 203 80 +;
+#X obj 233 80 +;
+#X obj 203 110 +;
+#X obj 233 110 +;
+#X obj 23 140 +;
+#X obj 53 140 +;
+#X obj 23 170 +;
+#X obj 53 170 +;
+#X obj 83 140 +;
+#X obj 113 140 +;
+#X obj 83 170 +;
+#X obj 113 170 +;
+#X obj 23 200 +;
+#X obj 53 200 +;
+#X obj 23 230 +;
+#X obj 53 230 +;
+#X obj 83 200 +;
+#X obj 113 200 +;
+#X obj 83 230 +;
+#X obj 113 230 +;
+#X obj 143 140 +;
+#X obj 173 140 +;
+#X obj 143 170 +;
+#X obj 173 170 +;
+#X obj 203 140 +;
+#X obj 233 140 +;
+#X obj 203 170 +;
+#X obj 233 170 +;
+#X obj 143 200 +;
+#X obj 173 200 +;
+#X obj 143 230 +;
+#X obj 173 230 +;
+#X obj 203 200 +;
+#X obj 233 200 +;
+#X obj 203 230 +;
+#X obj 233 230 +;
+#X connect 0 0 1 0;
+#X connect 0 0 2 0;
+#X connect 1 0 4 0;
+#X connect 2 0 3 0;
+#X connect 2 0 8 0;
+#X connect 4 0 5 0;
+#X connect 4 0 6 0;
+#X connect 5 0 16 0;
+#X connect 6 0 7 0;
+#X connect 8 0 9 0;
+#X connect 8 0 10 0;
+#X connect 9 0 12 0;
+#X connect 10 0 11 0;
+#X connect 10 0 32 0;
+#X connect 12 0 13 0;
+#X connect 12 0 14 0;
+#X connect 14 0 15 0;
+#X connect 16 0 17 0;
+#X connect 16 0 18 0;
+#X connect 17 0 20 0;
+#X connect 18 0 19 0;
+#X connect 18 0 24 0;
+#X connect 20 0 21 0;
+#X connect 20 0 22 0;
+#X connect 22 0 23 0;
+#X connect 24 0 25 0;
+#X connect 24 0 26 0;
+#X connect 25 0 28 0;
+#X connect 26 0 27 0;
+#X connect 28 0 29 0;
+#X connect 28 0 30 0;
+#X connect 30 0 31 0;
+#X connect 32 0 33 0;
+#X connect 32 0 34 0;
+#X connect 33 0 36 0;
+#X connect 34 0 35 0;
+#X connect 34 0 40 0;
+#X connect 36 0 37 0;
+#X connect 36 0 38 0;
+#X connect 37 0 48 0;
+#X connect 38 0 39 0;
+#X connect 40 0 41 0;
+#X connect 40 0 42 0;
+#X connect 41 0 44 0;
+#X connect 42 0 43 0;
+#X connect 44 0 45 0;
+#X connect 44 0 46 0;
+#X connect 46 0 47 0;
+#X connect 48 0 49 0;
+#X connect 48 0 50 0;
+#X connect 49 0 52 0;
+#X connect 50 0 51 0;
+#X connect 50 0 56 0;
+#X connect 52 0 53 0;
+#X connect 52 0 54 0;
+#X connect 54 0 55 0;
+#X connect 56 0 57 0;
+#X connect 56 0 58 0;
+#X connect 57 0 60 0;
+#X connect 58 0 59 0;
+#X connect 60 0 61 0;
+#X connect 60 0 62 0;
+#X connect 62 0 63 0;
diff --git a/desiredata/src/tests/desiredata-presentation-piksel06.pd b/desiredata/src/tests/desiredata-presentation-piksel06.pd
new file mode 100644
index 00000000..fee64d2d
--- /dev/null
+++ b/desiredata/src/tests/desiredata-presentation-piksel06.pd
@@ -0,0 +1,26 @@
+#N canvas 0 0 640 480 10;
+#X text 100 140 Zoomable patches (and def Canvas item);
+#X text 100 160 Client-side selection and clipboard;
+#X text 100 180 Client-side undo and redo: multiple \, atomic \, labeled
+\, history;
+#X text 100 200 Class browser and class name completions;
+#X text 100 220 Internationalization (the Patching-in-Tongues project)
+;
+#X text 100 240 Keyboard-based Navigation and Edition;
+#X text 100 260 Server Preferences (.pdrc Editor);
+#X text 100 280 Client Preferences (.ddrc Editor);
+#X text 100 300 Canvas Actions;
+#X text 100 320 #V for visual attributes;
+#V bg 255 255 0;
+#X text 100 340 Dialog autogeneration with def Dialog add;
+#X text 100 360 ClientClassTreeDialog;
+#X text 100 380 Deconstructors;
+#X text 100 400 desire.h;
+#X text 100 420 what is happening to desire.c these days;
+#X obj 94 31 bng 32 250 50 0 empty empty DesireData-0.39.A 40 15 1
+19 -262088 -1 -1;
+#X text 295 270 tab support in all dialogs;
+#X obj 0 0 + 242;
+#V pretty 1;
+#X text 99 440 scaling of selection or complete patch;
+#X coords 0 0 1 1 0 0 0;
diff --git a/desiredata/src/tests/gop-one.pd b/desiredata/src/tests/gop-one.pd
new file mode 100644
index 00000000..b1414997
--- /dev/null
+++ b/desiredata/src/tests/gop-one.pd
@@ -0,0 +1,18 @@
+#N canvas 447 533 552 376 10;
+#X obj 5 24 vsl 10 50 0 127 0 0 empty empty empty 0 -6 0 8 -262144
+-1 -1 0 1;
+#X obj 20 21 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X floatatom 20 58 5 0 0 0 - - -;
+#X obj 41 21 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X obj 6 124 outlet;
+#X obj 80 0 inlet;
+#X obj 136 8 inlet;
+#X connect 0 0 2 0;
+#X connect 1 0 4 0;
+#X connect 2 0 4 0;
+#X connect 3 0 4 0;
+#X connect 5 0 0 0;
+#X connect 6 0 1 0;
+#X coords 0 0 1 1 60 85 1 0 0;
diff --git a/desiredata/src/tests/gop-three.pd b/desiredata/src/tests/gop-three.pd
new file mode 100644
index 00000000..7ab5cb13
--- /dev/null
+++ b/desiredata/src/tests/gop-three.pd
@@ -0,0 +1,41 @@
+#N canvas 238 407 695 410 10;
+#N canvas 0 0 450 300 three 0;
+#X obj 89 21 gop-two;
+#X obj 22 65 vsl 10 50 0 127 0 0 empty empty empty 0 -6 0 8 -262144
+-1 -1 0 1;
+#X obj 41 61 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 63 61 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X floatatom 41 101 5 0 0 0 - - -;
+#X obj 259 3 inlet;
+#X obj 339 4 inlet;
+#X obj 51 237 outlet;
+#X connect 0 0 7 0;
+#X connect 1 0 4 0;
+#X connect 2 0 0 1;
+#X connect 4 0 0 0;
+#X connect 5 0 1 0;
+#X connect 6 0 2 0;
+#X coords 0 0 1 1 250 150 1 0 0;
+#X restore 182 100 pd three;
+#X obj 100 165 vsl 10 50 0 127 0 0 empty empty empty 0 -6 0 8 -262144
+-1 -1 0 1;
+#X floatatom 121 202 5 0 0 0 - - -;
+#X obj 121 262 print A;
+#X obj 182 262 print B;
+#X obj 100 43 random 127;
+#X obj 100 21 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 100 68 t f f;
+#X obj 425 62 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 460 120 gop-two;
+#X connect 0 0 4 0;
+#X connect 1 0 2 0;
+#X connect 2 0 3 0;
+#X connect 5 0 7 0;
+#X connect 6 0 5 0;
+#X connect 7 0 1 0;
+#X connect 7 1 0 0;
+#X connect 8 0 0 1;
diff --git a/desiredata/src/tests/gop-two.pd b/desiredata/src/tests/gop-two.pd
new file mode 100644
index 00000000..080cf53f
--- /dev/null
+++ b/desiredata/src/tests/gop-two.pd
@@ -0,0 +1,19 @@
+#N canvas 373 135 592 432 10;
+#X obj 80 20 gop-one;
+#X obj 9 44 vsl 10 50 0 127 0 0 empty empty empty 0 -6 0 8 -262144
+-1 -1 0 1;
+#X obj 25 40 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 50 40 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X floatatom 29 82 5 0 0 0 - - -;
+#X obj 81 162 outlet;
+#X obj 168 11 inlet;
+#X obj 237 12 inlet;
+#X connect 0 0 5 0;
+#X connect 1 0 4 0;
+#X connect 2 0 0 1;
+#X connect 4 0 0 0;
+#X connect 6 0 1 0;
+#X connect 7 0 2 0;
+#X coords 0 0 1 1 150 120 1 0 0;
diff --git a/desiredata/src/tests/sub.pd b/desiredata/src/tests/sub.pd
new file mode 100644
index 00000000..1a9e570b
--- /dev/null
+++ b/desiredata/src/tests/sub.pd
@@ -0,0 +1,21 @@
+#N canvas 586 146 668 714 10;
+#X obj 86 58 +;
+#X obj 107 130 -;
+#N canvas 0 0 450 300 foo 0;
+#X obj 110 30 inlet;
+#X obj 110 100 + 1.618;
+#X obj 110 130 * 3.14159;
+#X obj 110 180 outlet;
+#X connect 0 0 1 0;
+#X connect 1 0 2 0;
+#X connect 2 0 3 0;
+#X restore 224 153 pd foo;
+#X obj 101 73 +;
+#X obj 122 145 -;
+#X msg 220 120 42;
+#X floatatom 220 180 8 0 0 0 - - -;
+#X text 220 200 137.03;
+#X connect 0 0 1 0;
+#X connect 2 0 6 0;
+#X connect 3 0 4 0;
+#X connect 5 0 2 0;
diff --git a/desiredata/src/tests/subgop-test.pd b/desiredata/src/tests/subgop-test.pd
new file mode 100644
index 00000000..48fb0bb1
--- /dev/null
+++ b/desiredata/src/tests/subgop-test.pd
@@ -0,0 +1,8 @@
+#N canvas 0 0 450 300 10;
+#N canvas 0 0 450 300 foo 1;
+#X obj 10 24 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 276 183 print;
+#X coords 0 -1 1 1 85 60 1 0 0;
+#X restore 145 113 pd foo;
+#X obj 319 154 pack;
diff --git a/desiredata/src/u_pdreceive.c b/desiredata/src/u_pdreceive.c
new file mode 100644
index 00000000..8898e3a3
--- /dev/null
+++ b/desiredata/src/u_pdreceive.c
@@ -0,0 +1,321 @@
+/* Copyright (c) 2000 Miller Puckette.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in the Pd distribution. */
+
+/* the "pdreceive" command. This is a standalone program that receives messages
+from Pd via the netsend/netreceive ("FUDI") protocol, and copies them to
+standard output. */
+
+#include <sys/types.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#ifdef MSW
+#include <winsock.h>
+#else
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <unistd.h>
+#define SOCKET_ERROR -1
+#endif
+
+typedef struct _fdpoll
+{
+ int fdp_fd;
+ char *fdp_inbuf;
+ int fdp_inhead;
+ int fdp_intail;
+ int fdp_udp;
+} t_fdpoll;
+
+static int nfdpoll;
+static t_fdpoll *fdpoll;
+static int maxfd;
+static int sockfd;
+static int protocol;
+
+static void sockerror(char *s);
+static void x_closesocket(int fd);
+static void dopoll(void);
+#define BUFSIZE 4096
+
+int main(int argc, char **argv)
+{
+ int portno;
+ struct sockaddr_in server;
+#ifdef MSW
+ short version = MAKEWORD(2, 0);
+ WSADATA nobby;
+#endif
+ if (argc < 2 || sscanf(argv[1], "%d", &portno) < 1 || portno <= 0)
+ goto usage;
+ if (argc >= 3)
+ {
+ if (!strcmp(argv[2], "tcp"))
+ protocol = SOCK_STREAM;
+ else if (!strcmp(argv[2], "udp"))
+ protocol = SOCK_DGRAM;
+ else goto usage;
+ }
+ else protocol = SOCK_STREAM;
+#ifdef MSW
+ if (WSAStartup(version, &nobby)) sockerror("WSAstartup");
+#endif
+ sockfd = socket(AF_INET, protocol, 0);
+ if (sockfd < 0)
+ {
+ sockerror("socket()");
+ exit(1);
+ }
+ maxfd = sockfd + 1;
+ server.sin_family = AF_INET;
+ server.sin_addr.s_addr = INADDR_ANY;
+
+#ifdef IRIX
+ /* this seems to work only in IRIX but is unnecessary in
+ Linux. Not sure what MSW needs in place of this. */
+ if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, 0, 0) < 0)
+ fprintf(stderr, "setsockopt failed\n");
+#endif
+
+ /* assign client port number */
+ server.sin_port = htons((unsigned short)portno);
+
+ /* name the socket */
+ if (bind(sockfd, (struct sockaddr *)&server, sizeof(server)) < 0)
+ {
+ sockerror("bind");
+ x_closesocket(sockfd);
+ return (0);
+ }
+ if (protocol == SOCK_STREAM)
+ {
+ if (listen(sockfd, 5) < 0)
+ {
+ sockerror("listen");
+ x_closesocket(sockfd);
+ exit(1);
+ }
+ }
+ /* now loop forever selecting on sockets */
+ while (1)
+ dopoll();
+
+usage:
+ fprintf(stderr, "usage: pdreceive <portnumber> [udp|tcp]\n");
+ fprintf(stderr, "(default is tcp)\n");
+ exit(1);
+}
+
+static void addport(int fd)
+{
+ t_fdpoll *fp;
+ fdpoll = (t_fdpoll *)realloc(fdpoll,
+ (nfdpoll+1) * sizeof(t_fdpoll));
+ fp = fdpoll + nfdpoll;
+ fp->fdp_fd = fd;
+ nfdpoll++;
+ if (fd >= maxfd) maxfd = fd + 1;
+ fp->fdp_inhead = fp->fdp_intail = 0;
+ if (!(fp->fdp_inbuf = (char *) malloc(BUFSIZE)))
+ {
+ fprintf(stderr, "out of memory");
+ exit(1);
+ }
+ printf("number_connected %d;\n", nfdpoll);
+}
+
+static void rmport(t_fdpoll *x)
+{
+ int i;
+ t_fdpoll *fp;
+ for (i = nfdpoll, fp = fdpoll; i--; fp++)
+ {
+ if (fp == x)
+ {
+ x_closesocket(fp->fdp_fd);
+ free(fp->fdp_inbuf);
+ while (i--)
+ {
+ fp[0] = fp[1];
+ fp++;
+ }
+ fdpoll = (t_fdpoll *)realloc(fdpoll,
+ (nfdpoll-1) * sizeof(t_fdpoll));
+ nfdpoll--;
+ printf("number_connected %d;\n", nfdpoll);
+ return;
+ }
+ }
+ fprintf(stderr, "warning: item removed from poll list but not found");
+}
+
+static void doconnect(void)
+{
+ int fd = accept(sockfd, 0, 0);
+ if (fd < 0)
+ perror("accept");
+ else addport(fd);
+}
+
+static void udpread(void)
+{
+ char buf[BUFSIZE];
+ int ret = recv(sockfd, buf, BUFSIZE, 0);
+ if (ret < 0)
+ {
+ sockerror("recv (udp)");
+ x_closesocket(sockfd);
+ exit(1);
+ }
+ else if (ret > 0)
+ {
+#ifdef MSW
+ int j;
+ for (j = 0; j < ret; j++)
+ putchar(buf[j]);
+#else
+ if (write(1, buf, ret) < ret)
+ {
+ perror("write");
+ exit(1);
+ }
+#endif
+ }
+}
+
+static int tcpmakeoutput(t_fdpoll *x)
+{
+ char messbuf[BUFSIZE+1], *bp = messbuf;
+ int indx;
+ int inhead = x->fdp_inhead;
+ int intail = x->fdp_intail;
+ char *inbuf = x->fdp_inbuf;
+ if (intail == inhead)
+ return (0);
+ for (indx = intail; indx != inhead; indx = (indx+1)&(BUFSIZE-1))
+ {
+ /* search for a semicolon. */
+ char c = *bp++ = inbuf[indx];
+ if (c == ';')
+ {
+ intail = (indx+1)&(BUFSIZE-1);
+ if (inbuf[intail] == '\n')
+ intail = (intail+1)&(BUFSIZE-1);
+ *bp++ = '\n';
+#ifdef MSW
+ {
+ int j;
+ for (j = 0; j < bp - messbuf; j++)
+ putchar(messbuf[j]);
+ }
+#else
+ write(1, messbuf, bp - messbuf);
+#endif
+ x->fdp_inhead = inhead;
+ x->fdp_intail = intail;
+ return (1);
+ }
+ }
+ return (0);
+}
+
+static void tcpread(t_fdpoll *x)
+{
+ int readto =
+ (x->fdp_inhead >= x->fdp_intail ? BUFSIZE : x->fdp_intail-1);
+ int ret;
+
+ /* the input buffer might be full. If so, drop the whole thing */
+ if (readto == x->fdp_inhead)
+ {
+ fprintf(stderr, "pd: dropped message from gui\n");
+ x->fdp_inhead = x->fdp_intail = 0;
+ readto = BUFSIZE;
+ }
+ else
+ {
+ ret = recv(x->fdp_fd, x->fdp_inbuf + x->fdp_inhead,
+ readto - x->fdp_inhead, 0);
+ if (ret < 0)
+ {
+ sockerror("recv (tcp)");
+ rmport(x);
+ }
+ else if (ret == 0)
+ rmport(x);
+ else
+ {
+ x->fdp_inhead += ret;
+ if (x->fdp_inhead >= BUFSIZE)
+ x->fdp_inhead = 0;
+ while (tcpmakeoutput(x))
+ ;
+ }
+ }
+}
+
+static void dopoll(void)
+{
+ int i;
+ t_fdpoll *fp;
+ fd_set readset, writeset, exceptset;
+ FD_ZERO(&writeset);
+ FD_ZERO(&readset);
+ FD_ZERO(&exceptset);
+
+ FD_SET(sockfd, &readset);
+ if (protocol == SOCK_STREAM)
+ {
+ for (fp = fdpoll, i = nfdpoll; i--; fp++)
+ FD_SET(fp->fdp_fd, &readset);
+ }
+ if (select(maxfd+1, &readset, &writeset, &exceptset, 0) < 0)
+ {
+ perror("select");
+ exit(1);
+ }
+ if (protocol == SOCK_STREAM)
+ {
+ for (i = 0; i < nfdpoll; i++)
+ if (FD_ISSET(fdpoll[i].fdp_fd, &readset))
+ tcpread(&fdpoll[i]);
+ if (FD_ISSET(sockfd, &readset))
+ doconnect();
+ }
+ else
+ {
+ if (FD_ISSET(sockfd, &readset))
+ udpread();
+ }
+}
+
+
+static void sockerror(char *s)
+{
+#ifdef MSW
+ int err = WSAGetLastError();
+ if (err == 10054) return;
+ else if (err == 10044)
+ {
+ fprintf(stderr,
+ "Warning: you might not have TCP/IP \"networking\" turned on\n");
+ }
+#else
+ int err = errno;
+#endif
+ fprintf(stderr, "%s: %s (%d)\n", s, strerror(err), err);
+}
+
+static void x_closesocket(int fd)
+{
+#ifdef MSW
+ closesocket(fd);
+#else
+ close(fd);
+#endif
+}
diff --git a/desiredata/src/u_pdsend.c b/desiredata/src/u_pdsend.c
new file mode 100644
index 00000000..3efa1479
--- /dev/null
+++ b/desiredata/src/u_pdsend.c
@@ -0,0 +1,138 @@
+/* Copyright (c) 2000 Miller Puckette.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in the Pd distribution. */
+
+/* the "pdsend" command. This is a standalone program that forwards messages
+from its standard input to Pd via the netsend/netreceive ("FUDI") protocol. */
+
+#include <sys/types.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#ifdef MSW
+#include <winsock.h>
+#else
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <unistd.h>
+#define SOCKET_ERROR -1
+#endif
+
+void sockerror(char *s);
+void x_closesocket(int fd);
+#define BUFSIZE 4096
+
+int main(int argc, char **argv)
+{
+ int sockfd, portno, protocol;
+ struct sockaddr_in server;
+ struct hostent *hp;
+ char *hostname;
+#ifdef MSW
+ short version = MAKEWORD(2, 0);
+ WSADATA nobby;
+#endif
+ if (argc < 2 || sscanf(argv[1], "%d", &portno) < 1 || portno <= 0)
+ goto usage;
+ if (argc >= 3)
+ hostname = argv[2];
+ else hostname = "127.0.0.1";
+ if (argc >= 4)
+ {
+ if (!strcmp(argv[3], "tcp"))
+ protocol = SOCK_STREAM;
+ else if (!strcmp(argv[3], "udp"))
+ protocol = SOCK_DGRAM;
+ else goto usage;
+ }
+ else protocol = SOCK_STREAM;
+#ifdef MSW
+ if (WSAStartup(version, &nobby)) sockerror("WSAstartup");
+#endif
+
+ sockfd = socket(AF_INET, protocol, 0);
+ if (sockfd < 0)
+ {
+ sockerror("socket()");
+ exit(1);
+ }
+ /* connect socket using hostname provided in command line */
+ server.sin_family = AF_INET;
+ hp = gethostbyname(hostname);
+ if (hp == 0)
+ {
+ fprintf(stderr, "%s: unknown host\n", hostname);
+ x_closesocket(sockfd);
+ exit(1);
+ }
+ memcpy((char *)&server.sin_addr, (char *)hp->h_addr, hp->h_length);
+
+ /* assign client port number */
+ server.sin_port = htons((unsigned short)portno);
+
+ /* try to connect. */
+ if (connect(sockfd, (struct sockaddr *) &server, sizeof (server)) < 0)
+ {
+ sockerror("connect");
+ x_closesocket(sockfd);
+ exit(1);
+ }
+
+ /* now loop reading stdin and sending it to socket */
+ while (1)
+ {
+ char buf[BUFSIZE], *bp;
+ unsigned int nsent, nsend;
+ if (!fgets(buf, BUFSIZE, stdin))
+ break;
+ nsend = strlen(buf);
+ for (bp = buf, nsent = 0; nsent < nsend;)
+ {
+ int res = send(sockfd, buf, nsend-nsent, 0);
+ if (res < 0)
+ {
+ sockerror("send");
+ goto done;
+ }
+ nsent += res;
+ bp += res;
+ }
+ }
+done:
+ if (ferror(stdin))
+ perror("stdin");
+ exit (0);
+usage:
+ fprintf(stderr, "usage: pdsend <portnumber> [host] [udp|tcp]\n");
+ fprintf(stderr, "(default is localhost and tcp)\n");
+ exit(1);
+}
+
+void sockerror(char *s)
+{
+#ifdef MSW
+ int err = WSAGetLastError();
+ if (err == 10054) return;
+ else if (err == 10044)
+ {
+ fprintf(stderr,
+ "Warning: you might not have TCP/IP \"networking\" turned on\n");
+ }
+#else
+ int err = errno;
+#endif
+ fprintf(stderr, "%s: %s (%d)\n", s, strerror(err), err);
+}
+
+void x_closesocket(int fd)
+{
+#ifdef MSW
+ closesocket(fd);
+#else
+ close(fd);
+#endif
+}
diff --git a/desiredata/src/valgrind3.supp b/desiredata/src/valgrind3.supp
new file mode 100644
index 00000000..7ec16dbb
--- /dev/null
+++ b/desiredata/src/valgrind3.supp
@@ -0,0 +1,89 @@
+{
+ supp01
+ Memcheck:Param
+ ioctl(arg)
+ obj:/lib/ld-2.3.6.so
+ fun:snd_pcm_prepare
+ fun:snd_pcm_hw_params
+ fun:_Z12alsaio_setupP9_alsa_deviPiS1_ii
+ fun:_Z15alsa_open_audioiPiiS_iS_iS_ii
+ fun:sys_open_audio
+}
+{
+ supp02
+ Memcheck:Param
+ ioctl(arg)
+ obj:/lib/ld-2.3.6.so
+ fun:snd_pcm_prepare
+ fun:_Z15alsa_open_audioiPiiS_iS_iS_ii
+ fun:sys_open_audio
+}
+{
+ supp03
+ Memcheck:Param
+ ioctl(generic)
+ obj:/lib/ld-2.3.6.so
+ fun:snd_pcm_link
+ fun:_Z15alsa_open_audioiPiiS_iS_iS_ii
+ fun:sys_open_audio
+}
+{
+ supp04
+ Memcheck:Cond
+ obj:/lib/ld-2.3.6.so
+ obj:/lib/ld-2.3.6.so
+ obj:/lib/ld-2.3.6.so
+ obj:/lib/tls/i686/cmov/libc-2.3.6.so
+ obj:/lib/ld-2.3.6.so
+ fun:_dl_open
+ obj:/lib/tls/i686/cmov/libdl-2.3.6.so
+ obj:/lib/ld-2.3.6.so
+ obj:/lib/tls/i686/cmov/libdl-2.3.6.so
+ fun:dlopen
+ fun:_Z15sys_do_load_libP6_glistPc
+ fun:sys_load_lib
+}
+{
+ supp05
+ Memcheck:Cond
+ obj:/lib/ld-2.3.6.so
+ obj:/lib/tls/i686/cmov/libc-2.3.6.so
+ obj:/lib/ld-2.3.6.so
+ fun:_dl_open
+ obj:/lib/tls/i686/cmov/libdl-2.3.6.so
+ obj:/lib/ld-2.3.6.so
+ obj:/lib/tls/i686/cmov/libdl-2.3.6.so
+ fun:dlopen
+ fun:_Z15sys_do_load_libP6_glistPc
+ fun:sys_load_lib
+}
+{
+ supp06
+ Memcheck:Param
+ ioctl(arg)
+ obj:/lib/ld-2.3.6.so
+ fun:snd_pcm_start
+ fun:_Z15alsa_open_audioiPiiS_iS_iS_ii
+ fun:sys_open_audio
+}
+{
+ supp07
+ Memcheck:Param
+ ioctl(arg)
+ obj:/lib/ld-2.3.6.so
+ fun:snd_pcm_drop
+ fun:snd_pcm_close
+ fun:_Z16alsa_close_audiov
+ fun:sys_close_audio
+}
+{
+ supp08
+ Memcheck:Param
+ ioctl(arg)
+ obj:/lib/ld-2.3.6.so
+ fun:snd_pcm_hw_free
+ fun:snd_pcm_close
+ fun:_Z16alsa_close_audiov
+ fun:sys_close_audio
+}
+