This is a structural clojure editor for producing sound using Overtone(https://github.com/overtone/overtone), which is a wrapper library for sound engine, SuperCollider.
see: https://youtu.be/RuU0HI-paik
Dependencies:
s.options.maxLogins = 10;
s.boot;
lein repl
.(load-file "src/orenolisp/launch.clj")
This editor has two mode, typing-mode and selecting-mode.
By switching to selecting-mode, you can move around elements and manipulate expressions without modifier keys .
For example, type j
/k
to move to the next/previous element, respectively(This idea is inspired by Emacs plugin lispy-mode: https://github.com/abo-abo/lispy).
Keymap will be determined depending on the context (what you are selecting). For example:
a
- jump to first elements
- jump to second elemente
- jump to last elementl
- jump to parent elementa
or z
- increment/decrement first digits
or x
- increment/decrement second digitd
or c
- multiply by 2 or 1/2D
or C
- multiply by 10 or 1/10
By typing Alt-n
, you can turn current function into another function in the same category like:.
If you are selecting a parentheses, the first element will be changed.
This editor uses graphics to represent the parentheses. The table below show the equivalent codes of text and of this editor. Due to graphical representation of parentheses which is expanded vertically, it's easier to realize the correspondence of each parentheses. Brankets are represented using squared enclojures to distinguish the kind of parethesis clearly.
(let [freq 500 func (fn [ratio c-freq] (-> (sin-osc (* freq ratio)) (* (sin-osc c-freq) (lf-noise1 1/4))))] (-> (map func [1 3/2 5/4 11/7] (reductions * 100 [3/2 4/5])) splay)) |
This editor also replaces some functions with their graphical representation. The Overtone expression below and its image on the editor generate sine wave with varying frequencies from 100 to 1000 in 16 secs:
(sin-osc (line 100 1000 16)) |
The background color indicates how much it has been processed. The expression will convert into final value automatically after completion.
The transformation of variable binding is supported by the following instructions:
let
let
expression to define another variable.
Writing code for transformation in the structural editor is much simpler than in the text editor because there is no need to parse the text. The code below is the transformation of variable-binding.
(defn- make-let-binding [editor]
(let [parent-editor (-> '(let [___ ___])
conv/convert-sexp->editor
(ed/move :root))
second-placeholder-id (ed/get-id parent-editor [:child :right :child :right])]
(some-> editor
(ed/add-editor :parent parent-editor)
(ed/with-marks (fn [editor [marked-node-id]]
(-> editor
(ed/jump marked-node-id)
(ed/swap second-placeholder-id)
(ed/move :left)))))))
___
in the code represents a placeholder to be filled simultaneously after the transformation. This code works as below.
Marking the expression to be bound and selecting the expression to be wrapped by let
by the user
Injecting the expression (let [___ ___])
as parent into selected parentheses
(-> (let [___ ___]
(* (sin-osc 1000) (env-gen (env-perc 0 0.125) (impulse 8))))
(ringz 10 0.001) tanh)
Swaping the second placeholder and the marked expression
(-> (let [___ 1000]
(* (sin-osc ___) (env-gen (env-perc 0 0.125) (impulse 8))))
(ringz 10 0.001) tanh)
Finally the placeholders will be filled by the user
You can also transform the expression into an anonymous function and wrap it by map
The transformation with multiple arguments is available through multiple marks. You can call the transformation command again inside map
expression to append another argument.