From 4d84d14ac1aa13958eaa2971b03f7f929a519105 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?IOhannes=20m=20zm=C3=B6lnig?= Date: Fri, 8 Feb 2008 13:00:32 +0000 Subject: reorganized svn path=/trunk/; revision=9400 --- desiredata/src/ChangeLog | 233 + desiredata/src/TODO | 454 + desiredata/src/bgerror.tcl | 254 + desiredata/src/builtins.c | 3060 +++++++ desiredata/src/builtins_dsp.c | 3844 +++++++++ desiredata/src/config.h.in | 5 + desiredata/src/configure | 6562 ++++++++++++++ desiredata/src/configure.in | 213 + desiredata/src/cvs-switch-user | 5 + desiredata/src/d_fftroutine.c | 999 +++ desiredata/src/d_mayer_fft.c | 422 + desiredata/src/d_soundfile.c | 2059 +++++ desiredata/src/d_ugen.c | 1016 +++ desiredata/src/defaults.ddrc | 193 + desiredata/src/desire.c | 7332 ++++++++++++++++ desiredata/src/desire.h | 353 + desiredata/src/desire.tk | 9019 ++++++++++++++++++++ desiredata/src/dzinc.tcl | 157 + desiredata/src/icons/array.gif | Bin 0 -> 129 bytes desiredata/src/icons/bang.gif | Bin 0 -> 123 bytes desiredata/src/icons/canvas.gif | Bin 0 -> 89 bytes desiredata/src/icons/comment.gif | Bin 0 -> 108 bytes desiredata/src/icons/graph.gif | Bin 0 -> 115 bytes desiredata/src/icons/hradio.gif | Bin 0 -> 104 bytes desiredata/src/icons/hslider.gif | Bin 0 -> 115 bytes desiredata/src/icons/message.gif | Bin 0 -> 82 bytes desiredata/src/icons/mode_edit.gif | Bin 0 -> 90 bytes desiredata/src/icons/mode_run.gif | Bin 0 -> 85 bytes desiredata/src/icons/number.gif | Bin 0 -> 84 bytes desiredata/src/icons/number2.gif | Bin 0 -> 83 bytes desiredata/src/icons/object.gif | Bin 0 -> 121 bytes desiredata/src/icons/symbol.gif | Bin 0 -> 91 bytes desiredata/src/icons/toggle.gif | Bin 0 -> 116 bytes desiredata/src/icons/vradio.gif | Bin 0 -> 112 bytes desiredata/src/icons/vslider.gif | Bin 0 -> 114 bytes desiredata/src/icons/vu.gif | Bin 0 -> 106 bytes desiredata/src/install-sh | 251 + desiredata/src/iostream.txt | 61 + desiredata/src/kb-mode.tcl | 210 + desiredata/src/kernel.c | 2348 +++++ desiredata/src/locale/bokmal.tcl | 453 + desiredata/src/locale/brasiliano.tcl | 577 ++ desiredata/src/locale/catala.tcl | 58 + desiredata/src/locale/chinese.tcl | 560 ++ desiredata/src/locale/dansk.tcl | 564 ++ desiredata/src/locale/deutsch.tcl | 280 + desiredata/src/locale/english.tcl | 573 ++ desiredata/src/locale/espanol.tcl | 526 ++ desiredata/src/locale/euskara.tcl | 554 ++ desiredata/src/locale/francais.tcl | 539 ++ desiredata/src/locale/index.tcl | 21 + desiredata/src/locale/italiano.tcl | 544 ++ desiredata/src/locale/localeutils.tcl | 109 + desiredata/src/locale/nederlands.tcl | 599 ++ desiredata/src/locale/nihongo.tcl | 574 ++ desiredata/src/locale/polski.tcl | 557 ++ desiredata/src/locale/portugues.tcl | 119 + desiredata/src/locale/russkij.tcl | 574 ++ desiredata/src/locale/turkce.tcl | 572 ++ desiredata/src/m_atomic.h | 55 + desiredata/src/m_fifo.c | 443 + desiredata/src/m_pd.h | 936 ++ desiredata/src/m_sched.c | 654 ++ desiredata/src/m_simd.c | 145 + desiredata/src/m_simd.h | 82 + desiredata/src/m_simd_sse_gcc.c | 1131 +++ desiredata/src/m_simd_ve_gcc.c | 748 ++ desiredata/src/m_simd_ve_gcc.h | 18 + desiredata/src/main.c | 17 + desiredata/src/makefile.in | 122 + desiredata/src/notes.txt | 300 + desiredata/src/pkgIndex.tcl | 15 + desiredata/src/plusminus | 42 + desiredata/src/poe.tcl | 281 + desiredata/src/pre8.5.tcl | 209 + desiredata/src/profile_dd.tcl | 20 + desiredata/src/rules.txt | 42 + desiredata/src/s_audio.c | 724 ++ desiredata/src/s_audio_alsa.c | 594 ++ desiredata/src/s_audio_alsa.h | 40 + desiredata/src/s_audio_alsamm.c | 889 ++ desiredata/src/s_audio_asio.cpp | 1014 +++ desiredata/src/s_audio_jack.c | 381 + desiredata/src/s_audio_mmio.c | 571 ++ desiredata/src/s_audio_oss.c | 532 ++ desiredata/src/s_audio_pa.c | 332 + desiredata/src/s_audio_pablio.c | 304 + desiredata/src/s_audio_pablio.h | 112 + desiredata/src/s_audio_paring.c | 172 + desiredata/src/s_audio_paring.h | 101 + desiredata/src/s_audio_portaudio.c | 416 + desiredata/src/s_audio_sgi.c | 313 + desiredata/src/s_inter.c | 732 ++ desiredata/src/s_loader.c | 196 + desiredata/src/s_main.c | 632 ++ desiredata/src/s_midi.c | 619 ++ desiredata/src/s_midi_alsa.c | 209 + desiredata/src/s_midi_mmio.c | 505 ++ desiredata/src/s_midi_none.c | 16 + desiredata/src/s_midi_oss.c | 234 + desiredata/src/s_midi_pm.c | 239 + desiredata/src/s_midi_sgi.c | 143 + desiredata/src/s_path.c | 350 + desiredata/src/s_stuff.h | 321 + desiredata/src/s_watchdog.c | 40 + desiredata/src/tests/abstr-test.pd | 3 + desiredata/src/tests/abstr.pd | 11 + desiredata/src/tests/abstr2.pd | 15 + desiredata/src/tests/all_guis_and_gop.pd | 116 + desiredata/src/tests/all_guis_and_gop.pd.gif | Bin 0 -> 11002 bytes desiredata/src/tests/bof.pd | 27 + desiredata/src/tests/chun.pd | 36 + desiredata/src/tests/city.pd | 128 + .../src/tests/desiredata-presentation-piksel06.pd | 26 + desiredata/src/tests/gop-one.pd | 18 + desiredata/src/tests/gop-three.pd | 41 + desiredata/src/tests/gop-two.pd | 19 + desiredata/src/tests/sub.pd | 21 + desiredata/src/tests/subgop-test.pd | 8 + desiredata/src/u_pdreceive.c | 321 + desiredata/src/u_pdsend.c | 138 + desiredata/src/valgrind3.supp | 89 + 122 files changed, 64411 insertions(+) create mode 100644 desiredata/src/ChangeLog create mode 100644 desiredata/src/TODO create mode 100644 desiredata/src/bgerror.tcl create mode 100644 desiredata/src/builtins.c create mode 100644 desiredata/src/builtins_dsp.c create mode 100644 desiredata/src/config.h.in create mode 100755 desiredata/src/configure create mode 100644 desiredata/src/configure.in create mode 100755 desiredata/src/cvs-switch-user create mode 100644 desiredata/src/d_fftroutine.c create mode 100644 desiredata/src/d_mayer_fft.c create mode 100644 desiredata/src/d_soundfile.c create mode 100644 desiredata/src/d_ugen.c create mode 100644 desiredata/src/defaults.ddrc create mode 100644 desiredata/src/desire.c create mode 100644 desiredata/src/desire.h create mode 100644 desiredata/src/desire.tk create mode 100644 desiredata/src/dzinc.tcl create mode 100644 desiredata/src/icons/array.gif create mode 100644 desiredata/src/icons/bang.gif create mode 100644 desiredata/src/icons/canvas.gif create mode 100644 desiredata/src/icons/comment.gif create mode 100644 desiredata/src/icons/graph.gif create mode 100644 desiredata/src/icons/hradio.gif create mode 100644 desiredata/src/icons/hslider.gif create mode 100644 desiredata/src/icons/message.gif create mode 100644 desiredata/src/icons/mode_edit.gif create mode 100644 desiredata/src/icons/mode_run.gif create mode 100644 desiredata/src/icons/number.gif create mode 100644 desiredata/src/icons/number2.gif create mode 100644 desiredata/src/icons/object.gif create mode 100644 desiredata/src/icons/symbol.gif create mode 100644 desiredata/src/icons/toggle.gif create mode 100644 desiredata/src/icons/vradio.gif create mode 100644 desiredata/src/icons/vslider.gif create mode 100644 desiredata/src/icons/vu.gif create mode 100644 desiredata/src/install-sh create mode 100644 desiredata/src/iostream.txt create mode 100644 desiredata/src/kb-mode.tcl create mode 100644 desiredata/src/kernel.c create mode 100644 desiredata/src/locale/bokmal.tcl create mode 100644 desiredata/src/locale/brasiliano.tcl create mode 100644 desiredata/src/locale/catala.tcl create mode 100644 desiredata/src/locale/chinese.tcl create mode 100644 desiredata/src/locale/dansk.tcl create mode 100644 desiredata/src/locale/deutsch.tcl create mode 100644 desiredata/src/locale/english.tcl create mode 100644 desiredata/src/locale/espanol.tcl create mode 100644 desiredata/src/locale/euskara.tcl create mode 100644 desiredata/src/locale/francais.tcl create mode 100644 desiredata/src/locale/index.tcl create mode 100644 desiredata/src/locale/italiano.tcl create mode 100755 desiredata/src/locale/localeutils.tcl create mode 100644 desiredata/src/locale/nederlands.tcl create mode 100644 desiredata/src/locale/nihongo.tcl create mode 100644 desiredata/src/locale/polski.tcl create mode 100644 desiredata/src/locale/portugues.tcl create mode 100644 desiredata/src/locale/russkij.tcl create mode 100644 desiredata/src/locale/turkce.tcl create mode 100644 desiredata/src/m_atomic.h create mode 100644 desiredata/src/m_fifo.c create mode 100644 desiredata/src/m_pd.h create mode 100644 desiredata/src/m_sched.c create mode 100644 desiredata/src/m_simd.c create mode 100644 desiredata/src/m_simd.h create mode 100644 desiredata/src/m_simd_sse_gcc.c create mode 100644 desiredata/src/m_simd_ve_gcc.c create mode 100644 desiredata/src/m_simd_ve_gcc.h create mode 100644 desiredata/src/main.c create mode 100644 desiredata/src/makefile.in create mode 100644 desiredata/src/notes.txt create mode 100644 desiredata/src/pkgIndex.tcl create mode 100755 desiredata/src/plusminus create mode 100644 desiredata/src/poe.tcl create mode 100644 desiredata/src/pre8.5.tcl create mode 100644 desiredata/src/profile_dd.tcl create mode 100644 desiredata/src/rules.txt create mode 100644 desiredata/src/s_audio.c create mode 100644 desiredata/src/s_audio_alsa.c create mode 100644 desiredata/src/s_audio_alsa.h create mode 100644 desiredata/src/s_audio_alsamm.c create mode 100644 desiredata/src/s_audio_asio.cpp create mode 100644 desiredata/src/s_audio_jack.c create mode 100644 desiredata/src/s_audio_mmio.c create mode 100644 desiredata/src/s_audio_oss.c create mode 100644 desiredata/src/s_audio_pa.c create mode 100644 desiredata/src/s_audio_pablio.c create mode 100644 desiredata/src/s_audio_pablio.h create mode 100644 desiredata/src/s_audio_paring.c create mode 100644 desiredata/src/s_audio_paring.h create mode 100755 desiredata/src/s_audio_portaudio.c create mode 100644 desiredata/src/s_audio_sgi.c create mode 100644 desiredata/src/s_inter.c create mode 100644 desiredata/src/s_loader.c create mode 100644 desiredata/src/s_main.c create mode 100644 desiredata/src/s_midi.c create mode 100644 desiredata/src/s_midi_alsa.c create mode 100644 desiredata/src/s_midi_mmio.c create mode 100644 desiredata/src/s_midi_none.c create mode 100644 desiredata/src/s_midi_oss.c create mode 100644 desiredata/src/s_midi_pm.c create mode 100644 desiredata/src/s_midi_sgi.c create mode 100644 desiredata/src/s_path.c create mode 100644 desiredata/src/s_stuff.h create mode 100644 desiredata/src/s_watchdog.c create mode 100644 desiredata/src/tests/abstr-test.pd create mode 100644 desiredata/src/tests/abstr.pd create mode 100644 desiredata/src/tests/abstr2.pd create mode 100644 desiredata/src/tests/all_guis_and_gop.pd create mode 100644 desiredata/src/tests/all_guis_and_gop.pd.gif create mode 100644 desiredata/src/tests/bof.pd create mode 100644 desiredata/src/tests/chun.pd create mode 100644 desiredata/src/tests/city.pd create mode 100644 desiredata/src/tests/desiredata-presentation-piksel06.pd create mode 100644 desiredata/src/tests/gop-one.pd create mode 100644 desiredata/src/tests/gop-three.pd create mode 100644 desiredata/src/tests/gop-two.pd create mode 100644 desiredata/src/tests/sub.pd create mode 100644 desiredata/src/tests/subgop-test.pd create mode 100644 desiredata/src/u_pdreceive.c create mode 100644 desiredata/src/u_pdsend.c create mode 100644 desiredata/src/valgrind3.supp (limited to 'desiredata/src') 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 and + * 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 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 + * added button bar (that does like Ctrl+E & Put menu) + * .pdrc: -look + (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(sym_dsp),NULL); + + 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 + + 1. a keyboard operated cursor, a bit like Active, but one can use it like the mouse pointer + 2. snap to grid feature, or similiar + 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] 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<------------------ + + 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 + + is there something like listbox but which works as a popup menu ? + tk_optionMenu is an old-school version + 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) + + is there a wrapper for libagg for tcl? AGG of antigrain.com + 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 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/ + + 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 { 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 [namespace code Return] + bind .bgerrorDialog [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 +#include +#include +#include +#include +#include +#ifdef UNISTD +#include +#include +#include +#include +#include +#endif +#ifdef MSW +#include +#include +#endif +#ifdef MSW +#include +#else +#include +#include +#include +#include +#include +#define SOCKET_ERROR -1 +#endif +#ifdef MSW +#include +#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 */ +#ifdef MSW +#include +#else +#include +#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; in; 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; idix->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; ialist = 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, ab) +BINOP(binop_lt,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; ivec[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; ivec); 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; ia_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; in; 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; ia_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; ivec; + 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; ioutlet,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 +#include +#include +#include +extern int ugen_getsortno (); +#define DEFDELVS 64 /* LATER get this from canvas at DSP time */ +#ifdef HAVE_LIBFFTW3F +#include +#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 ,ab?a:b) DSPDSP(max) DSPNEW(max ,"max~") +PERFORM(lt ,ab) 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 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 +//#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; ilast = 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"); +} +/* */ + +/* ------------------------ 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 +#if HAVE_SYS_TYPES_H +# include +#endif +#if HAVE_SYS_STAT_H +# include +#endif +#if STDC_HEADERS +# include +# include +#else +# if HAVE_STDLIB_H +# include +# endif +#endif +#if HAVE_STRING_H +# if !STDC_HEADERS && HAVE_MEMORY_H +# include +# endif +# include +#endif +#if HAVE_STRINGS_H +# include +#endif +#if HAVE_INTTYPES_H +# include +#else +# if HAVE_STDINT_H +# include +# endif +#endif +#if HAVE_UNISTD_H +# include +#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 if you have libraries in a + nonstandard directory + CPPFLAGS C/C++ preprocessor flags, e.g. -I if you have + headers in a nonstandard directory + 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 &5\"") >&5 + (eval $ac_compiler --version &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:$LINENO: \"$ac_compiler -v &5\"") >&5 + (eval $ac_compiler -v &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:$LINENO: \"$ac_compiler -V &5\"") >&5 + (eval $ac_compiler -V &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 +#include +#include +#include +/* 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 +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 to if __STDC__ is defined, since + # 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 +#else +# include +#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 +_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 to if __STDC__ is defined, since + # 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 +#else +# include +#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 +_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 +#include +#include +#include + +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 + +_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 + +_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 +#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 +#include +#include + +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 +#include +#include +#include + +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 + +_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 + +_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 +#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 +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 +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 +#include +#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 declares $ac_func. + For example, HP-UX 11i 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 to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#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 declares _doprnt. + For example, HP-UX 11i declares gettimeofday. */ +#define _doprnt innocuous__doprnt + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char _doprnt (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#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 declares $ac_func. + For example, HP-UX 11i 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 to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#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 +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 +# define alloca _alloca +# else +# if HAVE_ALLOCA_H +# include +# 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 declares $ac_func. + For example, HP-UX 11i 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 to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#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 +_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 +_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 +#include + +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 +#include + +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 ." +_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 +#include +#include + + /* 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< 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<1) \ + { \ + for (j=k-i+2 ; (1<>1; (!((k2^=k)&k)); k>>=1); + if (k1>k2) + { + aa=fz[k1];fz[k1]=fz[k2];fz[k2]=aa; + } + } + for ( k=0 ; (1<> 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 +#include +#endif +#include +#ifdef MSW +#include +#endif +#include +#include +#include +#include + +#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 +#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 -skip -bytes -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>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 +#if (_POSIX_MEMLOCK - 0) >= 200112L +#include +#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 to skip in file + -nframes -onset ... onset in table to read into (NOT DONE YET) + -raw -resize -maxsize + 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; iname); + 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 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 -nframes -resize -maxsize ..."); + post("-raw ."); +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; iname); + 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 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 -nframes -bytes -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 to skip in file + -nframes -onset ... onset in table to read into (NOT DONE YET) + -raw -resize -maxsize */ +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; iname); + 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 -nframes -resize -maxsize ..."); + post("-raw ."); +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; iname); + 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 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 -nframes -bytes -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 /* debugging version... */ +#include +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; inoutlets = 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; ioutvec[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; ioutvec[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; ioutvec[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 +#include + +/* 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>= 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< 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; nbuffer = 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 +#include +#include +#include +#include +#include +#include "m_simd.h" +#include +#include +#include +#include + +#ifdef MSW +#include +#define snprintf _snprintf +#else +#include +#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 ab?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 M; + typedef std::pair KV; +private: + std::map 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 && xcanvas; + 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_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; inobs; 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; inobs; i++) if (d->obs[i]) break; + if (i==d->nobs) return; + d->nobs--; + for (; inobs; 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,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; inobs; 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_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; iq,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 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(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 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.lastx ? -1 : 1; + nchange = 1 + increment * (ammo.lastx - thisx); + x2 = thisx; + for (int i=0; i 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= 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 (dyvec; + 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; ivec)[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; in; 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<n; i++, phase += phaseincr) { + double sum = dcval; + if (sineflag) for (j=0, fj=phase; jvec + 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; ix; 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 (y2xtick.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->y2y1) {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; ivec[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; ivec[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; ivec[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; jvec[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; in; + /* drop "pd-" prefix from template symbol to print it: */ + binbuf_addv(b,"tt;","template",templatevec[i]->name + 3); + for (int j=0; jvec[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; jn; 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; in; 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; in; 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; in; 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; in; 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; in; 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; in; 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; ivec[i]; + for (int j=0; jvec[j]; + if (dataslot_matches(dataslot, dataslot2, 1)) { + conformaction[i] = j; + conformedfrom[j] = 1; + } + } + } + for (int i=0; ivec[i]; + for (int j=0; jvec[j], 0)) { + conformaction[i] = j; + conformedfrom[j] = 1; + } + } + if (nto != nfrom) doit = 1; + else for (int i=0; isym->name); + for (int i=0; ifirst); + } + 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; iargv[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->scrminscrmax ? f->scrmin : f->scrmax; if (coordscrmin>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->minmax ? f->min : f->max; if (valmin>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; ivis.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; ioutlinecolor, 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; iwidth, 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; inpoints; 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= 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=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=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=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; iw_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 ] 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; isym = 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; isym, vec, vp->w.w_symbol, 1); + else for (int i=0; isym, 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; isym = 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; isym, 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; ix=(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; iinlet,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 (jblah) 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; iname; + 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 (jc=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 (jname); 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=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 +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 /* 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 *object_table; +extern t_hash *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 +template static T min(T a, T b) {return a static T max(T a, T b) {return a>b?a:b;} +template 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 "" + #bind all "" + bind all <> "" + bind Text {} + bind Text {} + 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 {$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 . {$main ctrlkey %x %y %K %A 0} + bind . {$main ctrlkey %x %y %K %A 1} + switch $::OS { + osx { + bind . {$main ctrlkey %x %y %K %A 0} + bind . {$main ctrlkey %x %y %K %A 1} + } + } +# bind . {.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 {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= 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