├── sc ├── .gdignore ├── letters-test.scd ├── sequence-test.scd ├── sound-test.scd ├── config-test.scd ├── salonLetters.txt ├── walkers.scd ├── setup.scd ├── cube-routines.scd ├── Animatron │ └── Animatron.sc ├── dot.sc ├── dots.scd ├── midi-test.scd ├── cube-routines-mod.scd └── osc-test.scd ├── commands ├── .gdignore ├── init_example.osc ├── tutorial-cmds.osc └── init.osc ├── config ├── .gdignore └── config_example.osc ├── docs ├── .gdignore ├── help │ ├── help-bg.osc │ ├── help-flipv.osc │ ├── help-post.osc │ ├── help-fliph.osc │ ├── help-selected.osc │ ├── help-tutorial.osc │ ├── help-editor-append.osc │ ├── help-free.osc │ ├── help-stop.osc │ ├── help-at.osc │ ├── help-iter.osc │ ├── help-letter-scale.osc │ ├── help-list-commands.osc │ ├── help-routine-stop.osc │ ├── help-ungroup.osc │ ├── help-window-center.osc │ ├── help-editor-clear.osc │ ├── help-list-midi.osc │ ├── help-parent-free.osc │ ├── help-routine-free-all.osc │ ├── help-routine-free.osc │ ├── help-routine-start.osc │ ├── help-write.osc │ ├── help-error-reply.osc │ ├── help-list-children.osc │ ├── help-list-states.osc │ ├── help-midi-free.osc │ ├── help-play.osc │ ├── help-editor-font-size.osc │ ├── help-post-font-decrease.osc │ ├── help-post-font-increase.osc │ ├── help-post-font-size.osc │ ├── help-status-reply.osc │ ├── help-editor-font-decrease.osc │ ├── help-editor-font-increase.osc │ ├── help-frame-next.osc │ ├── help-oneshot.osc │ ├── help-osc-remote.osc │ ├── help-state-free.osc │ ├── help-frame-prev.osc │ ├── help-help.osc │ ├── help-midi-debug.osc │ ├── help-play-rand.osc │ ├── help-window-fullscreen.osc │ ├── help-parent.osc │ ├── help-window-position.osc │ ├── help-list-sequence.osc │ ├── help-slow.osc │ ├── help-speed.osc │ ├── help-window-screen.osc │ ├── help-osc-send.osc │ ├── help-window-top.osc │ ├── help-createordestroy.osc │ ├── help-editor-open.osc │ ├── help-letter.osc │ ├── help-list.osc │ ├── help-app-remote.osc │ ├── help-editor-save.osc │ ├── help-letter-spacing.osc │ ├── help-load-alphabet.osc │ ├── help-onfinish.osc │ ├── help-rand.osc │ ├── help-list-actors-reply.osc │ ├── help-say.osc │ ├── help-list-anims.osc │ ├── help-play-range.osc │ ├── help-select.osc │ ├── help-list-anims-reply.osc │ ├── help-load-defs.osc │ ├── help-list-assets.osc │ ├── help-routine.osc │ ├── help-sound-free.osc │ ├── help-behind.osc │ ├── help-choose-arg.osc │ ├── help-front.osc │ ├── help-assets-path.osc │ ├── help-size.osc │ ├── help-deselect.osc │ ├── help-angle.osc │ ├── help-size-x.osc │ ├── help-size-y.osc │ ├── help-sound.osc │ ├── help-color-b.osc │ ├── help-color-r.osc │ ├── help-rotate.osc │ ├── help-color-g.osc │ ├── help-scale.osc │ ├── help-state-add.osc │ ├── help-size-xy.osc │ ├── help-color.osc │ ├── help-scale-x.osc │ ├── help-scale-xy.osc │ ├── help-scale-y.osc │ ├── help-window-size.osc │ ├── help-create-group.osc │ ├── help-frame.osc │ ├── help-onframe-free.osc │ ├── help-ysort.osc │ ├── help-choose.osc │ ├── help-fade.osc │ ├── help-list-assets-reply.osc │ ├── help-wait.osc │ ├── help-alpha.osc │ ├── help-load-config.osc │ ├── help-onfinish-free.osc │ ├── help-position-x.osc │ ├── help-position-y.osc │ ├── help-position.osc │ ├── help-create.osc │ ├── help-loop.osc │ ├── help-move.osc │ ├── help-move-x.osc │ ├── help-move-y.osc │ ├── help-load.osc │ ├── help-pivot.osc │ ├── help-group.osc │ ├── help-onframe.osc │ ├── help-debug.osc │ ├── help-action.osc │ ├── help-midi.osc │ └── help-def.osc ├── help-actor-free.osc ├── tutorial.osc ├── help-create.osc ├── tutorial-index.osc ├── tutorial-utils-rand.osc ├── tutorial-controls.osc ├── KeyboardShortcuts.md.html ├── tutorial-actor-animation.osc ├── tutorial-commands.osc ├── tutorial-utils-custom-cmds.osc ├── tutorial-actor-multi.osc ├── tutorial-actor-attributes.osc ├── tutorial-actors.osc └── markdeep │ ├── slides.css │ └── apidoc.css ├── animations └── .gdignore ├── icon.png ├── icons ├── ull-16.png ├── ull-32.png ├── ull-48.png ├── ull-64.png ├── animatron.ico ├── ull-128.png ├── ull-256.png ├── ull.svg.import ├── action.svg.import ├── ull-16.png.import ├── ull-32.png.import ├── ull-48.png.import ├── ull-64.png.import ├── ull-128.png.import ├── ull-256.png.import ├── action.svg └── ull.svg ├── fonts ├── WalterTurncoat.ttf └── mononoki_Bold.ttf ├── addons └── gdosc │ ├── bin │ ├── x11 │ │ └── libgdosc.so │ ├── osx │ │ └── libgdosc.dylib │ └── win64 │ │ ├── libgdosc.dll │ │ ├── libgdosc.exp │ │ └── libgdosc.lib │ ├── gdoscmsg.gdns │ ├── gdoscsender.gdns │ ├── gdoscreceiver.gdns │ ├── gdosc.gdnlib │ ├── gdscript_oscsender_template.gd │ └── gdscript_oscreceiver_template.gd ├── transparent_bg.tres ├── RoutineNode.tscn ├── default_env.tres ├── actions ├── Action.gd ├── wander.gd ├── oscillate.gd └── wrap.gd ├── .gitignore ├── OscSender.gd ├── icon.png.import ├── RoutineNode.gd ├── SpeechBubble.tscn ├── MetaNode.tscn ├── Logger.gd ├── SpeechBubble.gd ├── Letters.gd ├── CustomCommands.gd ├── PostTextEdit.gd ├── Animation.gd ├── Helper.gd ├── AudioInputPlayer.gd ├── Config.gd ├── Main.tscn ├── MetaNode.gd ├── Midi.gd ├── OscTextEdit.gd ├── project.godot ├── README.md └── Main.gd /sc/.gdignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /commands/.gdignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /config/.gdignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/.gdignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /animations/.gdignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loopier/animatron-godot3/HEAD/icon.png -------------------------------------------------------------------------------- /docs/help/help-bg.osc: -------------------------------------------------------------------------------- 1 | /bg r:f 2 | 3 | /description Set the background color. 4 | -------------------------------------------------------------------------------- /docs/help-actor-free.osc: -------------------------------------------------------------------------------- 1 | /free actor:s 2 | 3 | Delete the ACTOR removing its instance. 4 | -------------------------------------------------------------------------------- /docs/help/help-flipv.osc: -------------------------------------------------------------------------------- 1 | /flipv actor:s 2 | 3 | /description Flip the actor vertically. 4 | -------------------------------------------------------------------------------- /docs/help/help-post.osc: -------------------------------------------------------------------------------- 1 | /post msg:s 2 | 3 | /description Print MSG in the post window. 4 | -------------------------------------------------------------------------------- /icons/ull-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loopier/animatron-godot3/HEAD/icons/ull-16.png -------------------------------------------------------------------------------- /icons/ull-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loopier/animatron-godot3/HEAD/icons/ull-32.png -------------------------------------------------------------------------------- /icons/ull-48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loopier/animatron-godot3/HEAD/icons/ull-48.png -------------------------------------------------------------------------------- /icons/ull-64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loopier/animatron-godot3/HEAD/icons/ull-64.png -------------------------------------------------------------------------------- /docs/help/help-fliph.osc: -------------------------------------------------------------------------------- 1 | /fliph actor:s 2 | 3 | /description Flip the actor horizontally. 4 | -------------------------------------------------------------------------------- /docs/help/help-selected.osc: -------------------------------------------------------------------------------- 1 | /selected 2 | 3 | /description Get the list of selected actors. 4 | -------------------------------------------------------------------------------- /docs/help/help-tutorial.osc: -------------------------------------------------------------------------------- 1 | /tutorial 2 | 3 | /description Load the tutorial in the editor. 4 | -------------------------------------------------------------------------------- /icons/animatron.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loopier/animatron-godot3/HEAD/icons/animatron.ico -------------------------------------------------------------------------------- /icons/ull-128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loopier/animatron-godot3/HEAD/icons/ull-128.png -------------------------------------------------------------------------------- /icons/ull-256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loopier/animatron-godot3/HEAD/icons/ull-256.png -------------------------------------------------------------------------------- /docs/help/help-editor-append.osc: -------------------------------------------------------------------------------- 1 | /editor/append msg:s 2 | 3 | /description Append MSG to editor. 4 | -------------------------------------------------------------------------------- /docs/help/help-free.osc: -------------------------------------------------------------------------------- 1 | /free actor:s 2 | 3 | /description Delete the actor (remove its instance). 4 | -------------------------------------------------------------------------------- /docs/help/help-stop.osc: -------------------------------------------------------------------------------- 1 | /stop actor:s 2 | 3 | /description Stop playing the actor's animation. 4 | -------------------------------------------------------------------------------- /docs/help/help-at.osc: -------------------------------------------------------------------------------- 1 | /at index:i 2 | 3 | /description Perform a CMD on the actor at the GROUP INDEX. 4 | -------------------------------------------------------------------------------- /docs/help/help-iter.osc: -------------------------------------------------------------------------------- 1 | /iter cmd:s 2 | 3 | /description Perform a CMD on every actor in the GROUP. 4 | -------------------------------------------------------------------------------- /docs/help/help-letter-scale.osc: -------------------------------------------------------------------------------- 1 | /letter/scale scale 2 | 3 | /description Set the scale of the letters. 4 | -------------------------------------------------------------------------------- /docs/help/help-list-commands.osc: -------------------------------------------------------------------------------- 1 | /list/commands 2 | 3 | /description Get list of available commands. 4 | -------------------------------------------------------------------------------- /docs/help/help-routine-stop.osc: -------------------------------------------------------------------------------- 1 | /routine/stop name:s 2 | 3 | /description Stop the routine named NAME. 4 | -------------------------------------------------------------------------------- /docs/help/help-ungroup.osc: -------------------------------------------------------------------------------- 1 | /ungroup group:s 2 | 3 | /description Remove the actor from a named group. 4 | -------------------------------------------------------------------------------- /docs/help/help-window-center.osc: -------------------------------------------------------------------------------- 1 | /window/center 2 | 3 | /description Center window in main display. 4 | -------------------------------------------------------------------------------- /fonts/WalterTurncoat.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loopier/animatron-godot3/HEAD/fonts/WalterTurncoat.ttf -------------------------------------------------------------------------------- /fonts/mononoki_Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loopier/animatron-godot3/HEAD/fonts/mononoki_Bold.ttf -------------------------------------------------------------------------------- /config/config_example.osc: -------------------------------------------------------------------------------- 1 | def /config 2 | /window/screen 1 3 | /window/center 4 | /window/top 5 | -------------------------------------------------------------------------------- /docs/help/help-editor-clear.osc: -------------------------------------------------------------------------------- 1 | /editor/clear 2 | 3 | /description Clears the editor. **CANNOT BE UNDONE.** 4 | -------------------------------------------------------------------------------- /docs/help/help-list-midi.osc: -------------------------------------------------------------------------------- 1 | /list/midi 2 | 3 | /description Get list of commands mapped to MIDI events. 4 | -------------------------------------------------------------------------------- /docs/help/help-parent-free.osc: -------------------------------------------------------------------------------- 1 | /parent/free child:s 2 | 3 | /description Free the CHILD from any parent. 4 | -------------------------------------------------------------------------------- /docs/help/help-routine-free-all.osc: -------------------------------------------------------------------------------- 1 | /routine/free/all 2 | 3 | /description Remove all existing routines. 4 | -------------------------------------------------------------------------------- /docs/help/help-routine-free.osc: -------------------------------------------------------------------------------- 1 | /routine/free name:s 2 | 3 | /description Remove the routine named NAME. 4 | -------------------------------------------------------------------------------- /docs/help/help-routine-start.osc: -------------------------------------------------------------------------------- 1 | /routine/start name:s 2 | 3 | /description Start the routine named NAME. 4 | -------------------------------------------------------------------------------- /docs/help/help-write.osc: -------------------------------------------------------------------------------- 1 | /write msg:s 2 | 3 | /description Write MSG string with assets mapped to letters. 4 | -------------------------------------------------------------------------------- /docs/help/help-error-reply.osc: -------------------------------------------------------------------------------- 1 | /error/reply error:s 2 | 3 | /description Return an error message to the client. 4 | -------------------------------------------------------------------------------- /docs/help/help-list-children.osc: -------------------------------------------------------------------------------- 1 | /list/children actor:s 2 | 3 | /description List the ACTOR's children (if any). 4 | -------------------------------------------------------------------------------- /docs/help/help-list-states.osc: -------------------------------------------------------------------------------- 1 | /list/states actor 2 | 3 | /description Get a list of states for the given ACTOR. 4 | -------------------------------------------------------------------------------- /docs/help/help-midi-free.osc: -------------------------------------------------------------------------------- 1 | /midi/free 2 | 3 | /description Unmap MIDI MIDIMSG for MIDINUM in channel MIDICH. 4 | -------------------------------------------------------------------------------- /docs/help/help-play.osc: -------------------------------------------------------------------------------- 1 | /play actor:s 2 | 3 | /description Play the actor's animation from the current frame. 4 | -------------------------------------------------------------------------------- /docs/help/help-editor-font-size.osc: -------------------------------------------------------------------------------- 1 | /editor/font/size size:i 2 | 3 | /description Set the font size of the editor. 4 | -------------------------------------------------------------------------------- /docs/help/help-post-font-decrease.osc: -------------------------------------------------------------------------------- 1 | /post/font/decrease 2 | 3 | /description Decrease the font size of the post. 4 | -------------------------------------------------------------------------------- /docs/help/help-post-font-increase.osc: -------------------------------------------------------------------------------- 1 | /post/font/increase 2 | 3 | /description Increase the font size of the post. 4 | -------------------------------------------------------------------------------- /docs/help/help-post-font-size.osc: -------------------------------------------------------------------------------- 1 | /post/font/size size:i 2 | 3 | /description Set the font size of the post window. 4 | -------------------------------------------------------------------------------- /docs/help/help-status-reply.osc: -------------------------------------------------------------------------------- 1 | /status/reply status:s 2 | 3 | /description Return a status message to the client. 4 | -------------------------------------------------------------------------------- /addons/gdosc/bin/x11/libgdosc.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loopier/animatron-godot3/HEAD/addons/gdosc/bin/x11/libgdosc.so -------------------------------------------------------------------------------- /docs/help/help-editor-font-decrease.osc: -------------------------------------------------------------------------------- 1 | /editor/font/decrease 2 | 3 | /description Decrease the font size of the editor. 4 | -------------------------------------------------------------------------------- /docs/help/help-editor-font-increase.osc: -------------------------------------------------------------------------------- 1 | /editor/font/increase 2 | 3 | /description Increase the font size of the editor. 4 | -------------------------------------------------------------------------------- /docs/help/help-frame-next.osc: -------------------------------------------------------------------------------- 1 | /frame/next actor:s 2 | 3 | /description Jump to the next frame of the ACTOR's' animation. 4 | -------------------------------------------------------------------------------- /docs/help/help-oneshot.osc: -------------------------------------------------------------------------------- 1 | /oneshot actor:s 2 | 3 | /description Play the ACTOR to the end, and stop. Then set VISIBILITY. 4 | -------------------------------------------------------------------------------- /docs/help/help-osc-remote.osc: -------------------------------------------------------------------------------- 1 | /osc/remote ip:s 2 | 3 | /description Register a remote OSC client at IP address on PORT. 4 | -------------------------------------------------------------------------------- /docs/help/help-state-free.osc: -------------------------------------------------------------------------------- 1 | /state/free actor state 2 | 3 | /description Remove the STATE from the ACTOR's state machine. 4 | -------------------------------------------------------------------------------- /addons/gdosc/bin/osx/libgdosc.dylib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loopier/animatron-godot3/HEAD/addons/gdosc/bin/osx/libgdosc.dylib -------------------------------------------------------------------------------- /addons/gdosc/bin/win64/libgdosc.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loopier/animatron-godot3/HEAD/addons/gdosc/bin/win64/libgdosc.dll -------------------------------------------------------------------------------- /addons/gdosc/bin/win64/libgdosc.exp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loopier/animatron-godot3/HEAD/addons/gdosc/bin/win64/libgdosc.exp -------------------------------------------------------------------------------- /addons/gdosc/bin/win64/libgdosc.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loopier/animatron-godot3/HEAD/addons/gdosc/bin/win64/libgdosc.lib -------------------------------------------------------------------------------- /docs/help/help-frame-prev.osc: -------------------------------------------------------------------------------- 1 | /frame/prev actor:s 2 | 3 | /description Jump to the previous frame of the ACTOR's' animation. 4 | -------------------------------------------------------------------------------- /docs/help/help-help.osc: -------------------------------------------------------------------------------- 1 | /help 2 | 3 | /description Open this file in a browser and print the keyboard shortcuts and commands. 4 | -------------------------------------------------------------------------------- /docs/help/help-midi-debug.osc: -------------------------------------------------------------------------------- 1 | /midi/debug [enable:b] 2 | 3 | /description Enable (or disable) reporting of MIDI input events. 4 | -------------------------------------------------------------------------------- /docs/help/help-play-rand.osc: -------------------------------------------------------------------------------- 1 | /play/rand actor:s 2 | 3 | /description Play the ACTOR frames in a random order. Defaults to TRUE. 4 | -------------------------------------------------------------------------------- /docs/help/help-window-fullscreen.osc: -------------------------------------------------------------------------------- 1 | /window/fullscreen [enable:b] 2 | 3 | /description Set fullscreen mode (defaults to true). 4 | -------------------------------------------------------------------------------- /docs/help/help-parent.osc: -------------------------------------------------------------------------------- 1 | /parent child:s 2 | 3 | /description Set the CHILD as child of PARENT. Will inherit all transformations. 4 | -------------------------------------------------------------------------------- /docs/help/help-window-position.osc: -------------------------------------------------------------------------------- 1 | /window/position x:i 2 | 3 | /description Move window to the specified position given in pixels. 4 | -------------------------------------------------------------------------------- /docs/help/help-list-sequence.osc: -------------------------------------------------------------------------------- 1 | /list/sequence actor:s 2 | 3 | /description Print the list of commands triggered on all ACTOR frames. 4 | -------------------------------------------------------------------------------- /docs/help/help-slow.osc: -------------------------------------------------------------------------------- 1 | /slow actor amount 2 | 3 | /description Devide the speed by a specific AMOUNT. Negative values play in reverse. 4 | -------------------------------------------------------------------------------- /docs/help/help-speed.osc: -------------------------------------------------------------------------------- 1 | /speed actor:s 2 | 3 | /description Set the playback speed (1 is normal speed). Negative values play in reverse. 4 | -------------------------------------------------------------------------------- /docs/help/help-window-screen.osc: -------------------------------------------------------------------------------- 1 | /window/screen screenIndex:i 2 | 3 | /description Move the window between displays (0 = main display). 4 | -------------------------------------------------------------------------------- /docs/help/help-osc-send.osc: -------------------------------------------------------------------------------- 1 | /osc/send addr:s 2 | 3 | /description Send an OSC message with an arbitrary number of arguments to a remote client. 4 | -------------------------------------------------------------------------------- /docs/help/help-window-top.osc: -------------------------------------------------------------------------------- 1 | /window/top [enable:b] 2 | 3 | /description Set window to be always on top of other windows (defaults to true). 4 | -------------------------------------------------------------------------------- /docs/help/help-createordestroy.osc: -------------------------------------------------------------------------------- 1 | /createordestroy actor:s 2 | 3 | /description Like `/create`, but if the actor already exists, it removes it. 4 | -------------------------------------------------------------------------------- /docs/help/help-editor-open.osc: -------------------------------------------------------------------------------- 1 | /editor/open [path:s] 2 | 3 | /description Open an OSC file in the editor. Opens a dialog if no PATH is provided. 4 | -------------------------------------------------------------------------------- /docs/help/help-letter.osc: -------------------------------------------------------------------------------- 1 | /letter letter:c 2 | 3 | /description Map a single letter to an asset. Creates an actor named after LETTER with ASSET. 4 | -------------------------------------------------------------------------------- /docs/help/help-list.osc: -------------------------------------------------------------------------------- 1 | /list 2 | 3 | /description Get list of current actor instances. Returned in the form of a `/list/actors/reply` OSC message. 4 | -------------------------------------------------------------------------------- /docs/help/help-app-remote.osc: -------------------------------------------------------------------------------- 1 | /app/remote [allow:b] 2 | 3 | /description Allow (or prevent) executing OSC commands from remote (non-localhost) clients. 4 | -------------------------------------------------------------------------------- /docs/help/help-editor-save.osc: -------------------------------------------------------------------------------- 1 | /editor/save [path:s] 2 | 3 | /description Save the editor contents into a file. Opens a dialog if no PATH is provided. 4 | -------------------------------------------------------------------------------- /docs/help/help-letter-spacing.osc: -------------------------------------------------------------------------------- 1 | /letter/spacing amount 2 | 3 | /description Set the spacing between letters. It's a multiplier of the actors' size. 4 | -------------------------------------------------------------------------------- /docs/help/help-load-alphabet.osc: -------------------------------------------------------------------------------- 1 | /load/alphabet 2 | 3 | /description Load the alphabet (default letters load from folders named `letter-[ASCII_CHAR]`) 4 | -------------------------------------------------------------------------------- /transparent_bg.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="StyleBoxFlat" format=2] 2 | 3 | [resource] 4 | content_margin_left = 10.0 5 | bg_color = Color( 0.6, 0.6, 0.6, 0 ) 6 | -------------------------------------------------------------------------------- /docs/help/help-onfinish.osc: -------------------------------------------------------------------------------- 1 | /onfinish actor:s 2 | 3 | /description Add SUBCOMMAND to be triggered on the last frame. The SUBCOMMAND can be any valid command. 4 | -------------------------------------------------------------------------------- /docs/help/help-rand.osc: -------------------------------------------------------------------------------- 1 | /rand cmd:s 2 | 3 | /description Send a CMD with a random value between MIN and `max.`**This only works with single-value commands.** 4 | -------------------------------------------------------------------------------- /docs/help/help-list-actors-reply.osc: -------------------------------------------------------------------------------- 1 | /list/actors/reply [actor:s] 2 | 3 | /description Return the list of instanced actors to the client (one name per argument). 4 | -------------------------------------------------------------------------------- /docs/help/help-say.osc: -------------------------------------------------------------------------------- 1 | /say actor:s 2 | 3 | /description Have the actor "say" something via a speech bubble, with an optional duration (defaults to three seconds). 4 | -------------------------------------------------------------------------------- /docs/help/help-list-anims.osc: -------------------------------------------------------------------------------- 1 | /list/anims 2 | 3 | /description Get list of available (loaded) animations. Returned in the form of a `/list/anims/reply` OSC message. 4 | -------------------------------------------------------------------------------- /docs/help/help-play-range.osc: -------------------------------------------------------------------------------- 1 | /play/range actor:s 2 | 3 | /description Play an ACTOR range of frames, begining on the START frame up to (and including) the END frame. 4 | -------------------------------------------------------------------------------- /docs/help/help-select.osc: -------------------------------------------------------------------------------- 1 | /select [actor:s] 2 | 3 | /description Add the actor to the selected set. If run without ACTOR it will return the list of selected actors. 4 | -------------------------------------------------------------------------------- /docs/help/help-list-anims-reply.osc: -------------------------------------------------------------------------------- 1 | /list/anims/reply [anim:s] 2 | 3 | /description Return the list of available (loaded) animations to the client (one name per argument). 4 | -------------------------------------------------------------------------------- /docs/help/help-load-defs.osc: -------------------------------------------------------------------------------- 1 | /load/defs filename 2 | 3 | /description Load a custom command definitions file, which should have the format [described below](#def-files). 4 | -------------------------------------------------------------------------------- /docs/help/help-list-assets.osc: -------------------------------------------------------------------------------- 1 | /list/assets 2 | 3 | /description Get list of available (unloaded) assets on disk. Returned in the form of a `/list/assets/reply` OSC message. 4 | -------------------------------------------------------------------------------- /docs/help/help-routine.osc: -------------------------------------------------------------------------------- 1 | /routine name:s 2 | 3 | /description Start a routine named NAME that sends CMD every INTERVAL of time (in seconds) for an arbitrary number of REPEATS. 4 | -------------------------------------------------------------------------------- /docs/help/help-sound-free.osc: -------------------------------------------------------------------------------- 1 | /sound/free band:i 2 | 3 | /description Unmap sound for the given BAND. If COMMAND and ACTOR are specified, remove only that COMMAND for the actor. 4 | -------------------------------------------------------------------------------- /sc/letters-test.scd: -------------------------------------------------------------------------------- 1 | "setup.scd".loadRelative.first; 2 | ( 3 | x.("/load/alphabet"); 4 | x.("/write", "alo"); 5 | x.("/letters/spacing", 0.25); 6 | x.("/letters/scale", 0.25); 7 | ) -------------------------------------------------------------------------------- /docs/help/help-behind.osc: -------------------------------------------------------------------------------- 1 | /behind actor:s 2 | 3 | /description Change the draw order for an actor to be behind a reference actor. To move to the background, use `/behind actor *`. 4 | -------------------------------------------------------------------------------- /docs/help/help-choose-arg.osc: -------------------------------------------------------------------------------- 1 | /choose/arg cmd:s 2 | 3 | /description Send a CMD with a value randomly chosen from any of the arguments. **This only works with single-value commands.** 4 | -------------------------------------------------------------------------------- /docs/help/help-front.osc: -------------------------------------------------------------------------------- 1 | /front actor:s 2 | 3 | /description Change the draw order for an actor to be in front of a reference actor. To move to the foreground, use `/front actor *`. 4 | -------------------------------------------------------------------------------- /docs/help/help-assets-path.osc: -------------------------------------------------------------------------------- 1 | /assets/path [path:s] 2 | 3 | /description Sets the path to the assets root directory. If no argument is provided, it returns the current value of the path. 4 | -------------------------------------------------------------------------------- /docs/help/help-size.osc: -------------------------------------------------------------------------------- 1 | /size actor:s 2 | 3 | /description Set the actor's uniform size. If DUR is set, interpolate the scale over that number of seconds, otherwise change instantaneously. 4 | -------------------------------------------------------------------------------- /RoutineNode.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=2 format=2] 2 | 3 | [ext_resource path="res://RoutineNode.gd" type="Script" id=1] 4 | 5 | [node name="TimerNode" type="Timer"] 6 | script = ExtResource( 1 ) 7 | -------------------------------------------------------------------------------- /docs/tutorial.osc: -------------------------------------------------------------------------------- 1 | # ANIMATRON TUTORIAL 2 | # ------------------ 3 | # Welcome to the Animatron Tutorial. 4 | 5 | # Put the cursor on the next line and press SHIFT + ENTER 6 | 7 | /tutorial/controls 8 | -------------------------------------------------------------------------------- /default_env.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Environment" load_steps=2 format=2] 2 | 3 | [sub_resource type="ProceduralSky" id=1] 4 | 5 | [resource] 6 | background_mode = 2 7 | background_sky = SubResource( 1 ) 8 | -------------------------------------------------------------------------------- /docs/help/help-deselect.osc: -------------------------------------------------------------------------------- 1 | /deselect [actor:s] 2 | 3 | /description Remove the actor from the selected set. If run without ACTOR it will deselect all (equivalent to `/deselect "*"` or `/deselect "!"`). 4 | -------------------------------------------------------------------------------- /docs/help/help-angle.osc: -------------------------------------------------------------------------------- 1 | /angle actor:s 2 | 3 | /description Set the actor's rotation angle to DEGREES. If DUR is set, interpolate the rotation over that number of seconds, otherwise change instantaneously. 4 | -------------------------------------------------------------------------------- /docs/help/help-size-x.osc: -------------------------------------------------------------------------------- 1 | /size/x actor:s 2 | 3 | /description Set the actor's uniform size on the x axis. If DUR is set, interpolate the scale over that number of seconds, otherwise change instantaneously. 4 | -------------------------------------------------------------------------------- /docs/help/help-size-y.osc: -------------------------------------------------------------------------------- 1 | /size/y actor:s 2 | 3 | /description Set the actor's uniform size on the y axis. If DUR is set, interpolate the scale over that number of seconds, otherwise change instantaneously. 4 | -------------------------------------------------------------------------------- /docs/help/help-sound.osc: -------------------------------------------------------------------------------- 1 | /sound band:i 2 | 3 | /description Map the amplitude of the sound input at the frequency BAND to any COMMAND within the range MIN and MAX (if ommited they default to `[0.0..1.0]`) 4 | -------------------------------------------------------------------------------- /docs/help/help-color-b.osc: -------------------------------------------------------------------------------- 1 | /color/b actor:s 2 | 3 | /description Add a Blue value to the actor. Should be in the 0-1 range (can be negative to subtract colour). Set to black (0,0,0) to restore its original colour. 4 | -------------------------------------------------------------------------------- /docs/help/help-color-r.osc: -------------------------------------------------------------------------------- 1 | /color/r actor:s 2 | 3 | /description Add a Red value to the actor. Should be in the 0-1 range (can be negative to subtract colour). Set to black (0,0,0) to restore its original colour. 4 | -------------------------------------------------------------------------------- /docs/help/help-rotate.osc: -------------------------------------------------------------------------------- 1 | /rotate actor:s 2 | 3 | /description Add DEGREE'S to the actor's rotation angle. If DUR is set, interpolate the rotation over that number of seconds, otherwise change instantaneously. 4 | -------------------------------------------------------------------------------- /docs/help/help-color-g.osc: -------------------------------------------------------------------------------- 1 | /color/g actor:s 2 | 3 | /description Add a Green value to the actor. Should be in the 0-1 range (can be negative to subtract colour). Set to black (0,0,0) to restore its original colour. 4 | -------------------------------------------------------------------------------- /docs/help/help-scale.osc: -------------------------------------------------------------------------------- 1 | /scale actor:s 2 | 3 | /description Set the actor's relative uniform scale to the current size. If DUR is set, interpolate the scale over that number of seconds, otherwise change instantaneously. 4 | -------------------------------------------------------------------------------- /docs/help/help-state-add.osc: -------------------------------------------------------------------------------- 1 | /state/add actor new_state ... next_states 2 | 3 | /description Add a NEW_STATE to the ACTOR's state machine. NEXT_STATES is an arbitrary number of next possible states. States are asset names. 4 | -------------------------------------------------------------------------------- /docs/help/help-size-xy.osc: -------------------------------------------------------------------------------- 1 | /size/xy actor:s 2 | 3 | /description Set the actor's size for the X and Y axis (may be different). If DUR is set, interpolate the scale over that number of seconds, otherwise change instantaneously. 4 | -------------------------------------------------------------------------------- /docs/help/help-color.osc: -------------------------------------------------------------------------------- 1 | /color actor:s 2 | 3 | /description Add an RGB colour to the actor. Red, green and blue should be in the 0-1 range (can be negative to subtract colour). Set to black (0,0,0) to restore its original colour. 4 | -------------------------------------------------------------------------------- /docs/help/help-scale-x.osc: -------------------------------------------------------------------------------- 1 | /scale/x actor:s 2 | 3 | /description Set the actor's relative scale to the current size on the x axis. If DUR is set, interpolate the scale over that number of seconds, otherwise change instantaneously. 4 | -------------------------------------------------------------------------------- /docs/help/help-scale-xy.osc: -------------------------------------------------------------------------------- 1 | /scale/xy actor:s 2 | 3 | /description Set the actor's relative scale to the current size on both axis. If DUR is set, interpolate the scale over that number of seconds, otherwise change instantaneously. 4 | -------------------------------------------------------------------------------- /docs/help/help-scale-y.osc: -------------------------------------------------------------------------------- 1 | /scale/y actor:s 2 | 3 | /description Set the actor's relative scale to the current size on the y axis. If DUR is set, interpolate the scale over that number of seconds, otherwise change instantaneously. 4 | -------------------------------------------------------------------------------- /docs/help/help-window-size.osc: -------------------------------------------------------------------------------- 1 | /window/size sx:i 2 | 3 | /description Set window to the specified size in pixels. -1 may be specified for either SX or SY, in which case it will be computed using the project viewport aspect ratio. 4 | -------------------------------------------------------------------------------- /docs/help/help-create-group.osc: -------------------------------------------------------------------------------- 1 | /create/group group:s 2 | 3 | /description Create a batch of actors with a given (loaded) animation. A group will be created with this name and each actor will be named after the group with an index sufix. 4 | -------------------------------------------------------------------------------- /docs/help/help-frame.osc: -------------------------------------------------------------------------------- 1 | /frame actor:s 2 | 3 | /description Jump to the given frame number (with wrapping). If a FLOAT from 0-1 is passed, it will jump to the frame corresponding to that position (0 being the first frame and 1 the last). 4 | -------------------------------------------------------------------------------- /docs/help/help-onframe-free.osc: -------------------------------------------------------------------------------- 1 | /onframe/free actor:s 2 | 3 | /description Remove SUBCOMMAND trigger from FRAME. The SUBCOMMAND only needs the command address (with leading `/`) and the actor name -- don't any the command parameter value. 4 | -------------------------------------------------------------------------------- /docs/help/help-ysort.osc: -------------------------------------------------------------------------------- 1 | /ysort [sort:b] 2 | 3 | /description Force actors to be sorted based on y position (lower on screen drawn later, i.e. "on top"). SORT argument defaults to TRUE, but initial state of y-sorting at startup is FALSE. 4 | -------------------------------------------------------------------------------- /docs/help/help-choose.osc: -------------------------------------------------------------------------------- 1 | /choose cmd1 2 | 3 | /description Randomly choose one of the **comma separated** commands and send it. Commands are fully formed commands with the regular OSC syntax. **NOTE: commas need to be SURROUNDED by SPACES.** 4 | -------------------------------------------------------------------------------- /docs/help/help-fade.osc: -------------------------------------------------------------------------------- 1 | /fade actor:s 2 | 3 | /description Set the actor's opacity realtive to the current value (where 1 is keep as it is). If DUR is set, interpolate the fade over that number of seconds, otherwise change instantaneously. 4 | -------------------------------------------------------------------------------- /docs/help/help-list-assets-reply.osc: -------------------------------------------------------------------------------- 1 | /list/assets/reply [asset:s] 2 | 3 | /description return the list of available (unloaded) assets to the client (one name per argument). assets must be loaded as anims in order to create actor instances. 4 | -------------------------------------------------------------------------------- /docs/help/help-wait.osc: -------------------------------------------------------------------------------- 1 | /wait duration 2 | 3 | /description Wait for DURATION seconds before executing the next command. Only relevant within a list of commands being executed together at once, such as inside a custom DEFined command list. 4 | -------------------------------------------------------------------------------- /docs/help/help-alpha.osc: -------------------------------------------------------------------------------- 1 | /alpha actor:s 2 | 3 | /description Set the actor's opacity, where 1 is fully opaque/visible and 0 is transparent/invisible). If DUR is set, interpolate the alpha over that number of seconds, otherwise change instantaneously. 4 | -------------------------------------------------------------------------------- /docs/help/help-load-config.osc: -------------------------------------------------------------------------------- 1 | /load/config filename:s 2 | 3 | /description Load a config file following the DEF syntax (**WARNING** This might change in the futre). After loading the file, the method defined with DEF needs to be explicitly called. 4 | -------------------------------------------------------------------------------- /docs/help/help-onfinish-free.osc: -------------------------------------------------------------------------------- 1 | /onfinish/free actor:s 2 | 3 | /description Remove SUBCOMMAND trigger from the last frame. The SUBCOMMAND only needs the command address (with leading `/`) and the actor name -- don't any the command parameter value. 4 | -------------------------------------------------------------------------------- /docs/help/help-position-x.osc: -------------------------------------------------------------------------------- 1 | /position/x actor:s 2 | 3 | /description Set the actor to the x coordinate (specified as fractions of the viewport from 0-1). If DUR is set, interpolate the movement over that number of seconds, otherwise change instantaneously. 4 | -------------------------------------------------------------------------------- /docs/help/help-position-y.osc: -------------------------------------------------------------------------------- 1 | /position/y actor:s 2 | 3 | /description Set the actor to the y coordinate (specified as fractions of the viewport from 0-1). If DUR is set, interpolate the movement over that number of seconds, otherwise change instantaneously. 4 | -------------------------------------------------------------------------------- /docs/help/help-position.osc: -------------------------------------------------------------------------------- 1 | /position actor:s 2 | 3 | /description Set the actor to the x,y coordinates (specified as fractions of the viewport from 0-1). If DUR is set, interpolate the movement over that number of seconds, otherwise change instantaneously. 4 | -------------------------------------------------------------------------------- /docs/help/help-create.osc: -------------------------------------------------------------------------------- 1 | /create actor:s 2 | 3 | /description Create a new actor with a given (loaded) animation. If the named actor already exists, change its animation to the one specified. The initial position of a new actor will be at (0.5,0.5), the centre of the viewport. 4 | -------------------------------------------------------------------------------- /docs/help-create.osc: -------------------------------------------------------------------------------- 1 | /create actor animation 2 | 3 | /despcription Create a new ACTOR with a given (loaded) ANIMATION. If the named actor already exists, change its animation to the one specified. The initial position of a new actor will be at (0.5,0.5), the centre of the viewport. 4 | -------------------------------------------------------------------------------- /docs/help/help-loop.osc: -------------------------------------------------------------------------------- 1 | /loop actor:s 2 | 3 | /description Set the ACTOR's animation to loop. 4 | /loop actor:s 5 | 6 | /description Enable or disable looped animation playback. ENABLE argument defaults to TRUE, and initial state of animation looping for new actors is also TRUE. 7 | -------------------------------------------------------------------------------- /docs/help/help-move.osc: -------------------------------------------------------------------------------- 1 | /move actor:s 2 | 3 | /description Move the actor to the x,y coordinates relative to the current position (specified as fractions of the viewport from 0-1). If DUR is set, interpolate the movement over that number of seconds, otherwise change instantaneously. 4 | -------------------------------------------------------------------------------- /docs/help/help-move-x.osc: -------------------------------------------------------------------------------- 1 | /move/x actor:s 2 | 3 | /description Move the actor to the x coordinate relative to the current position (specified as fractions of the viewport from 0-1). If DUR is set, interpolate the move/xment over that number of seconds, otherwise change instantaneously. 4 | -------------------------------------------------------------------------------- /docs/help/help-move-y.osc: -------------------------------------------------------------------------------- 1 | /move/y actor:s 2 | 3 | /description Move the actor to the y coordinate relative to the current position (specified as fractions of the viewport from 0-1). If DUR is set, interpolate the move/xment over that number of seconds, otherwise change instantaneously. 4 | -------------------------------------------------------------------------------- /docs/help/help-load.osc: -------------------------------------------------------------------------------- 1 | /load asset:s 2 | 3 | /description Load an (animation) asset from disk. It will create an ANIM with the same name as the asset. Wildcards are supported, so several animations can be loaded at once. The list of assets available to load can be found by calling `/list/assets`. 4 | -------------------------------------------------------------------------------- /actions/Action.gd: -------------------------------------------------------------------------------- 1 | extends Node 2 | class_name Action, "res://icons/action.svg" 3 | 4 | onready var actor = get_parent() 5 | onready var offsetNode = actor.get_node("Offset") 6 | var curTime : float = 0.0 7 | 8 | func _init(): 9 | pass 10 | 11 | 12 | func updateTime(delta : float): 13 | curTime += delta 14 | 15 | -------------------------------------------------------------------------------- /docs/help/help-pivot.osc: -------------------------------------------------------------------------------- 1 | /pivot actor:s 2 | 3 | /description Set the actor's animation pivot to the specified point. PX and PY should be in the normalized range 0-1, with 0 being left/top of the frame and 1 being right/bottom. If DUR is set, interpolate the pivot over that number of seconds, otherwise change instantaneously. 4 | -------------------------------------------------------------------------------- /docs/help/help-group.osc: -------------------------------------------------------------------------------- 1 | /group group:s 2 | 3 | /description Add the actor to a named group. If run without ACTOR it will return the list of actors in the group. Note that `/group "myGroup" "!"` may be used to add the current selection to a group. Use the group name as an actor name in all commands to apply it to all it's members. 4 | -------------------------------------------------------------------------------- /addons/gdosc/gdoscmsg.gdns: -------------------------------------------------------------------------------- 1 | [gd_resource type="NativeScript" load_steps=2 format=2] 2 | 3 | [ext_resource path="res://addons/gdosc/gdosc.gdnlib" type="GDNativeLibrary" id=1] 4 | 5 | [resource] 6 | 7 | resource_name = "oscmsg" 8 | class_name = "oscmsg" 9 | library = ExtResource( 1 ) 10 | _sections_unfolded = [ "Resource" ] 11 | -------------------------------------------------------------------------------- /docs/help/help-onframe.osc: -------------------------------------------------------------------------------- 1 | /onframe actor:s 2 | 3 | /description Add SUBCOMMAND to be triggered on FRAME. The SUBCOMMAND can be any valid command.

For example, to create an animation sequence, the animation asset can be changed on the desired FRAME:

`/create actorA animA`
`/onframe actorA 8 /create actorA animB`. 4 | -------------------------------------------------------------------------------- /addons/gdosc/gdoscsender.gdns: -------------------------------------------------------------------------------- 1 | [gd_resource type="NativeScript" load_steps=2 format=2] 2 | 3 | [ext_resource path="res://addons/gdosc/gdosc.gdnlib" type="GDNativeLibrary" id=1] 4 | 5 | [resource] 6 | 7 | resource_name = "oscsender" 8 | class_name = "oscsender" 9 | library = ExtResource( 1 ) 10 | _sections_unfolded = [ "Resource" ] 11 | -------------------------------------------------------------------------------- /docs/help/help-debug.osc: -------------------------------------------------------------------------------- 1 | /debug [enable:b] 2 | 3 | /description Enable (or disable) reporting of informative status messages (via OSC and to the debug window). By default, this is disabled when running in exported builds, but enabled when running in the Godot editor. This flag does not affect error reporting (errors are always reported). 4 | -------------------------------------------------------------------------------- /addons/gdosc/gdoscreceiver.gdns: -------------------------------------------------------------------------------- 1 | [gd_resource type="NativeScript" load_steps=2 format=2] 2 | 3 | [ext_resource path="res://addons/gdosc/gdosc.gdnlib" type="GDNativeLibrary" id=1] 4 | 5 | [resource] 6 | 7 | resource_name = "oscreceiver" 8 | class_name = "oscreceiver" 9 | library = ExtResource( 1 ) 10 | _sections_unfolded = [ "Resource" ] 11 | -------------------------------------------------------------------------------- /docs/help/help-action.osc: -------------------------------------------------------------------------------- 1 | /action actor:s 2 | 3 | /description Apply an action (behaviour) to the actor. Actions are script classes that define custom behaviours, such as "wander". Each action type will have its own unique list of arguments. You can see the [built-in actions here](#actions). Calling it without any ACTION will remove any existing actions. 4 | -------------------------------------------------------------------------------- /docs/tutorial-index.osc: -------------------------------------------------------------------------------- 1 | # INDEX 2 | # ----- 3 | # put the cursor on a line and press SHIFT + ENTER 4 | 5 | /tutorial/welcome 6 | /tutorial/controls 7 | /tutorial/commands 8 | 9 | # actors 10 | 11 | /tutorial/actors 12 | /tutorial/actor-attributes 13 | /tutorial/actor-animation 14 | /tutorial/actor-multi 15 | 16 | # utils 17 | 18 | /tutorial/utils-rand 19 | -------------------------------------------------------------------------------- /addons/gdosc/gdosc.gdnlib: -------------------------------------------------------------------------------- 1 | [general] 2 | 3 | singleton=false 4 | load_once=true 5 | symbol_prefix="godot_" 6 | reloadable=true 7 | 8 | [entry] 9 | 10 | X11.64="res://addons/gdosc/bin/x11/libgdosc.so" 11 | Windows.64="res://addons/gdosc/bin/win64/libgdosc.dll" 12 | OSX.64="res://addons/gdosc/bin/osx/libgdosc.dylib" 13 | 14 | [dependencies] 15 | 16 | X11.64=[ ] 17 | Windows.64=[ ] 18 | OSX.64=[ ] 19 | -------------------------------------------------------------------------------- /docs/help/help-midi.osc: -------------------------------------------------------------------------------- 1 | /midi 2 | 3 | /description Map the MIDIMSG (NOTEON, NOTEOFF, CC, VELOCITY) received in channel MIDICH to a COMMAND within a range between MIN and MAX. For `noteon/noteoff` events, a `*` wildcard can be passed as MIDINUM to use the note number as value (ignoring the velocity). The VELOCITY midimsg maps the velocity of all notes to COMMAND, passing it as an argument (ignoring the note number). 4 | -------------------------------------------------------------------------------- /docs/help/help-def.osc: -------------------------------------------------------------------------------- 1 | /def cmdName 2 | 3 | /description Define a custom OSC command that is a list of other OSC commands. This may be recursive, so each SUBCOMMAND may reference one of the built-in commands, or another custom-defined command. Another way to define custom commands is via the file `commands/init.osc`. The CMDNAME string (first argument) may include argument names, which may be referenced as SUBCOMMAND arguments using $NAME. Example: `/def "/addsel actor anim" "/create $actor $anim" "/select $actor"`. 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Godot-specific 2 | .import/ 3 | *.translation 4 | export.cfg 5 | export_presets.cfg 6 | .mono/ 7 | 8 | # For now, keep animations out of git by default (can be added explicitly when desired) 9 | animations/ 10 | runtime_data/ 11 | commands/ 12 | config/ 13 | 14 | # Generated by MacOS 15 | .DS_Store 16 | 17 | # Generated by Windows 18 | Thumbs.db 19 | 20 | # Applications 21 | *.app 22 | *.exe 23 | *.war 24 | 25 | # Large media files 26 | *.mp4 27 | *.tiff 28 | *.avi 29 | *.flv 30 | *.mov 31 | *.wmv 32 | 33 | -------------------------------------------------------------------------------- /commands/init_example.osc: -------------------------------------------------------------------------------- 1 | def /startup 2 | /load om-walk-* 3 | /wait 2 4 | /create walker om-walk-s 5 | /color walker 0.7 0.2 0.1 6 | /crowd 7 | /wait 3 8 | /say walker "Hi everybody!" 9 | 10 | def /createsel actor anim 11 | /create $actor $anim 12 | /select $actor 13 | 14 | def /crowd 15 | /deselect 16 | /createsel om1 om-walk-w 17 | /createsel om2 om-walk-w 18 | /createsel om3 om-walk-w 19 | /createsel om4 om-walk-w 20 | /createsel om5 om-walk-w 21 | /group crowd om? 22 | 23 | -------------------------------------------------------------------------------- /docs/tutorial-utils-rand.osc: -------------------------------------------------------------------------------- 1 | # RANDOM 2 | # ------ 3 | # single-value commands (commands with only one value as 4 | # agrument besides the TARGET), can be randomized with 5 | # the '/rand' command, which takes has a somewhat confusing 6 | # syntax, but which is consistent with the actor command syntax: 7 | # /rand /CMD TARGET MIN MAX 8 | 9 | # firts let's create something 10 | 11 | /free * 12 | /new box box 13 | 14 | # to randomize it's size we would use 15 | 16 | /rand /scale box 0.1 2 17 | 18 | # randomizing rotation would be done with 19 | 20 | /rand /rotate box 0 360 21 | 22 | /tutorial/index 23 | -------------------------------------------------------------------------------- /OscSender.gd: -------------------------------------------------------------------------------- 1 | extends Node 2 | 3 | var oscsndr 4 | 5 | func _ready(): 6 | 7 | oscsndr = load("res://addons/gdosc/gdoscsender.gdns").new() 8 | # [mandatory] will send messages to ip:port 9 | 10 | func connectRemote(args): 11 | var ip = args[0] 12 | var port = args[1] 13 | oscsndr.stop() 14 | oscsndr.setup( ip, port ) 15 | # [mandatory] enabling emission 16 | oscsndr.start() 17 | print("connected to %s:%s" % [ip, port]) 18 | 19 | func send(args): 20 | # address 21 | oscsndr.msg(args[0]) 22 | # args 23 | if len(args) > 1: 24 | for arg in args.slice(1,-1): 25 | oscsndr.add(arg) 26 | # sending the message 27 | oscsndr.send() 28 | print("sent OSC message: %s" % [args]) 29 | 30 | func _exit_tree ( ): 31 | # disable the sender, highly recommended! 32 | oscsndr.stop() 33 | -------------------------------------------------------------------------------- /sc/sequence-test.scd: -------------------------------------------------------------------------------- 1 | a = Animatron(); 2 | 3 | a.sendMsg("/free", "*"); 4 | ( 5 | a.sendMsg("/new", "na", "numbers"); 6 | a.sendMsg("/load", "square"); 7 | a.sendMsg("/speed", "na", 2/12); 8 | a.sendMsg("/scale", "na", 0.25); 9 | 10 | a.sendMsg("/onframe", "na", 4, "/position/x", "na", 0.2); 11 | a.sendMsg("/onframe", "na", 7, "/position/x", "na", 0.7); 12 | a.sendMsg("/onframe", "na", 2, "/scale", "na", 0.4); 13 | a.sendMsg("/onframe", "na", 8, "/scale", "na", 0.2); 14 | a.sendMsg("/onframe", "na", 9, "/create", "na", "square"); 15 | a.sendMsg("/onframe", "na", 3, "/create", "na", "numbers"); 16 | ) 17 | a.sendMsg("/onframe/free", "na", 4, "/position/x", "na"); 18 | a.sendMsg("/onframe/free", "na", 7, "/position/x", "na"); 19 | a.sendMsg("/create", "la", "letter-a") 20 | a.sendMsg("/list/assets"); -------------------------------------------------------------------------------- /actions/wander.gd: -------------------------------------------------------------------------------- 1 | extends Action 2 | 3 | var noise := OpenSimplexNoise.new() 4 | var wanderRange : float = 0.1 # as a fraction of the screen 5 | var wanderSpeed : float = 1 6 | 7 | 8 | func _init(args : Array): 9 | if args.size() > 0: 10 | wanderRange = float(args[0]) 11 | if args.size() > 1: 12 | wanderSpeed = float(args[1]) 13 | noise.seed = randi() 14 | noise.octaves = 2 15 | noise.period = 4.0 16 | noise.persistence = 0.5 17 | noise.lacunarity = 2 18 | 19 | 20 | func _physics_process(delta : float): 21 | updateTime(delta * wanderSpeed) 22 | var pos = Vector2(noise.get_noise_1d(curTime), 0) 23 | pos = pos.rotated(PI * noise.get_noise_2d(-5.37, curTime)) 24 | offsetNode.position = (pos * wanderRange * OS.window_size.y).linear_interpolate(Vector2(0,0), 1.0 - clamp(curTime*2.0, 0, 1)) 25 | -------------------------------------------------------------------------------- /docs/tutorial-controls.osc: -------------------------------------------------------------------------------- 1 | # CONTROLS 2 | # -------- 3 | # Congrats! You already know how to use Animatron! 4 | 5 | # What you just did by pressing SHIFT + ENTER is EVALUATE A LINE 6 | 7 | # You can also EVALUATE A BLOCK by pressing CTRL + ENTER 8 | # A BLOCK is a group of lines that are not separated by empty lines. For example: 9 | 10 | /editor/append Line1 added to the end of this file 11 | /editor/append Line2 added to the end of this file 12 | 13 | # Try putting the cursor on either of the previous lines and evaluating the block 14 | 15 | # Now do it again but only evaluating one line (SHIFT + ENTER) 16 | 17 | # To go to the next section, evaluate the next line. If you prefer to see the 18 | # the index, evaluate the last one. 19 | 20 | # next 21 | 22 | /tutorial/commands 23 | 24 | # up 25 | 26 | /tutorial/index 27 | -------------------------------------------------------------------------------- /icon.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="StreamTexture" 5 | path="res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex" 6 | metadata={ 7 | "vram_texture": false 8 | } 9 | 10 | [deps] 11 | 12 | source_file="res://icon.png" 13 | dest_files=[ "res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex" ] 14 | 15 | [params] 16 | 17 | compress/mode=0 18 | compress/lossy_quality=0.7 19 | compress/hdr_mode=0 20 | compress/bptc_ldr=0 21 | compress/normal_map=0 22 | flags/repeat=0 23 | flags/filter=true 24 | flags/mipmaps=false 25 | flags/anisotropic=false 26 | flags/srgb=2 27 | process/fix_alpha_border=true 28 | process/premult_alpha=false 29 | process/HDR_as_SRGB=false 30 | process/invert_color=false 31 | process/normal_map_invert_y=false 32 | stream=false 33 | size_limit=0 34 | detect_3d=true 35 | svg/scale=1.0 36 | -------------------------------------------------------------------------------- /sc/sound-test.scd: -------------------------------------------------------------------------------- 1 | ( 2 | a = Animatron(); 3 | s.waitForBoot{ 4 | Pdef(\a, Pbind(\amp, Pwhite(), \degree, Pwhite(0,7))).play; 5 | } 6 | ) 7 | 8 | a.sendMsg("/debug", true); 9 | a.sendMsg("/debug", false); 10 | a.sendMsg("/load", "circle"); 11 | a.sendMsg("/load", "canon-man"); 12 | a.sendMsg("/list/assets"); 13 | a.sendMsg("/free", "*"); 14 | ( 15 | a.sendMsg("/new", "ca", "circle"); 16 | a.sendMsg("/new", "mac", "canon-man"); 17 | // a.sendMsg("/color", "mac", 1,1,1); 18 | a.sendMsg("/frame", "mac", 300); 19 | a.sendMsg("/stop", "mac"); 20 | a.sendMsg("/sound", 1, "/scale", "ca", 0.0,1.0); 21 | a.sendMsg("/sound", 1, "/frame", "mac", 300.0,400.0); 22 | ) 23 | a.sendMsg("/sound/free", 1, "/scale", "ca"); 24 | a.sendMsg("/sound", 1, "/scale", "ca", 0.0,1.0); 25 | a.sendMsg("/sound/free", 1, "/frame", "mac"); 26 | a.sendMsg("/sound/free", 1); 27 | -------------------------------------------------------------------------------- /icons/ull.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="StreamTexture" 5 | path="res://.import/ull.svg-37c61327b2d32f8ed5f3a8adb33fc72d.stex" 6 | metadata={ 7 | "vram_texture": false 8 | } 9 | 10 | [deps] 11 | 12 | source_file="res://icons/ull.svg" 13 | dest_files=[ "res://.import/ull.svg-37c61327b2d32f8ed5f3a8adb33fc72d.stex" ] 14 | 15 | [params] 16 | 17 | compress/mode=0 18 | compress/lossy_quality=0.7 19 | compress/hdr_mode=0 20 | compress/bptc_ldr=0 21 | compress/normal_map=0 22 | flags/repeat=0 23 | flags/filter=true 24 | flags/mipmaps=false 25 | flags/anisotropic=false 26 | flags/srgb=2 27 | process/fix_alpha_border=true 28 | process/premult_alpha=false 29 | process/HDR_as_SRGB=false 30 | process/invert_color=false 31 | process/normal_map_invert_y=false 32 | stream=false 33 | size_limit=0 34 | detect_3d=true 35 | svg/scale=1.0 36 | -------------------------------------------------------------------------------- /icons/action.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="StreamTexture" 5 | path="res://.import/action.svg-deb8721e73a858622be9f72858aff2fe.stex" 6 | metadata={ 7 | "vram_texture": false 8 | } 9 | 10 | [deps] 11 | 12 | source_file="res://icons/action.svg" 13 | dest_files=[ "res://.import/action.svg-deb8721e73a858622be9f72858aff2fe.stex" ] 14 | 15 | [params] 16 | 17 | compress/mode=0 18 | compress/lossy_quality=0.7 19 | compress/hdr_mode=0 20 | compress/bptc_ldr=0 21 | compress/normal_map=0 22 | flags/repeat=0 23 | flags/filter=true 24 | flags/mipmaps=false 25 | flags/anisotropic=false 26 | flags/srgb=2 27 | process/fix_alpha_border=true 28 | process/premult_alpha=false 29 | process/HDR_as_SRGB=false 30 | process/invert_color=false 31 | process/normal_map_invert_y=false 32 | stream=false 33 | size_limit=0 34 | detect_3d=true 35 | svg/scale=1.0 36 | -------------------------------------------------------------------------------- /icons/ull-16.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="StreamTexture" 5 | path="res://.import/ull-16.png-71fa0dc090ddf935f1cd59124836de4b.stex" 6 | metadata={ 7 | "vram_texture": false 8 | } 9 | 10 | [deps] 11 | 12 | source_file="res://icons/ull-16.png" 13 | dest_files=[ "res://.import/ull-16.png-71fa0dc090ddf935f1cd59124836de4b.stex" ] 14 | 15 | [params] 16 | 17 | compress/mode=0 18 | compress/lossy_quality=0.7 19 | compress/hdr_mode=0 20 | compress/bptc_ldr=0 21 | compress/normal_map=0 22 | flags/repeat=0 23 | flags/filter=true 24 | flags/mipmaps=false 25 | flags/anisotropic=false 26 | flags/srgb=2 27 | process/fix_alpha_border=true 28 | process/premult_alpha=false 29 | process/HDR_as_SRGB=false 30 | process/invert_color=false 31 | process/normal_map_invert_y=false 32 | stream=false 33 | size_limit=0 34 | detect_3d=true 35 | svg/scale=1.0 36 | -------------------------------------------------------------------------------- /icons/ull-32.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="StreamTexture" 5 | path="res://.import/ull-32.png-b7e5ec678285ad754fc36dcef1e1ee70.stex" 6 | metadata={ 7 | "vram_texture": false 8 | } 9 | 10 | [deps] 11 | 12 | source_file="res://icons/ull-32.png" 13 | dest_files=[ "res://.import/ull-32.png-b7e5ec678285ad754fc36dcef1e1ee70.stex" ] 14 | 15 | [params] 16 | 17 | compress/mode=0 18 | compress/lossy_quality=0.7 19 | compress/hdr_mode=0 20 | compress/bptc_ldr=0 21 | compress/normal_map=0 22 | flags/repeat=0 23 | flags/filter=true 24 | flags/mipmaps=false 25 | flags/anisotropic=false 26 | flags/srgb=2 27 | process/fix_alpha_border=true 28 | process/premult_alpha=false 29 | process/HDR_as_SRGB=false 30 | process/invert_color=false 31 | process/normal_map_invert_y=false 32 | stream=false 33 | size_limit=0 34 | detect_3d=true 35 | svg/scale=1.0 36 | -------------------------------------------------------------------------------- /icons/ull-48.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="StreamTexture" 5 | path="res://.import/ull-48.png-3078c5a5eaa642339e4ec588ceb335d0.stex" 6 | metadata={ 7 | "vram_texture": false 8 | } 9 | 10 | [deps] 11 | 12 | source_file="res://icons/ull-48.png" 13 | dest_files=[ "res://.import/ull-48.png-3078c5a5eaa642339e4ec588ceb335d0.stex" ] 14 | 15 | [params] 16 | 17 | compress/mode=0 18 | compress/lossy_quality=0.7 19 | compress/hdr_mode=0 20 | compress/bptc_ldr=0 21 | compress/normal_map=0 22 | flags/repeat=0 23 | flags/filter=true 24 | flags/mipmaps=false 25 | flags/anisotropic=false 26 | flags/srgb=2 27 | process/fix_alpha_border=true 28 | process/premult_alpha=false 29 | process/HDR_as_SRGB=false 30 | process/invert_color=false 31 | process/normal_map_invert_y=false 32 | stream=false 33 | size_limit=0 34 | detect_3d=true 35 | svg/scale=1.0 36 | -------------------------------------------------------------------------------- /icons/ull-64.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="StreamTexture" 5 | path="res://.import/ull-64.png-80adc4edcdb1fd7e99ae24e7c78a4b89.stex" 6 | metadata={ 7 | "vram_texture": false 8 | } 9 | 10 | [deps] 11 | 12 | source_file="res://icons/ull-64.png" 13 | dest_files=[ "res://.import/ull-64.png-80adc4edcdb1fd7e99ae24e7c78a4b89.stex" ] 14 | 15 | [params] 16 | 17 | compress/mode=0 18 | compress/lossy_quality=0.7 19 | compress/hdr_mode=0 20 | compress/bptc_ldr=0 21 | compress/normal_map=0 22 | flags/repeat=0 23 | flags/filter=true 24 | flags/mipmaps=false 25 | flags/anisotropic=false 26 | flags/srgb=2 27 | process/fix_alpha_border=true 28 | process/premult_alpha=false 29 | process/HDR_as_SRGB=false 30 | process/invert_color=false 31 | process/normal_map_invert_y=false 32 | stream=false 33 | size_limit=0 34 | detect_3d=true 35 | svg/scale=1.0 36 | -------------------------------------------------------------------------------- /icons/ull-128.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="StreamTexture" 5 | path="res://.import/ull-128.png-0865dd289f1bea08db13d18ce0600ac5.stex" 6 | metadata={ 7 | "vram_texture": false 8 | } 9 | 10 | [deps] 11 | 12 | source_file="res://icons/ull-128.png" 13 | dest_files=[ "res://.import/ull-128.png-0865dd289f1bea08db13d18ce0600ac5.stex" ] 14 | 15 | [params] 16 | 17 | compress/mode=0 18 | compress/lossy_quality=0.7 19 | compress/hdr_mode=0 20 | compress/bptc_ldr=0 21 | compress/normal_map=0 22 | flags/repeat=0 23 | flags/filter=true 24 | flags/mipmaps=false 25 | flags/anisotropic=false 26 | flags/srgb=2 27 | process/fix_alpha_border=true 28 | process/premult_alpha=false 29 | process/HDR_as_SRGB=false 30 | process/invert_color=false 31 | process/normal_map_invert_y=false 32 | stream=false 33 | size_limit=0 34 | detect_3d=true 35 | svg/scale=1.0 36 | -------------------------------------------------------------------------------- /icons/ull-256.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="StreamTexture" 5 | path="res://.import/ull-256.png-9a0313a3dfac9419d880614fd03a5b5e.stex" 6 | metadata={ 7 | "vram_texture": false 8 | } 9 | 10 | [deps] 11 | 12 | source_file="res://icons/ull-256.png" 13 | dest_files=[ "res://.import/ull-256.png-9a0313a3dfac9419d880614fd03a5b5e.stex" ] 14 | 15 | [params] 16 | 17 | compress/mode=0 18 | compress/lossy_quality=0.7 19 | compress/hdr_mode=0 20 | compress/bptc_ldr=0 21 | compress/normal_map=0 22 | flags/repeat=0 23 | flags/filter=true 24 | flags/mipmaps=false 25 | flags/anisotropic=false 26 | flags/srgb=2 27 | process/fix_alpha_border=true 28 | process/premult_alpha=false 29 | process/HDR_as_SRGB=false 30 | process/invert_color=false 31 | process/normal_map_invert_y=false 32 | stream=false 33 | size_limit=0 34 | detect_3d=true 35 | svg/scale=1.0 36 | -------------------------------------------------------------------------------- /addons/gdosc/gdscript_oscsender_template.gd: -------------------------------------------------------------------------------- 1 | extends Object 2 | 3 | var oscsndr 4 | 5 | func _ready(): 6 | 7 | oscsndr = load("res://addons/gdosc/gdoscsender.gdns").new() 8 | # [mandatory] will send messages to ip:port 9 | oscsndr.setup( "127.0.0.1", 12000 ) 10 | # [mandatory] enabling emission 11 | oscsndr.start() 12 | 13 | func _process(delta): 14 | # creation of new message 15 | oscsndr.msg("/hello") 16 | # adding an object, will send its name 17 | oscsndr.add( self ) 18 | # adding a float 19 | oscsndr.add( delta ) 20 | # adding a Vector2 21 | oscsndr.add( Vector2( randf(), randf() ) ) 22 | # adding a Vector3 (position, scale, rotation, etc) 23 | oscsndr.add( Vector3( randf(), randf(), randf() ) ) 24 | # sending the message 25 | oscsndr.send() 26 | pass 27 | 28 | func _exit_tree ( ): 29 | # disable the sender, highly recommended! 30 | oscsndr.stop() 31 | -------------------------------------------------------------------------------- /commands/tutorial-cmds.osc: -------------------------------------------------------------------------------- 1 | def /tutorial/welcome 2 | /tutorial 3 | 4 | def /tutorial/index 5 | /editor/open docs/tutorial-index.osc 6 | 7 | def /tutorial/controls 8 | /editor/open docs/tutorial-controls.osc 9 | 10 | def /tutorial/commands 11 | /editor/open docs/tutorial-commands.osc 12 | 13 | # actors 14 | 15 | def /tutorial/actors 16 | /editor/open docs/tutorial-actors.osc 17 | 18 | def /tutorial/actor-attributes 19 | /editor/open docs/tutorial-actor-attributes.osc 20 | 21 | def /tutorial/actor-animation 22 | /editor/open docs/tutorial-actor-animation.osc 23 | 24 | def /tutorial/actor-multi 25 | /editor/open docs/tutorial-actor-multi.osc 26 | 27 | # utils 28 | 29 | def /tutorial/utils-rand 30 | /editor/open docs/tutorial-utils-rand.osc 31 | 32 | def /tutorial/utils-custom-cmds 33 | /editor/open docs/tutorial-utils-custom-cmds.osc 34 | -------------------------------------------------------------------------------- /docs/KeyboardShortcuts.md.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Keyboard Shortcuts 4 | 5 | ## Editor 6 | 7 | Keys | Description 8 | --------|------ 9 | `CTRL + H` | show this help and OSC commands. 10 | `CTRL + ENTER` | evaluate current block. 11 | `SHIFT + ENTER` | evaluate current line. 12 | `CTRL + E` | toggle editor and post window. 13 | `CTRL + SHIFT + E` | toggle editor. 14 | `CTRL + P` | toggle post window. 15 | `CTRL + SHIFT + P` | clear post window. 16 | `CTRL + O` | open a file in the text editor. 17 | `CTRL + S` | save the contents of the text editor to a file. 18 | `CTRL + D` | duplicate line. 19 | `CTRL + +` | increase font 20 | `CTRL + -` | increase font 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /sc/config-test.scd: -------------------------------------------------------------------------------- 1 | ( 2 | //////////////////////////////////////////////////////////// 3 | // Setup 4 | //////////////////////////////////////////////////////////// 5 | "setup.scd".loadRelative.first; 6 | ) 7 | 8 | n.sendMsg("/list/assets") 9 | n.sendMsg("/load/config", "res://config/config.osc"); 10 | n.sendMsg("/config"); 11 | n.sendMsg("/assets/path"); // report the current path 12 | n.sendMsg("/assets/path", "myanimations/"); 13 | n.sendMsg("/assets/path", "animations/"); 14 | n.sendMsg("/assets/path", "res://animations/"); // should do same as previous line 15 | n.sendMsg("/window/screen", 1); 16 | n.sendMsg("/window/position", 1500, 200); 17 | n.sendMsg("/window/center"); // works only on display 1 (?) 18 | n.sendMsg("/window/fullscreen", 1); 19 | n.sendMsg("/window/fullscreen", 0); 20 | n.sendMsg("/window/size", 640, -1); 21 | n.sendMsg("/window/top"); 22 | n.sendMsg("/window/top", false); 23 | n.sendMsg("/window/top", true); 24 | n.sendMsg("/window/top", 0); 25 | n.sendMsg("/window/top", 1); 26 | -------------------------------------------------------------------------------- /docs/tutorial-actor-animation.osc: -------------------------------------------------------------------------------- 1 | # ACTOR ANIMATION 2 | # --------------- 3 | # Some commands manage animation parameters. 4 | 5 | /free * 6 | /new box box-spitneat 7 | 8 | # For example, we can change the animation speed (1 being normal) 9 | 10 | /speed box 0.5 11 | 12 | /speed box 2 13 | 14 | /speed box 1 15 | 16 | # stop 17 | 18 | /stop box 19 | 20 | # set a frame (if the number is greater than the number for frames 21 | # it will wrap around 0) 22 | 23 | /frame box 8 24 | 25 | # play again 26 | 27 | /play box 28 | 29 | # play backwards 30 | 31 | /play/reverse box 32 | 33 | # play forwards 34 | 35 | /play box 36 | 37 | # stop the looping 38 | 39 | /noloop box 40 | 41 | # play once and vanish (it only hides the animation -- try evaluating it 42 | # multiple times 43 | 44 | /once box 45 | 46 | # in the next section we'll deal with multiple actors 47 | 48 | 49 | 50 | # next 51 | 52 | /tutorial/actor-multi 53 | 54 | # previous 55 | 56 | /tutorial/actor-attributes 57 | 58 | # up 59 | 60 | /tutorial/index 61 | -------------------------------------------------------------------------------- /RoutineNode.gd: -------------------------------------------------------------------------------- 1 | extends Timer 2 | 3 | # This is not the code for the Main.Routines node. 4 | # Main.Routines holds different instances of this script, which is a 5 | # single routine. 6 | 7 | var cmd : Array 8 | onready var main = get_parent().get_parent() 9 | onready var repeats = 0 setget setRepeats 10 | onready var iteration = 0 11 | 12 | func _ready(): 13 | wait_time = 1.0 14 | connect("timeout", self, "next") 15 | 16 | func setRepeats( inRepeats ): 17 | if inRepeats == "inf": 18 | repeats = 0 19 | return 20 | repeats = int(inRepeats) 21 | 22 | func next(): 23 | if len(cmd) <= 0: 24 | print("routine without commands: %s %s" % [name, cmd]) 25 | return 26 | 27 | # print("routine:%s iteration:%s/%s cmd:%s" % [name, iteration+1, repeats, cmd]) 28 | main.evalCommandList([cmd], null) 29 | 30 | if repeats != 0 and iteration >= (repeats - 1): 31 | print("routine ended after %s times: %s" % [iteration + 1, name]) 32 | iteration = 0 33 | remove_and_skip() 34 | return 35 | 36 | iteration = (iteration + 1) % max(repeats, 1) 37 | -------------------------------------------------------------------------------- /docs/tutorial-commands.osc: -------------------------------------------------------------------------------- 1 | # COMMANDS 2 | # -------- 3 | # The lines that you've been evaluating are called COMMANDS. 4 | 5 | # Everything in Animatron is controlled with commands. 6 | # The syntax for ALL commands is: 7 | 8 | /CMD TARGET ARGS... 9 | 10 | # the CMD is any string with a leading slash '/' 11 | # the TARGET is who are you commanding to do something 12 | # the ARGS is any number of parameters that we need to pass to the command (there 13 | # can be none) 14 | 15 | # to see a list of all the commands in the POST WINDOW (to the right of this text) evaluate 16 | 17 | /list/commands 18 | 19 | # see docs/Reference.md.html for descriptions. 20 | 21 | # We use commands to create and modify ACTORS, print info on the POST WINDOW, 22 | # and interact with the APPLICATION. 23 | # The list of commands is too long to cover them all, so we'll just show you some basic ones 24 | 25 | # For example, let's change de background color by passing it RGB values 26 | 27 | /bg 0.2 0.2 0.2 28 | 29 | # next 30 | 31 | /tutorial/actors 32 | 33 | # previous 34 | 35 | /tutorial/controls 36 | 37 | # up 38 | 39 | /tutorial/index 40 | -------------------------------------------------------------------------------- /sc/salonLetters.txt: -------------------------------------------------------------------------------- 1 | /load/alphabet 2 | 3 | /letters/spacing 0.2 4 | /letters/scale 1.2 5 | 6 | /write salon 7 | /create s letter-s 8 | 9 | /front l * 10 | /free * 11 | /list 12 | 13 | /rotate * 90 2 14 | 15 | /move * 0 -0.5 4 16 | 17 | 18 | ////////// 19 | 20 | /load/alphabet 21 | 22 | /create s letter-s 23 | /state/add s letter-s letter-a 24 | /state/add s letter-a letter-l 25 | /state/add s letter-l letter-o letter-a 26 | /state/add s letter-o letter-n 27 | /state/add s letter-n letter-s 28 | 29 | /load boomBig 30 | 31 | /def /let actor 32 | /create $actor letter-s 33 | /size $actor 0.333 34 | /rand /color/r $actor -0.6 -0.1 35 | /rand /color/g $actor -0.6 -0.1 36 | /rand /color/b $actor -0.6 -0.1 37 | /rand /position/x $actor 0.2 0.8 38 | /rand /position/y $actor 0.1 0.9 39 | /state/add $actor letter-s letter-s letter-a 40 | /state/add $actor letter-a letter-a letter-l 41 | /state/add $actor letter-l letter-l letter-o 42 | /state/add $actor letter-o letter-o letter-n 43 | /state/add $actor letter-n letter-n letter-s boomBig 44 | /state/add $actor boomBig letter-s 45 | 46 | /let a0 47 | 48 | /fade * 0 5 49 | /free * 50 | -------------------------------------------------------------------------------- /addons/gdosc/gdscript_oscreceiver_template.gd: -------------------------------------------------------------------------------- 1 | extends Object 2 | 3 | var oscrcv 4 | 5 | func _ready(): 6 | 7 | oscrcv = load("res://addons/gdosc/gdoscreceiver.gdns").new() 8 | # [optional] maximum number of messages in the buffer, default is 100 9 | oscrcv.max_queue( 20 ) 10 | # [optional] receiver will only keeps the "latest" message for each address 11 | oscrcv.avoid_duplicate( true ) 12 | # [mandatory] listening to port 14000 13 | oscrcv.setup( 14000 ) 14 | # [mandatory] starting the reception of messages 15 | oscrcv.start() 16 | 17 | func _process(delta): 18 | 19 | # check if there are pending messages 20 | while( oscrcv.has_message() ): 21 | # retrieval of the messages as a dictionary 22 | var msg = oscrcv.get_next() 23 | # printing the values, check console 24 | print( "address:", msg["address"] ) 25 | print( "typetag:", msg["typetag"] ) 26 | print( "from:" + str( msg["ip"] ) + ":" + str( msg["port"] ) ) 27 | print( "arguments: ") 28 | for i in range( 0, msg["arg_num"] ): 29 | print( "\t", i, " = ", msg["args"][i] ) 30 | pass 31 | 32 | func _exit_tree ( ): 33 | # disable the receiver, highly recommended! 34 | oscrcv.stop() 35 | -------------------------------------------------------------------------------- /docs/tutorial-utils-custom-cmds.osc: -------------------------------------------------------------------------------- 1 | # CUSTOM COMMANDS (DEFS) 2 | # ----------- 3 | # We can define custom commands with '/def'. 4 | # This is useful to combine simple commands into complex instructions. 5 | 6 | # The syntax for '/def' is 7 | 8 | /def /NEWCMD VARS... 9 | /CMD TARGET ARGS | $VARS ... 10 | /CMD TARGET ARGS | $VARS ... 11 | ... 12 | 13 | # NEWCMD: is the new command name - must include a leading slash '/' 14 | # VARS: (optional) are any number of strings that we can use in the embedded commands 15 | # CMD, TARGET and ARGS: any valid commands, including previously defined DEFs 16 | # they need to be tabluated (press tab on every new line) 17 | # VARS can be used in the commands with a leading $ 18 | 19 | # for exmaple, we can create an actor at a random position with a random 20 | # size and a random color 21 | 22 | /def /randactor actor anim 23 | /new $actor anim 24 | /rand /position/x $actor 0.1 0.9 25 | /rand /position/y $actor 0.1 0.9 26 | /rand /scale $actor 0.3 0.7 27 | /rand /color/r $actor 0 1 28 | /rand /color/g $actor 0 1 29 | /rand /color/b $actor 0 1 30 | -------------------------------------------------------------------------------- /docs/tutorial-actor-multi.osc: -------------------------------------------------------------------------------- 1 | # ACTOR MULTI 2 | # ----------- 3 | # Let's create a few squares 4 | 5 | /free * 6 | /new sq-red square 7 | /create sq-green square 8 | /create sq-white square 9 | 10 | # now let's randomize their scale, color and position (evaluate 11 | # the block as many times as needed until you see the 3 squares 12 | # overlapping each-other) 13 | 14 | /rand /scale sq* 0.3 0.7 15 | /rand /position/x sq* 0.3 0.7 16 | /rand /position/y sq* 0.3 0.7 17 | /rand /color/r sq-red 0.4 0.7 18 | /rand /color/g sq-green 0.4 0.7 19 | /color sq-white 1 1 1 20 | 21 | # using a WILDCARD '*' we can tell Animatron to send any 22 | # command to all actors who's name begin with 'sq'. 23 | 24 | # we can rearrange the order in which the actors are stacked 25 | # by choosing which one we want on top or below any other one 26 | 27 | # for example, let's put 'sqe' in front of 'sqi' 28 | 29 | /front sq-red sq-green 30 | 31 | # and back behind it 32 | 33 | /behind sq-red sq-green 34 | 35 | # or put 'sqe' on top of all 36 | 37 | /front sq-red * 38 | 39 | # or at the background 40 | 41 | /behind sq-red * 42 | 43 | 44 | 45 | 46 | # related 47 | 48 | /tutorial/utils-rand 49 | 50 | # previous 51 | 52 | /tutorial/actor-attributes 53 | 54 | # up 55 | 56 | /tutorial/index 57 | -------------------------------------------------------------------------------- /actions/oscillate.gd: -------------------------------------------------------------------------------- 1 | extends Action 2 | 3 | var oscPeriod := 1.0 # the period of one oscillation in seconds 4 | var oscRotRange : = 0.0 # between +/- this number of degrees 5 | var oscPosRange := Vector2(0.05, 0.05) # between +/- this (normalized) offset 6 | var oscPosFreq := Vector2(1, 2) # lissajous normalized frequencies (a, b) 7 | var oscPosPhase := 0.125 # the normalized phase (0-1 == 0-2pi) of the x component 8 | 9 | 10 | func _init(args : Array): 11 | if args.size() > 0: 12 | oscPeriod = float(args[0]) 13 | if args.size() > 1: 14 | oscRotRange = float(args[1]) 15 | if args.size() > 2: 16 | oscPosRange = Vector2(float(args[2]), float(args[2])) 17 | if args.size() > 3: 18 | oscPosRange.y = float(args[3]) 19 | if args.size() > 4: 20 | oscPosFreq = Vector2(float(args[4]), float(args[4])) 21 | if args.size() > 5: 22 | oscPosFreq.y = float(args[5]) 23 | if args.size() > 6: 24 | oscPosPhase = float(args[6]) 25 | 26 | 27 | func _physics_process(delta : float): 28 | var deltaRadians = TAU * delta / oscPeriod 29 | updateTime(deltaRadians) 30 | var pos = Vector2(sin(oscPosFreq.x * curTime + oscPosPhase * TAU), sin(oscPosFreq.y * curTime)) * oscPosRange 31 | offsetNode.position = pos * OS.window_size.y 32 | offsetNode.rotation = deg2rad(oscRotRange * sin(curTime)) 33 | -------------------------------------------------------------------------------- /SpeechBubble.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=4 format=2] 2 | 3 | [ext_resource path="res://SpeechBubble.gd" type="Script" id=1] 4 | 5 | [sub_resource type="DynamicFontData" id=1] 6 | font_path = "res://fonts/WalterTurncoat.ttf" 7 | 8 | [sub_resource type="DynamicFont" id=2] 9 | size = 18 10 | extra_spacing_bottom = -11 11 | font_data = SubResource( 1 ) 12 | 13 | [node name="SpeechBubble" type="Node2D"] 14 | script = ExtResource( 1 ) 15 | 16 | [node name="Anchor" type="Node2D" parent="."] 17 | 18 | [node name="ColorRect" type="ColorRect" parent="Anchor"] 19 | margin_bottom = 24.0 20 | __meta__ = { 21 | "_edit_use_anchors_": false 22 | } 23 | 24 | [node name="RichTextLabel" type="RichTextLabel" parent="Anchor"] 25 | margin_bottom = 24.0 26 | custom_colors/default_color = Color( 0, 0, 0, 1 ) 27 | custom_fonts/normal_font = SubResource( 2 ) 28 | bbcode_enabled = true 29 | fit_content_height = true 30 | scroll_active = false 31 | 32 | [node name="Timer" type="Timer" parent="."] 33 | one_shot = true 34 | 35 | [node name="Tween" type="Tween" parent="."] 36 | 37 | [connection signal="resized" from="Anchor/RichTextLabel" to="." method="_on_RichTextLabel_resized"] 38 | [connection signal="timeout" from="Timer" to="." method="_on_Timer_timeout"] 39 | [connection signal="tween_all_completed" from="Tween" to="." method="_on_Tween_tween_all_completed"] 40 | -------------------------------------------------------------------------------- /MetaNode.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=6 format=2] 2 | 3 | [ext_resource path="res://Animation.gd" type="Script" id=1] 4 | [ext_resource path="res://MetaNode.gd" type="Script" id=2] 5 | 6 | [sub_resource type="Shader" id=4] 7 | code = "shader_type canvas_item; 8 | 9 | uniform vec3 uAddColor = vec3(0, 0, 0); 10 | uniform bool uSelected = false; 11 | 12 | void fragment() { 13 | 14 | COLOR = texture(TEXTURE, UV); 15 | COLOR.rgb += uAddColor; 16 | if (uSelected) { 17 | if (COLOR.a < 1.0) COLOR.rgb = vec3(1); 18 | } 19 | }" 20 | 21 | [sub_resource type="ShaderMaterial" id=2] 22 | resource_local_to_scene = true 23 | shader = SubResource( 4 ) 24 | shader_param/uAddColor = Vector3( 0, 0, 0 ) 25 | shader_param/uSelected = false 26 | 27 | [sub_resource type="SpriteFrames" id=3] 28 | animations = [ ] 29 | 30 | [node name="MetaNode" type="KinematicBody2D"] 31 | position = Vector2( 500, 300 ) 32 | script = ExtResource( 2 ) 33 | 34 | [node name="Offset" type="Node2D" parent="."] 35 | 36 | [node name="Animation" type="AnimatedSprite" parent="Offset"] 37 | material = SubResource( 2 ) 38 | frames = SubResource( 3 ) 39 | script = ExtResource( 1 ) 40 | 41 | [node name="CollisionShape2D" type="CollisionShape2D" parent="."] 42 | 43 | [node name="Tween" type="Tween" parent="."] 44 | 45 | [connection signal="animation_finished" from="Offset/Animation" to="Offset/Animation" method="_on_Animation_animation_finished"] 46 | -------------------------------------------------------------------------------- /sc/walkers.scd: -------------------------------------------------------------------------------- 1 | ( 2 | //////////////////////////////////////////////////////////// 3 | // Setup 4 | //////////////////////////////////////////////////////////// 5 | "setup.scd".loadRelative.first; 6 | ) 7 | 8 | x.("/load om-walk-e") 9 | 10 | ( 11 | x.("/new bg bg-black"); 12 | x.("/size bg 2"); 13 | x.("/color bg 0.5 0.5 0.5"); 14 | x.("/behind bg *"); 15 | ) 16 | 17 | ( 18 | ~numActors = 20; 19 | ~numActors.do{ arg i; 20 | x.("/create om% om-walk-e".format(i)); 21 | x.("/frame om% %".format(i, 50.rand)); 22 | x.("/position om% % %".format(i, 1.0.rand, rrand(0.2,1))); 23 | x.("/color om% % % %".format(i, rrand(0, 0.5), rrand(0, 0.5), rrand(0, 0.5))); 24 | }; 25 | ) 26 | 27 | ( 28 | n.sendMsg("/def", "/update actor speed size rate", 29 | "/fade $actor 0 2", 30 | "/wait 2", 31 | "/fade $actor 1 2", 32 | "/speed $actor $speed", 33 | "/size $actor $size", // add time argument (2) at the end 34 | "/action $actor wrap 0 $rate 0") 35 | ) 36 | x.("/update om5 2 0.5 3") 37 | 38 | ( 39 | Tdef(\anim, { 40 | 16.do{ arg outer; 41 | ~numActors.do{ arg i; 42 | var size = exprand(0.5,6) * 1; 43 | var speed = size.linexp(0.5,8, 2, 0.25) * 1; 44 | x.("/update om% % % %".format(i, speed, size, speed * size * 0.15)); 45 | exprand(0.2,0.5).wait; 46 | }; 47 | 1.wait; 48 | }; 49 | }).play 50 | ) 51 | 52 | Tdef(\anim).stop 53 | x.("/fade om* 0 4") 54 | x.("/free *") 55 | 56 | x.("/list/assets") 57 | 58 | -------------------------------------------------------------------------------- /actions/wrap.gd: -------------------------------------------------------------------------------- 1 | extends Action 2 | 3 | var moveDir := 0.0 # the normalized direction of motion (angle in degrees) 4 | var moveSpeed := 1.0 # the speed of movement 5 | var rotSpeed := 0.0 # the speed of rotation 6 | const margin := 0.1 # extra "safety" zone around the viewport for wrapping 7 | 8 | 9 | func _init(args : Array): 10 | if args.size() > 0: 11 | moveDir = float(args[0]) 12 | if args.size() > 1: 13 | moveSpeed = float(args[1]) 14 | if args.size() > 2: 15 | rotSpeed = float(args[2]) 16 | 17 | 18 | func _physics_process(delta : float): 19 | updateTime(delta) 20 | var offset = Vector2(moveSpeed, 0).rotated(deg2rad(moveDir)) * delta 21 | var newPos : Vector2 = actor.position + offset * OS.window_size.y 22 | actor.rotation_degrees = wrapf(actor.rotation_degrees + rotSpeed * delta, -180, 180) 23 | var animNode = offsetNode.get_node("Animation") 24 | var animName = animNode.animation 25 | var halfSize = animNode.frames.get_frame(animName, 0).get_size() / 2 * actor.scale 26 | halfSize = halfSize.rotated(deg2rad(actor.rotation_degrees)).abs() 27 | var animPos : Vector2 = animNode.position * actor.scale; 28 | animPos = animPos.rotated(deg2rad(actor.rotation_degrees)) 29 | var extra : float = OS.window_size.y * margin 30 | 31 | actor.position = Vector2( 32 | wrapf(newPos.x, 33 | -halfSize.x - animPos.x - extra, 34 | OS.window_size.x + halfSize.x - animPos.x + extra), 35 | wrapf(newPos.y, 36 | -halfSize.y - animPos.y - extra, 37 | OS.window_size.y + halfSize.y - animPos.y + extra)) 38 | -------------------------------------------------------------------------------- /sc/setup.scd: -------------------------------------------------------------------------------- 1 | ( 2 | //////////////////////////////////////////////////////////// 3 | // Setup 4 | //////////////////////////////////////////////////////////// 5 | var separateBySpaces; 6 | OSCdef(\listActorsReply, { arg msg; 7 | "Actors: %".format(msg[1..]).postln; 8 | }, "/list/actors/reply"); 9 | OSCdef(\listAnimsReply, { arg msg; 10 | "Available animations:\n\t%".format(join(msg[1..], "\n\t")).postln; 11 | }, "/list/anims/reply"); 12 | OSCdef(\listAssetsReply, { arg msg; 13 | "Available assets:\n\t%".format(join(msg[1..], "\n\t")).postln; 14 | }, "/list/assets/reply"); 15 | OSCdef(\errorReply, { arg msg; 16 | "Error: %".format(msg[1]).postln; 17 | }, "/error/reply"); 18 | OSCdef(\statusReply, { arg msg; 19 | "Status: %".format(msg[1]).postln; 20 | }, "/status/reply"); 21 | n = NetAddr("localhost", 56101); 22 | separateBySpaces = { arg str; 23 | // This regex isn't perfect, but works 24 | // reasonably well for most of my cases... 25 | var regex = '"(.+?)"|(?:([^"]+?)(?=\\s))|(?:(?<=\\s)([^"]+))'.asString; 26 | var arr = str.asString.findRegexp(regex).flop.last.clump(4).collect{ |x| 27 | x.drop(1).collect(_.stripWhiteSpace) 28 | }.flatten.reject(_.isEmpty); 29 | if (arr.isEmpty) { arr = [ str ] }; 30 | arr 31 | }; 32 | 33 | x = { arg ...args; 34 | if (args.notEmpty) { 35 | var arr = separateBySpaces.(args[0]); 36 | if (arr.notEmpty) { 37 | arr = arr ++ args[1..]; 38 | n.sendMsg(*arr); 39 | arr 40 | }; 41 | } 42 | }; 43 | 44 | "Animatron ready.\nUse:\n\tn.sendMsg(\"/load\", \"asset\")\nor:\n\tx.(\"/load asset\")" 45 | ) 46 | -------------------------------------------------------------------------------- /docs/tutorial-actor-attributes.osc: -------------------------------------------------------------------------------- 1 | # CHANGING ACTOR ATTRIBUTES 2 | # --------------------------- 3 | # Actors can be manipulated to change their appearance an behaviour. 4 | # For a list of commands to change them, see the 'ACTOR' section in 5 | 6 | /list/commands 7 | 8 | # we'll show just a few of them and let you explore the rest 9 | 10 | # first, create a couple of actors 11 | 12 | /create box box-spitneat 13 | 14 | # POSITION 15 | # -------- 16 | # We can change the position of any actor with 17 | 18 | /position/x box 0.2 19 | 20 | # or 21 | /position/y box 0.8 22 | 23 | #or 24 | /position box 0.5 0.2 25 | 26 | # the center of the screen is at x:0.5 y:0.5, 0 being left and top, and 27 | # 1 being bottom and right 28 | 29 | /position box 0.5 0.5 30 | 31 | # SCALE 32 | # ---- 33 | # let's shrink it to half its size (1 is normal) 34 | 35 | /scale box 0.5 36 | 37 | # or make it bigger 38 | 39 | /scale box 1.5 40 | 41 | # ROTATION 42 | # -------- 43 | # we rotate the actor along it's pivot point by degrees 44 | 45 | /rotate box 90 46 | 47 | /rotate box -90 48 | 49 | # COLOR 50 | # ----- 51 | # the color is changed by specifying 3 color values (RED, GREEN and BLUE) 52 | 53 | /color/r box 1 54 | 55 | /color/g box 0.5 56 | 57 | /color/b box 0.7 58 | 59 | /color box 0.1 0.7 0.3 60 | 61 | /color box 0.3 0.2 0.6 62 | 63 | # back to the original color 64 | 65 | /color box 0 0 0 66 | 67 | # in the next section we'll cover animation manipulation 68 | 69 | 70 | 71 | # next 72 | 73 | /tutorial/actor-animation 74 | 75 | # previous 76 | 77 | /tutorial/actors 78 | 79 | # up 80 | 81 | /tutorial/index 82 | -------------------------------------------------------------------------------- /docs/tutorial-actors.osc: -------------------------------------------------------------------------------- 1 | # ACTORS 2 | # ------ 3 | # An ACTOR plays an image sequence (ANIM). 4 | 5 | # First we need to load the ANIM into memory with the '/load' command. 6 | # The argument is the ASSET (file) name. 7 | 8 | /load box-spitneat 9 | 10 | # to see a list of all the assets use 11 | 12 | /list/assets 13 | 14 | # now we can create an actor that plays the animation we just loaded. 15 | # 'box' is the actor NAME, and 'box-spitneat' the name of the ASSET that 16 | # we want it to play 17 | 18 | /create box box-spitneat 19 | 20 | # we can do both steps (load an create) at once with 21 | 22 | /new box box-spitneat 23 | 24 | # or by evaluating a block 25 | 26 | /load box-spitneat 27 | /create box box-spitneat 28 | 29 | # WARINING: long image sequences take a while to load, and the application 30 | # will freeze while loading, so it's better to pre-load the assets first, then 31 | # they'll be available without having to reload them, even if no actors 32 | # are using them. 33 | 34 | # to remove an actor from the stage 35 | 36 | /free box 37 | 38 | # more than one actor can use the same animation 39 | 40 | /create box-1 box-spitneat 41 | 42 | /create box-2 box-spitneat 43 | 44 | # You probably won't see it very well because they are one on top of the other. 45 | # We would need to move the one on top to see both of them. 46 | # In the next section we cover how to do this -- and other things. 47 | 48 | # but first, let's clear the stage using a wildcard '*', which is a way to 49 | # quickly access all actors on stage 50 | 51 | /free * 52 | 53 | 54 | # next 55 | 56 | /tutorial/actor-attributes 57 | 58 | # previous 59 | 60 | /tutorial/commands 61 | 62 | # up 63 | 64 | /tutorial/index 65 | -------------------------------------------------------------------------------- /Logger.gd: -------------------------------------------------------------------------------- 1 | extends Node 2 | 3 | enum { 4 | LOG_LEVEL_FATAL, 5 | LOG_LEVEL_ERROR, 6 | LOG_LEVEL_WARNING, 7 | LOG_LEVEL_INFO, 8 | LOG_LEVEL_DEBUG, 9 | LOG_LEVEL_VERBOSE, 10 | } 11 | 12 | const levelNames = ["FATAL", "ERROR", "WARNING", "INFO", "DEBUG", "VERBOSE"] 13 | 14 | onready var level = LOG_LEVEL_INFO setget setLevel, getLevel 15 | var target : TextEdit 16 | 17 | 18 | func setTarget( inTarget ): 19 | target = inTarget 20 | 21 | func setLevel( inLevel ): 22 | level = inLevel 23 | logMsg("Log level set to: %s" % [levelNames[level]]) 24 | 25 | func getLevel(): 26 | return level 27 | 28 | func setLevelFatal(): 29 | setLevel(LOG_LEVEL_FATAL) 30 | 31 | func setLevelError(): 32 | setLevel(LOG_LEVEL_ERROR) 33 | 34 | func setLevelWarning(): 35 | setLevel(LOG_LEVEL_WARNING) 36 | 37 | func setLevelInfo(): 38 | setLevel(LOG_LEVEL_INFO) 39 | 40 | func setLevelDebug(): 41 | setLevel(LOG_LEVEL_DEBUG) 42 | 43 | func setLevelVerbose(): 44 | setLevel(LOG_LEVEL_VERBOSE) 45 | 46 | func fatal( msg ): 47 | logMsg("[FATAL]: %s" % [msg], true) 48 | 49 | func error( msg ): 50 | if level < LOG_LEVEL_ERROR: 51 | return 52 | logMsg("[ERROR]: %s" % [msg], true) 53 | 54 | func warn( msg ): 55 | if level < LOG_LEVEL_WARNING: 56 | return 57 | logMsg("[WARNING]: %s" % [msg], true) 58 | 59 | func info( msg ): 60 | if level < LOG_LEVEL_INFO: 61 | return 62 | logMsg("[INFO]: %s" % [msg], true) 63 | 64 | func debug( msg ): 65 | if level < LOG_LEVEL_DEBUG: 66 | return 67 | logMsg("[DEBUG]: %s" % [msg]) 68 | 69 | func verbose( msg ): 70 | if level < LOG_LEVEL_VERBOSE: 71 | return 72 | logMsg("[VERBOSE]: %s" % [msg]) 73 | 74 | func logMsg( msg, post=false ): 75 | print(msg) 76 | if target != null and post: 77 | target.append(msg) 78 | 79 | func logDict( dict, post=false ): 80 | for key in dict: 81 | logMsg("%s:%s" % [key, dict[key]], post) 82 | -------------------------------------------------------------------------------- /SpeechBubble.gd: -------------------------------------------------------------------------------- 1 | extends Node2D 2 | 3 | onready var textNode = $Anchor/RichTextLabel 4 | onready var textBg = $Anchor/ColorRect 5 | onready var padding = 16 6 | onready var fadetime = 0 7 | onready var offset = Vector2(0, -96) 8 | 9 | # Called when the node enters the scene tree for the first time. 10 | func _ready(): 11 | visible = false 12 | # setText("ALO Blah\nBLAH alO") 13 | 14 | 15 | func setText(text, wait = 3): 16 | visible = true 17 | $Timer.wait_time = wait 18 | $Timer.stop() 19 | text = "[center]" + text 20 | textNode.bbcode_text = text 21 | resizeBubble() 22 | 23 | $Tween.remove_all() 24 | # $Tween.interpolate_property(textNode, "modulate", Color(0,0,0,1), Color(0,0,0,0), fadetime, Tween.TRANS_EXPO) 25 | # $Tween.interpolate_property(textBg, "modulate", textBg.color, Color(0,0,0,0), fadetime) 26 | $Tween.start() 27 | 28 | 29 | # distribute text on even lines 30 | func formatText(): 31 | print("TODO: format text in even lines") 32 | print("TODO: multiline") 33 | var words = textNode.text.count(" ") + 1 34 | # print("words: ", words) 35 | 36 | 37 | func resizeBubble(): 38 | formatText() 39 | var textSize = textNode.get_font("normal_font").get_string_size(textNode.text) 40 | textNode.margin_right = textSize.x + padding 41 | textNode.margin_bottom = textSize.y * textNode.get_line_count() + padding 42 | 43 | 44 | func _on_Timer_timeout(): 45 | queue_free() 46 | visible = false 47 | 48 | 49 | func _on_Tween_tween_all_completed(): 50 | $Timer.start() 51 | 52 | 53 | func _on_RichTextLabel_resized(): 54 | textBg.margin_right = textNode.margin_right 55 | textBg.margin_bottom = textNode.margin_bottom 56 | offset.x = textBg.margin_right / (-2) 57 | 58 | var animNode = get_node("../Offset/Animation") 59 | if animNode: 60 | var texSize = animNode.frames.get_frame(animNode.get_animation(), 0).get_size() 61 | offset.y = texSize.y * -0.55 - textNode.margin_bottom + animNode.position.y 62 | 63 | $Anchor.set_position(offset) 64 | -------------------------------------------------------------------------------- /Letters.gd: -------------------------------------------------------------------------------- 1 | # A class to manage typing with images 2 | class_name Letters 3 | extends Node 4 | 5 | 6 | onready var main = get_parent() 7 | # spacing is a multiplier of actor width 8 | var spacing = 1 9 | var scale = 1 10 | var msg = "" 11 | var alphabet := { 12 | "a": "letter-a", 13 | "b": "letter-b", 14 | "c": "letter-c", 15 | "d": "letter-d", 16 | "e": "letter-e", 17 | "f": "letter-f", 18 | "g": "letter-g", 19 | "h": "letter-h", 20 | "i": "letter-i", 21 | "j": "letter-j", 22 | "k": "letter-k", 23 | "l": "letter-l", 24 | "m": "letter-m", 25 | "n": "letter-n", 26 | "o": "letter-o", 27 | "p": "letter-p", 28 | "q": "letter-q", 29 | "r": "letter-r", 30 | "s": "letter-s", 31 | "t": "letter-t", 32 | "u": "letter-u", 33 | "v": "letter-v", 34 | "w": "letter-w", 35 | "x": "letter-x", 36 | "y": "letter-y", 37 | "z": "letter-z", 38 | } 39 | 40 | 41 | # Called when the node enters the scene tree for the first time. 42 | func _ready(): 43 | # loadAlphabet() 44 | pass # Replace with function body. 45 | 46 | 47 | # Called every frame. 'delta' is the elapsed time since the previous frame. 48 | #func _process(delta): 49 | # pass 50 | 51 | 52 | func loadAlphabet(inArgs, sender=null): 53 | for letter in alphabet.keys(): 54 | main.evalOscCommand("/load", [alphabet[letter]], null) 55 | 56 | 57 | func setLetter(inArgs, sender=null): 58 | var letter = inArgs[0] 59 | var source = inArgs[1] 60 | alphabet[letter] = source 61 | 62 | 63 | func write(inArgs, sender=null): 64 | msg = inArgs[0] 65 | for i in msg.length(): 66 | var letter = msg[i] 67 | var pos = i * spacing 68 | print(letter + ": " + alphabet[letter]) 69 | main.evalOscCommand("/create", [letter, alphabet[letter]], null) 70 | main.evalOscCommand("/position", [letter, pos, 0.5], null) 71 | 72 | 73 | func setSpacing(inArgs, sender=null): 74 | spacing = inArgs[0] as float 75 | write([msg], null) 76 | 77 | 78 | func setScale(inArgs, sender=null): 79 | print("TODO SCALE " + str(inArgs[0])) 80 | for x in msg: 81 | main.evalOscCommand("/scale", [x, inArgs[0]], null) 82 | -------------------------------------------------------------------------------- /CustomCommands.gd: -------------------------------------------------------------------------------- 1 | extends Node 2 | class_name CustomCommands 3 | 4 | var commands = {} 5 | 6 | 7 | func defineCommand(defCommand : String, defArgs : Array, commandList : Array): 8 | commands[defCommand] = { args = defArgs, cmds = commandList } 9 | 10 | 11 | func loadCommandFile(path): 12 | var file = File.new() 13 | file.open(path, File.READ) 14 | if not file.is_open(): 15 | print("Unable to open command defs file: " + path) 16 | return false 17 | var lineNum = 1 18 | var defCommand 19 | var defArgs = [] 20 | var commandList = [] 21 | while file.is_open() && !file.eof_reached(): 22 | var filteredLine = [] 23 | # @todo Replace when Godot Array gets a filter() function (4.0) 24 | for elem in file.get_csv_line(" "): 25 | if !elem.empty(): 26 | filteredLine.append(elem.strip_edges()) 27 | if !file.eof_reached() && !filteredLine.empty(): 28 | if filteredLine[0][0] == '#': 29 | # Ignore comment lines that start with '#' 30 | continue 31 | if filteredLine[0] == "def" && filteredLine.size() > 1: 32 | if defCommand && !commandList.empty(): 33 | defineCommand(defCommand, defArgs, commandList) 34 | defCommand = filteredLine[1] 35 | defArgs = filteredLine.slice(2, -1) 36 | commandList = [] 37 | print("%d: Defining '%s' with args: %s" % [lineNum, defCommand, defArgs]) 38 | else: 39 | print("%d: [%s] %s" % [lineNum, defCommand, filteredLine]) 40 | commandList.append(filteredLine) 41 | lineNum += 1 42 | file.close() 43 | if defCommand && !commandList.empty(): 44 | defineCommand(defCommand, defArgs, commandList) 45 | 46 | for k in commands: 47 | print("Command: ", k, "\n", commands[k]) 48 | return true 49 | 50 | 51 | func hasCommand(address): 52 | return commands.has(address) 53 | 54 | 55 | func getCommand(address): 56 | return commands[address] 57 | 58 | 59 | func getCommandSummary() -> String: 60 | var cmdList := [] 61 | for k in commands: 62 | cmdList.push_back("%-12s\t%s" % [k, (commands[k].args as PoolStringArray).join(' ')]) 63 | return (cmdList as PoolStringArray).join('\n') 64 | 65 | -------------------------------------------------------------------------------- /PostTextEdit.gd: -------------------------------------------------------------------------------- 1 | extends TextEdit 2 | 3 | var main 4 | 5 | var shortcutsHelp = "\nKeyboard shortcuts:\n" \ 6 | + "\t CTRL + H - show this Help and OSC commands.\n" \ 7 | + "\t CTRL + ENTER - evaluate block.\n" \ 8 | + "\t SHIFT + ENTER - evaluate line.\n" \ 9 | + "\t CTRL + E - toggle editor and post window.\n" \ 10 | + "\t CTRL + SHIFT + E - toggle editor.\n" \ 11 | + "\t CTRL + P - toggle post window.\n" \ 12 | + "\t CTRL + SHIFT + P - clear post window.\n" \ 13 | + "\t CTRL + O - open a file in the text editor.\n" \ 14 | + "\t CTRL + S - save text editor contents to a file.\n" \ 15 | + "\t CTRL + D - duplicate line.\n" \ 16 | + "\t CTRL + + - Increase font.\n" \ 17 | + "\t CTRL + - - Decrease font.\n" 18 | 19 | var help = "================================================================\n" \ 20 | + "To see the tutorial type:\n" \ 21 | + "\n" \ 22 | + "/tutorial\n" \ 23 | + "\n" \ 24 | + "and evaluate by hitting CTRL + ENTER while the cursor is on that line.\n" \ 25 | + "\n" \ 26 | + "See the docs by evaluating:\n" \ 27 | + "\n" \ 28 | + "/help\n" \ 29 | + shortcutsHelp \ 30 | + "================================================================\n\n" 31 | 32 | # Called when the node enters the scene tree for the first time. 33 | func _ready(): 34 | main = get_parent() 35 | set_text(help) 36 | 37 | func _on_PostTextEdit_gui_input(event): 38 | if event.is_action_pressed("increase_editor_font", true): 39 | increaseFont() 40 | elif event.is_action_pressed("decrease_editor_font", true): 41 | decreaseFont() 42 | 43 | func append( msg ): 44 | set_text("%s\n%s" % [get_text(), msg]) 45 | scroll_vertical = INF 46 | 47 | func printDict( dict ): 48 | for key in dict.keys(): 49 | append("%s: %s" % [key, dict[key]]) 50 | 51 | func clear(): 52 | set_text("") 53 | 54 | func help(): 55 | append(shortcutsHelp) 56 | 57 | func increaseFont(): 58 | var font = get("custom_fonts/font") 59 | font.set_size(font.get_size() + 1) 60 | main.post("font size: %d" % [font.get_size()]) 61 | 62 | func decreaseFont(): 63 | var font = get("custom_fonts/font") 64 | font.set_size(font.get_size() - 1) 65 | main.post("font size: %d" % [font.get_size()]) 66 | 67 | func setFontSize( size ): 68 | get("custom_fonts/font").set_size(size) 69 | -------------------------------------------------------------------------------- /sc/cube-routines.scd: -------------------------------------------------------------------------------- 1 | ( 2 | //////////////////////////////////////////////////////////// 3 | // Setup 4 | //////////////////////////////////////////////////////////// 5 | "setup.scd".loadRelative.first; 6 | ) 7 | 8 | ( 9 | // Create the actor setup commands 10 | n.sendMsg("/def", "/updown actor holdTime", 11 | "/speed $actor 1", 12 | "/frame $actor 0", 13 | "/noloop $actor", 14 | "/wait $holdTime", 15 | "/speed $actor -1", 16 | "/noloop $actor", 17 | ); 18 | n.sendMsg("/def", "/make-c actor red green blue offsetx offsety period holdTime", 19 | "/create $actor cube-unshrink-h", 20 | "/noloop $actor", 21 | "/color $actor $red $green $blue", 22 | "/size $actor 0.5", 23 | "/position $actor $offsetx $offsety", 24 | "/routine $actor inf $period /updown $actor $holdTime" 25 | ); 26 | x.("/load cube-unshrink-h"); 27 | ) 28 | 29 | ( 30 | // Algorithmically create and animate a bunch of cubes 31 | ~num = 15; 32 | x.("/routine/free/all"); 33 | x.("/free *"); 34 | ~num.do{ arg i; 35 | var rgb = rrand(-0.3, 0.3 ! 3); 36 | var row = (i % 3) - 1; 37 | var col = 1 - (i div: 3 - 1); 38 | var posx = 0.12 * col + 0.5; 39 | var posy = 0.25 * row + 0.5 + (0.105 * col); 40 | // Try different modulus, from 2 to ~num 41 | var period = (i % ~num).linexp(0, ~num-1, 0.5, 8); 42 | x.("/make-c c% % % % % % % %".format(i, rgb[0], rgb[1], rgb[2], posx, posy, period, period / 2).debug("cmd")); 43 | } 44 | ) 45 | 46 | 47 | 48 | x.("/action c* wander 0.2 0.5") 49 | x.("/rotate c* 90 1") 50 | { ~num.do{ arg i; x.("/size c% 0.5 2".format(i)); 0.25.wait; } }.fork 51 | { ~num.do{ arg i; x.("/rotate c% 90 2".format(i)); 0.25.wait; } }.fork 52 | { ~num.do{ arg i; x.("/fade c% 0 8".format(i)); 0.25.wait; } }.fork 53 | 54 | 55 | 56 | 57 | 58 | ( 59 | // An explicit version 60 | n.sendMsg("/def", "/make-cubes", 61 | "/make-c c1 0.2 0.2 0.2 0.62 0.355 12 6", 62 | "/make-c c2 -0.2 -0.2 -0.2 0.62 0.605 6 3", 63 | "/make-c c3 0.0 0.0 0.0 0.62 0.855 4 2", 64 | "/make-c c4 0.2 -0.2 -0.2 0.5 0.25 3 2", 65 | "/make-c c5 -0.2 0.2 -0.2 0.5 0.5 2 1", 66 | "/make-c c6 0.2 0.2 -0.2 0.5 0.75 1 0.5", 67 | "/make-c c7 -0.2 -0.2 0.2 0.38 0.145 0.666667 0.3333", 68 | "/make-c c8 0.2 -0.2 0.2 0.38 0.395 0.5 0.25", 69 | "/make-c c9 -0.2 0.2 0.2 0.38 0.645 0.333333 0.1666667" 70 | ); 71 | ) 72 | 73 | x.("/make-cubes") 74 | -------------------------------------------------------------------------------- /sc/Animatron/Animatron.sc: -------------------------------------------------------------------------------- 1 | Animatron { 2 | var <>osc; 3 | var <>oscReply; 4 | var <>config; 5 | var <>actors; 6 | var <>assets; 7 | 8 | *new { | addr="localhost", port=56101 | 9 | ^super.new.init(addr, port) 10 | } 11 | 12 | init { | addr="localhost", port=56101 | 13 | var separateBySpaces; 14 | 15 | this.osc = NetAddr(addr, port); 16 | 17 | OSCdef(\listActorsReply, { arg msg; 18 | "Actors: %".format(msg[1..]).postln; 19 | oscReply = msg.debug("oscdef"); 20 | }, "/list/actors/reply"); 21 | OSCdef(\listAnimsReply, { arg msg; 22 | "Available animations:\n\t%".format(join(msg[1..], "\n\t")).postln; 23 | }, "/list/anims/reply"); 24 | OSCdef(\listAssetsReply, { arg msg; 25 | "Available assets:\n\t%".format(join(msg[1..], "\n\t")).postln; 26 | }, "/list/assets/reply"); 27 | OSCdef(\errorReply, { arg msg; 28 | "Error: %".format(msg[1]).postln; 29 | oscReply = msg; 30 | }, "/error/reply"); 31 | OSCdef(\statusReply, { arg msg; 32 | "Status: %".format(msg[1]).postln; 33 | }, "/status/reply"); 34 | // OSCdef(\oscReply, { arg msg; 35 | // msg.debug("oscreply"); 36 | // }, "/error/reply"); 37 | 38 | // n = NetAddr("localhost", 56101); 39 | // separateBySpaces = { arg str; 40 | // // This regex isn't perfect, but works 41 | // // reasonably well for most of my cases... 42 | // var regex = '"(.+?)"|(?:([^"]+?)(?=\\s))|(?:(?<=\\s)([^"]+))'.asString; 43 | // var arr = str.asString.findRegexp(regex).flop.last.clump(4).collect{ |x| 44 | // x.drop(1).collect(_.stripWhiteSpace) 45 | // }.flatten.reject(_.isEmpty); 46 | // if (arr.isEmpty) { arr = [ str ] }; 47 | // arr 48 | // }; 49 | 50 | // x = { arg ...args; 51 | // if (args.notEmpty) { 52 | // var arr = separateBySpaces.(args[0]); 53 | // if (arr.notEmpty) { 54 | // arr = arr ++ args[1..]; 55 | // n.sendMsg(*arr); 56 | // arr 57 | // }; 58 | // } 59 | // }; 60 | 61 | // "Animatron ready.\nUse:\n\tn.sendMsg(\"/load\", \"asset\")\nor:\n\tx.(\"/load asset\")".postln; 62 | 63 | // x.("/load/config", Platform.userHomeDir++"/work/toplap-20221005-asturies/asturies-config.osc"); 64 | ^this.osc; 65 | } 66 | 67 | // doesNotUnderstand { |selector ...args| 68 | // // super.findRespondingMethodFor(selector); 69 | 70 | // } 71 | } -------------------------------------------------------------------------------- /sc/dot.sc: -------------------------------------------------------------------------------- 1 | ( 2 | //////////////////////////////////////////////////////////// 3 | // Setup 4 | //////////////////////////////////////////////////////////// 5 | "setup.scd".loadRelative.first; 6 | ) 7 | 8 | n.sendMsg("/help"); 9 | n.sendMsg("/list/assets"); 10 | n.sendMsg("/load", "dot-p-front"); 11 | n.sendMsg("/load", "dot-p-back"); 12 | n.sendMsg("/load", "dot-p-speak"); 13 | n.sendMsg("/load", "dot-p-speak-front"); 14 | n.sendMsg("/load", "dot-p-speak-right"); 15 | n.sendMsg("/load", "dot-p-01"); 16 | n.sendMsg("/load", "dot-p-02"); 17 | n.sendMsg("/load", "dot-p-03"); 18 | n.sendMsg("/load", "dot-p-04"); 19 | n.sendMsg("/load", "dot-p-07"); 20 | n.sendMsg("/load", "dot-p-08"); 21 | n.sendMsg("/load", "dot-p-09"); 22 | n.sendMsg("/load", "dot-p-10"); 23 | n.sendMsg("/load", "dot-p-11"); 24 | n.sendMsg("/load", "dot-p-12"); 25 | n.sendMsg("/load", "dot-p-13"); 26 | n.sendMsg("/load", "dot-p-14"); 27 | n.sendMsg("/load", "dot-p-15"); 28 | n.sendMsg("/load", "dot-p-16"); 29 | n.sendMsg("/load", "dot-p-17"); 30 | n.sendMsg("/load", "dot-p-18"); 31 | n.sendMsg("/load", "dot-p-20"); 32 | n.sendMsg("/create", "dot", "dot-p-01"); 33 | n.sendMsg("/create", "dot", "dot-p-02"); 34 | n.sendMsg("/create", "dot", "dot-p-03"); 35 | n.sendMsg("/create", "dot", "dot-p-04"); 36 | n.sendMsg("/create", "dot", "dot-p-07"); 37 | n.sendMsg("/create", "dot", "dot-p-08"); 38 | n.sendMsg("/create", "dot", "dot-p-10"); 39 | n.sendMsg("/create", "dot", "dot-p-11"); 40 | n.sendMsg("/create", "dot", "dot-p-12"); 41 | n.sendMsg("/create", "dot", "dot-p-13"); 42 | n.sendMsg("/create", "dot", "dot-p-14"); 43 | n.sendMsg("/create", "dot", "dot-p-15"); 44 | n.sendMsg("/create", "dot", "dot-p-16"); 45 | n.sendMsg("/create", "dot", "dot-p-17"); 46 | n.sendMsg("/create", "dot", "dot-p-18"); 47 | n.sendMsg("/create", "dot", "dot-p-20"); 48 | n.sendMsg("/create", "dot", "dot-p-speak-front"); 49 | ( 50 | n.sendMsg("/create", "dot", "dot-p-02"); 51 | n.sendMsg("/create", "dot", "dot-p-04"); 52 | n.sendMsg("/speed", "dot", 12/30); 53 | n.sendMsg("/speed", "dot", 0.40); 54 | n.sendMsg("/scale", "dot", 4.0); 55 | ) 56 | 57 | n.sendMsg("/color", "dot", 0.5,0.1,0); 58 | n.sendMsg("/stop", "dot"); 59 | n.sendMsg("/play", "dot"); 60 | n.sendMsg("/frame", "dot", 0); 61 | n.sendMsg("/position", "dot", 0.25, 0.5, 6); 62 | n.sendMsg("/position", "dat", 0.5, 0.6); 63 | n.sendMsg("/fliph", "dot"); -------------------------------------------------------------------------------- /Animation.gd: -------------------------------------------------------------------------------- 1 | extends AnimatedSprite 2 | 3 | var random = false setget setRandom 4 | var loopStart := 0 setget setStart 5 | var loopEnd := -1 setget setEnd 6 | var reverse := false 7 | var nextAnim := 0 8 | 9 | func _ready(): 10 | connect("frame_changed", self, "_on_Animation_frame_changed") 11 | 12 | func _on_Animation_animation_finished(): 13 | if not reverse: 14 | frame = loopStart 15 | else: 16 | frame = loopEnd 17 | 18 | # we need to manually stop the animation if the last frame of the range is 19 | # not the last frame the animation (loopEnd != last frame) 20 | if not frames.get_animation_loop(animation): 21 | stop() 22 | frame = loopEnd if not reverse else loopStart 23 | 24 | func _on_Animation_frame_changed(): 25 | # Logger.debug("play:%s frame:%s loop:%s start:%s end:%s speed:%s" % [is_playing(), frame, loop, loopStart, loopEnd, frames.get_animation_speed(animation)]) 26 | if random: 27 | set_frame( randi() % frames.get_frame_count( animation ) ) 28 | 29 | if loopEnd < 0: 30 | loopEnd = frames.get_frame_count(animation) - 1 31 | 32 | # Logger.debug("loop end: %s" % [reverse]) 33 | if not reverse and frame > loopEnd: 34 | emit_signal("animation_finished") 35 | if reverse and frame < loopStart or frame > loopEnd: 36 | emit_signal("animation_finished") 37 | 38 | func setSpeed(speed): 39 | if float(speed) < 0: 40 | reverse = true 41 | else: 42 | reverse = false 43 | play("", reverse) 44 | set_speed_scale(abs(float(speed))) 45 | 46 | func loop(loop): 47 | frames.set_animation_loop(animation, loop) 48 | play("", reverse) 49 | 50 | func setRandom(newRandom): 51 | random = newRandom 52 | if random and not is_playing(): 53 | play() 54 | 55 | func setRange(startFrame, endFrame): 56 | loopStart = int(startFrame) 57 | loopEnd = int(endFrame) 58 | reset() 59 | 60 | func setStart(startFrame): 61 | loopStart = int(startFrame) 62 | 63 | func setEnd(endFrame): 64 | loopEnd = int(endFrame) 65 | 66 | func reset(): 67 | Logger.debug("frame: %d st:%s end:%s rev:%s" % [frame, loopStart, loopEnd, reverse]) 68 | if frame < loopStart and not reverse: 69 | frame = loopStart 70 | elif frame >= loopEnd and not reverse: 71 | frame = loopStart 72 | elif frame > loopEnd and reverse: 73 | frame = loopEnd 74 | elif frame <= loopStart and reverse: 75 | frame = loopEnd 76 | Logger.debug("frame: %s" % [frame]) 77 | -------------------------------------------------------------------------------- /commands/init.osc: -------------------------------------------------------------------------------- 1 | def /init 2 | /load/defs midi 3 | 4 | # create and select an actor 5 | def /createsel actor anim 6 | /create $actor $anim 7 | /select $actor 8 | 9 | # load and create an actor 10 | def /new actor anim 11 | /load $anim 12 | /create $actor $anim 13 | 14 | # load, create and select an actor 15 | def /newsel actor anim 16 | /deselect 17 | /new $actor $anim 18 | /select $actor 19 | 20 | def /fast actor amount 21 | /speed $actor $amount 22 | 23 | def /center actor 24 | /position $actor 0.5 0.5 25 | 26 | def /left actor amout 27 | /move/x $actor -$amount 28 | 29 | def /right actor amout 30 | /move/x $actor $amount 0 31 | 32 | # play actor in reverse 33 | def /play/rev actor 34 | /play $actor true 35 | 36 | # play the animation once and vanish 37 | def /once actor 38 | /oneshot $actor 0 39 | 40 | # play the animation once and stop on the last frame 41 | def /noloop actor 42 | /oneshot $actor 1 43 | 44 | # visibility envelope 45 | def /adsr actor atk dec sus sust rel 46 | /fade $actor 0 47 | /fade $actor 1 $atk 48 | /wait $atk 49 | /fade $actor $sus $dec 50 | /wait $dec 51 | /wait $sust 52 | /fade $actor 0 $rel 53 | 54 | # visibility envelope 55 | def /ar actor atk rel 56 | /fade $actor 0 57 | /fade $actor 1 $atk 58 | /wait $atk 59 | /fade $actor 0 $rel 60 | 61 | ################################################################################ 62 | # colors 63 | ################################################################################ 64 | def /black actor 65 | /color $actor 0 0 0 66 | 67 | def /white actor 68 | /color $actor 1 1 1 69 | 70 | def /color/gray actor value 71 | /color $actor $value $value $value 72 | 73 | def /gray actor value 74 | /color $actor $value $value $value 75 | 76 | def /red actor value 77 | /color/r $actor $value 78 | 79 | def /green actor value 80 | /color/g $actor $value 81 | 82 | def /blue actor value 83 | /color/b $actor $value 84 | 85 | ################################################################################ 86 | # random 87 | ################################################################################ 88 | def /rand/pos actor 89 | /rand /position/x $actor 0 1 90 | /rand /position/y $actor 0 1 91 | 92 | # FIX: not working with wildcards -- dunno why 93 | def /rand/gray actor min max 94 | /rand /color/gray $actor $min $max 95 | -------------------------------------------------------------------------------- /icons/action.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /sc/dots.scd: -------------------------------------------------------------------------------- 1 | ( 2 | //////////////////////////////////////////////////////////// 3 | // Setup 4 | //////////////////////////////////////////////////////////// 5 | "setup.scd".loadRelative.first; 6 | ) 7 | 8 | x.("/load dot-explode") 9 | 10 | ( 11 | x.("/new bg bg-black"); 12 | x.("/size bg 2"); 13 | x.("/color bg 0.5 0.5 0.5"); 14 | x.("/behind bg *"); 15 | ) 16 | 17 | ( 18 | n.sendMsg("/def", "/createDot actor startFrame rate size posx posy", 19 | "/create $actor dot-explode", 20 | "/frame $actor $startFrame", 21 | "/speed $actor $rate", 22 | "/size $actor $size", 23 | "/onframe/free $actor 2 /frame $actor", 24 | "/onframe $actor 2 /frame $actor 0", 25 | "/position $actor $posx $posy" 26 | ); 27 | ) 28 | 29 | ( 30 | ~numActors = 30; 31 | ~numActors.do{ arg i; 32 | var t = i * 2pi / ~numActors; 33 | var posx = cos(t) * 0.4 + 0.5; 34 | var posy = sin(t) * 0.4 + 0.5; 35 | var size = i.linexp(0, ~numActors-1, 0.25, 2).debug("size"); 36 | x.("/createDot dot% % % % % %".format(i, 2.rand, rrand(0.75,1.333) * 0.25, size, posx, posy)); 37 | }; 38 | ) 39 | 40 | ( 41 | n.sendMsg("/def", "/update actor posx posy fadeTime", 42 | "/position $actor $posx $posy $fadeTime", 43 | ); 44 | ) 45 | x.("/update dot5 0.2 0.4 2") 46 | 47 | ( 48 | Tdef(\anim, { 49 | inf.do{ arg outer; 50 | var freq = rrand(0.5, 3); 51 | var offset = 2pi.rand; 52 | var fadeTime = rrand(1.0, 3); 53 | var elapsedTime = 0; 54 | ~numActors.do{ arg i; 55 | var t = i * 2pi / ~numActors * freq; 56 | var posx = cos(t + offset) * i.linexp(0, ~numActors-1, 0.02, 0.4) + 0.5; 57 | var posy = sin(t + offset) * i.linexp(0, ~numActors-1, 0.02, 0.4) + 0.5; 58 | var size = rrand(0.75,1.333) * 0.25; 59 | var fadeTime = i.linexp(0, ~numActors-1, 2, 0.5); 60 | // posx = (1 - posx).wrap(0.25, 0.75); 61 | // posy = (1 - posy).wrap(0.25, 0.75); 62 | x.("/update dot% % % % %".format(i, posx, posy, fadeTime)); 63 | elapsedTime = elapsedTime + 0.025; 64 | 0.025.wait; 65 | }; 66 | (fadeTime - elapsedTime).max(0).wait; 67 | }; 68 | }).play 69 | ) 70 | 71 | ( 72 | ~numActors.do{ arg i; 73 | var startFrame = 0; 74 | var oldEndFrame = 3; 75 | var endFrame = 2; 76 | var actor = "dot" ++ i; 77 | var numFrames = endFrame - startFrame + 1; 78 | x.("/frame % %".format(actor, rrand(startFrame, endFrame - 1))); 79 | x.("/onframe/free % % /frame %".format(actor, oldEndFrame, actor)); 80 | x.("/onframe/free % % /frame %".format(actor, endFrame, actor)); 81 | x.("/onframe % % /frame % %".format(actor, endFrame, actor, startFrame)); 82 | }; 83 | ) 84 | 85 | Tdef(\anim).stop 86 | x.("/free dot*") 87 | 88 | x.("/list/assets") 89 | x.("/list/anims") 90 | x.("/list") 91 | -------------------------------------------------------------------------------- /icons/ull.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 16 | 36 | 38 | 43 | 51 | 56 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /Helper.gd: -------------------------------------------------------------------------------- 1 | extends Object 2 | class_name Helper 3 | 4 | 5 | ############################################################ 6 | # Global (static) helper functions 7 | ############################################################ 8 | 9 | static func getGlobalPath(projectPath : String) -> String: 10 | var path = "" 11 | if OS.has_feature("editor"): 12 | # Running from an editor binary. 13 | # `path` will contain the absolute path to `hello.txt` located in the project root. 14 | if not projectPath.is_abs_path(): 15 | projectPath = "res://".plus_file(projectPath) 16 | path = ProjectSettings.globalize_path(projectPath) 17 | else: 18 | # Running from an exported project. 19 | # `path` will contain the absolute path to `hello.txt` next to the executable. 20 | # This is *not* identical to using `ProjectSettings.globalize_path()` with a `res://` path, 21 | # but is close enough in spirit. 22 | if projectPath.begins_with("res://"): 23 | projectPath = projectPath.substr("res://".length()) 24 | path = ( 25 | OS.get_executable_path().get_base_dir().plus_file(projectPath) 26 | if projectPath.is_rel_path() 27 | else projectPath 28 | ) 29 | return path 30 | 31 | 32 | # Return a path relative to a default directory, if you provide 33 | # a simple filename without any other path elements 34 | # getPathWithDefaultDir("hello.txt", "test") -> "test/hello.txt" 35 | # getPathWithDefaultDir("another/hello.txt", "test") -> "another/hello.txt" 36 | static func getPathWithDefaultDir(path : String, defaultDir : String) -> String: 37 | if path.get_file() == path: 38 | path = defaultDir.plus_file(path) 39 | return getGlobalPath(path) 40 | 41 | 42 | # Get a bool argument 43 | static func getBool(arg) -> bool: 44 | if typeof(arg) == TYPE_STRING: 45 | return arg.to_lower() == "true" or bool(int(arg)) 46 | else: 47 | return bool(arg) 48 | 49 | 50 | # Get a Vector2 argument from a single float/int value, 51 | # an array, or a string of two floats separated by a comma 52 | static func getVector2(arg) -> Vector2: 53 | var value : Vector2 54 | if typeof(arg) == TYPE_STRING: 55 | var parts = arg.split_floats(',') 56 | if not parts.empty(): 57 | value = Vector2(parts[0], parts[0]) 58 | if parts.size() > 1: 59 | value.y = parts[1] 60 | elif typeof(arg) == TYPE_ARRAY: 61 | if not arg.empty(): 62 | value = Vector2(arg[0], arg[0]) 63 | if arg.size() > 1: 64 | value.y = arg[1] as float 65 | else: 66 | value = Vector2(float(arg), float(arg)) 67 | return value 68 | 69 | static func linlin(val, inmin, inmax, outmin, outmax): 70 | return (float(val - inmin) / float(inmax - inmin)) * float(outmax - outmin) + outmin 71 | 72 | static func getViewSize() -> Vector2: 73 | return Vector2( 74 | ProjectSettings.get_setting("display/window/size/width"), 75 | ProjectSettings.get_setting("display/window/size/height") 76 | ) 77 | -------------------------------------------------------------------------------- /AudioInputPlayer.gd: -------------------------------------------------------------------------------- 1 | extends AudioStreamPlayer 2 | 3 | signal sound_changed(band, amp) 4 | 5 | const VU_COUNT = 4 6 | const FREQ_MAX = 11050.0 7 | 8 | const WIDTH = 400 9 | const HEIGHT = 100 10 | 11 | const MIN_DB = 60 12 | 13 | var spectrum 14 | var band 15 | var amp 16 | 17 | var cmds : Array 18 | 19 | func update(): 20 | #warning-ignore:integer_division 21 | # print("---") 22 | var w = WIDTH / VU_COUNT 23 | var prev_hz = 0 24 | for i in range(1, VU_COUNT+1): 25 | var hz = i * FREQ_MAX / VU_COUNT; 26 | var magnitude: float = spectrum.get_magnitude_for_frequency_range(prev_hz, hz).length() if spectrum else 0 27 | var amp = clamp((MIN_DB + linear2db(magnitude)) / MIN_DB, 0, 1) 28 | var height = amp * HEIGHT 29 | prev_hz = hz 30 | if amp > 0: 31 | emit_signal("sound_changed", i, amp) 32 | # print(i, ":", amp) 33 | 34 | 35 | func _process(_delta): 36 | update() 37 | 38 | func _on_AudioInputPlayer_sound_changed(band, amp): 39 | if not get_parent(): 40 | return 41 | var main = get_parent() 42 | Logger.verbose("band:%s amp:%s" % [band, amp]) 43 | for cmd in cmds: 44 | for key in cmd.keys(): 45 | # need for a check to avoid crash on removing cmds from band dictionaries 46 | if not cmd[key].has("addr"): return 47 | var addr = cmd[key]["addr"] 48 | var actor = cmd[key]["actor"].name 49 | var rangemin = cmd[key]["range"][0] 50 | var rangemax = cmd[key]["range"][1] 51 | var value = Helper.linlin(amp, 0.0, 1.0, rangemin, rangemax) 52 | main.evalOscCommand(addr, [actor, value], null) 53 | 54 | func _ready(): 55 | spectrum = AudioServer.get_bus_effect_instance(0,0) 56 | for i in range(VU_COUNT): 57 | cmds.append({}) 58 | connect("sound_changed", self, "_on_AudioInputPlayer_sound_changed") 59 | 60 | func addSoundCmd( band, cmd, actor, minVal, maxVal ): 61 | var key = getKey(cmd, actor) 62 | cmds[min(int(band), len(cmds)-1)][key] = {"addr": cmd, "actor": actor, "range": [float(minVal), float(maxVal)]} 63 | print(cmds) 64 | 65 | # removes all commands for BAND 66 | func removeAllSoundCmds( band ): 67 | cmds[min(band, len(cmds)-1)] = {} 68 | print(cmds) 69 | 70 | # removes only the CMD for ACTOR in BAND 71 | func removeSoundCmd( band, cmd, actor ): 72 | var key = getKey(cmd, actor) 73 | cmds[min(int(band), len(cmds)-1)].erase(key) 74 | print(cmds) 75 | 76 | func getKey(cmd, actor): 77 | return "%s/%s" % [cmd, actor.name] 78 | 79 | func eventToOsc(cmdsList, value, inmin, inmax): 80 | if not get_parent(): 81 | return 82 | var main = get_parent() 83 | for addr in cmdsList.keys(): 84 | if not addr.begins_with("/"): 85 | addr = "/" + addr 86 | var minval = cmdsList[addr][0] 87 | var maxval = cmdsList[addr][1] 88 | value = $Helper.linlin(value, inmin, inmax, minval, maxval) 89 | Logger.verbose("sending msg from MIDI: %s %f" % [addr, value]) 90 | main.evalOscCommand(addr, [name, value], null) 91 | -------------------------------------------------------------------------------- /Config.gd: -------------------------------------------------------------------------------- 1 | extends Node 2 | class_name Config 3 | 4 | onready var cmds : CustomCommands = get_parent().find_node("CustomCommands") 5 | onready var osc = get_parent().find_node("OscInterface") 6 | const defaultConfigDir := "config/" 7 | var defaultMidiFile := "commands/midi.osc" 8 | var animationAssetPath := Helper.getGlobalPath("animations/") setget animPathSet 9 | var allowRemoteClients := true 10 | 11 | # Called when the node enters the scene tree for the first time. 12 | func _ready(): 13 | Logger.info("User data dir: %s" % [OS.get_user_data_dir()]) 14 | 15 | 16 | ############################################################ 17 | # Helpers 18 | ############################################################ 19 | func animPathSet(path): 20 | animationAssetPath = Helper.getGlobalPath(path) 21 | 22 | 23 | ############################################################ 24 | # OSC config commands 25 | ############################################################ 26 | func loadConfig(args, sender): 27 | # print(cmds) 28 | if args.size() != 1: 29 | osc.reportError("loadConfig expects one argument", sender) 30 | return 31 | var configFile = Helper.getPathWithDefaultDir(args[0], defaultConfigDir) 32 | if cmds.loadCommandFile(configFile): 33 | osc.reportStatus("Loaded config from '%s'" % configFile, sender) 34 | else: 35 | osc.reportError("Couldn't open config file: '%s'" % [configFile], sender) 36 | 37 | 38 | func moveWindowToScreen(screen, sender): 39 | OS.set_current_screen(int(screen[0])) 40 | 41 | 42 | func setWindowPosition(pos, sender): 43 | Logger.debug("window position: %s" % [pos]) 44 | OS.set_window_position(Vector2(pos[0], pos[1])) 45 | 46 | 47 | func setWindowSize(args, sender): 48 | Logger.debug("window size: %s" % [args]) 49 | var size = Vector2(args[0], args[1]) 50 | var vp = get_viewport() 51 | var aspect = vp.size.x / vp.size.y 52 | if size.y < 0: 53 | size.y = size.x / aspect 54 | elif size.x < 0: 55 | size.x = size.y * aspect 56 | OS.set_window_size(size) 57 | 58 | 59 | func centerWindow(args, sender): 60 | if not args.empty(): 61 | osc.reportError("centerWindow expects no arguments", sender) 62 | return 63 | OS.set_window_position((OS.get_screen_size(OS.get_current_screen()) * 0.5) - (OS.get_window_size() * 0.5)) 64 | 65 | 66 | func fullscreen(args, sender): 67 | var fs = true if args.empty() else Helper.getBool(args[0]) 68 | OS.set_window_fullscreen(fs) 69 | 70 | 71 | func windowAlwaysOnTop(args, sender): 72 | var ot = true if args.empty() else Helper.getBool(args[0]) 73 | OS.set_window_always_on_top(ot) 74 | 75 | 76 | # This method sets the path, but also reports it back if run without args 77 | func setAnimationAssetPath(args, sender): 78 | var msg = "Asset path: " 79 | if args.size() == 1: 80 | msg = "Set " + msg 81 | self.animationAssetPath = args[0] 82 | if Directory.new().dir_exists(animationAssetPath): 83 | osc.reportStatus(msg + animationAssetPath, sender) 84 | else: 85 | osc.reportError("Invalid animation path: '%s'" % animationAssetPath, sender) 86 | 87 | 88 | func setAppRemote(args, sender): 89 | allowRemoteClients = true if args.empty() else Helper.getBool(args[0]) 90 | 91 | -------------------------------------------------------------------------------- /docs/markdeep/slides.css: -------------------------------------------------------------------------------- 1 | /* Request lanscape from the printer/browser */ 2 | @page { 3 | size: landscape; 4 | margin-bottom: 100px; 5 | } 6 | 7 | .md div.title { 8 | margin-top: 250px; 9 | margin-bottom: 40px; 10 | font-size: 50px; 11 | font-weight: bold; 12 | counter-increment: page; 13 | } 14 | 15 | .md div.subtitle { 16 | font-size: 30px; 17 | } 18 | 19 | .md hr { 20 | page-break-before: always; 21 | } 22 | 23 | body#md { 24 | width: 900px; 25 | max-width: 100%; 26 | font-size: 25px; 27 | padding: 40px; 28 | counter-reset: page; 29 | --accent-color: #39C; /* #F61;*/ 30 | } 31 | 32 | /* Disable section numbering */ 33 | .md h1:before {content: ""} 34 | .md h2:before {content: ""} 35 | 36 | .md svg.diagram { 37 | zoom: 150%; 38 | } 39 | 40 | /* Sections become presentation sections */ 41 | .md h1, .md .nonumberh1 { 42 | page-break-before: always; 43 | width: 1100px; 44 | text-align: center; 45 | margin-top: 20px; 46 | margin-bottom: 20px; 47 | padding-top: 300px; 48 | padding-bottom: 20px; 49 | border: none; 50 | color: var(--accent-color); 51 | margin-left: -100px; 52 | margin-right:-100px; 53 | font-size: 50px; 54 | counter-increment: page; 55 | } 56 | 57 | /* Subsections become slides */ 58 | .md h2, .md .nonumberh2 { 59 | page-break-before: always; 60 | width: 1100px; 61 | text-align: center; 62 | background: var(--accent-color); 63 | color: #FFF; 64 | margin-top: 100px; 65 | margin-bottom: 50px; 66 | padding-top: 20px; 67 | padding-bottom: 20px; 68 | border: none; 69 | margin-left: -100px; 70 | margin-right:-100px; 71 | font-size: 34px; 72 | counter-increment: page; 73 | } 74 | 75 | @media print{ 76 | footer { 77 | position: fixed; 78 | bottom: 0; 79 | right: 0; 80 | color: #AAA; 81 | font-size: 50%; 82 | } 83 | } 84 | 85 | @media screen { 86 | footer { display: none } 87 | 88 | .md h1, .md .nonumberh1 { 89 | /* Show slide divisions */ 90 | border-top: 1px solid black; 91 | } 92 | } 93 | 94 | /* Hide HR in printing */ 95 | @media print { 96 | .md hr { 97 | visibility: hidden; 98 | } 99 | } 100 | 101 | .md hr { 102 | counter-increment: page; 103 | } 104 | 105 | .md code { 106 | font-size: 100%; 107 | } 108 | 109 | .md pre.listing { 110 | font-size: 80%; 111 | border: 1px solid #CCC; 112 | } 113 | 114 | .md strong, .md b { 115 | color: var(--accent-color); 116 | } 117 | 118 | .md table { 119 | font-size: 100%; 120 | background-color: #eee; 121 | } 122 | 123 | .md table.table td { 124 | border: none; 125 | } 126 | 127 | .md table.table th { 128 | background-color: black; 129 | color: white; 130 | border: none; 131 | font-family: Verdana,Helvetica,Arial,sans-serif; 132 | } 133 | 134 | .md table.table th + th { 135 | border-left: 3px solid white; 136 | } 137 | 138 | .md table.table td + td { 139 | border-left: 3px solid white; 140 | } 141 | 142 | .md table.table tr:nth-child(n) { 143 | background-color: none; 144 | } 145 | 146 | -------------------------------------------------------------------------------- /Main.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=16 format=2] 2 | 3 | [ext_resource path="res://OscInterface.gd" type="Script" id=1] 4 | [ext_resource path="res://CustomCommands.gd" type="Script" id=2] 5 | [ext_resource path="res://Config.gd" type="Script" id=3] 6 | [ext_resource path="res://Midi.gd" type="Script" id=4] 7 | [ext_resource path="res://Letters.gd" type="Script" id=5] 8 | [ext_resource path="res://AudioInputPlayer.gd" type="Script" id=6] 9 | [ext_resource path="res://OscTextEdit.gd" type="Script" id=7] 10 | [ext_resource path="res://fonts/mononoki_Bold.ttf" type="DynamicFontData" id=8] 11 | [ext_resource path="res://transparent_bg.tres" type="StyleBox" id=9] 12 | [ext_resource path="res://PostTextEdit.gd" type="Script" id=10] 13 | [ext_resource path="res://OscSender.gd" type="Script" id=11] 14 | [ext_resource path="res://Main.gd" type="Script" id=13] 15 | 16 | [sub_resource type="AudioStreamMicrophone" id=1] 17 | 18 | [sub_resource type="DynamicFont" id=2] 19 | size = 22 20 | outline_color = Color( 0, 0, 0, 1 ) 21 | font_data = ExtResource( 8 ) 22 | 23 | [sub_resource type="DynamicFont" id=3] 24 | font_data = ExtResource( 8 ) 25 | 26 | [node name="Main" type="Node2D"] 27 | script = ExtResource( 13 ) 28 | 29 | [node name="OscInterface" type="Node" parent="."] 30 | script = ExtResource( 1 ) 31 | 32 | [node name="CustomCommands" type="Node" parent="."] 33 | script = ExtResource( 2 ) 34 | 35 | [node name="Config" type="Node" parent="."] 36 | script = ExtResource( 3 ) 37 | 38 | [node name="Actors" type="YSort" parent="."] 39 | sort_enabled = false 40 | 41 | [node name="Midi" type="Node" parent="."] 42 | script = ExtResource( 4 ) 43 | 44 | [node name="Letters" type="Node" parent="."] 45 | script = ExtResource( 5 ) 46 | 47 | [node name="AudioInputPlayer" type="AudioStreamPlayer" parent="."] 48 | stream = SubResource( 1 ) 49 | script = ExtResource( 6 ) 50 | 51 | [node name="OscTextEdit" type="TextEdit" parent="."] 52 | visible = false 53 | margin_right = 40.0 54 | margin_bottom = 40.0 55 | grow_horizontal = 0 56 | grow_vertical = 0 57 | size_flags_horizontal = 10 58 | size_flags_vertical = 10 59 | custom_colors/current_line_color = Color( 0, 0, 0, 0.0784314 ) 60 | custom_fonts/font = SubResource( 2 ) 61 | custom_styles/normal = ExtResource( 9 ) 62 | highlight_current_line = true 63 | syntax_highlighting = true 64 | show_line_numbers = true 65 | wrap_enabled = true 66 | caret_block_mode = true 67 | caret_blink = true 68 | script = ExtResource( 7 ) 69 | 70 | [node name="PostTextEdit" type="TextEdit" parent="."] 71 | margin_right = 40.0 72 | margin_bottom = 40.0 73 | size_flags_horizontal = 10 74 | size_flags_vertical = 10 75 | custom_fonts/font = SubResource( 3 ) 76 | custom_styles/read_only = ExtResource( 9 ) 77 | custom_styles/normal = ExtResource( 9 ) 78 | readonly = true 79 | wrap_enabled = true 80 | script = ExtResource( 10 ) 81 | 82 | [node name="OpenFileDialog" type="FileDialog" parent="."] 83 | margin_left = 203.0 84 | margin_top = 92.0 85 | margin_right = 803.0 86 | margin_bottom = 492.0 87 | window_title = "Open a File" 88 | mode = 0 89 | 90 | [node name="SaveFileDialog" type="FileDialog" parent="."] 91 | margin_left = 203.0 92 | margin_top = 92.0 93 | margin_right = 803.0 94 | margin_bottom = 492.0 95 | 96 | [node name="OscSender" type="Node" parent="."] 97 | script = ExtResource( 11 ) 98 | 99 | [node name="Routines" type="Node" parent="."] 100 | 101 | [connection signal="gui_input" from="OscTextEdit" to="OscTextEdit" method="_on_OscTextEdit_gui_input"] 102 | [connection signal="visibility_changed" from="OscTextEdit" to="OscTextEdit" method="_on_OscTextEdit_visibility_changed"] 103 | [connection signal="gui_input" from="PostTextEdit" to="PostTextEdit" method="_on_PostTextEdit_gui_input"] 104 | [connection signal="text_changed" from="PostTextEdit" to="PostTextEdit" method="_on_PostTextEdit_text_changed"] 105 | [connection signal="file_selected" from="OpenFileDialog" to="." method="_on_OpenFileDialog_file_selected"] 106 | [connection signal="file_selected" from="SaveFileDialog" to="." method="_on_SaveFileDialog_file_selected"] 107 | -------------------------------------------------------------------------------- /MetaNode.gd: -------------------------------------------------------------------------------- 1 | extends KinematicBody2D 2 | 3 | var stateMachine : Dictionary 4 | var frameCmds : Dictionary 5 | var finishCmds : Dictionary 6 | var isVisibleEnd := true setget setVisibleEnd 7 | var frameCmdsIndex = 0 8 | # frame that triggers the next command in the frameCmds 9 | var trigFrame = 0 10 | var main 11 | 12 | 13 | func _ready(): 14 | var animNode = get_node("Offset/Animation") 15 | animNode.connect("frame_changed", self, "_on_Animation_frame_changed") 16 | animNode.connect("animation_finished", self, "_on_Animation_animation_finished") 17 | 18 | func _on_Animation_frame_changed(): 19 | main = get_parent() 20 | if main == null: 21 | return 22 | main = main.get_parent() 23 | var anim = get_node("Offset/Animation").get_animation() 24 | var frame = get_node("Offset/Animation").get_frame() 25 | if frameCmds.has(frame): 26 | sendCmds(frame) 27 | 28 | func _on_Animation_animation_finished(): 29 | for cmd in finishCmds: 30 | main.evalOscCommand(finishCmds[cmd][0], finishCmds[cmd].slice(1,-1), null) 31 | 32 | set_visible(isVisibleEnd) 33 | nextState() 34 | 35 | func resetFrameCmds(): 36 | frameCmdsIndex = 0 37 | 38 | func addCmdToFrameCmds( inframe, cmd ): 39 | var anim = get_node("Offset/Animation").get_animation() 40 | # print("%s:%s %s:%s" % [typeof frame, frame, typeof cmd, cmd]) 41 | var numframes = get_node("Offset/Animation").get_sprite_frames().get_frame_count(anim) 42 | # print("%s/%s: %s %s" % [inframe, numframes, cmd, anim]) 43 | trigFrame = int(inframe) % numframes 44 | 45 | var key = getKey(cmd) 46 | if frameCmds.has(trigFrame): 47 | frameCmds[trigFrame][key] = cmd 48 | else: 49 | frameCmds[trigFrame] = {key: cmd} 50 | 51 | print("add cmd to frameCmds on frame %d: %s" % [trigFrame, cmd]) 52 | print(frameCmds) 53 | return frameCmds 54 | 55 | func removeCmdFromFrameCmds( inframe, cmd ): 56 | print("remove cmd for frame %s: %s" % [inframe, cmd]) 57 | var reply 58 | var key = getKey(cmd) 59 | inframe = int(inframe) 60 | 61 | if frameCmds.has(inframe): 62 | frameCmds[inframe].erase(key) 63 | reply = frameCmds[inframe] 64 | if len(frameCmds[inframe]) == 0: 65 | frameCmds.erase(inframe) 66 | else: 67 | # TODO: change to send '/report/error' 68 | reply = "Command not found in trigger frame %d: %s" % [inframe, cmd] 69 | print(reply) 70 | return reply 71 | 72 | func addFinishCmd( cmd ): 73 | var key = getKey(cmd) 74 | finishCmds[key] = cmd 75 | print("add onfinish cmd: %s : %s" % [key, cmd]) 76 | print("on finish: ", finishCmds) 77 | 78 | func removeFinishCmd( cmd ): 79 | print(cmd) 80 | var key = getKey(cmd) 81 | if finishCmds.has(key): 82 | finishCmds.erase(key) 83 | print("remove cmd: %s : %s" % [key, cmd]) 84 | print("on finish: ", finishCmds) 85 | 86 | func getFrameCmds(): 87 | return frameCmds 88 | 89 | func getKey( cmd ): 90 | if len(cmd) > 1: 91 | return "%s/%s" % [cmd[0], cmd[1]] 92 | return cmd[0] 93 | 94 | func sendCmds( inframe ): 95 | for cmd in frameCmds[inframe]: 96 | var addr = frameCmds[inframe][cmd][0] 97 | var args = frameCmds[inframe][cmd].slice(1,-1) 98 | main.evalOscCommand(addr, args, null) 99 | 100 | func listFrameCmds(): 101 | print("frame commands for %s:\n%s" % [name,frameCmds]) 102 | print("finish commands for %s:\n%s" % [name,finishCmds]) 103 | 104 | func setVisibleEnd(visible): 105 | isVisibleEnd = visible 106 | 107 | func listStates(): 108 | Logger.info("State machine: %s" % [name]) 109 | for state in stateMachine: 110 | Logger.info("%s : %s" % [state, stateMachine[state]]) 111 | 112 | func addState(newState, nextStates): 113 | stateMachine[newState] = nextStates if nextStates is Array else [nextStates] 114 | 115 | func removeState(state): 116 | stateMachine.erase(state) 117 | 118 | func nextState(): 119 | var animNode = get_node("Offset/Animation") 120 | var anim = animNode.get_animation() 121 | if not stateMachine.has(anim): 122 | return 123 | var nextPossibleStates = stateMachine[anim] 124 | var nextState = nextPossibleStates[ randi() % nextPossibleStates.size() ] 125 | animNode.set_animation(nextState) 126 | Logger.verbose("changing '%s' state from: %s to: %s" % [name, anim, nextState]) 127 | -------------------------------------------------------------------------------- /docs/markdeep/apidoc.css: -------------------------------------------------------------------------------- 1 | /* Custom stylesheet for API documentation by Aras Pranckevičius, http://aras-p.info/ 2 | and tweaked by Morgan McGuire. 3 | Licensed as public domain or BSD 2-clause, whichever is more convenient for you. 4 | Originally from https://github.com/aras-p/markdeep-docs-style */ 5 | body#md { 6 | max-width: 50em; 7 | font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; 8 | text-align: left; 9 | margin: 1.5em; 10 | padding: 0 1em; 11 | } 12 | 13 | /* if screen is wide enough, put table of contents on the right side */ 14 | @media screen and (min-width: 64em) { 15 | .md .longTOC, .md .mediumTOC, .md .shortTOC { 16 | max-width: 20em; 17 | left: 54em; 18 | display:block; 19 | position: fixed; 20 | top:0; 21 | bottom:0; 22 | overflow-y:scroll; 23 | margin-top:0; 24 | margin-bottom:0; 25 | padding-top:1em; 26 | } 27 | } 28 | 29 | /* for narrow screens or print, hide table of contents */ 30 | @media screen and (max-width: 64em) { 31 | .md .longTOC, .md .mediumTOC, .md .shortTOC { display: none; } 32 | } 33 | 34 | @media print { 35 | .md .longTOC, .md .mediumTOC, .md .shortTOC { display: none; } 36 | body { max-width: 100%; } 37 | } 38 | 39 | /* reset heading/link fonts to that of body */ 40 | .md a, 41 | .md div.title, contents, .md .tocHeader, 42 | .md h1, .md h2, .md h3, .md h4, .md h5, .md h6, 43 | .md .nonumberh1, .md .nonumberh2, .md .nonumberh3, .md .nonumberh4, .md .nonumberh5, .md .nonumberh6, 44 | .md .shortTOC, .md .mediumTOC, .md .longTOC { 45 | font-family: inherit; 46 | } 47 | 48 | @media screen {.md .tocTop { 49 | display: inline; 50 | }} 51 | 52 | .md div.title { 53 | margin: 0.4em 0 0 0; 54 | padding: 0; 55 | text-align: inherit; 56 | } 57 | 58 | .md div.subtitle { 59 | text-align: inherit; 60 | } 61 | 62 | /* faint border below headings */ 63 | .md h1, .md h2, .md h3, .md h4, 64 | .md .nonumberh1, .md .nonumberh2, .md .nonumberh3, .md .nonumberh4 { 65 | border-bottom: 1px solid rgba(0,0,0,.1); 66 | } 67 | /* heading font styles */ 68 | .md h1, .md .nonumberh1, .md div.title { 69 | font-size: 150%; 70 | font-weight: 600; 71 | color: rgba(0,0,0,.7); 72 | } 73 | .md h2, .md .nonumberh2 { 74 | font-size: 120%; 75 | font-weight: 400; 76 | color: rgba(0,0,0,.9); 77 | } 78 | .md h3, .md .nonumberh3 { 79 | font-size: 110%; 80 | font-weight: 400; 81 | color: rgba(0,0,0,.7); 82 | } 83 | /* no numbering of headings */ 84 | .md h1:before, .md h2:before, .md h3:before, .md h4:before { content: none; } 85 | 86 | /* link styling */ 87 | .md a:link, .md a:visited { 88 | color: #3f51b5; 89 | } 90 | 91 | /* inline and block code */ 92 | .md code, .md pre.listing { 93 | background-color: rgba(0,0,0,.05); 94 | padding: 0.1em 0.2em; 95 | border-radius: 0.15em; 96 | } 97 | .md pre.listing code { 98 | background-color: transparent; 99 | padding: 0; 100 | border: none; 101 | } 102 | 103 | /* table of contents styling; make all 3 forms of it look the same */ 104 | .md .longTOC, .md .mediumTOC, .md .shortTOC { 105 | font-size: inherit; 106 | line-height: 120%; 107 | margin: 1em 0; 108 | padding: .4rem; 109 | border-left: .1rem solid #3f51b5; 110 | } 111 | 112 | .md .tocHeader { 113 | margin: 0; 114 | padding: 0; 115 | border: none; 116 | font-size: inherit; 117 | } 118 | 119 | .md .tocNumber { 120 | display: none; 121 | } 122 | 123 | .md .longTOC .level1, .md .mediumTOC .level1, .md .shortTOC .level1 { 124 | font-weight: inherit; 125 | padding: 0; 126 | margin: 0; 127 | } 128 | 129 | .md .longTOC p, .md .mediumTOC p, .md .shortTOC p { 130 | overflow: hidden; 131 | text-overflow: ellipsis; 132 | } 133 | 134 | .md .longTOC center, .md .mediumTOC center, .md .shortTOC center, .md .tocHeader { 135 | text-align: left; 136 | } 137 | 138 | .md .longTOC b, .md .mediumTOC b, .md .shortTOC b { 139 | font-weight: 400; 140 | } 141 | 142 | .md .longTOC center b, .md .mediumTOC center b, .md .shortTOC center b { 143 | font-weight: bold; 144 | } 145 | 146 | .md .longTOC a, .md .mediumTOC a, .md .shortTOC a { 147 | color: black; 148 | } 149 | 150 | .md .longTOC .level1, .md .mediumTOC .level1, .md .shortTOC .level1, 151 | .md .longTOC .level2, .md .mediumTOC .level2, .md .shortTOC .level2, 152 | .md .longTOC .level3, .md .mediumTOC .level3, .md .shortTOC .level3 { 153 | white-space: nowrap; 154 | margin: 0; 155 | padding: 0; 156 | font-size: 90%; 157 | } 158 | 159 | /* tables; use fainter colors than regular markdeep style */ 160 | .md table.table { 161 | font-size: 90%; 162 | } 163 | 164 | .md table.table th { 165 | border: none; 166 | background-color: #ccc; 167 | color: rgba(0,0,0,.6); 168 | } 169 | .md table.table tr, .md table.table td { 170 | border-color: #eee; 171 | } 172 | .md table.table tr:nth-child(even) { 173 | background-color: #f4f4f4; 174 | } 175 | 176 | -------------------------------------------------------------------------------- /Midi.gd: -------------------------------------------------------------------------------- 1 | class_name Midi 2 | extends Node 3 | 4 | signal note_on_received(num, velocity, ch) 5 | signal note_off_received(num, velocity, ch) 6 | signal cc_received(num, value, ch) 7 | 8 | var debug = true 9 | var midiCmds : Dictionary 10 | 11 | # Called when the node enters the scene tree for the first time. 12 | func _ready(): 13 | OS.open_midi_inputs() 14 | print("MIDI devices: ",OS.get_connected_midi_inputs()) 15 | set_process_unhandled_input(true) 16 | 17 | func enableDebug(enable): 18 | debug = enable 19 | 20 | func _unhandled_input(event): 21 | if(event is InputEventMIDI): 22 | var signalMsg = "" 23 | var ch = event.get_channel() 24 | var num = 0 25 | var value = 0 26 | # print("MIDI: ", event.as_text()) 27 | # print("MIDI:", event.message) 28 | # print("MSG:", MIDI_MESSAGE_CONTROL_CHANGE) 29 | # var msg = "ch:" + str(ch) + " note:" + str(event.get_pitch()) + " vel:" + str(event.get_velocity()) + " inst:" + str(event.get_instrument()) + " pres:" + str(event.get_pressure()) + " cc#:" + str(event.get_controller_number()) + " ccv:" + str(event.get_controller_value()) 30 | # print(msg) 31 | if event.message == MIDI_MESSAGE_NOTE_ON: 32 | signalMsg = "noteon" 33 | num = event.get_pitch() 34 | value = event.get_velocity() 35 | elif event.message == MIDI_MESSAGE_NOTE_OFF: 36 | signalMsg = "noteoff" 37 | num = event.get_pitch() 38 | value = event.get_velocity() 39 | elif event.message == MIDI_MESSAGE_CONTROL_CHANGE: 40 | signalMsg = "cc" 41 | num = event.get_controller_number() 42 | value = event.get_controller_value() 43 | 44 | if debug: 45 | print("MIDI msg: %s - ch: %d - num:%d - val:%d - ch:%d" % [signalMsg, ch, num, value, event.get_channel()]) 46 | 47 | if signalMsg == "": 48 | return 49 | 50 | processMidiCmd(signalMsg, ch, num, value) 51 | 52 | func addMidiCmd( event, ch, num, cmd, actor, minVal, maxVal ): 53 | if String(num) == "*": 54 | for i in range(128): 55 | # to map any note midievent to a command, we need to 56 | # use note number as velocity value, so we pass 57 | # the same value for both min and max. If they are null 58 | # we give them a midi number 59 | if minVal == null: minVal = i + 1 60 | if maxVal == null: maxVal = i + 1 61 | var newMinVal = Helper.linlin(i, 0,127, minVal, maxVal) 62 | var newMaxVal = newMinVal 63 | addMidiCmd(event, ch, i, cmd, actor, newMinVal, newMaxVal) 64 | return 65 | var key = "%s/ch%s/%s" % [event, ch, num] 66 | midiCmds[key] = {"addr":cmd, "actor":actor.name, "value":[minVal, maxVal]} 67 | # print(midiCmds) 68 | Logger.info("added midi cmd %s: %s" % [key, midiCmds[key]]) 69 | 70 | func removeMidiCmd( event, ch, num, cmd, actor ): 71 | if String(num) == "*": 72 | for i in range(128): 73 | removeMidiCmd(event, ch, i, cmd, actor) 74 | return 75 | 76 | var key = "%s/ch%s/%s" % [event, ch, num] 77 | 78 | if not midiCmds.has(key): 79 | Logger.info("trying to erase non-existing MIDI cmd: %s" % [key]) 80 | return 81 | 82 | midiCmds.erase(key) 83 | Logger.info("midi cmds: %s" % [midiCmds]) 84 | 85 | func processMidiCmd( event, ch, num, val ): 86 | var key = getKey(event, ch, num) 87 | if not midiCmds.has(key): 88 | return 89 | 90 | eventToOsc(midiCmds[key], val) 91 | # 92 | if debug: 93 | Logger.debug("key: %s cmd: %s" % [key, midiCmds[key]] ) 94 | # print(midiCmds.keys()) 95 | 96 | func eventToOsc(cmd, value): 97 | print("event to osc: ", cmd, value) 98 | if not get_parent(): 99 | return 100 | 101 | var main = get_parent() 102 | var addr = cmd["addr"] 103 | if not addr.begins_with("/"): 104 | addr = "/" + addr 105 | var actor = cmd["actor"] 106 | var minval = cmd["value"][0] 107 | var maxval = cmd["value"][1] 108 | if actor == null: 109 | main.evalCommandList([[addr]], null) 110 | return 111 | elif minval == null or maxval == null: 112 | main.evalCommandList([[addr, actor]], null) 113 | return 114 | var args 115 | print("%s(%s) %s(%s)" % [minval, typeof(minval), maxval, typeof(maxval)]) 116 | if minval is String and minval.is_valid_float() and maxval is String and maxval.is_valid_float(): 117 | args = Helper.linlin(value, 0, 127, float(minval), float(maxval)) 118 | elif (minval is float or minval is int) and (maxval is float or maxval is int): 119 | args = Helper.linlin(value, 0, 127, float(minval), float(maxval)) 120 | else: 121 | args = minval 122 | 123 | Logger.verbose("MIDI PARSE: original:%s scaled:%s" % [value, args]) 124 | Logger.verbose("sending msg from MIDI: %s %s %f" % [addr, actor, value]) 125 | main.evalCommandList([[addr, actor, args]], null) 126 | 127 | func getKey(event, ch, num): 128 | return "%s/ch%s/%s" % [event, ch, num] 129 | 130 | func listCmds(): 131 | var cmds : String 132 | for key in midiCmds: 133 | var cmd = midiCmds[key]["addr"] 134 | var actor = midiCmds[key]["actor"] 135 | var args = midiCmds[key]["value"] 136 | cmds = "%s\n%s: %s %s %s" % [cmds, key, cmd, actor, args] 137 | # print(cmd, midiCmds[cmd]) 138 | # Logger.info(cmds) 139 | return cmds 140 | -------------------------------------------------------------------------------- /OscTextEdit.gd: -------------------------------------------------------------------------------- 1 | extends TextEdit 2 | 3 | const defaultTextEditorFile := "docs/tutorial.osc" 4 | const tutorialCmdsFile = "commands/tutorial-cmds.osc" 5 | var regex 6 | var main 7 | 8 | func _ready(): 9 | regex = RegEx.new() 10 | main = get_parent() 11 | set_visible(true) 12 | 13 | add_color_region("/", " ", Color(1, 0.439216, 0.521569)) 14 | add_color_region("#", "", Color(0.447059, 0.462745, 0.498039)) 15 | 16 | main.get_node("OscInterface").loadDefsFile([tutorialCmdsFile], null) 17 | 18 | 19 | func _on_OscTextEdit_gui_input(event): 20 | # Logger.verbose(event) 21 | # accept_event() 22 | if event.is_action_pressed("eval_line", true): 23 | undo() # FIX: this is a hack to remove the inserted line on pressing ENTER 24 | evalLine() 25 | elif event.is_action_pressed("eval_block", true): 26 | undo() # FIX: this is a hack to remove the inserted line on pressing ENTER 27 | evalBlock() 28 | elif event.is_action_pressed("open_file", true): 29 | main.get_node("OpenFileDialog").popup() 30 | elif event.is_action_pressed("save_file", true): 31 | main.get_node("SaveFileDialog").popup() 32 | elif event.is_action_pressed("duplicate_line", true): 33 | duplicateLine() 34 | elif event.is_action_pressed("increase_editor_font", true): 35 | increaseFont() 36 | elif event.is_action_pressed("decrease_editor_font", true): 37 | decreaseFont() 38 | 39 | func evalRegion(): 40 | textToOsc(get_selection_text()) 41 | 42 | func findPrevLinebreak( fromLine ): 43 | var ln = fromLine 44 | while ln > 0: 45 | ln = ln - 1 46 | if get_line(ln) == "": 47 | ln = ln + 1 48 | break 49 | return ln 50 | 51 | func findNextLinebreak( fromLine ): 52 | if get_line(fromLine) == "": 53 | return fromLine 54 | var ln = fromLine 55 | while ln < get_line_count(): 56 | ln = ln + 1 57 | if get_line(ln) == "": 58 | ln = ln - 1 59 | break 60 | return ln 61 | 62 | func evalBlock(): 63 | var line = cursor_get_line() 64 | var from = findPrevLinebreak(line) - 1 65 | var to = findNextLinebreak(line) 66 | cursor_set_column(len(get_line(line))) 67 | select(from, 0, to + 1, cursor_get_column()) 68 | var text = get_selection_text().strip_edges() 69 | Logger.debug("text: %s" % [text]) 70 | Logger.debug("def: %s" % [text.begins_with("/def")]) 71 | if text.begins_with("/def"): 72 | evalDefs(text) 73 | return 74 | Logger.debug("AFTER DEFS") 75 | textToOsc(text) 76 | deselect() 77 | 78 | 79 | func evalLine(): 80 | var ln = cursor_get_line() 81 | var col = cursor_get_column() 82 | selectLine() 83 | textToOsc(get_selection_text()) 84 | deselect() 85 | cursor_set_line(ln) 86 | cursor_set_column(col) 87 | 88 | func evalDefs(text): 89 | # group tabs with first non-indented line 90 | # FIX: 'defs' are already parsed in file, but doesn't work with this 91 | # This is a hack converting each line into a string so the parser 92 | # can reconvert it to a command. 93 | var def := Array(text.split("\n")[0].split(" ")) 94 | def.remove(0) 95 | var defCmd = def.pop_front() 96 | var defArgs = def 97 | var cmds : Array 98 | var regex = RegEx.new() 99 | regex.compile("\\n\\t(.*)") 100 | for result in regex.search_all(text): 101 | Logger.debug("def subcmd: %s" % [result.get_string()]) 102 | cmds.push_back(result.get_string().strip_edges().split(" ")) 103 | Logger.debug("def: %s args: %s" % [defCmd, defArgs]) 104 | Logger.debug("sub cmds: %s" % [cmds]) 105 | main.get_node("CustomCommands").defineCommand(defCmd, defArgs, cmds) 106 | 107 | func textToOsc( msgString ): 108 | var cmds = [] 109 | var lines = msgString.split("\n") 110 | for line in lines: 111 | var cmd = Array(line.strip_edges().split(" ")) # convert PoolStringArray to Array 112 | if len(cmd[0].strip_edges()) > 0: 113 | cmds.append(cmd) 114 | main.evalCommandList(cmds, null) 115 | Logger.debug(cmds) 116 | 117 | func selectLine(): 118 | var line = cursor_get_line() 119 | cursor_set_column(len(get_line(line))) 120 | select(line, 0, line, cursor_get_column()) 121 | 122 | func duplicateLine(): 123 | var col = cursor_get_column() 124 | cut() 125 | paste() 126 | paste() 127 | cursor_set_line(cursor_get_line() - 1) 128 | cursor_set_column(col) 129 | 130 | func loadTutorial(): 131 | # this is not an optimal way to do it, but we are using a method in 132 | # the Helper class 133 | var dirname = defaultTextEditorFile.split("/")[0] 134 | var filename = defaultTextEditorFile.split("/")[1] 135 | var file = File.new() 136 | var path = Helper.getPathWithDefaultDir(filename, dirname) 137 | file.open(path, File.READ) 138 | set_text(file.get_as_text()) 139 | 140 | func append( msg ): 141 | set_text("%s\n%s" % [get_text(), msg]) 142 | scroll_vertical = INF 143 | 144 | func increaseFont(): 145 | var font = get("custom_fonts/font") 146 | font.set_size(font.get_size() + 1) 147 | Logger.verbose("font size: %d" % [font.get_size()]) 148 | 149 | func decreaseFont(): 150 | var font = get("custom_fonts/font") 151 | font.set_size(font.get_size() - 1) 152 | Logger.verbose("font size: %d" % [font.get_size()]) 153 | 154 | func setFontSize( size ): 155 | get("custom_fonts/font").set_size(size) 156 | 157 | func clear(): 158 | set_text("") 159 | -------------------------------------------------------------------------------- /sc/midi-test.scd: -------------------------------------------------------------------------------- 1 | a = Animatron() 2 | MIDIClient.init; 3 | m = MIDIOut(0); 4 | a.sendMsg("/debug", false); 5 | a.sendMsg("/debug", true); 6 | a.sendMsg("/free", "*"); 7 | 8 | // ------------------------------------------------------------ 9 | // basic 10 | // ------------------------------------------------------------ 11 | ( 12 | a.sendMsg("/load", "numbers"); 13 | a.sendMsg("/create", "n", "numbers"); 14 | a.sendMsg("/create", "n2", "numbers"); 15 | a.sendMsg("/speed", "n", 1/12); 16 | a.sendMsg("/speed", "n2", 1/12); 17 | a.sendMsg("/scale", "n2", 1/2); 18 | a.sendMsg("/position/x", "n2", 1/4); 19 | ) 20 | // add/remove MIDI cmds 21 | a.sendMsg("/midi", "noteon", 0, 60, "/frame", "n", 0, 10); 22 | a.sendMsg("/midi", "noteon", 0, 60, "/frame", "n2", 0, 10); 23 | a.sendMsg("/midi/free", "noteon", 0, 60, "/frame", "n"); 24 | a.sendMsg("/midi/free", "noteon", 0, 60, "/frame", "n2"); 25 | a.sendMsg("/midi/free", "noteon", 0, 60, "/frame", "x2"); 26 | a.sendMsg("/midi/free", "noteon", 0, 61, "/frame", "n2"); 27 | 28 | // test MIDI cmds 29 | a.sendMsg("/midi", "noteon", 0, 60, "/frame", "n", 0, 10); 30 | a.sendMsg("/list/midi"); 31 | m.noteOn(0, 60,0); 32 | m.noteOff(0,60,0); 33 | a.sendMsg("/midi/free", "noteon", 0, 60, "/frame", "n"); 34 | 35 | // test 2 different MIDI channels 36 | a.sendMsg("/midi", "noteon", 0, 60, "/frame", "n", 0, 10); 37 | a.sendMsg("/midi", "noteon", 1, 60, "/scale", "n", 0.1, 2.0); 38 | a.sendMsg("/list/midi"); 39 | m.noteOn(0, 60, 127);m.allNotesOff(0); 40 | m.noteOn(1, 60, 127.rand);m.allNotesOff(1); 41 | a.sendMsg("/midi/free", "noteon", 0, 60, "/frame", "n"); 42 | a.sendMsg("/midi/free", "noteon", 1, 60, "/scale", "n"); 43 | 44 | a.sendMsg("/midi", "noteon", 0, "*", "/frame", "n", 0, 10); 45 | a.sendMsg("/midi/free", "noteon", 0, "*", "/frame", "n"); 46 | a.sendMsg("/list/midi"); 47 | // ------------------------------------------------------------ 48 | // matrix 49 | // ------------------------------------------------------------ 50 | ( 51 | 16.do{|i| 52 | var n = "n"++(i.mod(16).asInteger); 53 | a.sendMsg("/create", n, "numbers"); 54 | a.sendMsg("/stop", n); 55 | a.sendMsg("/scale", n, 0.2); 56 | a.sendMsg("/frame", n, i); 57 | a.sendMsg("/position/x", n, (i / 4).linlin(0,4, 0.2,0.8)); 58 | a.sendMsg("/position/y", n, (i.mod(4)).linlin(0,4, 0.2,0.8)); 59 | }; 60 | a.sendMsg("/midi", "noteon", 0, "*", "/frame", "n0", 0.0, 10.0); 61 | ) 62 | ( 63 | Tdef(\midi, { 64 | inf.do{ |i| 65 | // var ch = 16.rand; 66 | var ch = 0; 67 | // var note = 127.rand; 68 | // var vel = 127.rand; 69 | var note = 60; 70 | var vel = 10; 71 | m.noteOn(ch, note, vel); 72 | 0.1.wait; 73 | m.noteOff(ch, note, vel); 74 | 1.wait; 75 | }; 76 | }).play; 77 | ) 78 | Tdef(\midi).stop; 79 | 80 | // ------------------------------------------------------------ 81 | // complex 82 | // ------------------------------------------------------------ 83 | a.sendMsg("/load", "canon-man"); 84 | ( 85 | a.sendMsg("/create", "ha", "canon-man"); 86 | a.sendMsg("/create", "he", "canon-man"); 87 | a.sendMsg("/stop", "h*"); 88 | a.sendMsg("/frame", "ha", rrand(50,500)); 89 | a.sendMsg("/frame", "he", rrand(50,500)); 90 | a.sendMsg("/color", "he", 1,0,0); 91 | a.sendMsg("/position/x", "he", 0.2); 92 | a.sendMsg("/scale", "he", 0.5); 93 | ) 94 | a.sendMsg("/midi/debug", false); 95 | a.sendMsg("/new", "sqa", "square"); 96 | a.sendMsg("/midi", "noteon", 0, "*", "/rotate", "sqa", 0, 360); 97 | 98 | a.sendMsg("/midi/free", "noteon", 0, "*", "/rotate", "sqa"); 99 | a.sendMsg("/midi/debug", true); 100 | 101 | // all notes on 102 | a.sendMsg("/midi", "noteon", "*", "/frame", "ha", 50,360); 103 | m.noteOn(0, 127.rand, 127.rand.debug); 104 | a.sendMsg("/midi/free", "noteon", "*", "/frame", "ha"); 105 | // all notes off 106 | a.sendMsg("/midi", "noteoff", "*", "/frame", "ha", 50,360); 107 | m.noteOn(0, 127.rand, 127.rand.debug); 108 | a.sendMsg("/midi/free", "noteoff", "*", "/frame", "ha"); 109 | // all velocity 110 | a.sendMsg("/midi", "velocity", "*", "/scale", "ha", 0.1, 4); 111 | m.noteOn(0, 127.rand, 127.rand.debug); 112 | a.sendMsg("/midi/free", "velocity", "*", "/scale", "ha"); 113 | // note on -- using velocity as parameter 114 | a.sendMsg("/midi", "noteon", 60, "/frame", "ha", 50,360); 115 | a.sendMsg("/midi", "noteon", 60, "/scale", "ha", 0.1, 2.0); 116 | m.noteOn(0, 60, 127.rand.debug); 117 | a.sendMsg("/midi/free", "noteon", 60, "/frame", "ha"); 118 | a.sendMsg("/midi/free", "noteon", 60, "/scale", "ha"); 119 | // note off -- using velocity as parameter 120 | a.sendMsg("/midi", "noteoff", 60, "/frame", "ha", 50,360); 121 | m.noteOff(0, 60, 127.rand.debug); 122 | a.sendMsg("/midi/free", "noteoff", 60, "/frame", "ha"); 123 | // cc 124 | a.sendMsg("/midi", "cc", 1, "/frame", "he", 50,360); 125 | m.control(0, 1, 127.rand.debug); 126 | m.noteOn(0, 1, 127.rand.debug); 127 | a.sendMsg("/midi/free", "cc", 1, "/frame", "ha"); 128 | 129 | a.sendMsg("/stop", "h*"); 130 | 131 | Ziva.boot; 132 | ~m = Pmidi(MIDIOut(0)); 133 | ( 134 | [ 135 | ~m.fast.amp(Pwhite()).midinote(Pwhite(0,127)), 136 | ~m.faster.deg([0,17].pseq), 137 | ~m.deg([0,17].pseq).chan(1), 138 | ~m.faster.deg([0,17].pseq), 139 | ~m.bla([40,60].pseq.linlin(0,127,0.1,1.27).trace), 140 | nil 141 | ].ziva; 142 | ) 143 | Pdef(\ziva).remove 144 | 145 | /midi event ch 146 | a.sendMsg("/midi", "noteon", x, "/frame", a, min, max); 147 | noteon/chx/a cmd:[{addr:"/frame", actor:a, value:n.linlin(0,127,min,max)}] -------------------------------------------------------------------------------- /sc/cube-routines-mod.scd: -------------------------------------------------------------------------------- 1 | ( 2 | //////////////////////////////////////////////////////////// 3 | // Setup 4 | //////////////////////////////////////////////////////////// 5 | "setup.scd".loadRelative.first; 6 | ) 7 | 8 | ( 9 | // Create the actor setup commands 10 | // n.sendMsg("/def", "/updown actor holdTime", 11 | // "/speed $actor 1", 12 | // "/frame $actor 0", 13 | // "/noloop $actor", 14 | // "/wait $holdTime", 15 | // "/speed $actor -1", 16 | // "/noloop $actor", 17 | // ); 18 | // n.sendMsg("/def", "/make-c actor red green blue offsetx offsety period holdTime", 19 | // // "/create $actor cube-unshrink-h", 20 | // // "/create $actor cube", 21 | // // "/noloop $actor", 22 | // "/color $actor $red $green $blue", 23 | // "/size $actor 0.5", 24 | // "/position $actor $offsetx $offsety", 25 | // // "/routine $actor inf $period /updown $actor $holdTime" 26 | // ); 27 | n.sendMsg("/def", "/make actor red green blue offsetx offsety", 28 | "/color $actor $red $green $blue", 29 | "/size $actor 0.5", 30 | "/speed $actor 0.5", 31 | "/position $actor $offsetx $offsety", 32 | ); 33 | n.sendMsg("/def", "/make/states actor", 34 | "/state/add $actor cube cube cube-bubble", 35 | "/state/add $actor cube-tongue cube-open-eye cube-close", 36 | "/state/add $actor cube-close cube-open cube-bubble", 37 | "/state/add $actor cube-bubble cube-open cube-bubble", 38 | "/state/add $actor cube-open cube-open-eye cube-tongue cube-close", 39 | "/state/add $actor cube-open-eye cube-close cube-tongue", 40 | "/state/add $actor cube-shrink-v cube-unshrink-v", 41 | "/state/add $actor cube-shrink-h cube-unshrink-h", 42 | "/state/add $actor cube-unshrink-v cube-shrink-v cube-open", 43 | "/state/add $actor cube-unshrink-h cube-shrink-h cube-bubble", 44 | ); 45 | n.sendMsg("/def", "/free/states actor", 46 | "/state/free $actor cube", 47 | "/state/free $actor cube-tongue", 48 | "/state/free $actor cube-close", 49 | "/state/free $actor cube-bubble", 50 | "/state/free $actor cube-open", 51 | "/state/free $actor cube-open-eye", 52 | "/state/free $actor cube-shrink-v", 53 | "/state/free $actor cube-shrink-h", 54 | "/state/free $actor cube-unshrink-v", 55 | "/state/free $actor cube-unshrink-h", 56 | ); 57 | x.("/load cube*"); 58 | x.("/load cit-step"); 59 | x.("/free *"); 60 | ~num = 28; 61 | x.("/routine/free/all"); 62 | x.("/create/group c cube %".format(~num)); 63 | ) 64 | ( 65 | ~num.do{ arg i; 66 | // x.("/make/states c%".format(i)); 67 | // x.("/free/states c%".format(i)); 68 | // x.("/anim c% cube".format(i)); 69 | // x.("/state/add c% cube cube-open".format(i)); 70 | // x.("/state/add c% cube-bubble cube".format(i)); 71 | if( i%2 == 1, { 72 | x.("/state/add c% cube cube-bubble".format(i)); 73 | // x.("/state/add c% cube-open cube-open-eye".format(i)); 74 | // x.("/state/add c% cube-open-eye cube-close".format(i)); 75 | // x.("/state/add c% cube-close cube".format(i)); 76 | // x.("/state/add c% cube-bubble cube-shrink-v".format(i)); 77 | // x.("/state/add c% cube-shrink-v cube-unshrink-v".format(i)); 78 | // x.("/state/add c% cube-unshrink-v cube-bubble".format(i)); 79 | }); 80 | if( i%2 == 0, { 81 | x.("/state/add c% cube cube-open".format(i)); 82 | x.("/state/add c% cube-open cube-close".format(i)); 83 | x.("/state/add c% cube-close cube-open".format(i)); 84 | // x.("/state/add c% cube-bubble cube-open".format(i)); 85 | // x.("/state/add c% cube-open cube-tongue".format(i)); 86 | // x.("/state/add c% cube-tongue cube-close".format(i)); 87 | // x.("/state/add c% cube-close cube".format(i)); 88 | // x.("/state/add c% cube-shrink-h cube-unshrink-h".format(i)); 89 | // x.("/state/add c% cube-unshrink-h cube-bubble".format(i)); 90 | }); 91 | x.("/free/states c%".format(i)); 92 | x.("/anim c% cube".format(i)); 93 | }; 94 | ) 95 | 96 | ( 97 | // Algorithmically create and animate a bunch of cubes 98 | ~num.do{ arg i; 99 | var row = (i % 4) - 1; 100 | var col = 1 - (i div: 4 - 1); 101 | var posx = 0.12 * col + 0.5; 102 | var posy = 0.25 * row + 0.5 + (0.105 * col); 103 | var rgb = rrand(-0.3, 0.3 ! 3); 104 | // var rgb = col mod: 2 / 2 ! 3 * [1,1,-1]; 105 | // Try different modulus, from 2 to ~num 106 | // var period = (i % ~num).linexp(0, ~num-1, 0.5, 8); 107 | // x.("/make-c c% % % % % % % %".format(i, rgb[0], rgb[1], rgb[2], posx, posy, period, period / 2).debug("cmd")); 108 | x.("/make c% % % % % %".format(i, rgb[0], rgb[1], rgb[2], posx, posy).debug("cmd")); 109 | } 110 | ) 111 | 112 | 113 | x.("/list/routines") 114 | x.("/free *") 115 | x.("/free/states") 116 | x.("/speed * 0.75") 117 | x.("/list/states c0") 118 | x.("/list/anims") 119 | x.("/list/assets") 120 | x.("/list") 121 | x.("/load cit") 122 | x.("/action c* wander 0.2 0.5") 123 | x.("/rotate c* 90 1") 124 | { ~num.do{ arg i; x.("/size c% 0.5 0".format(i)); 0.0625.wait; } }.fork 125 | { ~num.do{ arg i; x.("/rotate c% 90 0".format(i)); 0.25.wait; } }.fork 126 | { ~num.do{ arg i; x.("/fade c% 0 8".format(i)); 0.25.wait; } }.fork 127 | ) 128 | 129 | x.("/flipv c7") 130 | x.("/state/add c7 cube-bubble cube-bubble cit") 131 | x.("/state/add c7 cit cube-shrink-v cube-bubble") 132 | 133 | 134 | 135 | ( 136 | // An explicit version 137 | n.sendMsg("/def", "/make-cubes", 138 | "/make-c c1 0.2 0.2 0.2 0.62 0.355 12 6", 139 | "/make-c c2 -0.2 -0.2 -0.2 0.62 0.605 6 3", 140 | "/make-c c3 0.0 0.0 0.0 0.62 0.855 4 2", 141 | "/make-c c4 0.2 -0.2 -0.2 0.5 0.25 3 2", 142 | "/make-c c5 -0.2 0.2 -0.2 0.5 0.5 2 1", 143 | "/make-c c6 0.2 0.2 -0.2 0.5 0.75 1 0.5", 144 | "/make-c c7 -0.2 -0.2 0.2 0.38 0.145 0.666667 0.3333", 145 | "/make-c c8 0.2 -0.2 0.2 0.38 0.395 0.5 0.25", 146 | "/make-c c9 -0.2 0.2 0.2 0.38 0.645 0.333333 0.1666667" 147 | ); 148 | ) 149 | 150 | x.("/make-cubes") 151 | x.("/make/states c7") 152 | 153 | x.("/load cube-*") 154 | x.("/free *") 155 | x.("/create c cube-open-eye") 156 | x.("/make/states c") 157 | x.("/speed c 0.5") 158 | x.("/stop c") 159 | x.("/frame c 10") 160 | x.("/anim c cube-open-eye"); 161 | x.("/stop c"); 162 | x.("/state/add c cube-open-eye cube-tongue") 163 | x.("/state/add c cube-tongue cube-open-eye cube-tongue") 164 | x.("/state/add c cube-open cube-close cube-open-eye") 165 | x.("/state/add c cube-open-eye cube-close") 166 | x.("/state/add c cube-close cube-open") 167 | x.("/state/add c cube cube-shrink-h cube-shrink-v cube-bubble") 168 | x.("/state/add c cube-shrink-h cube-unshrink-h") 169 | x.("/state/add c cube-shrink-v cube-unshrink-v") 170 | x.("/state/add c cube-unshrink-v cube-shrink-v cube-shrink-h cube-bubble") 171 | x.("/state/add c cube-unshrink-h cube-shrink-h cube-shrink-v cube-bubble") 172 | x.("/state/add c cube-bubble cube-shrink-v cube-shrink-h") 173 | x.("/list/assets") 174 | x.("/color c 0.2 0.1 0") -------------------------------------------------------------------------------- /project.godot: -------------------------------------------------------------------------------- 1 | ; Engine configuration file. 2 | ; It's best edited using the editor UI and not directly, 3 | ; since the parameters that go here are not all obvious. 4 | ; 5 | ; Format: 6 | ; [section] ; section goes between [] 7 | ; param=value ; assign values to parameters 8 | 9 | config_version=4 10 | 11 | _global_script_classes=[ { 12 | "base": "Node", 13 | "class": "Action", 14 | "language": "GDScript", 15 | "path": "res://actions/Action.gd" 16 | }, { 17 | "base": "Node", 18 | "class": "Config", 19 | "language": "GDScript", 20 | "path": "res://Config.gd" 21 | }, { 22 | "base": "Node", 23 | "class": "CustomCommands", 24 | "language": "GDScript", 25 | "path": "res://CustomCommands.gd" 26 | }, { 27 | "base": "Object", 28 | "class": "Helper", 29 | "language": "GDScript", 30 | "path": "res://Helper.gd" 31 | }, { 32 | "base": "Node", 33 | "class": "Letters", 34 | "language": "GDScript", 35 | "path": "res://Letters.gd" 36 | }, { 37 | "base": "Node", 38 | "class": "Midi", 39 | "language": "GDScript", 40 | "path": "res://Midi.gd" 41 | } ] 42 | _global_script_class_icons={ 43 | "Action": "res://icons/action.svg", 44 | "Config": "", 45 | "CustomCommands": "", 46 | "Helper": "", 47 | "Letters": "", 48 | "Midi": "" 49 | } 50 | 51 | [application] 52 | 53 | config/name="Animatron" 54 | config/description="A live coding framework for 2D animation." 55 | run/main_scene="res://Main.tscn" 56 | config/use_custom_user_dir=true 57 | config/icon="res://icon.png" 58 | 59 | [audio] 60 | 61 | enable_audio_input=true 62 | 63 | [autoload] 64 | 65 | Logger="*res://Logger.gd" 66 | 67 | [display] 68 | 69 | window/size/width=1920 70 | window/size/height=1080 71 | window/stretch/mode="2d" 72 | window/stretch/aspect="keep" 73 | 74 | [global] 75 | 76 | frame=false 77 | audio=false 78 | memor=false 79 | memory=false 80 | 81 | [input] 82 | 83 | ui_accept={ 84 | "deadzone": 0.5, 85 | "events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":16777222,"physical_scancode":0,"unicode":0,"echo":false,"script":null) 86 | , Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":32,"physical_scancode":0,"unicode":0,"echo":false,"script":null) 87 | , Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":0,"pressure":0.0,"pressed":false,"script":null) 88 | , Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":16777221,"physical_scancode":0,"unicode":0,"echo":false,"script":null) 89 | ] 90 | } 91 | eval_block={ 92 | "deadzone": 0.5, 93 | "events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":true,"meta":false,"command":true,"pressed":false,"scancode":16777221,"physical_scancode":0,"unicode":0,"echo":false,"script":null) 94 | ] 95 | } 96 | toggle_editor={ 97 | "deadzone": 0.5, 98 | "events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":true,"control":true,"meta":false,"command":true,"pressed":false,"scancode":69,"physical_scancode":0,"unicode":0,"echo":false,"script":null) 99 | ] 100 | } 101 | toggle_post={ 102 | "deadzone": 0.5, 103 | "events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":true,"meta":false,"command":true,"pressed":false,"scancode":80,"physical_scancode":0,"unicode":0,"echo":false,"script":null) 104 | ] 105 | } 106 | toggle_editor_and_post={ 107 | "deadzone": 0.5, 108 | "events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":true,"meta":false,"command":true,"pressed":false,"scancode":69,"physical_scancode":0,"unicode":0,"echo":false,"script":null) 109 | ] 110 | } 111 | clear_post={ 112 | "deadzone": 0.5, 113 | "events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":true,"control":true,"meta":false,"command":true,"pressed":false,"scancode":80,"physical_scancode":0,"unicode":0,"echo":false,"script":null) 114 | ] 115 | } 116 | post_commands={ 117 | "deadzone": 0.5, 118 | "events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":true,"meta":false,"command":true,"pressed":false,"scancode":72,"physical_scancode":0,"unicode":0,"echo":false,"script":null) 119 | ] 120 | } 121 | eval_line={ 122 | "deadzone": 0.5, 123 | "events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":true,"control":false,"meta":false,"command":false,"pressed":false,"scancode":16777221,"physical_scancode":0,"unicode":0,"echo":false,"script":null) 124 | ] 125 | } 126 | open_file={ 127 | "deadzone": 0.5, 128 | "events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":true,"meta":false,"command":true,"pressed":false,"scancode":79,"physical_scancode":0,"unicode":0,"echo":false,"script":null) 129 | ] 130 | } 131 | save_file={ 132 | "deadzone": 0.5, 133 | "events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":true,"meta":false,"command":true,"pressed":false,"scancode":83,"physical_scancode":0,"unicode":0,"echo":false,"script":null) 134 | ] 135 | } 136 | duplicate_line={ 137 | "deadzone": 0.5, 138 | "events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":true,"meta":false,"command":true,"pressed":false,"scancode":68,"physical_scancode":0,"unicode":0,"echo":false,"script":null) 139 | ] 140 | } 141 | increase_editor_font={ 142 | "deadzone": 0.5, 143 | "events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":true,"meta":false,"command":true,"pressed":false,"scancode":43,"physical_scancode":0,"unicode":0,"echo":false,"script":null) 144 | , Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":true,"meta":false,"command":true,"pressed":false,"scancode":61,"physical_scancode":0,"unicode":0,"echo":false,"script":null) 145 | ] 146 | } 147 | decrease_editor_font={ 148 | "deadzone": 0.5, 149 | "events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":true,"meta":false,"command":true,"pressed":false,"scancode":45,"physical_scancode":0,"unicode":0,"echo":false,"script":null) 150 | ] 151 | } 152 | pedal_input={ 153 | "deadzone": 0.5, 154 | "events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":true,"shift":true,"control":true,"meta":true,"command":true,"pressed":false,"scancode":0,"physical_scancode":70,"unicode":0,"echo":false,"script":null) 155 | ] 156 | } 157 | 158 | [memory] 159 | 160 | limits/message_queue/max_size_kb=8192 161 | 162 | [physics] 163 | 164 | common/enable_pause_aware_picking=true 165 | 166 | [rendering] 167 | 168 | environment/default_environment="res://default_env.tres" 169 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Animatron 2 | 3 | A tool for real-time visual poetry. 4 | 5 | ## What is it? 6 | 7 | **Animatron** is an experimental environment (very much "work in 8 | progress") that enables creation of "visual poetry," in the form of 9 | animations and images, created in real-time through live coding. It 10 | implemented using the open-source [Godot 11 | engine](https://godotengine.org/), and communicates with any "client" 12 | application or live coding language — such as 13 | [SuperCollider](https://supercollider.github.io/) — via the 14 | network, using the Open Sound Control (OSC) protocol. 15 | 16 | # Installation 17 | 18 | - Download `animatron-YOUR_PLATFORM-vX.X.X_X.zip` from the [latest release](https://github.com/loopier/animatron-godot3/releases). 19 | - Download `animatron-assets-vX.X.X_X.zip` from the [latest release](https://github.com/loopier/animatron-godot3/releases) 20 | 21 | ## Linux 22 | - Uncompress `animatron-linux-vX.X.X_X.zip` 23 | - Uncompress `animatron-assets-vX.X.X_X.zip` 24 | - Move the **CONTENTS** of the `animatron-assets-vX.X.X_X` directory (not the directory itself) into `animatron-linux-vX.X.X_X`. You should end up with a structure similar to this: 25 | 26 | ``` 27 | animatron-linux-vX.X.X_X/ 28 | ├── animations/ 29 | ├── commands/ 30 | ├── config/ 31 | ├── docs/ 32 | ├── fonts/ 33 | ├── icons/ 34 | ├── scripts/ 35 | ├── ... 36 | ├── Animatron.pck 37 | ├── Animatron.x86_64 38 | ├── libgdosc.so 39 | ``` 40 | Run `Animatron.x86_64` executable by double-clicking it. 41 | Alternatively: open a terminal and run the command: 42 | 43 | ``` 44 | $ path/to/animatron/Animatron.x86_64 45 | ``` 46 | 47 | ## Windows 48 | - Uncompress `animatron-windows-vX.X.X_X.zip` 49 | - Uncompress `animatron-assets-vX.X.X_X.zip` 50 | - Move the **CONTENTS** of the `animatron-assets-vX.X.X_X` folder (not the folder itself) into `animatron-windows-vX.X.X_X`. You should end up with a structure similar to this: 51 | 52 | ``` 53 | animatron-windows-vX.X.X_X/ 54 | ├── animations/ 55 | ├── commands/ 56 | ├── config/ 57 | ├── docs/ 58 | ├── fonts/ 59 | ├── icons/ 60 | ├── scripts/ 61 | ├── ... 62 | ├── Animatron.pck 63 | ├── Animatron.exe 64 | ├── libgdosc.dll 65 | ``` 66 | 67 | Run `Animatron.exe` by double-clicking it. 68 | 69 | If you see an error like "Can't open dynamic library ... The specified module could not be found", you may need to install the [MSVC Redistributable package](https://learn.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist?view=msvc-170). 70 | 71 | ## MacOS 72 | 73 | - Uncompress the `animatron-macos-vX.X.X.zip` file. This should unpack an `Animatron.app` bundle. 74 | - CTRL + CLICK (or RIGHT-CLICK) on `Animatron.app` and select `Show package contents` from the popup menu. 75 | - Navigate to `Contents/MacOS` 76 | - Uncompress the `animatron-assets-VX.X.X.zip` file. 77 | - Move the **CONTENTS** of the assets folder (not the folder itself) into `Animatron.app/Contents/MacOs`. You should end up with a structure similar to this: 78 | 79 | ``` 80 | Animatron.app 81 | └── Contents 82 | ├── ... 83 | ├── MacOS 84 | │ └── Animatron 85 | ├── animations/ 86 | ├── commands/ 87 | ├── config/ 88 | ├── docs/ 89 | ├── fonts/ 90 | ├── icons/ 91 | ├── scripts/ 92 | ``` 93 | 94 | Run `Animatron.app` by double-clicking it. The first time you run it, it may be prevented from opening by the macOS Gatekeeper. In this case, you should right-click (or Control-click) the app and select *Open*. If a security warning dialog appears, click the *Open* button to explicitly give permission to run it (only do this if you're sure you've downloaded Animatron from a reliable source). Once you've given your permission, it will remember it for future runs. 95 | 96 | If `Animatron.app` fails to run even after following the above steps, it may have the "quarantine" extended attribute set. This can happen if the program you used to download it (e.g. Safari, Chrome, Telegram) is not trusted. If you are sure it's from a safe place, you may remove the quarantine flag by opening the *Terminal* app and changing to the directory where you have `Animatron.app`. From that directory, run the following command: 97 | 98 | ``` 99 | $ cd ~/Downloads # change to wherever you have the app installed 100 | $ xattr -d -r com.apple.quarantine Animatron.app 101 | ``` 102 | 103 | # Compile from source 104 | 105 | Clone or download this repository. 106 | 107 | 1. Install [Godot](https://godotengine.org/download) (currently Animatron only works with Godot v3.X). 108 | 109 | 1. Clone or download [this 110 | repository](https://github.com/loopier/animatron). 111 | 112 | 1. Copy some image files (`.jpg` or `.png`) into the `animations/` 113 | directory in the repository. These will be available to use as 114 | animation sources. 115 | 116 | 1. Run Godot, choose *Scan* from the Project Manager and navigate to 117 | the location of the downloaded/cloned `animatron` project. Click 118 | "Select Current Folder," then open the Animatron project from the 119 | list of available projects. 120 | 121 | 1. Run it using the *Play* button in the upper-right corner of the 122 | Godot window (on Windows, press F5). 123 | 124 | 1. Using an external program (such as the 125 | [SuperCollider](https://supercollider.github.io/) language), send 126 | OSC messages to the program, by default on port 56101). You can 127 | find some examples in [osc-test.scd](sc/osc-test.scd). 128 | 129 | Refer to the [OSC command reference](docs/Reference.md.html) — 130 | note that this file can be opened on your local machine in any web 131 | browser and it will appear correctly formatted. 132 | 133 | # Usage 134 | 135 | The best way to learn how it works is running through the tutorial. Type `/tutorial` and press `CTRL + ENTER`. Follow the instructions and you'll get the hang of it pretty quickly. 136 | 137 | See also the [OSC Reference](docs/Reference.md.html) for a list of commands and their usage. 138 | 139 | # Remote 140 | 141 | Animatron can also be used remotely via OSC messages. The commands are the same. The exact syntax of the message depends on the software you're using to send the messages. 142 | 143 | But first, we need to set up the communication system. Animatron is listening for OSC messages on port `56101`. Following is an example for SuperCollider running on the same machine as Animatron. 144 | 145 | ``` 146 | a = NetAdress("localhost", 56101); 147 | a.sendMsg("/bg", 0, 0, 0.2); 148 | a.sendMsg("/new", "sq", "square"); 149 | a.sendMsg("/color", "sq", 1,0,0); 150 | // ... etc 151 | ``` 152 | 153 | To get replies, an OSC listener needs to be set up on the client side: 154 | 155 | ``` 156 | a = NetAdress("localhost", 56101); 157 | 158 | OSCdef(\listActorsReply, { arg msg; 159 | "Actors: %".format(msg[1..]).postln; 160 | oscReply = msg.debug("oscdef"); 161 | }, "/list/actors/reply"); 162 | OSCdef(\listAnimsReply, { arg msg; 163 | "Available animations:\n\t%".format(join(msg[1..], "\n\t")).postln; 164 | }, "/list/anims/reply"); 165 | OSCdef(\listAssetsReply, { arg msg; 166 | "Available assets:\n\t%".format(join(msg[1..], "\n\t")).postln; 167 | }, "/list/assets/reply"); 168 | OSCdef(\errorReply, { arg msg; 169 | "Error: %".format(msg[1]).postln; 170 | oscReply = msg; 171 | }, "/error/reply"); 172 | OSCdef(\statusReply, { arg msg; 173 | "Status: %".format(msg[1]).postln; 174 | }, "/status/reply"); 175 | ``` 176 | 177 | If you're going to use SuperCollider often, you can copy the `Animatron/` folder you'll find in the `sc/` directory to your SuperCollider `Extensions/` folder. When creating an instance, a listener for the replies is automatically set up: 178 | 179 | ``` 180 | a = Animatron(); 181 | a.sendMsg("/list/assets"); // see the post window 182 | ``` 183 | 184 | # License 185 | 186 | Animatron is Copyright © 2021 by Glen Fraser, Roger Pibernat and 187 | contributors. 188 | 189 | Animatron is distributed under the terms of the GNU Public license version 3 (or 190 | later). See [LICENSE](LICENSE) for all the details. 191 | 192 | -------------------------------------------------------------------------------- /Main.gd: -------------------------------------------------------------------------------- 1 | extends Node2D 2 | 3 | var oscrcv 4 | # Actor commands: 5 | # The first argument for all these commands is the target actor(s). 6 | # It may be "!" (selection), an actor instance name or a wildcard string. 7 | onready var actorCmds = { 8 | "/free": funcref($OscInterface, "freeActor"), 9 | "/anim": funcref($OscInterface, "setActorAnim"), 10 | # play 11 | "/play": funcref($OscInterface, "playActor"), 12 | "/play/range": funcref($OscInterface, "playActorRange"), 13 | "/oneshot": funcref($OscInterface, "playActorOneshot"), 14 | "/loop": funcref($OscInterface, "playActorLoop"), 15 | "/play/rand": funcref($OscInterface, "playActorRandom"), 16 | "/stop": funcref($OscInterface, "stopActor"), 17 | "/frame": funcref($OscInterface, "setActorFrame"), 18 | "/frame/next": funcref($OscInterface, "nextActorFrame"), 19 | "/frame/prev": funcref($OscInterface, "previousActorFrame"), 20 | # absolute position 21 | "/position": funcref($OscInterface, "setActorPosition"), 22 | "/position/x": funcref($OscInterface, "setActorPositionX"), 23 | "/position/y": funcref($OscInterface, "setActorPositionY"), 24 | # relative position 25 | "/move": funcref($OscInterface, "moveActor"), 26 | "/move/x": funcref($OscInterface, "moveActorX"), 27 | "/move/y": funcref($OscInterface, "moveActorY"), 28 | # absolute angle 29 | "/angle": funcref($OscInterface, "setActorAngle"), 30 | # relative angle 31 | "/rotate": funcref($OscInterface, "rotateActor"), 32 | # absolute size 33 | "/size": funcref($OscInterface, "setActorSize"), 34 | "/size/xy": funcref($OscInterface, "setActorSizeXY"), 35 | "/size/x": funcref($OscInterface, "setActorSizeX"), 36 | "/size/y": funcref($OscInterface, "setActorSizeY"), 37 | # relative size 38 | "/scale": funcref($OscInterface, "scaleActor"), 39 | "/scale/xy": funcref($OscInterface, "scaleActorXY"), 40 | "/scale/x": funcref($OscInterface, "scaleActorX"), 41 | "/scale/y": funcref($OscInterface, "scaleActorY"), 42 | 43 | "/pivot": funcref($OscInterface, "setActorPivot"), 44 | "/alpha": funcref($OscInterface, "setActorAlpha"), 45 | "/fade": funcref($OscInterface, "setActorFade"), 46 | "/fade/toggle": funcref($OscInterface, "toggleActorFade"), 47 | "/speed": funcref($OscInterface, "setActorSpeed"), 48 | "/slow": funcref($OscInterface, "setActorSpeedSlow"), # /fast is an alias of /speed 49 | "/fliph": funcref($OscInterface, "flipActorH"), 50 | "/flipv": funcref($OscInterface, "flipActorV"), 51 | "/color": funcref($OscInterface, "colorActor"), 52 | "/color/r": funcref($OscInterface, "colorRedActor"), 53 | "/color/g": funcref($OscInterface, "colorGreenActor"), 54 | "/color/b": funcref($OscInterface, "colorBlueActor"), 55 | "/say": funcref($OscInterface, "sayActor"), 56 | "/action": funcref($OscInterface, "actionActor"), 57 | "/behind": funcref($OscInterface, "behindActor"), 58 | "/front": funcref($OscInterface, "frontActor"), 59 | "/sound": funcref($OscInterface, "soundActor"), 60 | "/sound/free": funcref($OscInterface, "soundFreeActor"), 61 | "/midi": funcref($OscInterface, "midiActor"), 62 | "/midi/free": funcref($OscInterface, "midiFreeActor"), 63 | "/midi/free/all": funcref($OscInterface, "midiFreeAll"), 64 | "/onframe": funcref($OscInterface, "onFrameActor"), 65 | "/onfinish": funcref($OscInterface, "onFinishActor"), 66 | "/onframe/free": funcref($OscInterface, "onFrameFreeActor"), 67 | "/onfinish/free": funcref($OscInterface, "onFinishFreeActor"), 68 | "/list/sequence": funcref($OscInterface, "getActorFrameCmds"), 69 | "/state/add": funcref($OscInterface, "addActorState"), 70 | "/state/free": funcref($OscInterface, "freeActorState"), 71 | "/list/states": funcref($OscInterface, "listActorStates"), 72 | } 73 | 74 | onready var otherCmds = { 75 | "/load": funcref($OscInterface, "loadAsset"), 76 | "/create": funcref($OscInterface, "createActor"), 77 | "/create/group": funcref($OscInterface, "createActorGroup"), 78 | "/createordestroy": funcref($OscInterface, "createOrDestroyActor"), 79 | "/parent": funcref($OscInterface, "parentActor"), 80 | "/parent/free": funcref($OscInterface, "parentFreeActor"), 81 | "/list/children": funcref($OscInterface, "listActorChildren"), 82 | "/ysort": funcref($OscInterface, "ySortActors"), 83 | "/list": funcref($OscInterface, "listActors"), # shortcut for /list/actors 84 | "/list/actors": funcref($OscInterface, "listActors"), 85 | "/list/anims": funcref($OscInterface, "listAnims"), 86 | "/list/assets": funcref($OscInterface, "listAssets"), 87 | "/group": funcref($OscInterface, "groupActor"), 88 | "/ungroup": funcref($OscInterface, "ungroupActor"), 89 | "/iter": funcref($OscInterface, "iterateGroup"), 90 | "/at": funcref($OscInterface, "atGroupItem"), 91 | "/select": funcref($OscInterface, "selectActor"), 92 | "/deselect": funcref($OscInterface, "deselectActor"), 93 | "/selected": funcref($OscInterface, "listSelectedActors"), 94 | "/def": funcref($OscInterface, "defCommand"), 95 | "/load/defs": funcref($OscInterface, "loadDefsFile"), 96 | "/debug": funcref($OscInterface, "enableStatusMessages"), 97 | "/midi/debug": funcref($OscInterface, "midiEnableStatusMessages"), 98 | "/list/midi": funcref($OscInterface, "listMidiCmds"), 99 | 100 | #rand 101 | "/rand": funcref($OscInterface, "randCmdArg"), 102 | "/choose": funcref($OscInterface, "chooseCmd"), 103 | "/choose/arg": funcref($OscInterface, "chooseArg"), 104 | 105 | # time 106 | # "/wait" command is handled specially 107 | "/routine": funcref($OscInterface, "newRoutine"), 108 | "/routine/start": funcref($OscInterface, "startRoutine"), 109 | "/routine/stop": funcref($OscInterface, "stopRoutine"), 110 | "/routine/free": funcref($OscInterface, "freeRoutine"), 111 | "/routine/free/all": funcref($OscInterface, "routineFreeAll"), 112 | "/list/routines": funcref($OscInterface, "listRoutines"), 113 | 114 | # write 115 | "/load/alphabet": funcref($Letters, "loadAlphabet"), 116 | "/write": funcref($Letters, "write"), 117 | "/letter": funcref($Letters, "setLetter"), 118 | "/letters/spacing": funcref($Letters, "setSpacing"), 119 | "/letters/scale": funcref($Letters, "setScale"), 120 | 121 | # app 122 | "/bg": funcref($OscInterface, "setBackgroundColor"), 123 | "/list/commands": funcref($OscInterface, "listCommands"), 124 | "/help": funcref($OscInterface, "openHelp"), 125 | "/user/datapath": funcref($OscInterface, "postUserDataPath"), 126 | 127 | # editor 128 | "/tutorial": funcref($OscInterface, "loadTutorial"), 129 | "/editor/open": funcref($OscInterface, "openFile"), 130 | "/editor/save": funcref($OscInterface, "saveFile"), 131 | "/editor/append": funcref($OscInterface, "editorAppend"), 132 | "/editor/font/size": funcref($OscInterface, "editorFontSize"), 133 | "/editor/font/increase": funcref($OscInterface, "editorIncreaseFont"), 134 | "/editor/font/decrease": funcref($OscInterface, "editorDecreaseFont"), 135 | "/editor/clear": funcref($OscInterface, "editorClear"), 136 | "/post": funcref($OscInterface, "postMsg"), 137 | "/post/font/size": funcref($OscInterface, "postFontSize"), 138 | "/post/font/increase": funcref($OscInterface, "postIncreaseFont"), 139 | "/post/font/decrease": funcref($OscInterface, "postDecreaseFont"), 140 | "/post/open": funcref($OscInterface, "postFile"), 141 | "/post/clear": funcref($OscInterface, "postClear"), 142 | 143 | # logger 144 | "/log": funcref($OscInterface, "logMsg"), 145 | "/log/level": funcref($OscInterface, "setLogLevel"), 146 | 147 | # osc 148 | "/osc/remote": funcref($OscInterface, "connectOscRemote"), 149 | "/osc/send": funcref($OscInterface, "sendOsc"), 150 | 151 | # config commands 152 | "/load/config": funcref($Config, "loadConfig"), 153 | "/assets/path": funcref($Config, "setAnimationAssetPath"), 154 | "/app/remote": funcref($Config, "setAppRemote"), 155 | 156 | # app window 157 | "/window/screen": funcref($Config, "moveWindowToScreen"), 158 | "/window/position": funcref($Config, "setWindowPosition"), 159 | "/window/size": funcref($Config, "setWindowSize"), 160 | "/window/center": funcref($Config, "centerWindow"), 161 | "/window/fullscreen": funcref($Config, "fullscreen"), 162 | "/window/top": funcref($Config, "windowAlwaysOnTop"), 163 | } 164 | 165 | 166 | func getActorCommandSummary() -> String: 167 | return (actorCmds.keys() as PoolStringArray).join('\n') 168 | 169 | 170 | func getOtherCommandSummary() -> String: 171 | return (otherCmds.keys() as PoolStringArray).join('\n') 172 | 173 | 174 | func _ready(): 175 | Logger.setLevel(Logger.LOG_LEVEL_INFO) 176 | # Logger.setLevel(Logger.LOG_LEVEL_VERBOSE) 177 | Logger.setTarget(get_node("PostTextEdit")) 178 | Logger.info("version 0.1.0_17") 179 | randomize() 180 | 181 | # See: https://gitlab.com/frankiezafe/gdosc 182 | oscrcv = load("res://addons/gdosc/gdoscreceiver.gdns").new() 183 | # [optional] maximum number of messages in the buffer, default is 100 184 | oscrcv.max_queue( 256 ) 185 | # [optional] receiver will only keeps the "latest" message for each address 186 | oscrcv.avoid_duplicate( false ) 187 | # [mandatory] listening to port 14000 188 | oscrcv.setup( 56101 ) 189 | # [mandatory] starting the reception of messages 190 | oscrcv.start() 191 | 192 | # Load initial set of custom command definitions (if it exists) 193 | $OscInterface.loadDefsFile(["init.osc"], null) 194 | 195 | # Load default config file (if it exists) and call config command 196 | $Config.loadConfig(["config.osc"], null) 197 | evalCommandList([["/config"]], null) 198 | 199 | var w = OS.get_window_size().x 200 | var h = OS.get_window_size().y 201 | var gap = 10 202 | $OscTextEdit._set_size(Vector2(w*2/3, h)) 203 | $PostTextEdit._set_size(Vector2(w*1/3 - gap, h)) 204 | $PostTextEdit._set_position(Vector2(w*2/3 + gap, 0)) 205 | 206 | # $Letters.loadAlphabet([]) 207 | 208 | 209 | func evalCommandList(commands : Array, sender): 210 | while !commands.empty(): 211 | var cmd = commands.pop_front() 212 | var addr : String = cmd[0] 213 | if addr[0] != '/': 214 | # Allow addresses missing the slash at start 215 | addr = addr.insert(0, '/') 216 | var args = cmd.slice(1, -1) if cmd.size() > 1 else [] 217 | if addr == "/wait": 218 | var waitTime = $OscInterface.wait(args, sender) 219 | if waitTime: 220 | Logger.debug("Starting wait of %f seconds..." % [waitTime]) 221 | yield(get_tree().create_timer(waitTime), "timeout") 222 | Logger.debug("...done waiting %f seconds" % [waitTime]) 223 | else: 224 | var subCmds = evalOscCommand(addr, args, sender) 225 | if typeof(subCmds) == TYPE_ARRAY: 226 | commands = subCmds + commands 227 | 228 | 229 | func evalOscCommand(address : String, args, sender): 230 | Logger.debug("+++ evalOscCommand(%s, %s" % [address, args]) 231 | var applyToSelection = address.ends_with("!") 232 | if applyToSelection: 233 | address = address.trim_suffix("!") 234 | args.insert(0, "!") 235 | 236 | if actorCmds.has(address): 237 | actorCmds[address].call_func(args, sender) 238 | elif otherCmds.has(address): 239 | otherCmds[address].call_func(args, sender) 240 | elif $CustomCommands.hasCommand(address): 241 | var cmd = $CustomCommands.getCommand(address) 242 | if args.size() != cmd.args.size(): 243 | $OscInterface.reportError("Custom command '%s' expects %d arguments" 244 | % [address, cmd.args.size()], sender) 245 | return 246 | var subCmds = [] 247 | for subCmd in cmd.cmds: 248 | var subAddr = subCmd[0] 249 | Logger.debug("subCmd: (%s)%s" % [typeof(subCmd), subCmd]) 250 | # Logger.logDict($CustomCommands.commands) 251 | var subArgs = Array(subCmd).slice(1, -1) if subCmd.size() > 1 else [] 252 | for i in range(subArgs.size()): 253 | if subArgs[i].begins_with("$"): 254 | var idx = cmd.args.find(subArgs[i].substr(1)) 255 | if idx >= 0: subArgs[i] = args[idx] 256 | subCmds.push_back([subAddr] + subArgs) 257 | # Evaluation happens later, in the caller 258 | return subCmds 259 | else: 260 | $OscInterface.reportError("OSC command not found: " + address, sender) 261 | 262 | 263 | func processOscMsg(address : String, args : Array, sender): 264 | evalCommandList([[address] + args], sender) 265 | 266 | 267 | func _process(_delta): 268 | # check if there are pending messages 269 | while( oscrcv.has_message() ): 270 | # retrieval of the messages as a dictionary 271 | var msg = oscrcv.get_next() 272 | var sender = [msg["ip"], msg["port"]] 273 | if not $Config.allowRemoteClients and sender[0] != "127.0.0.1": 274 | Logger.warn("Skipping non-local OSC message from %s" % [sender]) 275 | continue 276 | var address = msg["address"] 277 | var args = msg["args"] 278 | # printing the values, check console 279 | if false: 280 | Logger.debug( "address: %s" % [address] ) 281 | Logger.debug( "typetag: %s" % [msg["typetag"]] ) 282 | Logger.debug( "from: %s:%s" % [msg["ip"], msg["port"]] ) 283 | Logger.debug( "arguments: ") 284 | for i in range( 0, msg["arg_num"] ): 285 | Logger.debug( "\t%s = %s" % [i, args[i]] ) 286 | 287 | processOscMsg(address, args, sender) 288 | 289 | 290 | func _exit_tree ( ): 291 | # disable the receiver, highly recommended! 292 | oscrcv.stop() 293 | 294 | func _input(event): 295 | # Logger.debug(event.as_text()) 296 | if event.is_action_pressed("toggle_editor", true): 297 | $OscTextEdit.set_visible(not($OscTextEdit.is_visible())) 298 | elif event.is_action_pressed("toggle_editor_and_post", true): 299 | $OscTextEdit.set_visible(not($OscTextEdit.is_visible())) 300 | $PostTextEdit.set_visible($OscTextEdit.is_visible()) 301 | elif event.is_action_pressed("clear_post", true): 302 | $PostTextEdit.clear() 303 | elif event.is_action_pressed("toggle_post", true): 304 | $PostTextEdit.set_visible(not($PostTextEdit.is_visible())) 305 | elif event.is_action_pressed("post_commands", true): 306 | $OscTextEdit.set_visible(true) 307 | $PostTextEdit.set_visible($OscTextEdit.is_visible()) 308 | $PostTextEdit.help() 309 | evalOscCommand("/list/commands", [], null) 310 | elif event.is_action_pressed("pedal_input", true): 311 | processOscMsg("/pedal/pressed", [], null) 312 | 313 | func _on_OpenFileDialog_file_selected(path): 314 | openFile(path) 315 | 316 | func openFile(path): 317 | $OscTextEdit.text = getTextFromFile(path) 318 | 319 | func getTextFromFile(path) -> String: 320 | var file = File.new() 321 | var text : String 322 | var err = file.open(path, File.READ) 323 | if err: 324 | if path.is_rel_path(): 325 | var tryPath = OS.get_executable_path().get_base_dir() + "/" + path 326 | err = file.open(tryPath, File.READ) 327 | if err: 328 | Logger.error("can't open relative path as resource, or relative to executable (%s)" % [ProjectSettings.globalize_path(tryPath)]) 329 | else: 330 | Logger.error("can't open absolute path: %s" % [ProjectSettings.globalize_path(path)]) 331 | if !err: 332 | Logger.verbose("opened file: %s" % [path]) 333 | text = file.get_as_text() 334 | file.close() 335 | return text 336 | 337 | func _on_SaveFileDialog_file_selected(path): 338 | saveFile(path) 339 | 340 | func saveFile(path): 341 | Logger.info("save file to: %s" % [path]) 342 | var file = File.new() 343 | file.open(path, File.WRITE) 344 | file.store_string($OscTextEdit.text) 345 | file.close() 346 | 347 | func post(msg): 348 | $PostTextEdit.append(msg) 349 | 350 | 351 | -------------------------------------------------------------------------------- /sc/osc-test.scd: -------------------------------------------------------------------------------- 1 | ( 2 | //////////////////////////////////////////////////////////// 3 | // Setup 4 | //////////////////////////////////////////////////////////// 5 | "setup.scd".loadRelative.first; 6 | ) 7 | 8 | ( 9 | Tdef(\a, { 10 | 100.do{|x| 11 | // "om"++x.postln; 12 | n.sendMsg("/create", "om"++x, "om-walk-sw"); 13 | n.sendMsg("/speed", "om"++x, rrand(0.7,2.0)); 14 | 0.1.wait; 15 | } 16 | }).play 17 | ) 18 | 19 | ( 20 | //////////////////////////////////////////////////////////// 21 | // Comprehensive unit tests 22 | //////////////////////////////////////////////////////////// 23 | var test = { |description, msg, waittime=0.5| 24 | ("-- " ++ description).postln; 25 | msg.(); 26 | waittime.wait; 27 | }; 28 | var create = { 29 | test.("empty list", { 30 | n.sendMsg("/list"); // or /list/actors 31 | }); 32 | test.("create one instance with animation", { 33 | n.sendMsg("/create", "omo", "om-walk-SW"); 34 | n.sendMsg("/list"); 35 | }); 36 | }; 37 | var transform = { 38 | test.("transform", { 39 | n.sendMsg("/position", "omo", 0.5, 0.5); 40 | 1.0.wait; 41 | n.sendMsg("/fliph", "omo"); 42 | 1.0.wait; 43 | n.sendMsg("/fliph", "omo"); 44 | n.sendMsg("/flipv", "omo"); 45 | 1.0.wait; 46 | n.sendMsg("/flipv", "omo"); 47 | }); 48 | }; 49 | var walkcycle = { 50 | test.("turn-around test", { 51 | n.sendMsg("/create", "omo", "om-walk-W"); 52 | 1.0.wait; 53 | n.sendMsg("/create", "omo", "om-walk-NW"); 54 | 1.0.wait; 55 | n.sendMsg("/create", "omo", "om-walk-N"); 56 | 1.0.wait; 57 | n.sendMsg("/create", "omo", "om-walk-NE"); 58 | 1.0.wait; 59 | n.sendMsg("/create", "omo", "om-walk-E"); 60 | 1.0.wait; 61 | n.sendMsg("/create", "omo", "om-walk-SE"); 62 | 1.0.wait; 63 | n.sendMsg("/create", "omo", "om-walk-S"); 64 | 1.0.wait; 65 | n.sendMsg("/create", "omo", "om-to-idle-S"); 66 | 1.0.wait; 67 | n.sendMsg("/create", "omo", "om-to-idle-SW"); 68 | 1.0.wait; 69 | n.sendMsg("/create", "omo", "om-to-idle-SE"); 70 | }); 71 | }; 72 | var transport = { 73 | test.("transport", { 74 | n.sendMsg("/create", "omo", "om-walk-SW"); 75 | n.sendMsg("/stop", "omo"); 76 | 1.0.wait; 77 | n.sendMsg("/play", "omo"); 78 | }); 79 | test.("speed", { 80 | n.sendMsg("/speed", "omo", 2.0); 81 | 1.0.wait; 82 | n.sendMsg("/speed", "omo", 0.5); 83 | 1.0.wait; 84 | n.sendMsg("/speed", "omo", 1.0); 85 | }); 86 | test.("frame navigation", { 87 | n.sendMsg("/stop", "omo"); 88 | }); 89 | test.("wraps frame number", { 90 | n.sendMsg("/frame", "omo", 100); 91 | 1.0.wait; 92 | n.sendMsg("/frame", "omo", 4); 93 | }); 94 | }; 95 | var free = { 96 | test.("free", {n.sendMsg("/free", "omo", 4);}); 97 | }; 98 | var wildcards = { 99 | 10.do { |x| 100 | test.("wildcards", 101 | { 102 | n.sendMsg("/create", "om"++x, "om-walk-SW"); 103 | n.sendMsg("/speed", "om"++x, rrand(0.7,2.0)); 104 | }, 0.1); 105 | }; 106 | }; 107 | var wildcardsfree = { 108 | test.("wildcards free", {n.sendMsg("/free", "om*");}) 109 | }; 110 | var color = { 111 | test.("change color", {n.sendMsg("/color", "om*", 1,1,1);}) 112 | }; 113 | var select = { 114 | test.("none selected", {n.sendMsg("/selected")}); 115 | test.("select one", { 116 | n.sendMsg("/create", "omo", "om-walk-SW"); 117 | n.sendMsg("/position", "omo", 0.5, 0.5); 118 | n.sendMsg("/select", "omo"); 119 | n.sendMsg("/selected"); 120 | }); 121 | test.("select non-existent", { 122 | n.sendMsg("/select", "blu"); 123 | n.sendMsg("/selected".postln); 124 | }); 125 | test.("select with '?'", { 126 | n.sendMsg("/create", "oma", "om-walk-SE"); 127 | n.sendMsg("/position", "oma", 0.25, 0.5); 128 | n.sendMsg("/select", "om?"); 129 | n.sendMsg("/selected".postln); 130 | }); 131 | test.("deselect one", { 132 | n.sendMsg("/deselect", "omo"); 133 | }); 134 | test.("list selected", { 135 | n.sendMsg("/selected".postln); 136 | }); 137 | }; 138 | var group = { 139 | test.("add omo and oma to 'walkers' group", { 140 | n.sendMsg("/group", "walkers", "om?"); 141 | }); 142 | test.("list group members", { 143 | n.sendMsg("/group", "walkers"); 144 | }); 145 | test.("remove oma from 'walkers'", { 146 | n.sendMsg("/ungroup", "walkers", "omo"); 147 | }); 148 | test.("list group members", { 149 | n.sendMsg("/group", "walkers"); 150 | }); 151 | }; 152 | var say = { 153 | test.("say something", { 154 | n.sendMsg("/create", "omo", "om-idle-SW"); 155 | n.sendMsg("/position", "omo", 0.5, 0.5); 156 | n.sendMsg("/say", "omo", "something"); 157 | 4.wait; 158 | // n.sendMsg("/say", "omo", "something else\nin two lines"); 159 | n.sendMsg("/say", "omo", "something else in two lines"); 160 | 4.wait; 161 | // n.sendMsg("/say", "omo", "something\nvertical\nin many\nlines"); 162 | n.sendMsg("/say", "omo", "something vertical in many lines"); 163 | 4.wait; 164 | // n.sendMsg("/say", "omo", "something during\na given time", 4); 165 | n.sendMsg("/say", "omo", "something during a given time", 4); 166 | 167 | }) 168 | }; 169 | var manysay = { 170 | test.("many say something",{ 171 | 10.do{|x| 172 | n.sendMsg("/create", "om"++x, "om-idle-"++["SW","S"].choose); 173 | if(0.5.coin, {n.sendMsg("/fliph", "om"++x)}); 174 | n.sendMsg("/color", "om"++x, 1.0.rand, 0.2.rand, 0.2.rand); 175 | n.sendMsg("/position", "om"++x, rrand(0.1,0.9), rrand(0.2,0.8)); 176 | rrand(0.2,3.0).wait; 177 | n.sendMsg("/say", "om"++x, "I'm om"++x, rrand(3,6)); 178 | rrand(0.1,2.0).wait; 179 | }; 180 | }); 181 | }; 182 | var listruntimedata = { 183 | test.("files/assets available to load at runtime", { 184 | n.sendMsg("/list/assets"); 185 | }); 186 | test.("anims loaded at runtime", { 187 | n.sendMsg("/list/anims"); 188 | }); 189 | }; 190 | var loadruntime = { 191 | test.("load file at runtime", { 192 | 100.do{|x| 193 | n.sendMsg("/create", "om"++x, "om-idle-"++["e","n","w","s","nw","ne","sw","se"].choose); 194 | n.sendMsg("/position", "om"++x, rrand(0.1,0.9), rrand(0.2,0.8)); 195 | n.sendMsg("/speed", "om"++x, rrand(0.5,2.0)); 196 | 0.1.wait; 197 | }; 198 | }); 199 | }; 200 | // syntax for a new test: 201 | // var testname = { 202 | // test.("a description", { 203 | // n.sendMsg(...); 204 | // // ... 205 | // }, 206 | // waittime: defaults-to-1.0); 207 | // }; 208 | // 209 | // then add it to the task with: 210 | // 211 | // testname.(); 212 | // 213 | // comment to disble tests 214 | t = Task { 215 | // create.(); 216 | // transform.(); 217 | // walkcycle.(); 218 | // transport.(); 219 | // 2.0.wait; 220 | // free.(); 221 | // wildcards.(); 222 | // color.(); 223 | // select.(); 224 | // 1.0.wait; 225 | // group.(); 226 | // 2.wait; 227 | // say.(); 228 | // manysay.(); 229 | listruntimedata.(); 230 | loadruntime.(); 231 | 4.wait; 232 | wildcardsfree.(); 233 | }; 234 | t.start; 235 | ) 236 | 237 | n.sendMsg("/list/anims"); 238 | 239 | ( 240 | //////////////////////////////////////////////////////////// 241 | // Alternative OSC interface testing (run OSCdef setup first) 242 | //////////////////////////////////////////////////////////// 243 | Tdef(\test, { 244 | n.sendMsg("/list/assets"); 245 | ["run", "om-walk-sw", "om-walk-nw", "om-walk-s", "fox-walk", "frog-jump"].do{ |name| n.sendMsg("/load", name) }; 246 | n.sendMsg("/list/anims"); 247 | n.sendMsg("/invalid", "frog"); 248 | n.sendMsg("/free", "*"); 249 | n.sendMsg("/list"); 250 | n.sendMsg("/create", "runner", "run"); 251 | n.sendMsg("/create", "omo", "om-walk-sw"); 252 | n.sendMsg("/create", "oma", "om-walk-nw"); 253 | n.sendMsg("/select", "om*"); 254 | n.sendMsg("/select"); 255 | n.sendMsg("/deselect", "omo"); 256 | n.sendMsg("/selected"); 257 | n.sendMsg("/stop!"); 258 | n.sendMsg("/stop", "omo"); 259 | n.sendMsg("/frame!", 3); 260 | n.sendMsg("/frame", "omo", 3); 261 | n.sendMsg("/play!"); 262 | n.sendMsg("/play", "om?"); 263 | n.sendMsg("/position!", 0.25, 0.25); 264 | n.sendMsg("/position", "omo", 0.75, 0.5, 2); 265 | n.sendMsg("/speed!", 0.5); 266 | n.sendMsg("/speed", "omo", 1.5); 267 | n.sendMsg("/fliph!"); 268 | n.sendMsg("/fliph", "omo"); 269 | n.sendMsg("/flipv!"); 270 | n.sendMsg("/flipv", "omo"); 271 | n.sendMsg("/create", "omi", "om-walk-s"); 272 | n.sendMsg("/position", "omi", 0.5, 0.5); 273 | n.sendMsg("/group", "inverted", "om*"); 274 | n.sendMsg("/group", "inverted"); 275 | n.sendMsg("/ungroup", "inverted", "omi"); 276 | n.sendMsg("/group", "inverted"); 277 | n.sendMsg("/color!", 0.8, 0.5, 0); 278 | n.sendMsg("/color", "omi", 0, 0.5, 0.8); 279 | n.sendMsg("/deselect", "*"); 280 | n.sendMsg("/list"); 281 | n.sendMsg("/free!"); 282 | n.sendMsg("/create", "fox", "fox-walk"); 283 | n.sendMsg("/create", "frog", "frog-jump"); 284 | n.sendMsg("/group", "others", "f*"); 285 | n.sendMsg("/group", "others"); 286 | n.sendMsg("/speed", "others", 4); 287 | n.sendMsg("/select", "others"); 288 | n.sendMsg("/list"); 289 | n.sendMsg("/free!"); 290 | n.sendMsg("/list"); 291 | n.sendMsg("/say", "omo", "something"); 292 | n.sendMsg("/say", "omi", "something else", 8); 293 | n.sendMsg("/select", "oma"); 294 | n.sendMsg("/say!", "I'm oma", 4); 295 | n.sendMsg("/deselect"); 296 | }).play 297 | 298 | // The expected output is: 299 | /* 300 | Available assets: 301 | default 302 | fox-walk 303 | ... 304 | om-walk-w 305 | pickaxe 306 | march 307 | run 308 | Status: loaded sequences: [res://animations/run_12fps] 309 | Status: loaded sprites: [res://animations/om-walk-sw.png] 310 | Status: loaded sprites: [res://animations/om-walk-nw.png] 311 | Status: loaded sprites: [res://animations/om-walk-s.png] 312 | Status: loaded sprites: [res://animations/fox-walk_6x1_8fps.png] 313 | Status: loaded sprites: [res://animations/frog-jump_4x2_8fps.png] 314 | Available animations: 315 | fox-walk 316 | frog-jump 317 | om-walk-nw 318 | om-walk-s 319 | om-walk-sw 320 | run 321 | Error: OSC command not found: /invalid 322 | Error: No matches found for: * 323 | Status: Freed: [] 324 | Anims: [ ] 325 | Status: Created node 'runner' with 'run' 326 | Status: Created node 'omo' with 'om-walk-sw' 327 | Status: Created node 'oma' with 'om-walk-nw' 328 | Status: selected: [omo, oma] 329 | Status: selected: [oma] 330 | Status: Created node 'omi' with 'om-walk-s' 331 | Status: 'inverted' members: [omo, oma, omi] 332 | Status: 'inverted' members: [omo, oma] 333 | Anims: [ runner, omo, oma, omi ] 334 | Status: Freed: [] 335 | Status: Created node 'fox' with 'fox-walk' 336 | Status: Created node 'frog' with 'frog-jump' 337 | Status: 'others' members: [fox, frog] 338 | Anims: [ runner, omo, oma, omi, fox, frog ] 339 | Status: Freed: [fox, frog] 340 | Anims: [ runner, omo, oma, omi ] 341 | */ 342 | 343 | // And you should see a slow orange upside-down om at 344 | // the upper-left, a blue om facing you in the 345 | // centre, and a fast black upside-down om at the right. 346 | // They'll have some speech bubbles that last a short while. 347 | ) 348 | 349 | // If you have a commands/init.osc file installed that defines 350 | // /createsel and /startup, you can run these custom commands 351 | // (like macros). 352 | n.sendMsg("/wait", 2) 353 | n.sendMsg("/startup"); 354 | n.sendMsg("/createsel", "frog", "frog-jump") 355 | n.sendMsg("/deselect") 356 | 357 | n.sendMsg("/def", "/waitasset", "/wait 1", "/list/assets") 358 | n.sendMsg("/def", "/waitanim", "/wait 2", "/list/anims") 359 | n.sendMsg("/def", "/waitlist", "/waitasset", "/waitanim") 360 | n.sendMsg("/waitasset") 361 | n.sendMsg("/waitlist") 362 | 363 | n.sendMsg("/def", "/waitlist", "/wait 2", "/list/assets", "/wait 2", "/list/anims") 364 | n.sendMsg("/waitlist") 365 | 366 | n.sendMsg("/def", "/hello", "/list/assets", "/group bob") 367 | n.sendMsg("/hello") 368 | n.sendMsg("/def", "/test arg1 b", "/create $arg1 $b") 369 | n.sendMsg("/test", "fred", "steve") 370 | 371 | n.sendMsg("/list/anims") 372 | ( 373 | n.sendMsg("/def", "/square actor", 374 | "/new $actor om-walk-e", 375 | "/position $actor 0.9 0.25 2", 376 | "/wait 4", 377 | "/new $actor om-walk-s", 378 | "/position $actor 0.8 0.9 2", 379 | "/wait 3", 380 | "/new $actor om-walk-w", 381 | "/position $actor 0.2 0.9 1", 382 | "/wait 2", 383 | "/new $actor om-walk-n", 384 | "/position $actor 0.1 0.25 1") 385 | ) 386 | n.sendMsg("/square", "om5") 387 | n.sendMsg("/load/defs", "test.osc") 388 | n.sendMsg("/startup") 389 | 390 | n.sendMsg("/list/assets"); 391 | n.sendMsg("/load", "march"); 392 | n.sendMsg("/create", "m1", "march") 393 | n.sendMsg("/select", "m?") 394 | (1..5).do{|i| n.sendMsg("/position", "m" ++ i, i.linlin(1,5,0,1), 1, 4) } 395 | n.sendMsg("/rotate!", 90, 12) 396 | n.sendMsg("/scale!", "0.25,4", 1) 397 | n.sendMsg("/fade!", 0, 4) 398 | 399 | n.sendMsg("/load", "om-jump-up") 400 | n.sendMsg("/load", "pickaxe") 401 | n.sendMsg("/list/anims") 402 | n.sendMsg("/create", "om", "om-jump-up-nw") 403 | n.sendMsg("/create", "axe", "pickaxe") 404 | 405 | n.sendMsg("/def", "/go", "/free *", "/create axe pickaxe", "/position axe 0.25 0.5", "/scale axe 2 2") 406 | n.sendMsg("/go") // call repeatedly quickly and check for flicker (fixed tweening with 0 duration) 407 | 408 | // If you have a 1024x600 image, you should name it bg-black_1x1_1fps.png 409 | // and can set it as the background (covering the whole view) like this: 410 | n.sendMsg("/load", "bg-black") 411 | n.sendMsg("/create", "bg", "bg-black") 412 | n.sendMsg("/position", "bg", 0.5,0.5) 413 | n.sendMsg("/window/fullscreen", false) 414 | n.sendMsg("/position", "axe", 0.5, 0.5) 415 | n.sendMsg("/position", "om", 0.5, 0.5) 416 | n.sendMsg("/free", "bg") 417 | n.sendMsg("/list") 418 | 419 | ( 420 | n.sendMsg("/load", "pickaxe"); 421 | n.sendMsg("/create", "bigger", "pickaxe"); 422 | n.sendMsg("/create", "axe1", "pickaxe"); 423 | n.sendMsg("/create", "axe2", "pickaxe"); 424 | n.sendMsg("/create", "axe3", "pickaxe"); 425 | n.sendMsg("/scale", "bigger", 2, 2); 426 | n.sendMsg("/position", "bigger", 0.4, 1); 427 | n.sendMsg("/position", "axe1", 0.5, 0.5); 428 | n.sendMsg("/position", "axe2", 0.55, 0.55); 429 | n.sendMsg("/position", "axe3", 0.525, 0.6); 430 | n.sendMsg("/color", "axe1", 0.7, 0, 0); 431 | n.sendMsg("/color", "axe2", 0, 0.7, 0); 432 | n.sendMsg("/color", "axe3", 0, 0, 0.7); 433 | ) 434 | 435 | x.("/list"); 436 | x.("/behind bigger axe*"); 437 | x.("/behind axe* bigger"); 438 | x.("/front bigger axe*"); 439 | x.("/front axe* bigger"); 440 | 441 | x.("/select axe1"); 442 | x.("/select axe2"); 443 | 444 | x.("/behind! axe3"); 445 | x.("/front! axe3"); 446 | x.("/behind! bigger"); 447 | x.("/front! bigger"); 448 | 449 | ( 450 | ////////// Wander action 451 | { 452 | x.("/free *"); 453 | x.("/load pickaxe"); 454 | 100.do{ |i| 455 | var name = "axe" ++ i; 456 | var scl = i.linexp(0,99,0.1,3); 457 | x.("/create % pickaxe".format(name)); 458 | x.("/position % % 0.5".format(name, i.linlin(0,99, 0,0.9))); 459 | x.("/rotate % 360 20".format(name)); 460 | x.("/pivot % 0 1 10".format(name)); 461 | x.("/action % wander 0.2 2".format(name)); 462 | x.("/fade % 0.5".format(name)); 463 | x.("/scale % % %".format(name, scl, scl)); 464 | 0.05.wait; 465 | } 466 | }.forkIfNeeded 467 | ) 468 | 469 | ( 470 | ////////// Oscillate action 471 | // "Cartoon walking" character 472 | x.("/free *"); 473 | x.("/load cube"); 474 | x.("/create cube cube"); 475 | x.("/position cube 0.2 0.2"); 476 | x.("/action cube oscillate 1 15 0.05 0.1 1 2 0.125"); 477 | x.("/position cube 0.8 0.5 4"); 478 | ) 479 | 480 | x.("/load/defs init_example.osc") 481 | x.("/load/defs commands/init_example.osc") 482 | x.("/load/config config_example.osc") 483 | x.("/load/config config/config_example.osc") 484 | x.("/config") 485 | x.("/something") 486 | 487 | x.("/list/assets") 488 | x.("/assets/path animations") 489 | x.("/assets/path C:/Users/holag/Documents/Programming/gitreps/animatron/animations") 490 | 491 | x.("/load letter-a") 492 | x.("/load letter-b") 493 | x.("/load letter-c") 494 | x.("/list/anims") 495 | x.("/new a letter-a") 496 | x.("/new b letter-b") 497 | x.("/new c letter-c") 498 | x.("/scale", "a", 0.5") 499 | x.("/scale", "b", 0.5") 500 | x.("/position", "a", 0.25, 0.5); 501 | x.("/position", "b", 0.75, 0.5); 502 | x.("/group", "ltrs", "a", "b"); 503 | x.("/group", "ltrs", "b"); 504 | x.("/group", "ltrs"); 505 | x.("/stop", "ltrs"); 506 | x.("/play", "ltrs"); 507 | x.("/stop", "b"); 508 | x.("/list/actors") 509 | 510 | ( 511 | x.("/new", "n", "numbers"); 512 | x.("/speed", "n", 1/12); 513 | // x.("/play/rand", "n"); 514 | // x.("/play/rand", "n", 0); 515 | x.("/play/reverse", "n"); 516 | // x.("/play/reverse", "n", 0); 517 | // x.("/stop", "n"); 518 | // x.("/scale", "n", 0.1, 15); 519 | // x.("/scale", "n", 1, 0); 520 | // x.("/scale", "n", 1.1, 10); 521 | // x.("/scale", "n", 0.7, 2); 522 | // x.("/scale/xy", "n", 0.2, 0.3, 0.2); 523 | // x.("/scale/x", "n", 0.5, 2.0); 524 | // x.("/scale/y", "n", 0.4, 2.0); 525 | // x.("/position/x", "n", 0.2); 526 | // x.("/position/x", "n", 0.3, 0.7); 527 | // x.("/position/y", "n", 0.2); 528 | // x.("/position/y", "n", 0.7, 0.2); 529 | ) 530 | ( 531 | x.("/new", "na", "square"); 532 | x.("/new", "ne", "square"); 533 | x.("/new", "ni", "square"); 534 | x.("/scale/x", "n*", 0.5); 535 | x.("/pivot", "n*", 0.5, 1.0); 536 | x.("/position/y", "n*", 0.9); 537 | x.("/position/x", "na", 0.2); 538 | x.("/position/x", "ni", 0.8); 539 | x.("/sound", "na", 1, "/scale/y"); 540 | x.("/sound", "na", 1, "/position/y"); 541 | x.("/sound", "ne", 2, "/scale/y"); 542 | x.("/sound", "ni", 3, "/scale/y"); 543 | ) 544 | x.("/free", "*") 545 | x.("/sound/free", "na", 1) 546 | x.("/sound", "na", 1, "play") 547 | 548 | ( 549 | x.("/new", "sqa", "square"); 550 | // x.("/color", "sqa", 1,0,0); 551 | x.("/color/r", "sqa", 0.0); 552 | x.("/color/g", "sqa", 0.0); 553 | x.("/color/b", "sqa", 0.0); 554 | x.("/sound", "sqa", 1, "/color/r"); 555 | ) 556 | x.("/load/config", Platform.userHomeDir++"/work/animatron/config/asturies-config.osc"); 557 | ( 558 | x.("/full", "bg"); 559 | x.("/new", "m", "mouth"); 560 | x.("/behind", "bg", "*") 561 | x.("/stop", "m"); 562 | x.("/stop", "bg"); 563 | x.("/color/orange", "bg"); 564 | x.("/speed", "bg", rrand(0.3,0.7)); 565 | x.("/speed", "m", 0.2); 566 | x.("/play/rand", "m"); 567 | x.("/scale", "m", 0.25); 568 | ) 569 | ( 570 | x.("/load", "spiral-1"); 571 | x.("/load", "square"); 572 | x.("/new", "sp", "spiral-1"); 573 | x.("/new", "spa", "spiral-1"); 574 | x.("/new", "spi", "spiral-1"); 575 | x.("/new", "sq", "square"); 576 | x.("/pivot", "spa", 0.47, 0.51); 577 | x.("/speed", "sp", rrand(0.3,0.6)); 578 | x.("/speed", "spa", rrand(0.4,0.6)); 579 | x.("/speed", "spi", rrand(0.4,0.6)); 580 | x.("/rotate", "spa", 360.rand); 581 | x.("/color", "sq", 0.3,0.05,0.02); 582 | x.("/color", "spa", 0.3,0.05,0.02); 583 | x.("/color", "sp", 0.7,0.55,0.02); 584 | x.("/color", "spa", 0.7,0.60,0.02); 585 | x.("/behind", "sq", "*"); 586 | x.("/scale", "sq", 2, 1.2, 0); 587 | x.("/") 588 | ) 589 | ( 590 | x.("/load", "square"); 591 | x.("/load", "canon-man"); 592 | x.("/new", "bg", "square"); 593 | x.("/scale", "bg", 2,1.2); 594 | x.("/behind", "bg", "*"); 595 | x.("/stop", "bg"); 596 | x.("/new", "man", "canon-man"); 597 | x.("/new", "mana", "canon-man"); 598 | x.("/speed", "man", 1.5); 599 | x.("/play", "man", 0); 600 | x.("/color", "man", 1,0,0); 601 | ) 602 | a = Animatron.new; 603 | a.sendMsg("/load/config", "config-abstract.osc") 604 | a.sendMsg("/list"); 605 | a.sendMsg("/list/assets"); 606 | a.sendMsg("/list/anims"); 607 | a.sendMsg("/load", "bg"); 608 | a.sendMsg("/load", "square"); 609 | a.sendMsg("/load", "rect-long"); 610 | a.sendMsg("/new", "bg", "bg"); 611 | a.sendMsg("/new", "lna", "rect-long"); 612 | a.sendMsg("/color/white", "lna"); 613 | a.sendMsg("/scale/y", "lna", 0.25); 614 | a.sendMsg("/speed", "lna", 0.4); --------------------------------------------------------------------------------