├── .gitignore
├── DESIGN.md
├── LICENSE.md
├── README.md
├── TUTORIAL.md
├── desktop
├── core
│ ├── library.js
│ ├── library
│ │ ├── _bang.js
│ │ ├── _comment.js
│ │ ├── _midi.js
│ │ ├── _null.js
│ │ ├── _osc.js
│ │ ├── _udp.js
│ │ ├── a.js
│ │ ├── b.js
│ │ ├── c.js
│ │ ├── d.js
│ │ ├── e.js
│ │ ├── f.js
│ │ ├── g.js
│ │ ├── h.js
│ │ ├── i.js
│ │ ├── j.js
│ │ ├── k.js
│ │ ├── l.js
│ │ ├── m.js
│ │ ├── n.js
│ │ ├── o.js
│ │ ├── p.js
│ │ ├── q.js
│ │ ├── r.js
│ │ ├── s.js
│ │ ├── t.js
│ │ ├── u.js
│ │ ├── v.js
│ │ ├── w.js
│ │ ├── x.js
│ │ ├── y.js
│ │ └── z.js
│ ├── operator.js
│ └── orca.js
├── icon.icns
├── icon.ico
├── icon.png
├── icon.svg
├── main.js
├── package-lock.json
├── package.json
└── sources
│ ├── index.html
│ ├── links
│ ├── fonts.css
│ ├── main.css
│ ├── reset.css
│ └── theme.css
│ ├── media
│ └── fonts
│ │ ├── input_mono_medium.ttf
│ │ └── input_mono_regular.ttf
│ └── scripts
│ ├── cursor.js
│ ├── events.js
│ ├── history.js
│ ├── io.js
│ ├── io.midi.js
│ ├── io.osc-standalone.js
│ ├── io.osc.js
│ ├── io.udp.js
│ ├── keyboard.js
│ ├── lib
│ ├── controller.js
│ └── theme.js
│ ├── source.js
│ └── terminal.js
├── docs.js
├── examples
├── _midi.orca
├── _osc.orca
├── _udp.orca
├── bang.orca
├── benchmark.orca
├── boolean.orca
├── cycle.orca
├── delay.orca
├── if+else.orca
├── increment.orca
├── kombine.orca
├── octave.orca
├── pendulum.orca
├── popcorn.orca
├── projects
│ ├── dotgrid.orca
│ ├── midi-step-sequencer.orca
│ └── sonicpi.orca
├── read+write.orca
├── subtraction.orca
├── timing.orca
├── triage.orca
├── variable.orca
└── wave.orca
├── listener.js
└── resources
├── glyph.grid
├── glyph.png
├── glyph.svg
├── logo.grid
├── logo.png
├── logo.svg
├── preview.hardware.jpg
└── preview.jpg
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | builds/
3 | .DS_Store
4 | */.DS_Store
5 |
--------------------------------------------------------------------------------
/DESIGN.md:
--------------------------------------------------------------------------------
1 | # Design
2 |
3 | | Families | Glyphs
4 | | ---------- | -----------
5 | | Directions | N S E W Z
6 | | Math | A F I M R
7 | | Writers | G P X
8 | | Readers | O Q T
9 | | Jumpers | J Y
10 | | Timers | C D
11 | | Variables | K V
12 | | Misc | B H L U
13 | | Special | * # ; : =
14 |
15 | ## Unstable Glyphs
16 |
17 | - `V` could be made into two special glyphs, one for reading and one for writing.
18 |
19 | ## Attributes
20 |
21 | | ID# | Glyph | Rating | Stable | Outputs
22 | | --- | ----- | ------ | ------ | -------
23 | | 10 | A | +++++ | X | Any
24 | | 11 | B | ++++ | X | *
25 | | 12 | C | +++++ | X | Any
26 | | 13 | D | +++++ | X | *
27 | | 14 | E | +++++ | X |
28 | | 15 | F | +++++ | X | *
29 | | 16 | G | +++++ | X | Any - Multi - Unlocked
30 | | 17 | H | +++++ | X | Any
31 | | 18 | I | +++++ | X | Any
32 | | 19 | J | +++++ | X | Any
33 | | 20 | K | ++++ | |
34 | | 21 | L | ++ | |
35 | | 22 | M | +++++ | X | Any
36 | | 23 | N | +++++ | X |
37 | | 24 | O | +++++ | X | Any
38 | | 25 | P | +++++ | X | Any - Unlocked
39 | | 26 | Q | +++++ | X | Any - Multi
40 | | 27 | R | +++++ | X | Any
41 | | 28 | S | +++++ | X |
42 | | 29 | T | +++++ | X | Any
43 | | 30 | U | +++++ | X |
44 | | 31 | V | ++++ | | Any
45 | | 32 | W | +++++ | X |
46 | | 33 | X | +++++ | X | Any - Unlocked
47 | | 34 | Y | +++++ | X | Any
48 | | 35 | Z | +++ | X |
49 | | 36 | * | +++++ | X |
50 | | 37 | # | +++++ | X |
51 | | 39 | : | +++++ | X |
52 | | 38 | ; | +++++ | X |
53 | | 40 | = | +++++ | X |
54 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Hundredrabbits
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ORCΛ
2 |
3 |
4 |
5 | **Each letter of the alphabet is an operation**, lowercase letters operate on bang(`*`), uppercase letters operate each frame. Have a look at some project created with [#ORCΛ](https://twitter.com/hashtag/ORCΛ), or some [example files](https://github.com/hundredrabbits/Orca/tree/master/examples). Here's an [introduction video](https://www.youtube.com/watch?v=RaI_TuISSJE). You can see the [design notes](DESIGN.md) for specs and upcoming features. If you need some help, visit the [chatroom](https://talk.lurk.org/channel/orca).
6 |
7 | For a portable version of Orca, built entirely in C, visit [Orca-c](http://github.com/hundredrabbits/Orca-c).
8 |
9 | ## Install & Run
10 |
11 | You can download [builds](https://hundredrabbits.itch.io/orca) for **OSX, Windows and Linux**, or if you wish to build it yourself, follow these steps:
12 |
13 | ```
14 | git clone https://github.com/hundredrabbits/Orca.git
15 | cd Orca/desktop/
16 | npm install
17 | npm start
18 | ```
19 |
20 |
21 |
22 | ## Operators
23 |
24 | - `A` **add**(a, b): Outputs the sum of inputs.
25 | - `B` **bool**(val): Bangs if input is not empty, or 0.
26 | - `C` **clock**('rate, mod): Outputs a constant value based on the runtime frame.
27 | - `D` **delay**('rate, mod): Bangs on a fraction of the runtime frame.
28 | - `E` **east**: Moves eastward, or bangs.
29 | - `F` **if**(a, b): Bangs if both inputs are equal.
30 | - `G` **generator**('x, 'y, 'len): Writes distant operators with offset.
31 | - `H` **halt**: Stops southward operators from operating.
32 | - `I` **increment**(min, max): Increments southward operator.
33 | - `J` **jumper**(val): Outputs the northward operator.
34 | - `K` **konkat**('len): Outputs multiple variables.
35 | - `L` **loop**('len): Loops a number of eastward operators.
36 | - `M` **modulo**(val, mod): Outputs the modulo of input.
37 | - `N` **north**: Moves Northward, or bangs.
38 | - `O` **offset**('x, 'y, val): Reads a distant operator with offset.
39 | - `P` **push**('len, 'key, val): Writes an eastward operator with offset.
40 | - `Q` **query**('x, 'y, 'len): Reads distant operators with offset.
41 | - `R` **random**(min, max): Outputs a random value.
42 | - `S` **south**: Moves southward, or bangs.
43 | - `T` **track**('len, 'key, val): Reads an eastward operator with offset.
44 | - `U` **uturn**('n, 'e, 's, 'w): Reverses movement of inputs.
45 | - `V` **variable**('write, read): Reads and write globally available variables.
46 | - `W` **west**: Moves westward, or bangs.
47 | - `X` **teleport**('x, 'y, val): Writes a distant operator with offset.
48 | - `Y` **jymper**(val): Outputs the westward operator.
49 | - `Z` **zoom**: Moves eastwardly, respawns west on collision.
50 | - `*` **bang**: Bangs neighboring operators.
51 | - `#` **comment**: Comments a line, or characters until the next hash.
52 | - `:` **midi**('channel, 'octave, 'note, velocity, length): Sends a MIDI note.
53 | - `;` **udp**: Sends a UDP message.
54 | - `=` **osc**(path): Sends a OSC message.
55 |
56 | ## Controls
57 |
58 | ### Terminal Controls
59 |
60 | - `enter` toggle insert/write.
61 | - `space` toggle play/pause.
62 | - `>` increase BPM.
63 | - `<` decrease BPM.
64 | - `shift+arrowKey` Expand cursor.
65 | - `ctrl+arrowKey` Leap cursor.
66 | - `alt+arrowKey` Move selection.
67 |
68 | ### Edit
69 |
70 | - `ctrl+c` copy selection.
71 | - `ctrl+x` cut selection.
72 | - `ctrl+v` paste selection.
73 | - `ctrl+z` undo.
74 | - `ctrl+shift+z` redo.
75 |
76 | ### Grid Controls
77 |
78 | - `]` increase grid size vertically.
79 | - `[` decrease grid size vertically.
80 | - `}` increase grid size horizontally.
81 | - `{` decrease grid size horizontally.
82 | - `ctrl/meta+]` increase program size vertically.
83 | - `ctrl/meta+[` decrease program size vertically.
84 | - `ctrl/meta+}` increase program size horizontally.
85 | - `ctrl/meta+{` decrease program size horizontally.
86 |
87 | ### Window
88 |
89 | - `ctrl+=` Zoom In.
90 | - `ctrl+-` Zoom Out.
91 | - `ctrl+0` Zoom Reset.
92 | - `tab` Toggle interface.
93 | - `backquote` Toggle background.
94 |
95 | To open the console, press `ctrl+.`.
96 |
97 | ## MIDI
98 |
99 | The [MIDI](https://en.wikipedia.org/wiki/MIDI) operator `:` takes up to 5 inputs('channel, 'octave, 'note, velocity, length).
100 |
101 | For example, `:25C`, is a **C note, on the 5th octave, through the 3rd MIDI channel**, `:04c`, is a **C# note, on the 4th octave, through the 1st MIDI channel**. Velocity is an optional value from `0`(0/127) to `f`(127/127). Note length is a value from `0`(1/16) to `f`(16/16), which is a ratio of a full bar, *f* being `16/16`(a full bar), *8* being `1/2`(half), *4* being `1/4`(quarter). See it in action with [midi.orca](https://github.com/hundredrabbits/Orca/blob/master/examples/_midi.orca).
102 |
103 | #### List Midi Devices
104 |
105 | In console, type `terminal.io.midi.list()` to see the list of available midi devices.
106 |
107 | #### Select Midi Device
108 |
109 | In console, type `terminal.io.midi.select(1)` to select the second midi device.
110 |
111 | ## UDP
112 |
113 | The [UDP](https://nodejs.org/api/dgram.html#dgram_socket_send_msg_offset_length_port_address_callback) operator `;` locks each consecutive eastwardly ports. For example, `;hello`, will send the string "hello", on bang, to the port `49160` on `localhost`
114 |
115 | You can use the [listener.js](https://github.com/hundredrabbits/Orca/blob/master/listener.js) to test UDP messages. See it in action with [udp.orca](https://github.com/hundredrabbits/Orca/blob/master/examples/_udp.orca).
116 |
117 | #### Select UDP Port
118 |
119 | In console, type `terminal.io.udp.select(49160)` to select the **49160** udp port.
120 |
121 | ## OSC
122 |
123 | The [OSC](https://github.com/MylesBorins/node-osc) operator `=` locks each consecutive eastwardly ports.
124 |
125 | First char is used for path, nexts are sent as integers using [base36 Table](https://github.com/hundredrabbits/Orca#base36-table). For example, `=1abc` will send `10`, `11` and `12` to `/1`, via the port `49162` on `localhost`; `=a123` will send `1`, `2` and `3`, to the path `/a`. You can use the [listener.js](https://github.com/hundredrabbits/Orca/blob/master/examples/listener.js) to test OSC messages. See it in action with [osc.orca](https://github.com/hundredrabbits/Orca/blob/master/examples/_osc.orca) or try it with [SonicPi](https://github.com/hundredrabbits/Orca/blob/master/TUTORIAL.md#sonicpi).
126 |
127 | #### Select OSC Port
128 |
129 | In console, type `terminal.io.osc.select(49162)` to select the **49162** osc port.
130 |
131 |
132 |
133 | ## Base36 Table
134 |
135 | Orca operates on a base of 36 increments. Operators using numeric values will typically also operate on letters and convert them into values as per the following table. For instance `Dp` will bang every *24th frame*.
136 |
137 | | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B |
138 | | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: |
139 | | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
140 | | **C** | **D** | **E** | **F** | **G** | **H** | **I** | **J** | **K** | **L** | **M** | **N** |
141 | | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 |
142 | | **O** | **P** | **Q** | **R** | **S** | **T** | **U** | **V** | **W** | **X** | **Y** | **Z** |
143 | | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 |
144 |
145 | ## Extras
146 |
147 | - This application supports the [Ecosystem Theme](https://github.com/hundredrabbits/Themes).
148 | - Support this project through [Patreon](https://patreon.com/100).
149 | - See the [License](LICENSE.md) file for license rights and limitations (MIT).
150 | - Pull Requests are welcome!
151 |
--------------------------------------------------------------------------------
/TUTORIAL.md:
--------------------------------------------------------------------------------
1 | # Tutorial
2 |
3 | If this is your first time hearing about Orca, watch this [introduction video](https://www.youtube.com/watch?v=RaI_TuISSJE). If you are on Windows, use something like [loopMidi](http://www.tobias-erichsen.de/software/loopmidi.html) to help routing midi signal across applications.
4 |
5 | | Families | Glyphs
6 | | ---------- | -----------
7 | | Directions | N S E W Z
8 | | [Math](https://www.youtube.com/watch?v=CR1TMGYhCoE) | A F I M R
9 | | Writers | G P X
10 | | Readers | O Q T
11 | | [Jumpers](https://www.youtube.com/watch?v=CR1TMGYhCoE) | J Y
12 | | Timers | C D
13 | | Variables | K V
14 | | Misc | B H L U
15 | | Special | * # ; : =
16 |
17 | ## SonicPi
18 |
19 | To send [OSC messages](https://github.com/hundredrabbits/Orca#osc) to [SonicPi](http://sonic-pi.net), select [port 4559](https://github.com/hundredrabbits/Orca#osc). SonicPi listens to the address defined in `sync`, to send to the `live_loop`, bang the OSC node `=`, like `=a`. Have a look at [sonicpi.orca](https://github.com/hundredrabbits/Orca/blob/master/examples/projects/sonicpi.orca) to see it in action.
20 |
21 | ```
22 | live_loop :drum do
23 | use_real_time
24 | sync "/osc/a"
25 | sample :bd_haus, rate: 1
26 | end
27 | ```
28 |
29 | ## Dotgrid
30 |
31 | To send [UDP messages](https://github.com/hundredrabbits/Orca#udp) to [Dotgrid](http://github.com/hundredrabbits/Dotgrid), select [port 49160](https://github.com/hundredrabbits/Orca#udp). To draw lines on Dotgrid, you need to bang the UDP node `;` with different [commands](https://github.com/hundredrabbits/Dotgrid/blob/master/desktop/sources/scripts/listener.js). Have a look at [dotgrid.orca](https://github.com/hundredrabbits/Orca/blob/master/examples/projects/dotgrid.orca) to see it in action.
32 |
33 | - `;0`, clear layer **#1**.
34 | - `;0l1234`, add a line from `1,2` to `3,4`.
35 | - `;`, redraw.
36 |
37 | Here's a list of supported operations.
38 |
39 | ```
40 | ;0 // Clear Layer 1
41 | ;0l1234 // Add Line from 1,2 to 3,4
42 | ;0c1234 // Add Clockwise Arc from 1,2 to 3,4
43 | ;0r1234 // Add Reverse Arc from 1,2 to 3,4
44 | ; // Redraw
45 | ```
46 |
47 | ## Ableton Live
48 |
49 | To send [Midi notes](https://github.com/hundredrabbits/Orca#midi) to [Ableton Live](https://www.ableton.com/en/) instruments, bang the Midi node `:`, like `:03C` to send to _Channel 1, Octave 3, Note C_. Have a look at [midi.orca](https://github.com/hundredrabbits/Orca/blob/master/examples/_midi.orca) to see it in action.
50 |
51 | - Launch Ableton Live.
52 | - Create a new midi instrument track.
53 | - Select `IAC Driver(Bus 1)`(OSX), or `LoopMidi`(Windows), in the instrument's inputs dropdown.
54 | - Activate the **In** toggle.
55 |
56 | The midi instrument should begin receiving midi notes as soon as the Orca window is **in focus**.
57 |
58 | # Patterns
59 |
60 | Here's a collection of recurring patterns in the design of Orca machines.
61 |
62 | ## J Funnel
63 |
64 | Move two horizontal values next to each other.
65 |
66 | ```
67 | .1Y12.
68 | ...JJ.
69 | ..A12.
70 | ..3...
71 | ```
72 |
73 | ## X Stack
74 |
75 | Move two vertical values next to each other.
76 |
77 | ```
78 | .21X1..
79 | .10X2..
80 | ...A21.
81 | ...3...
82 | ```
83 |
84 | ## Y Projector
85 |
86 | A very simple projector using a yumper.
87 |
88 | ```
89 | ..D4..
90 | .H*...
91 | .Ey.E.
92 | ......
93 | ```
94 |
--------------------------------------------------------------------------------
/desktop/core/library.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | module.exports = {
4 | '0': require('./library/_null'),
5 | '1': require('./library/_null'),
6 | '2': require('./library/_null'),
7 | '3': require('./library/_null'),
8 | '4': require('./library/_null'),
9 | '5': require('./library/_null'),
10 | '6': require('./library/_null'),
11 | '7': require('./library/_null'),
12 | '8': require('./library/_null'),
13 | '9': require('./library/_null'),
14 | 'a': require('./library/a'),
15 | 'b': require('./library/b'),
16 | 'c': require('./library/c'),
17 | 'd': require('./library/d'),
18 | 'e': require('./library/e'),
19 | 'f': require('./library/f'),
20 | 'g': require('./library/g'),
21 | 'h': require('./library/h'),
22 | 'i': require('./library/i'),
23 | 'j': require('./library/j'),
24 | 'k': require('./library/k'),
25 | 'l': require('./library/l'),
26 | 'm': require('./library/m'),
27 | 'n': require('./library/n'),
28 | 'o': require('./library/o'),
29 | 'p': require('./library/p'),
30 | 'q': require('./library/q'),
31 | 'r': require('./library/r'),
32 | 's': require('./library/s'),
33 | 't': require('./library/t'),
34 | 'u': require('./library/u'),
35 | 'v': require('./library/v'),
36 | 'w': require('./library/w'),
37 | 'x': require('./library/x'),
38 | 'y': require('./library/y'),
39 | 'z': require('./library/z'),
40 | '*': require('./library/_bang'),
41 | '#': require('./library/_comment'),
42 | ':': require('./library/_midi'),
43 | ';': require('./library/_udp'),
44 | '=': require('./library/_osc')
45 | }
46 |
--------------------------------------------------------------------------------
/desktop/core/library/_bang.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Operator = require('../operator')
4 |
5 | function OperatorBang (orca, x, y, passive) {
6 | Operator.call(this, orca, x, y, '*', true)
7 |
8 | this.name = 'bang'
9 | this.info = 'Bangs neighboring operators.'
10 | this.draw = false
11 |
12 | this.haste = function () {
13 | this.passive = true
14 | this.erase()
15 | }
16 | }
17 |
18 | module.exports = OperatorBang
19 |
--------------------------------------------------------------------------------
/desktop/core/library/_comment.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Operator = require('../operator')
4 |
5 | function OperatorComment (orca, x, y, passive) {
6 | Operator.call(this, orca, x, y, '#', true)
7 |
8 | this.name = 'comment'
9 | this.info = 'Comments a line, or characters until the next hash.'
10 | this.draw = false
11 |
12 | this.haste = function () {
13 | for (let x = this.x + 1; x <= orca.w; x++) {
14 | orca.lock(x, this.y)
15 | if (orca.glyphAt(x, this.y) === this.glyph) { break }
16 | }
17 | this.passive = false
18 | this.lock()
19 | }
20 | }
21 |
22 | module.exports = OperatorComment
23 |
--------------------------------------------------------------------------------
/desktop/core/library/_midi.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Operator = require('../operator')
4 |
5 | function OperatorMidi (orca, x, y, passive) {
6 | Operator.call(this, orca, x, y, ':', true)
7 |
8 | this.name = 'midi'
9 | this.info = 'Sends a MIDI note.'
10 |
11 | this.ports.haste.channel = { x: 1, y: 0 }
12 | this.ports.haste.octave = { x: 2, y: 0 }
13 | this.ports.haste.note = { x: 3, y: 0 }
14 | this.ports.input.velocity = { x: 4, y: 0 }
15 | this.ports.input.length = { x: 5, y: 0 }
16 |
17 | this.run = function () {
18 | if (!this.bang()) { return }
19 |
20 | let rawChannel = this.listen(this.ports.haste.channel)
21 | let rawOctave = this.listen(this.ports.haste.octave, true)
22 | let rawNote = this.listen(this.ports.haste.note)
23 | let rawVelocity = this.listen(this.ports.input.velocity)
24 | let rawLength = this.listen(this.ports.input.length)
25 |
26 | if (rawChannel === '.' || orca.valueOf(rawChannel) > 15 || rawOctave === 0 || rawOctave > 8 || rawNote === '.' || rawVelocity === '0') { return }
27 |
28 | // 0 - 16
29 | const channel = clamp(orca.valueOf(rawChannel), 0, 15)
30 | // 1 - 9
31 | const octave = clamp(rawNote === 'b' ? rawOctave + 1 : rawOctave, 1, 9)
32 | // 0 - 11
33 | const note = ['C', 'c', 'D', 'd', 'E', 'F', 'f', 'G', 'g', 'A', 'a', 'B'].indexOf(rawNote === 'e' ? 'F' : rawNote === 'b' ? 'C' : rawNote)
34 | // 0 - F(127)
35 | const velocity = rawVelocity === '.' ? 127 : parseInt((clamp(orca.valueOf(rawVelocity), 0, 15) / 15) * 127)
36 | // 0 - F(15)
37 | const length = clamp(orca.valueOf(rawLength), 1, 15)
38 |
39 | if (note < 0) { console.warn(`Unknown note:${rawNote}`); return }
40 |
41 | this.draw = false
42 |
43 | terminal.io.midi.send(channel, octave, note, velocity, length)
44 | }
45 |
46 | function clamp (v, min, max) { return v < min ? min : v > max ? max : v }
47 | }
48 |
49 | module.exports = OperatorMidi
50 |
--------------------------------------------------------------------------------
/desktop/core/library/_null.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Operator = require('../operator')
4 |
5 | function OperatorNull (orca, x, y, passive) {
6 | Operator.call(this, orca, x, y, '.', passive)
7 |
8 | this.name = 'null'
9 | this.info = 'empty'
10 | }
11 |
12 | module.exports = OperatorNull
13 |
--------------------------------------------------------------------------------
/desktop/core/library/_osc.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Operator = require('../operator')
4 |
5 | function OperatorOsc (orca, x, y, passive) {
6 | Operator.call(this, orca, x, y, '=', true)
7 |
8 | this.name = 'osc'
9 | this.info = 'Sends a OSC message.'
10 |
11 | this.ports.input.path = { x: 1, y: 0 }
12 |
13 | this.haste = function () {
14 | this.path = this.listen(this.ports.input.path)
15 | this.msg = ''
16 | for (let x = 2; x <= 36; x++) {
17 | const g = orca.glyphAt(this.x + x, this.y)
18 | if (g === '.') { break }
19 | orca.lock(this.x + x, this.y)
20 | this.msg += g
21 | }
22 | }
23 |
24 | this.run = function () {
25 | if (!this.path || this.path === '' || !this.bang()) { return }
26 | this.draw = false
27 | terminal.io.osc.send('/' + this.path, this.msg)
28 | }
29 | }
30 |
31 | module.exports = OperatorOsc
32 |
--------------------------------------------------------------------------------
/desktop/core/library/_udp.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Operator = require('../operator')
4 |
5 | function OperatorUdp (orca, x, y, passive) {
6 | Operator.call(this, orca, x, y, ';', true)
7 |
8 | this.name = 'udp'
9 | this.info = 'Sends a UDP message.'
10 |
11 | this.haste = function () {
12 | this.msg = ''
13 | for (let x = 1; x <= 36; x++) {
14 | const g = orca.glyphAt(this.x + x, this.y)
15 | if (g === '.') { break }
16 | orca.lock(this.x + x, this.y)
17 | this.msg += g
18 | }
19 | }
20 |
21 | this.run = function () {
22 | if (!this.bang()) { return }
23 | this.draw = false
24 | terminal.io.udp.send(this.msg)
25 | }
26 | }
27 |
28 | module.exports = OperatorUdp
29 |
--------------------------------------------------------------------------------
/desktop/core/library/a.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Operator = require('../operator')
4 |
5 | function OperatorA (orca, x, y, passive) {
6 | Operator.call(this, orca, x, y, 'a', passive)
7 |
8 | this.name = 'add'
9 | this.info = 'Outputs the sum of inputs.'
10 |
11 | this.ports.input.a = { x: 1, y: 0 }
12 | this.ports.input.b = { x: 2, y: 0 }
13 | this.ports.output = { x: 0, y: 1 }
14 |
15 | this.run = function () {
16 | const a = this.listen(this.ports.input.a, true)
17 | const b = this.listen(this.ports.input.b, true)
18 | const res = orca.keyOf(a + b)
19 | this.output(`${res}`)
20 | }
21 | }
22 |
23 | module.exports = OperatorA
24 |
--------------------------------------------------------------------------------
/desktop/core/library/b.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Operator = require('../operator')
4 |
5 | function OperatorB (orca, x, y, passive) {
6 | Operator.call(this, orca, x, y, 'b', passive)
7 |
8 | this.name = 'bool'
9 | this.info = 'Bangs if input is not empty, or 0.'
10 |
11 | this.ports.input.val = { x: 1, y: 0, unlock: true }
12 | this.ports.output = { x: 0, y: 1 }
13 |
14 | this.run = function () {
15 | const val = this.listen(this.ports.input.val)
16 | const res = val !== '.' && val !== '0' ? '*' : '.'
17 | this.output(`${res}`)
18 | }
19 | }
20 |
21 | module.exports = OperatorB
22 |
--------------------------------------------------------------------------------
/desktop/core/library/c.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Operator = require('../operator')
4 |
5 | function OperatorC (orca, x, y, passive) {
6 | Operator.call(this, orca, x, y, 'c', passive)
7 |
8 | this.name = 'clock'
9 | this.info = 'Outputs a constant value based on the runtime frame.'
10 |
11 | this.ports.haste.rate = { x: -1, y: 0 }
12 | this.ports.input.mod = { x: 1, y: 0 }
13 | this.ports.output = { x: 0, y: 1 }
14 |
15 | this.run = function () {
16 | const mod = this.listen(this.ports.input.mod, true)
17 | const rate = this.listen(this.ports.haste.rate, true, 1)
18 | const val = (Math.floor(orca.f / rate) % (mod || 10))
19 | const res = orca.keyOf(val)
20 | this.output(`${res}`)
21 | }
22 | }
23 |
24 | module.exports = OperatorC
25 |
--------------------------------------------------------------------------------
/desktop/core/library/d.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Operator = require('../operator')
4 |
5 | function OperatorD (orca, x, y, passive) {
6 | Operator.call(this, orca, x, y, 'd', passive)
7 |
8 | this.name = 'delay'
9 | this.info = 'Bangs on a fraction of the runtime frame.'
10 |
11 | this.ports.haste.rate = { x: -1, y: 0 }
12 | this.ports.input.mod = { x: 1, y: 0 }
13 | this.ports.output = { x: 0, y: 1 }
14 |
15 | this.run = function () {
16 | const mod = this.listen(this.ports.input.mod, true)
17 | const rate = this.listen(this.ports.haste.rate, true, 1)
18 | const val = (Math.floor(orca.f) % ((mod || 10) * rate))
19 | const res = val === 0 ? '*' : '.'
20 | this.output(`${res}`)
21 | }
22 | }
23 |
24 | module.exports = OperatorD
25 |
--------------------------------------------------------------------------------
/desktop/core/library/e.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Operator = require('../operator')
4 |
5 | function OperatorE (orca, x, y, passive) {
6 | Operator.call(this, orca, x, y, 'e', passive)
7 |
8 | this.name = 'east'
9 | this.info = 'Moves eastward, or bangs.'
10 | this.draw = false
11 |
12 | this.haste = function () {
13 | this.move(1, 0)
14 | this.passive = false
15 | }
16 | }
17 |
18 | module.exports = OperatorE
19 |
--------------------------------------------------------------------------------
/desktop/core/library/f.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Operator = require('../operator')
4 |
5 | function OperatorF (orca, x, y, passive) {
6 | Operator.call(this, orca, x, y, 'f', passive)
7 |
8 | this.name = 'if'
9 | this.info = 'Bangs if both inputs are equal.'
10 |
11 | this.ports.input.a = { x: 1, y: 0 }
12 | this.ports.input.b = { x: 2, y: 0 }
13 | this.ports.output = { x: 0, y: 1 }
14 |
15 | this.run = function () {
16 | const a = this.listen(this.ports.input.a)
17 | const b = this.listen(this.ports.input.b)
18 | const res = a === b ? '*' : '.'
19 | this.output(`${res}`)
20 | }
21 | }
22 |
23 | module.exports = OperatorF
24 |
--------------------------------------------------------------------------------
/desktop/core/library/g.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Operator = require('../operator')
4 |
5 | function OperatorG (orca, x, y, passive) {
6 | Operator.call(this, orca, x, y, 'g', passive)
7 |
8 | this.name = 'generator'
9 | this.info = 'Writes distant operators with offset.'
10 |
11 | this.ports.haste.x = { x: -3, y: 0 }
12 | this.ports.haste.y = { x: -2, y: 0 }
13 | this.ports.haste.len = { x: -1, y: 0 }
14 |
15 | this.haste = function () {
16 | this.ports.input = []
17 | this.len = this.listen(this.ports.haste.len, true)
18 | if (this.len < 1) { return }
19 | const x = this.listen(this.ports.haste.x, true)
20 | const y = this.listen(this.ports.haste.y, true) + 1
21 | this.ports.output = { x: x, y: y, unlock: true }
22 | for (let i = 0; i < this.len; i++) {
23 | this.ports.input.push({ x: i + 1, y: 0 })
24 | }
25 | }
26 |
27 | this.run = function () {
28 | // Read
29 | let str = ''
30 | for (const id in this.ports.input) {
31 | str += this.listen(this.ports.input[id])
32 | }
33 | // Write
34 | for (let i = 0; i < str.length; i++) {
35 | orca.write(this.x + this.ports.output.x + i, this.y + this.ports.output.y, str[i])
36 | }
37 | }
38 | }
39 |
40 | module.exports = OperatorG
41 |
--------------------------------------------------------------------------------
/desktop/core/library/h.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Operator = require('../operator')
4 |
5 | function OperatorH (orca, x, y, passive) {
6 | Operator.call(this, orca, x, y, 'h', passive)
7 |
8 | this.name = 'halt'
9 | this.info = 'Stops southward operators from operating.'
10 |
11 | this.ports.output = { x: 0, y: 1 }
12 |
13 | this.haste = function () {
14 | orca.lock(this.x + this.ports.output.x, this.y + this.ports.output.y)
15 | }
16 | }
17 |
18 | module.exports = OperatorH
19 |
--------------------------------------------------------------------------------
/desktop/core/library/i.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Operator = require('../operator')
4 |
5 | function OperatorI (orca, x, y, passive) {
6 | Operator.call(this, orca, x, y, 'i', passive)
7 |
8 | this.name = 'increment'
9 | this.info = 'Increments southward operator.'
10 |
11 | this.ports.input.min = { x: 1, y: 0 }
12 | this.ports.input.max = { x: 2, y: 0 }
13 | this.ports.output = { x: 0, y: 1 }
14 |
15 | this.run = function () {
16 | const min = this.listen(this.ports.input.min, true)
17 | const max = this.listen(this.ports.input.max, true)
18 | const val = this.listen(this.ports.output, true)
19 |
20 | if (min === max) { return }
21 |
22 | const real = { min: min < max ? min : max, max: min > max ? min : max }
23 | const next = val + (min < max ? 1 : -1)
24 | const res = next >= real.max ? real.min : next < real.min ? real.max - 1 : next
25 |
26 | this.output(`${orca.keyOf(res)}`)
27 | }
28 | }
29 |
30 | module.exports = OperatorI
31 |
--------------------------------------------------------------------------------
/desktop/core/library/j.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Operator = require('../operator')
4 |
5 | function OperatorJ (orca, x, y, passive) {
6 | Operator.call(this, orca, x, y, 'j', passive)
7 |
8 | this.name = 'jumper'
9 | this.info = 'Outputs the northward operator.'
10 |
11 | this.ports.input.val = { x: 0, y: -1 }
12 | this.ports.output = { x: 0, y: 1 }
13 |
14 | this.haste = function () {
15 | orca.lock(this.x, this.y + 1)
16 | }
17 |
18 | this.run = function () {
19 | const val = this.listen(this.ports.input.val)
20 | this.output(val)
21 | }
22 | }
23 |
24 | module.exports = OperatorJ
25 |
--------------------------------------------------------------------------------
/desktop/core/library/k.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Operator = require('../operator')
4 |
5 | function OperatorK (orca, x, y, passive) {
6 | Operator.call(this, orca, x, y, 'k', passive)
7 |
8 | this.name = 'konkat'
9 | this.info = 'Outputs multiple variables.'
10 |
11 | this.ports.haste.len = { x: -1, y: 0 }
12 |
13 | this.haste = function () {
14 | this.len = this.listen(this.ports.haste.len, true)
15 | for (let x = 1; x <= this.len; x++) {
16 | orca.lock(this.x + x, this.y)
17 | const g = orca.glyphAt(this.x + x, this.y)
18 | if (g !== '.') {
19 | orca.lock(this.x + x, this.y + 1)
20 | }
21 | }
22 | }
23 |
24 | this.run = function () {
25 | const a = []
26 | for (let x = 1; x <= this.len; x++) {
27 | const g = orca.glyphAt(this.x + x, this.y)
28 | orca.write(this.x + x, this.y + 1, query(g))
29 | }
30 | }
31 |
32 | function query (name) {
33 | if (name === '.') { return }
34 | for (const id in orca.runtime) {
35 | const operator = orca.runtime[id]
36 | if (orca.lockAt(operator.x, operator.y)) { continue }
37 | if (operator.glyph !== 'v' && operator.glyph !== 'V') { continue }
38 | if (operator.storage.write !== name) { continue }
39 | return operator.storage.read
40 | }
41 | return '.'
42 | }
43 | }
44 |
45 | module.exports = OperatorK
46 |
--------------------------------------------------------------------------------
/desktop/core/library/l.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Operator = require('../operator')
4 |
5 | function OperatorL (orca, x, y, passive) {
6 | Operator.call(this, orca, x, y, 'l', passive)
7 |
8 | this.name = 'loop'
9 | this.info = 'Loops a number of eastward operators.'
10 |
11 | this.ports.haste.len = { x: -1, y: 0 }
12 |
13 | this.haste = function () {
14 | this.len = this.listen(this.ports.haste.len, true)
15 | for (let x = 1; x <= this.len; x++) {
16 | orca.lock(this.x + x, this.y)
17 | }
18 | }
19 |
20 | this.run = function () {
21 | if (!this.len || this.len < 1) { return }
22 | const a = []
23 | for (let x = 1; x <= this.len; x++) {
24 | a.push(orca.glyphAt(this.x + x, this.y))
25 | }
26 | a.push(a.shift())
27 | for (const id in a) {
28 | const x = parseInt(id) + 1
29 | orca.write(this.x + x, this.y, a[id])
30 | }
31 | }
32 | }
33 |
34 | module.exports = OperatorL
35 |
--------------------------------------------------------------------------------
/desktop/core/library/m.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Operator = require('../operator')
4 |
5 | function OperatorM (orca, x, y, passive) {
6 | Operator.call(this, orca, x, y, 'm', passive)
7 |
8 | this.name = 'modulo'
9 | this.info = 'Outputs the modulo of input.'
10 |
11 | this.ports.input.val = { x: 1, y: 0 }
12 | this.ports.input.mod = { x: 2, y: 0 }
13 | this.ports.output = { x: 0, y: 1 }
14 |
15 | this.run = function () {
16 | const val = this.listen(this.ports.input.val, true)
17 | const mod = this.listen(this.ports.input.mod, true)
18 | const key = val % (mod !== 0 ? mod : 1)
19 | const res = orca.keyOf(key)
20 | this.output(`${res}`)
21 | }
22 | }
23 |
24 | module.exports = OperatorM
25 |
--------------------------------------------------------------------------------
/desktop/core/library/n.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Operator = require('../operator')
4 |
5 | function OperatorN (orca, x, y, passive) {
6 | Operator.call(this, orca, x, y, 'n', passive)
7 |
8 | this.name = 'north'
9 | this.info = 'Moves Northward, or bangs.'
10 | this.draw = false
11 |
12 | this.haste = function () {
13 | this.move(0, -1)
14 | this.passive = false
15 | }
16 | }
17 |
18 | module.exports = OperatorN
19 |
--------------------------------------------------------------------------------
/desktop/core/library/o.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Operator = require('../operator')
4 |
5 | function OperatorO (orca, x, y, passive) {
6 | Operator.call(this, orca, x, y, 'o', passive)
7 |
8 | this.name = 'offset'
9 | this.info = 'Reads a distant operator with offset.'
10 |
11 | this.ports.haste.x = { x: -2, y: 0 }
12 | this.ports.haste.y = { x: -1, y: 0 }
13 | this.ports.input.val = { x: 1, y: 0 }
14 | this.ports.output = { x: 0, y: 1 }
15 |
16 | this.haste = function () {
17 | const x = this.listen(this.ports.haste.x, true) + 1
18 | const y = this.listen(this.ports.haste.y, true)
19 | this.ports.input.val = { x: x, y: y }
20 | }
21 |
22 | this.run = function () {
23 | const res = this.listen(this.ports.input.val)
24 | this.output(`${res}`)
25 | }
26 | }
27 |
28 | module.exports = OperatorO
29 |
--------------------------------------------------------------------------------
/desktop/core/library/p.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Operator = require('../operator')
4 |
5 | function OperatorP (orca, x, y, passive) {
6 | Operator.call(this, orca, x, y, 'p', passive)
7 |
8 | this.name = 'push'
9 | this.info = 'Writes an eastward operator with offset.'
10 |
11 | this.ports.haste.len = { x: -1, y: 0 }
12 | this.ports.haste.key = { x: -2, y: 0 }
13 | this.ports.input.val = { x: 1, y: 0 }
14 |
15 | this.haste = function () {
16 | this.len = this.listen(this.ports.haste.len, true)
17 | if (this.len < 1) { return }
18 | this.key = this.listen(this.ports.haste.key, true)
19 | this.ports.output = { x: (this.key % this.len), y: 1, unlock: true }
20 | for (let x = 0; x < this.len; x++) {
21 | orca.lock(this.x + x, this.y + 1)
22 | }
23 | }
24 |
25 | this.run = function () {
26 | const res = this.listen(this.ports.input.val)
27 | this.output(`${res}`)
28 | }
29 | }
30 |
31 | module.exports = OperatorP
32 |
--------------------------------------------------------------------------------
/desktop/core/library/q.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Operator = require('../operator')
4 |
5 | function OperatorQ (orca, x, y, passive) {
6 | Operator.call(this, orca, x, y, 'q', passive)
7 |
8 | this.name = 'query'
9 | this.info = 'Reads distant operators with offset.'
10 |
11 | this.ports.haste.x = { x: -3, y: 0 }
12 | this.ports.haste.y = { x: -2, y: 0 }
13 | this.ports.haste.len = { x: -1, y: 0 }
14 |
15 | this.haste = function () {
16 | this.ports.input = []
17 | this.len = this.listen(this.ports.haste.len, true)
18 | if (this.len < 1) { return }
19 | const x = this.listen(this.ports.haste.x, true)
20 | const y = this.listen(this.ports.haste.y, true)
21 | this.ports.output = { x: 0, y: 1 }
22 | for (let i = 1; i <= this.len; i++) {
23 | this.ports.input.push({ x: i + x, y: y })
24 | orca.lock(this.x + this.ports.output.x + i - this.len, this.y + 1)
25 | }
26 | }
27 |
28 | this.run = function () {
29 | // Read
30 | let str = ''
31 | for (const id in this.ports.input) {
32 | str += this.listen(this.ports.input[id])
33 | }
34 | // Write
35 | for (let i = 0; i < str.length; i++) {
36 | orca.write(this.x + this.ports.output.x + i - str.length + 1, this.y + this.ports.output.y, str[i])
37 | }
38 | }
39 | }
40 |
41 | module.exports = OperatorQ
42 |
--------------------------------------------------------------------------------
/desktop/core/library/r.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Operator = require('../operator')
4 |
5 | function OperatorR (orca, x, y, passive) {
6 | Operator.call(this, orca, x, y, 'r', passive)
7 |
8 | this.name = 'random'
9 | this.info = 'Outputs a random value.'
10 |
11 | this.ports.input.min = { x: 1, y: 0 }
12 | this.ports.input.max = { x: 2, y: 0 }
13 | this.ports.output = { x: 0, y: 1 }
14 |
15 | this.run = function () {
16 | const min = this.listen(this.ports.input.min, true)
17 | const max = this.listen(this.ports.input.max, true)
18 | const val = parseInt((Math.random() * (max - min)) + min)
19 | const res = orca.keyOf(val)
20 | this.output(`${res}`)
21 | }
22 | }
23 |
24 | module.exports = OperatorR
25 |
--------------------------------------------------------------------------------
/desktop/core/library/s.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Operator = require('../operator')
4 |
5 | function OperatorS (orca, x, y, passive) {
6 | Operator.call(this, orca, x, y, 's', passive)
7 |
8 | this.name = 'south'
9 | this.info = 'Moves southward, or bangs.'
10 | this.draw = false
11 |
12 | this.haste = function () {
13 | this.move(0, 1)
14 | this.passive = false
15 | }
16 | }
17 |
18 | module.exports = OperatorS
19 |
--------------------------------------------------------------------------------
/desktop/core/library/t.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Operator = require('../operator')
4 |
5 | function OperatorT (orca, x, y, passive) {
6 | Operator.call(this, orca, x, y, 't', passive)
7 |
8 | this.name = 'track'
9 | this.info = 'Reads an eastward operator with offset.'
10 |
11 | this.ports.input.val = { x: 1, y: 0 }
12 | this.ports.haste.len = { x: -1, y: 0 }
13 | this.ports.haste.key = { x: -2, y: 0 }
14 |
15 | this.haste = function () {
16 | this.len = this.listen(this.ports.haste.len, true)
17 | if (this.len < 1) { return }
18 | this.ports.output = { x: 0, y: 1 }
19 | this.key = this.listen(this.ports.haste.key, true)
20 | for (let x = 1; x <= this.len; x++) {
21 | orca.lock(this.x + x, this.y)
22 | }
23 | this.ports.input.val = { x: (this.key % this.len) + 1, y: 0 }
24 | }
25 |
26 | this.run = function () {
27 | const res = this.listen(this.ports.input.val)
28 | this.output(`${res}`)
29 | }
30 | }
31 |
32 | module.exports = OperatorT
33 |
--------------------------------------------------------------------------------
/desktop/core/library/u.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Operator = require('../operator')
4 |
5 | function OperatorU (orca, x, y, passive) {
6 | Operator.call(this, orca, x, y, 'u', passive)
7 |
8 | this.name = 'uturn'
9 | this.info = 'Reverses movement of inputs.'
10 |
11 | this.ports.haste.n = { x: 0, y: -1, unlock: true }
12 | this.ports.haste.e = { x: 1, y: 0, unlock: true }
13 | this.ports.haste.s = { x: 0, y: 1, unlock: true }
14 | this.ports.haste.w = { x: -1, y: 0, unlock: true }
15 |
16 | this.run = function () {
17 | for (const id in this.ports.haste) {
18 | this.flip(id, this.ports.haste[id])
19 | }
20 | }
21 |
22 | this.flip = function (id, vector) {
23 | const pos = { x: this.x + vector.x, y: this.y + vector.y }
24 | const g = orca.glyphAt(pos.x, pos.y).toLowerCase()
25 |
26 | if (g === '.') { return }
27 | if (!this.ports.haste[g]) { return }
28 |
29 | orca.write(pos.x, pos.y, id.toUpperCase())
30 | }
31 | }
32 |
33 | module.exports = OperatorU
34 |
--------------------------------------------------------------------------------
/desktop/core/library/v.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Operator = require('../operator')
4 | // TODO
5 | function OperatorV (orca, x, y, passive) {
6 | Operator.call(this, orca, x, y, 'v', passive)
7 |
8 | this.name = 'variable'
9 | this.info = 'Reads and write globally available variables.'
10 |
11 | this.ports.haste.write = { x: -1, y: 0 }
12 | this.ports.input.read = { x: 1, y: 0 }
13 | this.ports.output = { x: 0, y: 1 }
14 |
15 | this.storage = { write: null, read: null }
16 |
17 | this.haste = function () {
18 | this.storage.write = this.listen(this.ports.haste.write)
19 | this.storage.read = this.listen(this.ports.input.read)
20 |
21 | if (this.storage.write !== '.' && this.storage.read !== '.') {
22 | this.ports.output = null
23 | }
24 | }
25 |
26 | this.run = function () {
27 | if (this.storage.write !== '.' || this.storage.read === '.') { return }
28 | this.output(query(this.storage.read))
29 | }
30 |
31 | function query (name) {
32 | if (name === '.') { return '.' }
33 | for (const id in orca.runtime) {
34 | const operator = orca.runtime[id]
35 | if (orca.lockAt(operator.x, operator.y)) { continue }
36 | if (operator.glyph !== 'v' && operator.glyph !== 'V') { continue }
37 | if (operator.storage.write !== name) { continue }
38 | return operator.storage.read
39 | }
40 | return '.'
41 | }
42 | }
43 |
44 | module.exports = OperatorV
45 |
--------------------------------------------------------------------------------
/desktop/core/library/w.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Operator = require('../operator')
4 |
5 | function OperatorW (orca, x, y, passive) {
6 | Operator.call(this, orca, x, y, 'w', passive)
7 |
8 | this.name = 'west'
9 | this.info = 'Moves westward, or bangs.'
10 | this.draw = false
11 |
12 | this.haste = function () {
13 | this.move(-1, 0)
14 | this.passive = false
15 | }
16 | }
17 |
18 | module.exports = OperatorW
19 |
--------------------------------------------------------------------------------
/desktop/core/library/x.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Operator = require('../operator')
4 |
5 | function OperatorX (orca, x, y, passive) {
6 | Operator.call(this, orca, x, y, 'x', passive)
7 |
8 | this.name = 'teleport'
9 | this.info = 'Writes a distant operator with offset.'
10 |
11 | this.ports.haste.x = { x: -2, y: 0 }
12 | this.ports.haste.y = { x: -1, y: 0 }
13 | this.ports.input.val = { x: 1, y: 0 }
14 | this.ports.output = { x: 0, y: 1, unlock: true }
15 |
16 | this.haste = function () {
17 | const x = this.listen(this.ports.haste.x, true)
18 | const y = this.listen(this.ports.haste.y, true) + 1
19 | this.ports.output = { x: x, y: y, unlock: true }
20 | }
21 |
22 | this.run = function () {
23 | const res = this.listen(this.ports.input.val)
24 | this.output(`${res}`)
25 | }
26 | }
27 |
28 | module.exports = OperatorX
29 |
--------------------------------------------------------------------------------
/desktop/core/library/y.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Operator = require('../operator')
4 |
5 | function OperatorY (orca, x, y, passive) {
6 | Operator.call(this, orca, x, y, 'y', passive)
7 |
8 | this.name = 'jymper'
9 | this.info = 'Outputs the westward operator.'
10 |
11 | this.ports.input.val = { x: -1, y: 0 }
12 | this.ports.output = { x: 1, y: 0 }
13 |
14 | this.haste = function () {
15 | orca.lock(this.x + 1, this.y)
16 | }
17 |
18 | this.run = function () {
19 | const val = this.listen(this.ports.input.val)
20 | this.output(val)
21 | }
22 | }
23 |
24 | module.exports = OperatorY
25 |
--------------------------------------------------------------------------------
/desktop/core/library/z.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Operator = require('../operator')
4 |
5 | function OperatorZ (orca, x, y, passive) {
6 | Operator.call(this, orca, x, y, 'z', passive)
7 |
8 | this.name = 'zoom'
9 | this.info = 'Moves eastwardly, respawns west on collision.'
10 | this.draw = false
11 |
12 | this.haste = function () {
13 | if (orca.glyphAt(this.x + 1, this.y) === '.') { this.move(1, 0); return }
14 | for (var x = this.x; x >= 0; x--) {
15 | const g = orca.glyphAt(x - 1, this.y)
16 | if (g === '.' && x !== 0) { continue }
17 | orca.write(x, this.y, 'Z')
18 | this.erase()
19 | break
20 | }
21 | }
22 | }
23 |
24 | module.exports = OperatorZ
25 |
--------------------------------------------------------------------------------
/desktop/core/operator.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | function Operator (orca, x, y, glyph = '.', passive = false) {
4 | this.name = 'unknown'
5 | this.x = x
6 | this.y = y
7 | this.passive = passive
8 | this.draw = true
9 | this.glyph = passive ? glyph.toUpperCase() : glyph
10 | this.info = '--'
11 | this.ports = { input: {}, haste: {}, bang: !passive }
12 |
13 | // Actions
14 |
15 | this.listen = function (port, toValue = false, min = 0, max = 36) {
16 | if (!port) { return toValue ? 0 : '.' }
17 | const g = orca.glyphAt(this.x + port.x, this.y + port.y)
18 | return toValue ? clamp(orca.valueOf(g), min, max) : g
19 | }
20 |
21 | this.output = function (g) {
22 | if (!this.ports.output) { return }
23 | orca.write(this.x + this.ports.output.x, this.y + this.ports.output.y, g)
24 | }
25 |
26 | // Phases
27 |
28 | this.permissions = function () {
29 | for (const id in this.ports.haste) {
30 | const port = this.ports.haste[id]
31 | if (!port.unlock) {
32 | orca.lock(this.x + port.x, this.y + port.y)
33 | }
34 | }
35 | for (const id in this.ports.input) {
36 | const port = this.ports.input[id]
37 | if (!port.unlock) {
38 | orca.lock(this.x + port.x, this.y + port.y)
39 | }
40 | }
41 | if (this.ports.output && !this.ports.output.unlock) {
42 | orca.lock(this.x + this.ports.output.x, this.y + this.ports.output.y)
43 | }
44 | }
45 |
46 | this.haste = function () {
47 | }
48 |
49 | this.run = function () {
50 | }
51 |
52 | // Helpers
53 |
54 | this.lock = function () {
55 | orca.lock(this.x, this.y)
56 | }
57 |
58 | this.replace = function (g) {
59 | orca.write(this.x, this.y, g)
60 | }
61 |
62 | this.erase = function () {
63 | this.replace('.')
64 | }
65 |
66 | this.explode = function () {
67 | this.replace('*')
68 | this.lock()
69 | }
70 |
71 | this.move = function (x, y) {
72 | const offset = { x: this.x + x, y: this.y + y }
73 | if (!orca.inBounds(offset.x, offset.y)) { this.explode(); return }
74 | const collider = orca.glyphAt(offset.x, offset.y)
75 | if (collider === this.glyph) { return }
76 | if (collider !== '*' && collider !== '.' && collider !== this.glyph) { this.explode(); return }
77 | this.erase()
78 | this.x += x
79 | this.y += y
80 | this.replace(this.glyph)
81 | this.lock()
82 | }
83 |
84 | this.bang = function () {
85 | if (orca.glyphAt(this.x + 1, this.y) === '*') { return { x: 1, y: 0 } }
86 | if (orca.glyphAt(this.x - 1, this.y) === '*') { return { x: -1, y: 0 } }
87 | if (orca.glyphAt(this.x, this.y + 1) === '*') { return { x: 0, y: 1 } }
88 | if (orca.glyphAt(this.x, this.y - 1) === '*') { return { x: 0, y: -1 } }
89 | return false
90 | }
91 |
92 | // Docs
93 |
94 | this._ports = function () {
95 | let ports = ''
96 | if (Object.keys(this.ports.haste).length > 0) {
97 | for (const name in this.ports.haste) {
98 | ports += `'${name}, `
99 | }
100 | }
101 | if (Object.keys(this.ports.input).length > 0) {
102 | for (const name in this.ports.input) {
103 | ports += `${name}, `
104 | }
105 | }
106 | return ports !== '' ? '(' + ports.substr(0, ports.length - 2) + ')' : ''
107 | }
108 |
109 | this.docs = function () {
110 | return `\`${this.glyph.toUpperCase()}\` **${this.name}**${this._ports()}: ${this.info}`
111 | }
112 |
113 | function clamp (v, min, max) { return v < min ? min : v > max ? max : v }
114 | }
115 |
116 | module.exports = Operator
117 |
--------------------------------------------------------------------------------
/desktop/core/orca.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const library = require('./library')
4 |
5 | function Orca (terminal, host = null) {
6 | this.w = 65 // Default Width
7 | this.h = 25 // Default Height
8 | this.s = '' // String
9 | this.f = host ? host.f : 0 // Frame
10 |
11 | this.host = host
12 |
13 | this.terminal = terminal
14 | this.keys = Object.keys(library).slice(0, 36)
15 | this.locks = []
16 | this.ports = {}
17 | this.runtime = []
18 |
19 | this.run = function () {
20 | this.runtime = this.parse()
21 | this.operate(this.runtime)
22 | this.f += 1
23 | }
24 |
25 | this.reset = function (w = this.w, h = this.h) {
26 | this.w = w
27 | this.h = h
28 | this.s = new Array((this.h * this.w) + 1).join('.')
29 | }
30 |
31 | this.load = function (w, h, s, f = 0) {
32 | this.w = w
33 | this.h = h
34 | this.f = f
35 | this.s = this.clean(s)
36 | return this
37 | }
38 |
39 | this.write = function (x, y, g) {
40 | if (!g) { return }
41 | if (g.length !== 1) { return }
42 | if (!this.inBounds(x, y)) { return }
43 | if (!this.isAllowed(g)) { return }
44 | if (this.glyphAt(x, y) === g) { return }
45 | const index = this.indexAt(x, y)
46 | this.s = this.s.substr(0, index) + g + this.s.substr(index + g.length)
47 | }
48 |
49 | this.clean = function (str) {
50 | let s = `${str}`
51 | s = s.replace(/\n/g, '').trim()
52 | s = s.substr(0, this.w * this.h)
53 | return s
54 | }
55 |
56 | // Operators
57 |
58 | this.parse = function () {
59 | const a = []
60 | for (let y = 0; y < this.h; y++) {
61 | for (let x = 0; x < this.w; x++) {
62 | const g = this.glyphAt(x, y)
63 | const operator = this.cast(g, x, y)
64 | if (operator) {
65 | a.push(operator)
66 | }
67 | }
68 | }
69 | return a
70 | }
71 |
72 | this.cast = function (g, x, y) {
73 | if (g === '.') { return }
74 | if (!library[g.toLowerCase()]) { return }
75 | const passive = g === g.toUpperCase() && this.valueOf(g) > 9
76 | return new library[g.toLowerCase()](this, x, y, passive)
77 | }
78 |
79 | this.operate = function (operators) {
80 | this.release()
81 | for (const id in operators) {
82 | const operator = operators[id]
83 | if (this.lockAt(operator.x, operator.y)) { continue }
84 | if (operator.passive || operator.bang()) {
85 | operator.haste()
86 | operator.permissions()
87 | }
88 | }
89 | for (const id in operators) {
90 | const operator = operators[id]
91 | if (this.lockAt(operator.x, operator.y)) { continue }
92 | if (operator.passive || operator.bang()) {
93 | operator.run()
94 | }
95 | }
96 | }
97 |
98 | // Locks
99 |
100 | this.release = function () {
101 | this.locks = []
102 | }
103 |
104 | this.unlock = function (x, y) {
105 | const index = this.locks.indexOf(`${x}:${y}`)
106 | this.locks.splice(index, 1)
107 | }
108 |
109 | this.lock = function (x, y) {
110 | if (this.lockAt(x, y)) { return }
111 | this.locks.push(`${x}:${y}`)
112 | }
113 |
114 | // IO
115 |
116 | this.input = function (g) {
117 | this.write(0, 0, g)
118 | }
119 |
120 | this.output = function () {
121 | return this.s.charAt(this.s.length - 1)
122 | }
123 |
124 | // Helpers
125 |
126 | this.inBounds = function (x, y) {
127 | return x >= 0 && x < this.w && y >= 0 && y < this.h
128 | }
129 |
130 | this.isAllowed = function (g) {
131 | return g === '.' || !!library[`${g}`.toLowerCase()]
132 | }
133 |
134 | this.keyOf = function (val) {
135 | return this.keys[val % 36]
136 | }
137 |
138 | this.valueOf = function (g) {
139 | return clamp(this.keys.indexOf(`${g}`.toLowerCase()), 0, 35)
140 | }
141 |
142 | this.indexAt = function (x, y) {
143 | return x + (this.w * y)
144 | }
145 |
146 | this.posAt = function (index) {
147 | return { x: index % this.w, y: parseInt(index / this.w) }
148 | }
149 |
150 | this.glyphAt = function (x, y, req = null) {
151 | return this.s.charAt(this.indexAt(x, y))
152 | }
153 |
154 | this.lockAt = function (x, y) {
155 | return this.locks.indexOf(`${x}:${y}`) > -1
156 | }
157 |
158 | // Tools
159 |
160 | this.format = function () {
161 | const a = []
162 | for (let y = 0; y < this.h; y++) {
163 | a.push(this.s.substr(y * this.w, this.w))
164 | }
165 | return a.reduce((acc, val) => {
166 | return `${acc}${val}\n`
167 | }, '')
168 | }
169 |
170 | this.toString = function () {
171 | return this.format().trim()
172 | }
173 |
174 | this.reset()
175 |
176 | function clamp (v, min, max) { return v < min ? min : v > max ? max : v }
177 | }
178 |
179 | module.exports = Orca
180 |
--------------------------------------------------------------------------------
/desktop/icon.icns:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hamstah/Orca/cd4f96db307dbdcc1d4f687f7f70ed47dfd0bbe7/desktop/icon.icns
--------------------------------------------------------------------------------
/desktop/icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hamstah/Orca/cd4f96db307dbdcc1d4f687f7f70ed47dfd0bbe7/desktop/icon.ico
--------------------------------------------------------------------------------
/desktop/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hamstah/Orca/cd4f96db307dbdcc1d4f687f7f70ed47dfd0bbe7/desktop/icon.png
--------------------------------------------------------------------------------
/desktop/icon.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/desktop/main.js:
--------------------------------------------------------------------------------
1 | const { app, BrowserWindow, webFrame, Menu } = require('electron')
2 | const path = require('path')
3 | const url = require('url')
4 | const shell = require('electron').shell
5 |
6 | let isShown = true
7 |
8 | app.win = null
9 |
10 | app.on('ready', () => {
11 | app.win = new BrowserWindow({
12 | width: 710,
13 | height: 450,
14 | minWidth: 320,
15 | minHeight: 320,
16 | frame: process.platform === 'win32',
17 | resizable: true,
18 | icon: __dirname + '/icon.ico',
19 | transparent: process.platform !== 'win32',
20 | skipTaskbar: process.platform !== 'win32',
21 | autoHideMenuBar: process.platform !== 'win32'
22 | })
23 |
24 | app.win.loadURL(`file://${__dirname}/sources/index.html`)
25 | // app.inspect()
26 |
27 | app.win.on('closed', () => {
28 | win = null
29 | app.quit()
30 | })
31 |
32 | app.win.on('hide', function () {
33 | isShown = false
34 | })
35 |
36 | app.win.on('show', function () {
37 | isShown = true
38 | })
39 |
40 | app.on('window-all-closed', () => {
41 | app.quit()
42 | })
43 |
44 | app.on('activate', () => {
45 | if (app.win === null) {
46 | createWindow()
47 | } else {
48 | app.win.show()
49 | }
50 | })
51 | })
52 |
53 | app.inspect = function () {
54 | app.win.toggleDevTools()
55 | }
56 |
57 | app.toggleFullscreen = function () {
58 | app.win.setFullScreen(!app.win.isFullScreen())
59 | }
60 |
61 | app.toggleVisible = function () {
62 | if (process.platform === 'win32') {
63 | if (!app.win.isMinimized()) { app.win.minimize() } else { app.win.restore() }
64 | } else {
65 | if (isShown && !app.win.isFullScreen()) { app.win.hide() } else { app.win.show() }
66 | }
67 | }
68 |
69 | app.injectMenu = function (menu) {
70 | try {
71 | Menu.setApplicationMenu(Menu.buildFromTemplate(menu))
72 | } catch (err) {
73 | console.warn('Cannot inject menu.')
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/desktop/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Orca",
3 | "version": "0.1.0",
4 | "main": "main.js",
5 | "scripts": {
6 | "start": "electron .",
7 | "time": "node time.js",
8 | "docs": "node ../docs.js",
9 | "fix": "standard --fix",
10 | "clean": "rm -r ~/Desktop/Orca-darwin-x64/ ; rm -r ~/Desktop/Orca-linux-x64/ ; rm -r ~/Desktop/Orca-win32-x64/ ; echo 'cleaned build location'",
11 | "build_osx": "electron-packager . Orca --platform=darwin --arch=x64 --out ~/Desktop/ --overwrite --icon=icon.icns ; echo 'Built for OSX'",
12 | "build_linux": "electron-packager . Orca --platform=linux --arch=x64 --out ~/Desktop/ --overwrite --icon=icon.ico ; echo 'Built for LINUX'",
13 | "build_win": "electron-packager . Orca --platform=win32 --arch=x64 --out ~/Desktop/ --overwrite --icon=icon.ico ; echo 'Built for WIN'",
14 | "build": "npm run clean ; npm run build_osx ; npm run build_linux ; npm run build_win",
15 | "push_osx": "~/butler push ~/Desktop/Orca-darwin-x64/ hundredrabbits/orca:osx-64",
16 | "push_linux": "~/butler push ~/Desktop/Orca-linux-x64/ hundredrabbits/orca:linux-64",
17 | "push_win": "~/butler push ~/Desktop/Orca-win32-x64/ hundredrabbits/orca:windows-64",
18 | "push_status": "~/butler status hundredrabbits/orca",
19 | "push": "npm run build ; npm run push_osx ; npm run push_linux ; npm run push_win ; npm run clean ; npm run push_status"
20 | },
21 | "devDependencies": {
22 | "electron": "^3.1.1",
23 | "electron-packager": "^12.2.0",
24 | "electron-rebuild": "^1.8.2"
25 | },
26 | "dependencies": {
27 | "node-osc": "^3.0.0"
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/desktop/sources/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | Orca
13 |
14 |
15 |
73 |
74 |
75 |
--------------------------------------------------------------------------------
/desktop/sources/links/fonts.css:
--------------------------------------------------------------------------------
1 | /* Input */
2 |
3 | @font-face {
4 | font-family: 'input_mono_regular';
5 | src: url('../media/fonts/input_mono_regular.ttf') format('truetype');
6 | font-weight: normal;
7 | font-style: normal;
8 | }
9 |
10 | @font-face {
11 | font-family: 'input_mono_medium';
12 | src: url('../media/fonts/input_mono_medium.ttf') format('truetype');
13 | font-weight: normal;
14 | font-style: normal;
15 | }
--------------------------------------------------------------------------------
/desktop/sources/links/main.css:
--------------------------------------------------------------------------------
1 | body { font-family: 'input_mono_regular'; padding:30px; overflow: hidden; -webkit-app-region: drag; transition: background-color 500ms; }
2 | body.transparent { background:transparent !important; }
3 | canvas { display: block;white-space: pre;font-size: 11px;line-height: 10px; text-transform: uppercase; width:300px; margin:0px auto; -webkit-app-region: drag; opacity: 0; transition: opacity 1000ms}
4 | canvas.ready { opacity: 1 }
5 |
--------------------------------------------------------------------------------
/desktop/sources/links/reset.css:
--------------------------------------------------------------------------------
1 | * { margin:0;padding:0;border:0;outline:0;text-decoration:none;font-weight:inherit;font-style:inherit;color:inherit;font-size:100%;font-family:inherit;vertical-align:baseline;list-style:none;border-collapse:collapse;border-spacing:0; -webkit-font-smoothing: antialiased;-moz-osx-font-smoothing: grayscale;}
--------------------------------------------------------------------------------
/desktop/sources/links/theme.css:
--------------------------------------------------------------------------------
1 | body { background:var(--background) !important }
2 |
--------------------------------------------------------------------------------
/desktop/sources/media/fonts/input_mono_medium.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hamstah/Orca/cd4f96db307dbdcc1d4f687f7f70ed47dfd0bbe7/desktop/sources/media/fonts/input_mono_medium.ttf
--------------------------------------------------------------------------------
/desktop/sources/media/fonts/input_mono_regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hamstah/Orca/cd4f96db307dbdcc1d4f687f7f70ed47dfd0bbe7/desktop/sources/media/fonts/input_mono_regular.ttf
--------------------------------------------------------------------------------
/desktop/sources/scripts/cursor.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | function Cursor (terminal) {
4 | this.x = 0
5 | this.y = 0
6 | this.w = 1
7 | this.h = 1
8 | this.mode = 0
9 | this.block = []
10 |
11 | this.move = function (x, y) {
12 | this.x = clamp(this.x + x, 0, terminal.orca.w - 1)
13 | this.y = clamp(this.y - y, 0, terminal.orca.h - 1)
14 | terminal.update()
15 | }
16 |
17 | this.scale = function (x, y) {
18 | this.w = clamp(this.w + x, 1, terminal.orca.w - this.x)
19 | this.h = clamp(this.h - y, 1, terminal.orca.h - this.y)
20 | terminal.update()
21 | }
22 |
23 | this.drag = function (x, y) {
24 | this.cut()
25 | this.move(x, y)
26 | this.paste()
27 | }
28 |
29 | this.reset = function (pos = false) {
30 | if (pos) {
31 | this.x = 0
32 | this.y = 0
33 | }
34 | this.move(0, 0)
35 | this.w = 1
36 | this.h = 1
37 | this.mode = 0
38 | }
39 |
40 | this.selectAll = function () {
41 | this.x = 0
42 | this.y = 0
43 | this.w = terminal.orca.w
44 | this.h = terminal.orca.h
45 | this.mode = 0
46 | terminal.update()
47 | }
48 |
49 | this.copy = function () {
50 | this.block = this.getBlock()
51 | }
52 |
53 | this.cut = function () {
54 | this.copy()
55 | this.erase()
56 | }
57 |
58 | this.paste = function () {
59 | this.writeBlock(this.toRect(), this.block)
60 | }
61 |
62 | this.read = function () {
63 | return terminal.orca.glyphAt(this.x, this.y)
64 | }
65 |
66 | this.write = function (g) {
67 | if (this.mode === 2) {
68 | terminal.io.sendKey(event.key)
69 | return
70 | }
71 | terminal.orca.write(this.x, this.y, g)
72 | if (this.mode === 1) {
73 | this.move(1, 0)
74 | }
75 | terminal.history.record()
76 | }
77 |
78 | this.erase = function () {
79 | if (this.w === 1 && this.h === 1 && terminal.orca.glyphAt(this.x, this.y) === '.') { this.move(-1, 0); return } // Backspace Effect
80 | this.eraseBlock(this.x, this.y, this.w, this.h)
81 | terminal.history.record()
82 | }
83 |
84 | this.goto = function (str) {
85 | const i = terminal.orca.s.indexOf(str)
86 | if (i < 0) { return }
87 | const pos = terminal.orca.posAt(i)
88 | this.x = pos.x + 1
89 | this.y = pos.y
90 | }
91 |
92 | this.toggleMode = function (val) {
93 | this.mode = this.mode === 0 ? val : 0
94 | }
95 |
96 | this.inspect = function (name = true, ports = false) {
97 | if (this.w > 1 || this.h > 1) { return 'multi' }
98 | const port = terminal.portAt(this.x, this.y)
99 | if (port) { return `${port.name}` }
100 | if (terminal.orca.lockAt(this.x, this.y)) { return 'locked' }
101 | return 'empty'
102 | }
103 |
104 | // Block
105 |
106 | this.getBlock = function (rect = this.toRect()) {
107 | const block = []
108 | for (let _y = rect.y; _y < rect.y + rect.h; _y++) {
109 | const line = []
110 | for (let _x = rect.x; _x < rect.x + rect.w; _x++) {
111 | line.push(terminal.orca.glyphAt(_x, _y))
112 | }
113 | block.push(line)
114 | }
115 | return block
116 | }
117 |
118 | this.writeBlock = function (rect, block) {
119 | if (!block || block.length === 0) { return }
120 | let _y = rect.y
121 | for (const lineId in block) {
122 | let _x = rect.x
123 | for (const glyphId in block[lineId]) {
124 | terminal.orca.write(_x, _y, block[lineId][glyphId])
125 | _x++
126 | }
127 | _y++
128 | }
129 | terminal.history.record()
130 | }
131 |
132 | this.eraseBlock = function (x, y, w, h) {
133 | for (let _y = y; _y < y + h; _y++) {
134 | for (let _x = x; _x < x + w; _x++) {
135 | terminal.orca.write(_x, _y, '.')
136 | }
137 | }
138 | terminal.history.record()
139 | }
140 |
141 | this.toRect = function () {
142 | return { x: this.x, y: this.y, w: this.w, h: this.h }
143 | }
144 |
145 | function clamp (v, min, max) { return v < min ? min : v > max ? max : v }
146 | }
147 |
148 | module.exports = Cursor
149 |
--------------------------------------------------------------------------------
/desktop/sources/scripts/events.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | window.addEventListener('dragover', function (e) {
4 | e.stopPropagation()
5 | e.preventDefault()
6 | e.dataTransfer.dropEffect = 'copy'
7 | })
8 |
9 | window.addEventListener('drop', function (e) {
10 | e.preventDefault()
11 | e.stopPropagation()
12 |
13 | const file = e.dataTransfer.files[0]
14 | const path = file.path ? file.path : file.name
15 |
16 | if (!path || path.indexOf('.orca') < 0) { console.log('Orca', 'Not a orca file'); return }
17 |
18 | terminal.source.path = path
19 | terminal.source.read(path)
20 | })
21 |
22 | window.onresize = (event) => {
23 | terminal.align()
24 | }
25 |
--------------------------------------------------------------------------------
/desktop/sources/scripts/history.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | function History (terminal, orca = terminal.orca) {
4 | this.index = 0
5 | this.frames = []
6 |
7 | this.record = function () {
8 | if (this.index === this.frames.length) {
9 | this.append()
10 | } else {
11 | this.fork()
12 | }
13 | this.index = this.frames.length
14 | }
15 |
16 | this.undo = function () {
17 | if (this.index === 0) { console.warn('History', 'Reached beginning'); return }
18 |
19 | this.index = clamp(this.index - 1, 0, this.frames.lengt - 1)
20 | this.apply(this.frames[this.index])
21 | }
22 |
23 | this.redo = function () {
24 | if (this.index > this.frames.length - 1) { console.warn('History', 'Reached end'); return }
25 |
26 | this.index = clamp(this.index + 1, 0, this.frames.lengt - 1)
27 | this.apply(this.frames[this.index])
28 | }
29 |
30 | this.apply = function (f) {
31 | if (!f || f.length !== terminal.orca.s.length) { return }
32 | terminal.orca.s = this.frames[this.index]
33 | }
34 |
35 | this.reset = function () {
36 | this.index = 0
37 | this.frames = []
38 | }
39 |
40 | this.append = function () {
41 | this.frames.push(terminal.orca.s)
42 | }
43 |
44 | this.fork = function () {
45 | this.frames = this.frames.slice(0, this.index + 1)
46 | this.frames.push(terminal.orca.s)
47 | }
48 |
49 | function clamp (v, min, max) { return v < min ? min : v > max ? max : v }
50 | }
51 |
52 | module.exports = History
53 |
--------------------------------------------------------------------------------
/desktop/sources/scripts/io.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Midi = require('./io.midi')
4 | const Udp = require('./io.udp')
5 | const Osc = require('./io.osc')
6 |
7 | function IO (terminal) {
8 | this.midi = new Midi(terminal)
9 | this.udp = new Udp(terminal)
10 | this.osc = new Osc(terminal)
11 |
12 | this.start = function () {
13 | this.midi.start()
14 | this.udp.start()
15 | this.osc.start()
16 | this.clear()
17 | }
18 |
19 | this.clear = function () {
20 | this.midi.clear()
21 | this.udp.clear()
22 | this.osc.clear()
23 | }
24 |
25 | this.run = function () {
26 | this.midi.run()
27 | this.udp.run()
28 | this.osc.run()
29 | }
30 |
31 | this.length = function () {
32 | return this.midi.stack.length + this.udp.stack.length + this.osc.stack.length
33 | }
34 |
35 | this.toString = function () {
36 | let text = ''
37 | for (let i = 0; i < this.length(); i++) {
38 | text += '|'
39 | }
40 | while (text.length - 1 <= terminal.size.grid.w) {
41 | text += '-'
42 | }
43 | return text
44 | }
45 | }
46 |
47 | module.exports = IO
48 |
--------------------------------------------------------------------------------
/desktop/sources/scripts/io.midi.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | function Midi (terminal) {
4 | this.index = 0
5 | this.devices = []
6 | this.stack = []
7 |
8 | this.start = function () {
9 | console.info('Starting Midi..')
10 | this.setup()
11 | }
12 |
13 | this.clear = function () {
14 | this.stack = []
15 | }
16 |
17 | this.run = function () {
18 | for (const id in this.stack) {
19 | this.play(this.stack[id], this.device())
20 | }
21 | }
22 |
23 | this.update = function () {
24 | terminal.controller.clearCat('default', 'Midi')
25 | const devices = terminal.io.midi.list()
26 | for (const id in devices) {
27 | terminal.controller.add('default', 'Midi', `${devices[id].name} ${terminal.io.midi.index === parseInt(id) ? ' — Active' : ''}`, () => { terminal.io.midi.select(id) }, '')
28 | }
29 | if (devices.length < 1) {
30 | terminal.controller.add('default', 'Midi', `No Device Available`)
31 | }
32 | if (devices.length > 1) {
33 | terminal.controller.add('default', 'Midi', `Next Device`, () => { terminal.io.midi.next(id) }, 'CmdOrCtrl+Shift+M')
34 | }
35 | terminal.controller.commit()
36 | }
37 |
38 | // Midi
39 |
40 | this.send = function (channel, octave, note, velocity, length) {
41 | this.stack.push([channel, octave, note, velocity, length])
42 | }
43 |
44 | this.play = function (data = this.stack, device) {
45 | const channel = convertChannel(data[0])
46 | const note = convertNote(data[1], data[2])
47 | const velocity = data[3]
48 | const length = window.performance.now() + convertLength(data[4], terminal.bpm)
49 |
50 | if (!device) { console.warn('No midi device!'); return }
51 |
52 | device.send([channel[0], note, velocity])
53 | device.send([channel[1], note, velocity], length)
54 | }
55 |
56 | this.select = function (id) {
57 | if (!this.devices[id]) { return }
58 | this.index = parseInt(id)
59 | this.update()
60 | console.log(`Midi Device: ${this.device().name}`)
61 | return this.device()
62 | }
63 |
64 | this.device = function () {
65 | return this.devices[this.index]
66 | }
67 |
68 | this.list = function () {
69 | return this.devices
70 | }
71 |
72 | this.next = function () {
73 | this.select((this.index + 1) % this.devices.length)
74 | }
75 |
76 | // Setup
77 |
78 | this.setup = function () {
79 | if (!navigator.requestMIDIAccess) { return }
80 | navigator.requestMIDIAccess({ sysex: false }).then(this.access, (err) => {
81 | console.warn('No Midi', err)
82 | })
83 | }
84 |
85 | this.access = function (midiAccess) {
86 | const iter = midiAccess.outputs.values()
87 | for (let i = iter.next(); i && !i.done; i = iter.next()) {
88 | terminal.io.midi.devices.push(i.value)
89 | }
90 | terminal.io.midi.select(0)
91 | }
92 |
93 | this.toString = function () {
94 | return this.devices.length > 0 ? `${this.devices[this.index].name}` : 'No Midi'
95 | }
96 |
97 | function convertChannel (id) {
98 | // return [id + 144, id + 128].toString(16);
99 | if (id === 0) { return [0x90, 0x80] } // ch1
100 | if (id === 1) { return [0x91, 0x81] } // ch2
101 | if (id === 2) { return [0x92, 0x82] } // ch3
102 | if (id === 3) { return [0x93, 0x83] } // ch4
103 | if (id === 4) { return [0x94, 0x84] } // ch5
104 | if (id === 5) { return [0x95, 0x85] } // ch6
105 | if (id === 6) { return [0x96, 0x86] } // ch7
106 | if (id === 7) { return [0x97, 0x87] } // ch8
107 | if (id === 8) { return [0x98, 0x88] } // ch9
108 | if (id === 9) { return [0x99, 0x89] } // ch10
109 | if (id === 10) { return [0x9A, 0x8A] } // ch11
110 | if (id === 11) { return [0x9B, 0x8B] } // ch12
111 | if (id === 12) { return [0x9C, 0x8C] } // ch13
112 | if (id === 13) { return [0x9D, 0x8D] } // ch14
113 | if (id === 14) { return [0x9E, 0x8E] } // ch15
114 | if (id === 15) { return [0x9F, 0x8F] } // ch16
115 | }
116 |
117 | function convertNote (octave, note) {
118 | return 24 + (octave * 12) + note // 60 = C3
119 | }
120 |
121 | function convertLength (val, bpm) {
122 | return (60000 / bpm) * (val / 15)
123 | }
124 |
125 | function clamp (v, min, max) { return v < min ? min : v > max ? max : v }
126 | }
127 |
128 | module.exports = Midi
129 |
--------------------------------------------------------------------------------
/desktop/sources/scripts/io.osc-standalone.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | function Osc (terminal) {
4 | this.index = 0
5 | this.routes = []
6 | this.stack = []
7 |
8 | this.start = function () {
9 | console.info('Starting OSC..')
10 | this.setup()
11 | }
12 |
13 | this.clear = function () {
14 | this.stack = []
15 | }
16 |
17 | this.run = function () {
18 | for (const id in this.stack) {
19 | this.play(this.stack[id])
20 | }
21 | }
22 |
23 | this.send = function (msg) {
24 | this.stack.push(msg)
25 | }
26 |
27 | this.play = function (data) {
28 | // see io.osc.js
29 |
30 | // const args = data.split('.').filter(d => d !== '')
31 | // if (args.length !== 0) {
32 | // const key = args[0]
33 | // const def = this.config.defs[key]
34 | // const pattern = def.pattern
35 |
36 | // if(pattern.length !== args.length - 1) {
37 | // console.log(`Number of arguments provided does not match the pattern length of this def`)
38 | // return
39 | // }
40 |
41 | // const values = []
42 | // for(let i = 0, l = pattern.length; i < l; i++) {
43 | // const type = pattern[i]
44 | // if (type !== 'f' && type !== 'i' && type !== 's') {
45 | // console.log(`Don't know how to send OSC argument with type '${type}'`)
46 | // return
47 | // }
48 |
49 | // const value =
50 | // type === 'f' ? parseInt(split[1]) / 10.0
51 | // : type === 'i' ? parseInt(split[1])
52 | // /* type === 's' ? */ : split[1]
53 |
54 | // function nextMultipleOf4 (x) {
55 | // const rem = x % 4
56 | // return rem === 0 ? x : (x + 4 - rem)
57 | // }
58 |
59 | // function writeOscString (val, buf, pos) {
60 | // let localPos = pos
61 | // for (let i = 0; i < val.length; i++) {
62 | // const ch = val.charCodeAt(i)
63 | // localPos = buf.writeUInt8(ch & 0xFF, localPos)
64 | // }
65 | // // Add length, terminating 0 and pad to multiple of 4
66 | // return nextMultipleOf4(pos + val.length + 1)
67 | // }
68 |
69 | // let msglen = 0
70 | // { // Calculate message length
71 | // // Zero-terminated address string
72 | // msglen += nextMultipleOf4(address.length + 1)
73 | // // Type tag with two args arg: comma, letter (key), letter (value), terminating 0
74 | // msglen += 4
75 | // // Zero-terminated key string
76 | // msglen += nextMultipleOf4(key.length + 1)
77 | // if (type === 'f' || type === 'i') {
78 | // // 32-bit float or int
79 | // msglen += 4
80 | // } else if (type === 's') {
81 | // // Zero terminated value string
82 | // msglen += nextMultipleOf4(value.length + 1)
83 | // }
84 | // }
85 |
86 | // // Get buffer cleared to 0
87 | // const buf = Buffer.alloc(msglen)
88 | // let pos = 0
89 |
90 | // pos = writeOscString(address, buf, pos)
91 | // pos = writeOscString(`,s${type}`, buf, pos)
92 | // pos = writeOscString(key, buf, pos)
93 |
94 | // if (type === 'f') {
95 | // pos = buf.writeFloatBE(value, pos)
96 | // } else if (type === 'i') {
97 | // pos = buf.writeInt32BE(value, pos)
98 | // } else if (type === 's') {
99 | // pos = writeOscString(value, buf, pos)
100 | // }
101 | // }
102 |
103 | // this.port.send(buf, def.port, def.address, (err) => {
104 | // if (err) { console.log(err) }
105 | // })
106 | }
107 |
108 | this.setup = function () {
109 | this.config = require('../../core/bridge/oscConfig')
110 | this.clients = {}
111 | for (const key in this.config.defs) {
112 | const def = this.config.defs[key]
113 | const address = def.address
114 | const port = def.port
115 | if (!this.clients[`${address}:${port}`]) {
116 | this.clients[`${address}:${port}`] = new osc.Client(address, port)
117 | console.log(`OSC client ${address}:${port} created`)
118 | }
119 | }
120 | }
121 | }
122 |
123 | module.exports = Osc
124 |
--------------------------------------------------------------------------------
/desktop/sources/scripts/io.osc.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const osc = require('node-osc')
4 |
5 | function Osc (terminal) {
6 | this.stack = []
7 | this.port = 49162
8 | this.ip = '127.0.0.1'
9 |
10 | this.start = function () {
11 | console.info('Starting OSC..')
12 | this.setup()
13 | }
14 |
15 | this.clear = function () {
16 | this.stack = []
17 | }
18 |
19 | this.run = function () {
20 | for (const id in this.stack) {
21 | this.play(this.stack[id])
22 | }
23 | }
24 |
25 | this.send = function (path, msg) {
26 | this.stack.push({ path, msg })
27 | }
28 |
29 | this.play = function ({ path, msg }) {
30 | const oscMsg = new osc.Message(path)
31 | for (var i = 0; i < msg.length; i++) {
32 | oscMsg.append(terminal.orca.valueOf(msg.charAt(i)))
33 | }
34 | this.client.send(oscMsg, (err) => {
35 | if (err) { console.warn(err) }
36 | })
37 | }
38 |
39 | this.select = function (port) {
40 | if (port < 1000) { console.warn('Unavailable port'); return }
41 | this.port = port
42 | this.setup()
43 | console.log(`OSC Port: ${this.port}`)
44 | return this.port
45 | }
46 |
47 | this.setup = function () {
48 | if (this.client) { this.client.kill() }
49 | this.client = new osc.Client(this.ip, this.port)
50 | }
51 | }
52 |
53 | module.exports = Osc
54 |
--------------------------------------------------------------------------------
/desktop/sources/scripts/io.udp.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const dgram = require('dgram')
4 |
5 | function Udp (terminal) {
6 | this.index = 0
7 | this.stack = []
8 | this.server = null
9 | this.port = 49160
10 | this.ip = '127.0.0.1'
11 |
12 | this.start = function () {
13 | console.info('UDP Starting..')
14 | this.setup()
15 | }
16 |
17 | this.clear = function () {
18 | this.stack = []
19 | }
20 |
21 | this.run = function () {
22 | for (const id in this.stack) {
23 | this.play(this.stack[id])
24 | }
25 | }
26 |
27 | this.send = function (msg) {
28 | this.stack.push(msg)
29 | }
30 |
31 | this.play = function (data) {
32 | this.server.send(Buffer.from(`${data}`), this.port, this.ip, (err) => {
33 | if (err) { console.log(err) }
34 | })
35 | }
36 |
37 | this.select = function (port = 49160) {
38 | if (port < 1000) { console.warn('Unavailable port'); return }
39 | this.port = port
40 | console.log(`UDP Port: ${this.port}`)
41 | return this.port
42 | }
43 |
44 | this.setup = function () {
45 | this.server = dgram.createSocket('udp4')
46 | }
47 | }
48 |
49 | module.exports = Udp
50 |
--------------------------------------------------------------------------------
/desktop/sources/scripts/keyboard.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | function Keyboard (terminal) {
4 | this.locks = []
5 | this.history = ''
6 |
7 | this.onKeyDown = function (event) {
8 | // Reset
9 | if ((event.metaKey || event.ctrlKey) && event.key === 'Backspace') {
10 | terminal.reset()
11 | event.preventDefault()
12 | return
13 | }
14 |
15 | if (event.key === 'c' && (event.metaKey || event.ctrlKey)) { terminal.cursor.copy(); event.preventDefault(); return }
16 | if (event.key === 'x' && (event.metaKey || event.ctrlKey)) { terminal.cursor.cut(); event.preventDefault(); return }
17 | if (event.key === 'v' && (event.metaKey || event.ctrlKey)) { terminal.cursor.paste(); event.preventDefault(); return }
18 | if (event.key === 'a' && (event.metaKey || event.ctrlKey)) { terminal.cursor.selectAll(); event.preventDefault(); return }
19 |
20 | // Undo/Redo
21 | if (event.key === 'z' && (event.metaKey || event.ctrlKey) && event.shiftKey) { terminal.history.redo(); event.preventDefault(); return }
22 | if (event.key === 'z' && (event.metaKey || event.ctrlKey)) { terminal.history.undo(); event.preventDefault(); return }
23 |
24 | if (event.keyCode === 38) { terminal.keyboard.onArrowUp(event.shiftKey, (event.metaKey || event.ctrlKey), event.altKey); return }
25 | if (event.keyCode === 40) { terminal.keyboard.onArrowDown(event.shiftKey, (event.metaKey || event.ctrlKey), event.altKey); return }
26 | if (event.keyCode === 37) { terminal.keyboard.onArrowLeft(event.shiftKey, (event.metaKey || event.ctrlKey), event.altKey); return }
27 | if (event.keyCode === 39) { terminal.keyboard.onArrowRight(event.shiftKey, (event.metaKey || event.ctrlKey), event.altKey); return }
28 |
29 | if (event.metaKey) { return }
30 | if (event.ctrlKey) { return }
31 |
32 | if (event.key === 'Backquote') { terminal.toggleBackground(); return }
33 | if (event.key === 'Tab') { terminal.toggleInterface(); return }
34 | if (event.key === 'Enter') { terminal.cursor.toggleMode(1); return }
35 | if (event.key === 'Backspace' || event.key === '.') { terminal.cursor.erase(); return }
36 | if (event.key === ' ') { terminal.pause(); event.preventDefault(); return }
37 | if (event.key === 'Escape') { terminal.clear(); terminal.isPaused = false; terminal.cursor.reset(); return }
38 |
39 | if (event.key === ']') { terminal.modGrid(1, 0); event.preventDefault(); return }
40 | if (event.key === '[') { terminal.modGrid(-1, 0); event.preventDefault(); return }
41 | if (event.key === '}') { terminal.modGrid(0, 1); event.preventDefault(); return }
42 | if (event.key === '{') { terminal.modGrid(0, -1); event.preventDefault(); return }
43 | if (event.key === '>') { terminal.modSpeed(1); event.preventDefault(); return }
44 | if (event.key === '<') { terminal.modSpeed(-1); event.preventDefault(); return }
45 |
46 | if (event.key.length === 1) {
47 | terminal.cursor.write(event.key)
48 | terminal.update()
49 | }
50 | }
51 |
52 | this.onKeyUp = function (event) {
53 | terminal.update()
54 | }
55 |
56 | this.onArrowUp = function (mod = false, skip = false, drag = false) {
57 | const leap = skip ? terminal.size.grid.h : 1
58 | if (drag) {
59 | terminal.cursor.drag(0, leap)
60 | } else if (mod) {
61 | terminal.cursor.scale(0, leap)
62 | } else {
63 | terminal.cursor.move(0, leap)
64 | }
65 | }
66 |
67 | this.onArrowDown = function (mod = false, skip = false, drag = false) {
68 | const leap = skip ? terminal.size.grid.h : 1
69 | if (drag) {
70 | terminal.cursor.drag(0, -leap)
71 | } else if (mod) {
72 | terminal.cursor.scale(0, -leap)
73 | } else {
74 | terminal.cursor.move(0, -leap)
75 | }
76 | }
77 |
78 | this.onArrowLeft = function (mod = false, skip = false, drag = false) {
79 | const leap = skip ? terminal.size.grid.w : 1
80 | if (drag) {
81 | terminal.cursor.drag(-leap, 0)
82 | } else if (mod) {
83 | terminal.cursor.scale(-leap, 0)
84 | } else {
85 | terminal.cursor.move(-leap, 0)
86 | }
87 | }
88 |
89 | this.onArrowRight = function (mod = false, skip = false, drag = false) {
90 | const leap = skip ? terminal.size.grid.w : 1
91 | if (drag) {
92 | terminal.cursor.drag(leap, 0)
93 | } else if (mod) {
94 | terminal.cursor.scale(leap, 0)
95 | } else {
96 | terminal.cursor.move(leap, 0)
97 | }
98 | }
99 |
100 | document.onkeydown = (event) => { this.onKeyDown(event) }
101 | document.onkeyup = (event) => { this.onKeyUp(event) }
102 | }
103 |
104 | module.exports = Keyboard
105 |
--------------------------------------------------------------------------------
/desktop/sources/scripts/lib/controller.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | function Controller () {
4 | const fs = require('fs')
5 | const { dialog, app } = require('electron').remote
6 |
7 | this.menu = { default: {} }
8 | this.mode = 'default'
9 |
10 | this.app = require('electron').remote.app
11 |
12 | this.start = function () {
13 | }
14 |
15 | this.add = function (mode, cat, label, fn, accelerator) {
16 | if (!this.menu[mode]) { this.menu[mode] = {} }
17 | if (!this.menu[mode][cat]) { this.menu[mode][cat] = {} }
18 | this.menu[mode][cat][label] = { fn: fn, accelerator: accelerator }
19 | console.log(`${mode}/${cat}/${label} ${accelerator ? '<' + accelerator + '>' : ''}`)
20 | }
21 |
22 | this.add_role = function (mode, cat, label) {
23 | if (!this.menu[mode]) { this.menu[mode] = {} }
24 | if (!this.menu[mode][cat]) { this.menu[mode][cat] = {} }
25 | this.menu[mode][cat][label] = { role: label }
26 | }
27 |
28 | this.clearCat = function (mode, cat) {
29 | if (this.menu[mode]) { this.menu[mode][cat] = {} }
30 | }
31 |
32 | this.set = function (mode = 'default') {
33 | this.mode = mode
34 | this.commit()
35 | }
36 |
37 | this.format = function () {
38 | const f = []
39 | const m = this.menu[this.mode]
40 | for (const cat in m) {
41 | const submenu = []
42 | for (const name in m[cat]) {
43 | const option = m[cat][name]
44 | if (option.role) {
45 | submenu.push({ role: option.role })
46 | } else {
47 | submenu.push({ label: name, accelerator: option.accelerator, click: option.fn })
48 | }
49 | }
50 | f.push({ label: cat, submenu: submenu })
51 | }
52 | return f
53 | }
54 |
55 | this.commit = function () {
56 | this.app.injectMenu(this.format())
57 | }
58 |
59 | this.accelerator_for_key = function (key, menu) {
60 | const acc = { basic: null, ctrl: null }
61 | for (cat in menu) {
62 | const options = menu[cat]
63 | for (const id in options.submenu) {
64 | const option = options.submenu[id]; if (option.role) { continue }
65 | acc.basic = (option.accelerator.toLowerCase() === key.toLowerCase()) ? option.label.toUpperCase().replace('TOGGLE ', '').substr(0, 8).trim() : acc.basic
66 | acc.ctrl = (option.accelerator.toLowerCase() === ('CmdOrCtrl+' + key).toLowerCase()) ? option.label.toUpperCase().replace('TOGGLE ', '').substr(0, 8).trim() : acc.ctrl
67 | }
68 | }
69 | return acc
70 | }
71 | }
72 |
73 | module.exports = new Controller()
74 |
--------------------------------------------------------------------------------
/desktop/sources/scripts/lib/theme.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | function Theme (_default) {
4 | const themer = this
5 |
6 | this.active = _default
7 |
8 | this.el = document.createElement('style')
9 | this.el.type = 'text/css'
10 |
11 | this.install = function (host = document.body, callback) {
12 | console.log('Theme', 'Installing..')
13 | host.appendChild(this.el)
14 | this.callback = callback
15 | }
16 |
17 | this.start = function () {
18 | console.log('Theme', 'Starting..')
19 | if (isJson(localStorage.theme)) {
20 | const storage = JSON.parse(localStorage.theme)
21 | if (validate(storage)) {
22 | console.log('Theme', 'Found theme in localStorage!')
23 | this.load(storage)
24 | return
25 | }
26 | }
27 | this.load(_default)
28 | }
29 |
30 | this.load = function (data) {
31 | const theme = parse(data)
32 | if (!validate(theme)) { console.warn('Theme', 'Not a theme', theme); return }
33 | console.log('Theme', `Loading theme with background ${theme.background}.`)
34 | this.el.innerHTML = `:root { --background: ${theme.background}; --f_high: ${theme.f_high}; --f_med: ${theme.f_med}; --f_low: ${theme.f_low}; --f_inv: ${theme.f_inv}; --b_high: ${theme.b_high}; --b_med: ${theme.b_med}; --b_low: ${theme.b_low}; --b_inv: ${theme.b_inv}; }`
35 | localStorage.setItem('theme', JSON.stringify(theme))
36 | this.active = theme
37 | if (this.callback) {
38 | this.callback()
39 | }
40 | }
41 |
42 | this.reset = function () {
43 | this.load(_default)
44 | }
45 |
46 | function parse (any) {
47 | if (any && any.background) { return any } else if (any && any.data) { return any.data } else if (any && isJson(any)) { return JSON.parse(any) } else if (any && isHtml(any)) { return extract(any) }
48 | return null
49 | }
50 |
51 | // Drag
52 |
53 | this.drag = function (e) {
54 | e.stopPropagation()
55 | e.preventDefault()
56 | e.dataTransfer.dropEffect = 'copy'
57 | }
58 |
59 | this.drop = function (e) {
60 | e.preventDefault()
61 | e.stopPropagation()
62 | const file = e.dataTransfer.files[0]
63 | if (!file || !file.name) { console.warn('Theme', 'Unnamed file.'); return }
64 | if (file.name.indexOf('.thm') < 0 && file.name.indexOf('.svg') < 0) { console.warn('Theme', 'Skipped, not a theme'); return }
65 | const reader = new FileReader()
66 | reader.onload = function (e) {
67 | themer.load(e.target.result)
68 | }
69 | reader.readAsText(file)
70 | }
71 |
72 | this.open = function () {
73 | const fs = require('fs')
74 | const { dialog, app } = require('electron').remote
75 | let paths = dialog.showOpenDialog(app.win, { properties: ['openFile'], filters: [{ name: 'Themes', extensions: ['svg'] }] })
76 | if (!paths) { console.log('Nothing to load') }
77 | fs.readFile(paths[0], 'utf8', function (err, data) {
78 | if (err) throw err
79 | themer.load(data)
80 | })
81 | }
82 |
83 | window.addEventListener('dragover', this.drag)
84 | window.addEventListener('drop', this.drop)
85 |
86 | // Helpers
87 |
88 | function validate (json) {
89 | if (!json) { return false }
90 | if (!json.background) { return false }
91 | if (!json.f_high) { return false }
92 | if (!json.f_med) { return false }
93 | if (!json.f_low) { return false }
94 | if (!json.f_inv) { return false }
95 | if (!json.b_high) { return false }
96 | if (!json.b_med) { return false }
97 | if (!json.b_low) { return false }
98 | if (!json.b_inv) { return false }
99 | return true
100 | }
101 |
102 | function extract (text) {
103 | const svg = new DOMParser().parseFromString(text, 'text/xml')
104 | try {
105 | return {
106 | 'background': svg.getElementById('background').getAttribute('fill'),
107 | 'f_high': svg.getElementById('f_high').getAttribute('fill'),
108 | 'f_med': svg.getElementById('f_med').getAttribute('fill'),
109 | 'f_low': svg.getElementById('f_low').getAttribute('fill'),
110 | 'f_inv': svg.getElementById('f_inv').getAttribute('fill'),
111 | 'b_high': svg.getElementById('b_high').getAttribute('fill'),
112 | 'b_med': svg.getElementById('b_med').getAttribute('fill'),
113 | 'b_low': svg.getElementById('b_low').getAttribute('fill'),
114 | 'b_inv': svg.getElementById('b_inv').getAttribute('fill')
115 | }
116 | } catch (err) {
117 | console.warn('Theme', 'Incomplete SVG Theme', err)
118 | }
119 | }
120 |
121 | function isJson (text) {
122 | try { JSON.parse(text); return true } catch (error) { return false }
123 | }
124 |
125 | function isHtml (text) {
126 | try { new DOMParser().parseFromString(text, 'text/xml'); return true } catch (error) { return false }
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/desktop/sources/scripts/source.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | function Source (terminal) {
4 | const Orca = require('../../core/orca')
5 | const fs = require('fs')
6 | const { dialog, app } = require('electron').remote
7 |
8 | this.path = null
9 |
10 | this.new = function () {
11 | console.log('New')
12 |
13 | this.path = null
14 |
15 | terminal.orca = new Orca(terminal)
16 | terminal.resize()
17 | terminal.history.reset()
18 | }
19 |
20 | this.open = function () {
21 | console.log('Open')
22 | let paths = dialog.showOpenDialog(app.win, { properties: ['openFile'], filters: [{ name: 'Orca Machines', extensions: ['orca'] }] })
23 | if (!paths) { console.log('Nothing to load') }
24 | this.path = paths[0]
25 | this.read(paths[0])
26 | }
27 |
28 | this.save = function (as = false) {
29 | console.log('Save')
30 | if (this.path && !as) {
31 | this.write(this.path)
32 | } else {
33 | dialog.showSaveDialog((path) => {
34 | if (path === undefined) { return }
35 | if (path.indexOf('.orca') < 0) { path += '.orca' }
36 | terminal.source.write(path)
37 | terminal.source.path = path
38 | })
39 | }
40 | }
41 |
42 | this.revert = function () {
43 | console.log('Revert')
44 | this.read(this.path)
45 | }
46 |
47 | // I/O
48 |
49 | this.write = function (path) {
50 | fs.writeFile(path, this.generate(), (err) => {
51 | if (err) { alert('An error ocurred updating the file' + err.message); console.log(err) }
52 | })
53 | }
54 |
55 | this.read = function (path) {
56 | fs.readFile(path, 'utf8', (err, data) => {
57 | if (err) throw err
58 | terminal.load(this.parse(data))
59 | terminal.history.record()
60 | })
61 | }
62 |
63 | // Converters
64 |
65 | this.generate = function (orca = terminal.orca) {
66 | return `${orca}`
67 | }
68 |
69 | this.parse = function (text) {
70 | const lines = text.split('\n')
71 | const w = lines[0].length
72 | const h = lines.length
73 | const s = lines.join('\n').trim()
74 | return new Orca(terminal).load(w, h, s)
75 | }
76 |
77 | // Etc
78 |
79 | this.name = function () {
80 | const parts = this.path.replace(/\\/g, '/').split('/')
81 | return parts[parts.length - 1].replace('.orca', '').trim()
82 | }
83 |
84 | this.toString = function () {
85 | return this.path ? this.name() : 'blank'
86 | }
87 | }
88 |
89 | module.exports = Source
90 |
--------------------------------------------------------------------------------
/desktop/sources/scripts/terminal.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | function Terminal (tile = { w: 20, h: 30 }) {
4 | const Orca = require('../../core/orca')
5 | const Cursor = require('./cursor')
6 | const Source = require('./source')
7 | const History = require('./history')
8 | const Keyboard = require('./keyboard')
9 | const IO = require('./io')
10 |
11 | this.library = require('../../core/library')
12 |
13 | this.io = new IO(this)
14 | this.cursor = new Cursor(this)
15 | this.source = new Source(this)
16 | this.history = new History(this)
17 | this.keyboard = new Keyboard(this)
18 | this.controller = new Controller()
19 |
20 | // Themes
21 | this.theme = new Theme({ background: '#000000', f_high: '#ffffff', f_med: '#777777', f_low: '#444444', f_inv: '#000000', b_high: '#eeeeee', b_med: '#72dec2', b_low: '#444444', b_inv: '#ffb545' })
22 |
23 | this.el = document.createElement('canvas')
24 | this.context = this.el.getContext('2d')
25 | this.size = { width: 0, height: 0, ratio: 0.5, grid: { w: 8, h: 8 } }
26 | this.isPaused = false
27 | this.showInterface = true
28 | this.timer = null
29 | this.bpm = 120
30 |
31 | this.install = function (host) {
32 | host.appendChild(this.el)
33 | this.theme.install(host)
34 | }
35 |
36 | this.start = function () {
37 | this.theme.start()
38 | this.io.start()
39 | this.source.new()
40 | this.history.record()
41 | this.setSpeed(120)
42 | this.resize()
43 | this.update()
44 | this.el.className = 'ready'
45 | }
46 |
47 | this.run = function () {
48 | if (this.isPaused) { return }
49 | this.io.clear()
50 | this.orca.run()
51 | this.io.run()
52 | this.update()
53 | }
54 |
55 | this.pause = function () {
56 | this.isPaused = !this.isPaused
57 | console.log(this.isPaused ? 'Paused' : 'Unpaused')
58 | this.update()
59 | }
60 |
61 | this.load = function (orca, frame = 0) {
62 | this.history.reset()
63 | this.orca = orca
64 | this.resize()
65 | this.update()
66 | }
67 |
68 | this.update = function () {
69 | this.clear()
70 | this.ports = this.findPorts()
71 | this.drawProgram()
72 | this.drawInterface()
73 | }
74 |
75 | this.reset = function () {
76 | this.theme.reset()
77 | }
78 |
79 | //
80 |
81 | this.setSpeed = function (bpm) {
82 | this.bpm = clamp(bpm, 60, 300)
83 | console.log(`Changed speed to ${this.bpm}.`)
84 | clearInterval(this.timer)
85 | this.timer = setInterval(() => { this.run() }, (60000 / bpm) / 4)
86 | this.update()
87 | }
88 |
89 | this.setGrid = function (w, h) {
90 | this.size.grid.w = w
91 | this.size.grid.h = h
92 | this.update()
93 | }
94 |
95 | this.setSize = function (w, h) {
96 | if (w < 17 || h < 17) { return }
97 |
98 | let block = `${this.orca}`
99 | if (h > this.orca.h) {
100 | block = `${block}${`\n${'.'.repeat(this.orca.w)}`.repeat((h - this.orca.h))}`
101 | } else if (h < this.orca.h) {
102 | block = `${block}`.split('\n').slice(0, (h - this.orca.h)).join('\n').trim()
103 | }
104 |
105 | if (w > this.orca.w) {
106 | block = `${block}`.split('\n').map((val) => { return val + ('.').repeat((w - this.orca.w)) }).join('\n').trim()
107 | } else if (w < this.orca.w) {
108 | block = `${block}`.split('\n').map((val) => { return val.substr(0, val.length + (w - this.orca.w)) }).join('\n').trim()
109 | }
110 |
111 | this.orca.load(w, h, block, this.orca.f)
112 | this.resize()
113 | }
114 |
115 | this.modSpeed = function (mod = 0) {
116 | this.setSpeed(this.bpm + mod)
117 | }
118 |
119 | this.modGrid = function (x = 0, y = 0) {
120 | const w = clamp(this.size.grid.w + x, 4, 16)
121 | const h = clamp(this.size.grid.h + y, 4, 16)
122 | this.setGrid(w, h)
123 | }
124 |
125 | this.modSize = function (x = 0, y = 0) {
126 | const w = ((parseInt(this.orca.w / this.size.grid.w) + x) * this.size.grid.w) + 1
127 | const h = ((parseInt(this.orca.h / this.size.grid.h) + y) * this.size.grid.h) + 1
128 | this.setSize(w, h)
129 | }
130 |
131 | this.modZoom = function (mod = 0, set = false) {
132 | const { webFrame } = require('electron')
133 | const currentZoomFactor = webFrame.getZoomFactor()
134 | webFrame.setZoomFactor(set ? mod : currentZoomFactor + mod)
135 | }
136 |
137 | this.toggleInterface = function () {
138 | this.showInterface = this.showInterface !== true
139 | }
140 |
141 | this.toggleBackground = function () {
142 | document.body.className = document.body.className === 'transparent' ? '' : 'transparent'
143 | }
144 |
145 | //
146 |
147 | this.isCursor = function (x, y) {
148 | return x === this.cursor.x && y === this.cursor.y
149 | }
150 |
151 | this.isSelection = function (x, y) {
152 | return !!(x >= this.cursor.x && x < this.cursor.x + this.cursor.w && y >= this.cursor.y && y < this.cursor.y + this.cursor.h)
153 | }
154 |
155 | this.portAt = function (x, y, req = null) {
156 | return this.ports[`${x}:${y}`]
157 | }
158 |
159 | this.findPorts = function () {
160 | const h = {}
161 | for (const id in this.orca.runtime) {
162 | const g = this.orca.runtime[id]
163 | if (this.orca.lockAt(g.x, g.y)) { continue }
164 | if (!h[`${g.x}:${g.y}`]) {
165 | h[`${g.x}:${g.y}`] = { type: g.passive && g.draw ? 'passive' : 'none', name: `${g.name}` }
166 | }
167 | for (const id in g.ports.haste) {
168 | const port = g.ports.haste[id]
169 | h[`${g.x + port.x}:${g.y + port.y}`] = { type: 'haste', name: `${g.glyph}'${id}` }
170 | }
171 | for (const id in g.ports.input) {
172 | const port = g.ports.input[id]
173 | h[`${g.x + port.x}:${g.y + port.y}`] = { type: 'input', name: `${g.glyph}:${id}` }
174 | }
175 | if (g.ports.output) { h[`${g.x + g.ports.output.x}:${g.y + g.ports.output.y}`] = { type: 'output', name: `${g.glyph}.out` } }
176 | }
177 | if (this.orca.host) {
178 | h[`0:0`] = { type: 'input', name: `${this.orca.id}:input` }
179 | h[`${this.orca.w - 1}:${this.orca.h - 1}`] = { type: 'output', name: `${this.orca.id}.output` }
180 | }
181 | return h
182 | }
183 |
184 | // Canvas
185 |
186 | this.clear = function () {
187 | this.context.clearRect(0, 0, this.size.width, this.size.height)
188 | }
189 |
190 | this.guide = function (x, y) {
191 | const g = this.orca.glyphAt(x, y)
192 | if (g !== '.') { return g }
193 | if (x % this.size.grid.w === 0 && y % this.size.grid.h === 0) { return '+' }
194 | return g
195 | }
196 |
197 | this.drawProgram = function () {
198 | for (let y = 0; y < this.orca.h; y++) {
199 | for (let x = 0; x < this.orca.w; x++) {
200 | const port = this.ports[`${x}:${y}`]
201 | const glyph = this.guide(x, y)
202 | const isCursor = this.isCursor(x, y)
203 | if (this.showInterface === false && glyph === '.' && !isCursor) { continue }
204 | const styles = { isSelection: this.isSelection(x, y), isCursor: isCursor, isPort: port ? port.type : false, isLocked: this.orca.lockAt(x, y) }
205 | this.drawSprite(x, y, glyph, styles)
206 | }
207 | }
208 | }
209 |
210 | this.drawInterface = function () {
211 | if (this.showInterface !== true) { return }
212 |
213 | const col = this.size.grid.w
214 | // Cursor
215 | this.write(`${this.cursor.x},${this.cursor.y}`, col * 0, 1, this.size.grid.w)
216 | this.write(`${this.cursor.w}:${this.cursor.h}`, col * 1, 1, this.size.grid.w)
217 | this.write(`${this.cursor.inspect()}`, col * 2, 1, this.size.grid.w)
218 | this.write(`${this.source}${this.cursor.mode === 2 ? '^' : this.cursor.mode === 1 ? '+' : ''}`, col * 3, 1, this.size.grid.w)
219 | this.write(`${this.io.midi}`, col * 4, 1, this.size.grid.w * 2)
220 |
221 | // Grid
222 | this.write(`${this.orca.w}x${this.orca.h}`, col * 0, 0, this.size.grid.w)
223 | this.write(`${this.size.grid.w}/${this.size.grid.h}`, col * 1, 0, this.size.grid.w)
224 | this.write(`${this.orca.f}f${this.isPaused ? '*' : ''}`, col * 2, 0, this.size.grid.w)
225 | this.write(`${this.bpm}${this.orca.f % 4 === 0 ? '*' : ''}`, col * 3, 0, this.size.grid.w)
226 | this.write(`${this.io}`, col * 4, 0, this.size.grid.w)
227 | }
228 |
229 | this.drawSprite = function (x, y, g, styles = { isCursor: false, isSelection: false, isPort: false, f: null, b: null }) {
230 | const ctx = this.context
231 |
232 | ctx.textBaseline = 'bottom'
233 | ctx.textAlign = 'center'
234 | ctx.font = `${tile.h * 0.75}px input_mono_medium`
235 |
236 | // Highlight Variables
237 | if (g === 'V' && this.cursor.read() === 'V') {
238 | ctx.fillStyle = this.theme.active.b_inv
239 | ctx.fillRect(x * tile.w, (y) * tile.h, tile.w, tile.h)
240 | ctx.fillStyle = this.theme.active.background
241 | } else if (styles.f && styles.b && this.theme.active[styles.f] && this.theme.active[styles.b]) {
242 | ctx.fillStyle = this.theme.active[styles.b]
243 | ctx.fillRect(x * tile.w, (y) * tile.h, tile.w, tile.h)
244 | ctx.fillStyle = this.theme.active[styles.f]
245 | } else if (styles.isSelection) {
246 | ctx.fillStyle = this.theme.active.b_inv
247 | ctx.fillRect(x * tile.w, (y) * tile.h, tile.w, tile.h)
248 | ctx.fillStyle = this.theme.active.f_inv
249 | } else if (styles.isPort) {
250 | if (styles.isPort === 'output') { // Output
251 | ctx.fillStyle = this.theme.active.b_high
252 | ctx.fillRect(x * tile.w, (y) * tile.h, tile.w, tile.h)
253 | ctx.fillStyle = this.theme.active.f_low
254 | } else if (styles.isPort === 'input') { // Input
255 | ctx.fillStyle = this.theme.active.b_high
256 | } else if (styles.isPort === 'passive') { // Passive
257 | ctx.fillStyle = this.theme.active.b_med
258 | ctx.fillRect(x * tile.w, (y) * tile.h, tile.w, tile.h)
259 | ctx.fillStyle = this.theme.active.f_low
260 | } else if (styles.isPort === 'haste') { // Haste
261 | ctx.fillStyle = this.theme.active.background
262 | ctx.fillRect(x * tile.w, (y) * tile.h, tile.w, tile.h)
263 | ctx.fillStyle = this.theme.active.b_med
264 | } else {
265 | ctx.fillStyle = this.theme.active.background
266 | ctx.fillRect(x * tile.w, (y) * tile.h, tile.w, tile.h)
267 | ctx.fillStyle = this.theme.active.f_high
268 | }
269 | } else if (styles.isLocked) {
270 | ctx.fillStyle = this.theme.active.f_med
271 | } else {
272 | ctx.fillStyle = this.theme.active.f_low
273 | }
274 | ctx.fillText(styles.isCursor && (g === '.' || g === '+') ? (!this.isPaused ? '@' : '~') : g, (x + 0.5) * tile.w, (y + 1) * tile.h)
275 | }
276 |
277 | this.write = function (text, offsetX, offsetY, limit) {
278 | let x = 0
279 | while (x < text.length && x < limit - 1) {
280 | const c = text.substr(x, 1)
281 | this.drawSprite(offsetX + x, this.orca.h + offsetY, c, { f: 'f_high', b: 'background' })
282 | x += 1
283 | }
284 | }
285 |
286 | this.align = function () {
287 | this.el.style.marginTop = (((window.innerHeight - (terminal.size.height * terminal.size.ratio)) / 2) - 20) + 'px'
288 | }
289 |
290 | this.resize = function (resizeWindow = true) {
291 | this.size.width = tile.w * this.orca.w
292 | this.size.height = tile.h * this.orca.h + (tile.h * 3)
293 | this.el.width = this.size.width
294 | this.el.height = this.size.height + tile.h
295 | this.el.style.width = (this.size.width * this.size.ratio) + 'px'
296 | this.el.style.height = (this.size.height * this.size.ratio) + 'px'
297 |
298 | this.align()
299 |
300 | if (resizeWindow === true) {
301 | const { remote } = require('electron')
302 | const win = remote.getCurrentWindow()
303 | const width = parseInt((this.size.width * this.size.ratio) + 60)
304 | const height = parseInt((this.size.height * this.size.ratio) + 30)
305 | const size = win.getSize()
306 | if (width > size[0]) {
307 | win.setSize(width, height, true)
308 | }
309 | }
310 | }
311 |
312 | function clamp (v, min, max) { return v < min ? min : v > max ? max : v }
313 | }
314 |
315 | module.exports = Terminal
316 |
--------------------------------------------------------------------------------
/docs.js:
--------------------------------------------------------------------------------
1 | const lib = require('./desktop/core/library')
2 |
3 | console.log("## Operators\n")
4 |
5 | for(const id in lib){
6 | const operator = new lib[id]()
7 | if(operator.glyph === '.'){ continue; }
8 | console.log(`- ${operator.docs()}`)
9 | }
10 |
11 | console.log("\n")
--------------------------------------------------------------------------------
/examples/_midi.orca:
--------------------------------------------------------------------------------
1 | .........................................
2 | .#.MIDI.#................................
3 | .........................................
4 | .........................................
5 | .........................................
6 | .............################............
7 | .............#..............#............
8 | ..4C4........#..Channel..1..#............
9 | .D414TCDFE...#..Octave...5..#............
10 | ..:05D.......#..Notes.CDFE..#............
11 | .............#..............#............
12 | .............################............
13 | .........................................
14 | .........................................
15 | .........................................
16 | .........................................
17 | .........................................
--------------------------------------------------------------------------------
/examples/_osc.orca:
--------------------------------------------------------------------------------
1 | .........................................
2 | .#.OSC.#.................................
3 | .........................................
4 | .#.VALUES.#..............................
5 | .........................................
6 | .D8......................................
7 | .*=a123..................................
8 | .........................................
9 | .#.EMPTY.#...............................
10 | .........................................
11 | .D8......................................
12 | .*=b.....................................
13 | .........................................
14 | .........................................
15 | .........................................
16 | .........................................
17 | .........................................
--------------------------------------------------------------------------------
/examples/_udp.orca:
--------------------------------------------------------------------------------
1 | .........................................
2 | .#.UDP.#.................................
3 | .........................................
4 | .........................................
5 | ....Cf......Cf...........................
6 | ...F10.....F12...........................
7 | ..B.H.....B.H............................
8 | ...xS......xS............................
9 | .........................................
10 | ...S.....................................
11 | ..5;HELLO.4;ORCA.........................
12 | .........................................
13 | .........................................
14 | .........................................
15 | .........................................
16 | .........................................
17 | .........................................
--------------------------------------------------------------------------------
/examples/bang.orca:
--------------------------------------------------------------------------------
1 | .........................................
2 | .#.BANG.#................................
3 | .........................................
4 | .........................................
5 | .........................................
6 | .........................................
7 | .........................................
8 | ..............2D.H.......................
9 | ................xE.......................
10 | ........................#.BANG.#.........
11 | .........................................
12 | .........................................
13 | .........................................
14 | .........................................
15 | .........................................
16 | .........................................
17 | .........................................
--------------------------------------------------------------------------------
/examples/benchmark.orca:
--------------------------------------------------------------------------------
1 | .........................................
2 | .#.BENCHMARK.#...........................
3 | .........................................
4 | .4C4......C4......3Ka.b.3Ka.b............
5 | ..24T02S..24T02S....SC0...SD0............
6 | ..aVS.....bV2......cV0...................
7 | .........................................
8 | .2Kab..2Kab..2Kab..2Kab..2Kab............
9 | ..AS0...FS0...IS0...MS0...RS0............
10 | ..s...........r.....0.....h..............
11 | .........................................
12 | .........................................
13 | .........................................
14 | .........................................
15 | .........................................
16 | .........................................
17 | .........................................
--------------------------------------------------------------------------------
/examples/boolean.orca:
--------------------------------------------------------------------------------
1 | .........................................
2 | ..#.BOOLEAN.#............................
3 | .........................................
4 | ..#.OR.#..#.NOR.#..#AND.#..#.XOR.#.......
5 | .........................................
6 | ....R01......R01....6C2.......R01........
7 | ..A11......A01.....1X1......1X0..........
8 | ..23T011...13T100...4C2......4C2.........
9 | ....1........0.....A10......A00..........
10 | ...................13T001...03T010.......
11 | .....................0......F10..........
12 | ..#.NOT.#................................
13 | .........................................
14 | ..4C2....................................
15 | ...02T10.................................
16 | .....1...................................
17 | .........................................
--------------------------------------------------------------------------------
/examples/cycle.orca:
--------------------------------------------------------------------------------
1 | .........................................
2 | .#.CYCLE.#...............................
3 | .........................................
4 | .........................................
5 | .........................................
6 | ......................U..................
7 | ...............U.........................
8 | ................N........................
9 | .........................................
10 | .........................................
11 | .......................U.................
12 | ................U........................
13 | .........................................
14 | .........................................
15 | .........................................
16 | .........................................
17 | .........................................
--------------------------------------------------------------------------------
/examples/delay.orca:
--------------------------------------------------------------------------------
1 | .........................................
2 | .#.DELAY.#...............................
3 | .........................................
4 | .........................................
5 | .........................................
6 | .........................................
7 | ........C4.....4C4.....4C4.....4C8.......
8 | ........1.......1.......1.......5........
9 | .........................................
10 | .........................................
11 | ........D2......D4.....4D4.....4D8.......
12 | .........................................
13 | .........................................
14 | .........................................
15 | .........................................
16 | .........................................
17 | .........................................
--------------------------------------------------------------------------------
/examples/if+else.orca:
--------------------------------------------------------------------------------
1 | .........................................
2 | .#.IF.ELSE.#.............................
3 | .........................................
4 | ..4C8..2C4...............................
5 | .aV2..bV0...#.ASSIGN.#...................
6 | .........................................
7 | ..2Kab...V1..............................
8 | ...F13......#.IF.#.......................
9 | .1V.Y....................................
10 | .....J...V0..............................
11 | ....F....*..#.ELSE.#.....................
12 | ..0V*....................................
13 | .........................................
14 | .........................................
15 | .........................................
16 | .........................................
17 | .........................................
--------------------------------------------------------------------------------
/examples/increment.orca:
--------------------------------------------------------------------------------
1 | .........................................
2 | .#.INCREMENT.#...........................
3 | .........................................
4 | ..03O....................................
5 | .30Xc....................................
6 | .....Ac2...Va............................
7 | ...aV0...8Ly02468ac......................
8 | .........................................
9 | ..03O....................................
10 | .30Xi....................................
11 | .....Ai3...Vb............................
12 | ...bV0...8Lx0369cfi......................
13 | .........................................
14 | .........................................
15 | .........................................
16 | .........................................
17 | .........................................
--------------------------------------------------------------------------------
/examples/kombine.orca:
--------------------------------------------------------------------------------
1 | .........................................
2 | .#.KOMBINE.#.............................
3 | .........................................
4 | .4C4.....................................
5 | ..04T3454................................
6 | ..oV3.#.OCTAVE.#.........................
7 | .........................................
8 | .2C4.....................................
9 | ..04TCDEF...............3Konv............
10 | ..nVC.#.NOTE.#............4F3............
11 | .........................................
12 | .1C4.....................................
13 | ..14T0123................................
14 | ..vV0.#.VELOCITY.#.......................
15 | .........................................
16 | .........................................
17 | .........................................
--------------------------------------------------------------------------------
/examples/octave.orca:
--------------------------------------------------------------------------------
1 | .........................................
2 | .#.OCTAVE.#..............................
3 | .........................................
4 | .........................................
5 | .........................................
6 | .........................................
7 | .............4Cc.........................
8 | .............34cTCcDdEFfGgAaB............
9 | ..............aVE........................
10 | .........................................
11 | ..............D4..Va.....................
12 | ...............:03E......................
13 | .........................................
14 | .........................................
15 | .........................................
16 | .........................................
17 | .........................................
--------------------------------------------------------------------------------
/examples/pendulum.orca:
--------------------------------------------------------------------------------
1 | .........................................
2 | .#.PENDULUM.#............................
3 | .........................................
4 | .........................................
5 | .........................................
6 | ............U........W.....U.............
7 | ....................J....................
8 | ...................B.H...................
9 | ....................xS...................
10 | .........................................
11 | .........................................
12 | .........................................
13 | .........................................
14 | .........................................
15 | .........................................
16 | .........................................
17 | .........................................
--------------------------------------------------------------------------------
/examples/popcorn.orca:
--------------------------------------------------------------------------------
1 | .........................................
2 | .#.POPCORN.#.............................
3 | .........................................
4 | ...C8.........8C4........................
5 | .2H18T13579bdf.16T2345...................
6 | ...xV1.........yV3.......................
7 | .........................................
8 | ..Vx.Vy..................................
9 | ..fYf2...................................
10 | ....JJ...................................
11 | ...Hf22Q.................................
12 | ...*:04C.................................
13 | ........#5C4a5C4G4d4G4C..#...............
14 | ........#5C4a5C4G4d4G4C..#...............
15 | ........#5C5D5d5D5d5C5D5C#...............
16 | ........#5D4a5C4a5C4g5C..#...............
17 | .........................................
--------------------------------------------------------------------------------
/examples/projects/dotgrid.orca:
--------------------------------------------------------------------------------
1 | .........................................
2 | .#.DOTGRID.#.............................
3 | .........................................
4 | .#.CLEAR.#...#.LINE.#..#.DRAW.#..........
5 | .........................................
6 | ..D2........D4...........................
7 | ..*.........*Y*..........................
8 | ..;1........J6;1ca4ga....................
9 | ............*Y*..........................
10 | ............J6;1cgaag....................
11 | ............*Y*..........................
12 | ............J6;1cag4a....................
13 | ............*Y*..........D2..............
14 | .............6;1c4aa4..6;*...............
15 | .........................................
16 | .........................................
17 | .........................................
--------------------------------------------------------------------------------
/examples/projects/midi-step-sequencer.orca:
--------------------------------------------------------------------------------
1 | .........................................
2 | .#.note.sequencer.#......................
3 | .........................................
4 | .........................................
5 | ..U......................................
6 | .....W.U.................................
7 | .........................................
8 | ..S......................................
9 | .........................................
10 | .........................................
11 | ..S...NYNYNYN11G0........................
12 | .......Y.Y.Y.01G1....................V1..
13 | ..........J....0....................A21..
14 | .......15X.........................M34...
15 | .................................1V3.....
16 | ...........V1.#.notes.#..................
17 | .U.........24TABCE.......................
18 | ......U...:03CCF.........................
19 | ..........N..............................
20 | .........................................
21 | .........................................
22 | .........................................
23 | .........................................
24 | .........................................
25 | .........................................
--------------------------------------------------------------------------------
/examples/projects/sonicpi.orca:
--------------------------------------------------------------------------------
1 | .........................................
2 | .#.SONICPI.#.............................
3 | .........................................
4 | .........................................
5 | ..C8.....................................
6 | ..28T*...................................
7 | .........................................
8 | ....=a...................................
9 | .........................................
10 | .........................................
11 | .4C8.....................................
12 | ..68T..*...*.............................
13 | ....*....................................
14 | ....=b...................................
15 | .........................................
16 | .........................................
17 | .........................................
--------------------------------------------------------------------------------
/examples/read+write.orca:
--------------------------------------------------------------------------------
1 | .........................................
2 | .#.READ.WRITE.#..........................
3 | .........................................
4 | .........................................
5 | .........................................
6 | ......C4.........C2..........C4..........
7 | ......10O1230...014Q1234.....14T1230.....
8 | ........1.......12345678.......1.........
9 | .........................................
10 | .........................................
11 | ......C4.C4......C2..........C4.C4.......
12 | ......10X1......014G1234.....14P1........
13 | ........1230.......1234........1230......
14 | ...................1234..................
15 | .........................................
16 | .........................................
17 | .........................................
--------------------------------------------------------------------------------
/examples/subtraction.orca:
--------------------------------------------------------------------------------
1 | .........................................
2 | .#.SUBTRACTION.#.........................
3 | .........................................
4 | .13X9.#.A.#..............................
5 | .01X4.#.B.#..............................
6 | .........................................
7 | ...4zT0zyxwvutsrqponmlkjihgfedcba98765432
8 | ...A9w...................................
9 | .rV5.....................................
10 | ............Vr...........................
11 | .#.RESULT.#.5............................
12 | .........................................
13 | .........................................
14 | .........................................
15 | .........................................
16 | .........................................
--------------------------------------------------------------------------------
/examples/timing.orca:
--------------------------------------------------------------------------------
1 | .........................................
2 | .#.TIMING.#..............................
3 | .........................................
4 | ..C8.C2........C8.D2.....................
5 | ..5.X1.........5.X.......................
6 | ...#10101010#...#.*.*.*.*#...............
7 | ..C8.C3........C8.D3.....................
8 | ..5.X1.........5.X.......................
9 | ...#01201012#...#*..*.*..#...............
10 | ..C8.C3........C8.D4.....................
11 | ..5.X1.........5.X.......................
12 | ...#01201012#...#...*...*#...............
13 | ..C8.C4........C8.D5.....................
14 | ..5.X1.........5.X.......................
15 | ...#12301230#...#..*..*..#...............
16 | .........................................
17 | .........................................
--------------------------------------------------------------------------------
/examples/triage.orca:
--------------------------------------------------------------------------------
1 | .........................................
2 | ..#.TRIAGE.#.............................
3 | .........................................
4 | ..D2....D6......D6......D6...............
5 | ...H.....................................
6 | ..xE....u.......u.......u................
7 | ...E.E.E.E.E...E.E.....E.................
8 | ............................U............
9 | .......U...E.....E.....E.................
10 | ............................S.U..........
11 | ...............U.E.....E.....E...........
12 | ........................S.......U........
13 | .......................U.....E...........
14 | .........................................
15 | ............................*.*.*........
16 | ............................0.0.0........
17 | .........................................
--------------------------------------------------------------------------------
/examples/variable.orca:
--------------------------------------------------------------------------------
1 | .........................................
2 | .#.VARIABLES.#...........................
3 | .........................................
4 | .#.WRITE.#...............................
5 | .........................................
6 | .aV1.bV2.cV3.............................
7 | .........................................
8 | .#.READ.#................................
9 | .........................................
10 | ..Va..Vb..Vc.............................
11 | ..1...2...3..............................
12 | .........................................
13 | .........................................
14 | .........................................
15 | .........................................
16 | .........................................
17 | .........................................
--------------------------------------------------------------------------------
/examples/wave.orca:
--------------------------------------------------------------------------------
1 | .........................................
2 | .#.WAVE.#......Va........................
3 | ...............6XE.......................
4 | .........................................
5 | .8C8............................:04F.....
6 | ..2..C6.........................:04E.....
7 | ..J..56T123432..................:04D.....
8 | ..2Y2Y23........................:04C.....
9 | ......JJ........................:03B.....
10 | .....A23........................:03A.....
11 | ...aV5..........................:03G.....
12 | ................................:03F.....
13 | ................................:03E.....
14 | ................................:03D.....
15 | ................................:03C.....
16 | .........................................
17 | .........................................
--------------------------------------------------------------------------------
/listener.js:
--------------------------------------------------------------------------------
1 | const UDP_PORT = 49160
2 | const OSC_PORT = 49162
3 |
4 | const dgram = require('dgram');
5 | const udpserver = dgram.createSocket('udp4');
6 |
7 | const osc = require('./desktop/node_modules/node-osc')
8 | const oscserver = new osc.Server(OSC_PORT, '127.0.0.1')
9 |
10 | console.log(`Started Listener\n\nUDP:${UDP_PORT}\nOSC:${OSC_PORT}\n`)
11 |
12 | // Error
13 |
14 | udpserver.on('error', (err) => {
15 | console.log(`UDP server:\n${err.stack}`);
16 | udpserver.close();
17 | })
18 |
19 | oscserver.on('error', (err) => {
20 | console.log(`OSC server:\n${err.stack}`);
21 | oscserver.close();
22 | })
23 |
24 | // Message
25 |
26 | udpserver.on('message', (msg, rinfo) => {
27 | console.log(`UDP server: ${msg} from ${rinfo.address}:${rinfo.port}`);
28 | })
29 |
30 | oscserver.on('message', (msg, rinfo) => {
31 | console.log(`OSC server: ${msg} from ${rinfo.address}:${rinfo.port} at /${msg[0]}`)
32 | })
33 |
34 | udpserver.bind(UDP_PORT)
--------------------------------------------------------------------------------
/resources/glyph.grid:
--------------------------------------------------------------------------------
1 | {
2 | "settings": {
3 | "size": {
4 | "width": 870,
5 | "height": 300
6 | }
7 | },
8 | "layers": [
9 | [],
10 | [
11 | {
12 | "type": "arc_c",
13 | "vertices": [
14 | {
15 | "x": 165,
16 | "y": 90
17 | },
18 | {
19 | "x": 240,
20 | "y": 165
21 | },
22 | {
23 | "x": 165,
24 | "y": 240
25 | },
26 | {
27 | "x": 90,
28 | "y": 165
29 | },
30 | {
31 | "x": 165,
32 | "y": 90
33 | }
34 | ]
35 | },
36 | {
37 | "type": "close",
38 | "vertices": []
39 | },
40 | {
41 | "type": "arc_c_full",
42 | "vertices": [
43 | {
44 | "x": 600,
45 | "y": 165
46 | },
47 | {
48 | "x": 525,
49 | "y": 90
50 | }
51 | ]
52 | },
53 | {
54 | "type": "arc_c_full",
55 | "vertices": [
56 | {
57 | "x": 630,
58 | "y": 165
59 | },
60 | {
61 | "x": 705,
62 | "y": 240
63 | }
64 | ]
65 | },
66 | {
67 | "type": "arc_c_full",
68 | "vertices": [
69 | {
70 | "x": 345,
71 | "y": 240
72 | },
73 | {
74 | "x": 420,
75 | "y": 165
76 | }
77 | ]
78 | }
79 | ],
80 | [
81 | {
82 | "type": "line",
83 | "vertices": [
84 | {
85 | "x": 255,
86 | "y": 75
87 | },
88 | {
89 | "x": 255,
90 | "y": 255
91 | }
92 | ]
93 | },
94 | {
95 | "type": "line",
96 | "vertices": [
97 | {
98 | "x": 435,
99 | "y": 75
100 | },
101 | {
102 | "x": 435,
103 | "y": 255
104 | }
105 | ]
106 | },
107 | {
108 | "type": "line",
109 | "vertices": [
110 | {
111 | "x": 615,
112 | "y": 75
113 | },
114 | {
115 | "x": 615,
116 | "y": 255
117 | }
118 | ]
119 | },
120 | {
121 | "type": "line",
122 | "vertices": [
123 | {
124 | "x": 795,
125 | "y": 75
126 | },
127 | {
128 | "x": 795,
129 | "y": 255
130 | }
131 | ]
132 | },
133 | {
134 | "type": "line",
135 | "vertices": [
136 | {
137 | "x": 75,
138 | "y": 75
139 | },
140 | {
141 | "x": 75,
142 | "y": 255
143 | }
144 | ]
145 | }
146 | ]
147 | ],
148 | "styles": [
149 | {
150 | "thickness": 31,
151 | "strokeLinecap": "round",
152 | "strokeLinejoin": "round",
153 | "color": "#000",
154 | "fill": "none",
155 | "mirror_style": 0
156 | },
157 | {
158 | "thickness": 30,
159 | "strokeLinecap": "butt",
160 | "strokeLinejoin": "bevel",
161 | "color": "#000",
162 | "fill": "none",
163 | "mirror_style": 0
164 | },
165 | {
166 | "thickness": 1,
167 | "strokeLinecap": "round",
168 | "strokeLinejoin": "round",
169 | "color": "#ddd",
170 | "fill": "none",
171 | "mirror_style": 0
172 | }
173 | ]
174 | }
--------------------------------------------------------------------------------
/resources/glyph.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hamstah/Orca/cd4f96db307dbdcc1d4f687f7f70ed47dfd0bbe7/resources/glyph.png
--------------------------------------------------------------------------------
/resources/glyph.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resources/logo.grid:
--------------------------------------------------------------------------------
1 | {
2 | "settings": {
3 | "size": {
4 | "width": 855,
5 | "height": 300
6 | }
7 | },
8 | "layers": [
9 | [
10 | {
11 | "type": "arc_r",
12 | "vertices": [
13 | {
14 | "x": 585,
15 | "y": 120
16 | },
17 | {
18 | "x": 570,
19 | "y": 105
20 | },
21 | {
22 | "x": 480,
23 | "y": 105
24 | },
25 | {
26 | "x": 465,
27 | "y": 120
28 | },
29 | {
30 | "x": 465,
31 | "y": 180
32 | },
33 | {
34 | "x": 480,
35 | "y": 195
36 | },
37 | {
38 | "x": 570,
39 | "y": 195
40 | },
41 | {
42 | "x": 585,
43 | "y": 180
44 | }
45 | ]
46 | },
47 | {
48 | "type": "arc_c",
49 | "vertices": [
50 | {
51 | "x": 285,
52 | "y": 105
53 | },
54 | {
55 | "x": 390,
56 | "y": 105
57 | },
58 | {
59 | "x": 405,
60 | "y": 120
61 | },
62 | {
63 | "x": 405,
64 | "y": 135
65 | },
66 | {
67 | "x": 390,
68 | "y": 150
69 | },
70 | {
71 | "x": 285,
72 | "y": 150
73 | }
74 | ]
75 | },
76 | {
77 | "type": "arc_c",
78 | "vertices": [
79 | {
80 | "x": 390,
81 | "y": 150
82 | },
83 | {
84 | "x": 405,
85 | "y": 165
86 | },
87 | {
88 | "x": 405,
89 | "y": 195
90 | }
91 | ]
92 | },
93 | {
94 | "type": "arc_c",
95 | "vertices": [
96 | {
97 | "x": 645,
98 | "y": 105
99 | },
100 | {
101 | "x": 750,
102 | "y": 105
103 | },
104 | {
105 | "x": 765,
106 | "y": 120
107 | },
108 | {
109 | "x": 765,
110 | "y": 195
111 | }
112 | ]
113 | },
114 | {
115 | "type": "arc_c",
116 | "vertices": [
117 | {
118 | "x": 765,
119 | "y": 135
120 | },
121 | {
122 | "x": 750,
123 | "y": 150
124 | }
125 | ]
126 | },
127 | {
128 | "type": "arc_r",
129 | "vertices": [
130 | {
131 | "x": 750,
132 | "y": 150
133 | },
134 | {
135 | "x": 660,
136 | "y": 150
137 | },
138 | {
139 | "x": 645,
140 | "y": 165
141 | },
142 | {
143 | "x": 645,
144 | "y": 165
145 | },
146 | {
147 | "x": 645,
148 | "y": 180
149 | },
150 | {
151 | "x": 660,
152 | "y": 195
153 | },
154 | {
155 | "x": 750,
156 | "y": 195
157 | },
158 | {
159 | "x": 765,
160 | "y": 180
161 | }
162 | ]
163 | },
164 | {
165 | "type": "line",
166 | "vertices": [
167 | {
168 | "x": 285,
169 | "y": 105
170 | },
171 | {
172 | "x": 285,
173 | "y": 195
174 | }
175 | ]
176 | },
177 | {
178 | "type": "arc_c",
179 | "vertices": [
180 | {
181 | "x": 225,
182 | "y": 180
183 | },
184 | {
185 | "x": 210,
186 | "y": 195
187 | },
188 | {
189 | "x": 120,
190 | "y": 195
191 | },
192 | {
193 | "x": 105,
194 | "y": 180
195 | },
196 | {
197 | "x": 105,
198 | "y": 120
199 | },
200 | {
201 | "x": 120,
202 | "y": 105
203 | },
204 | {
205 | "x": 210,
206 | "y": 105
207 | },
208 | {
209 | "x": 225,
210 | "y": 120
211 | }
212 | ]
213 | },
214 | {
215 | "type": "close",
216 | "vertices": []
217 | }
218 | ],
219 | [],
220 | [
221 | {
222 | "type": "line",
223 | "vertices": [
224 | {
225 | "x": 255,
226 | "y": 75
227 | },
228 | {
229 | "x": 255,
230 | "y": 225
231 | }
232 | ]
233 | },
234 | {
235 | "type": "line",
236 | "vertices": [
237 | {
238 | "x": 435,
239 | "y": 75
240 | },
241 | {
242 | "x": 435,
243 | "y": 225
244 | }
245 | ]
246 | },
247 | {
248 | "type": "line",
249 | "vertices": [
250 | {
251 | "x": 615,
252 | "y": 75
253 | },
254 | {
255 | "x": 615,
256 | "y": 225
257 | }
258 | ]
259 | }
260 | ]
261 | ],
262 | "styles": [
263 | {
264 | "thickness": 12,
265 | "strokeLinecap": "square",
266 | "strokeLinejoin": "round",
267 | "color": "#000",
268 | "fill": "none",
269 | "mirror_style": 0
270 | },
271 | {
272 | "thickness": 5,
273 | "strokeLinecap": "round",
274 | "strokeLinejoin": "round",
275 | "color": "#f00",
276 | "fill": "none",
277 | "mirror_style": 0
278 | },
279 | {
280 | "thickness": 2,
281 | "strokeLinecap": "round",
282 | "strokeLinejoin": "round",
283 | "color": "#ddd",
284 | "fill": "none",
285 | "mirror_style": 0
286 | }
287 | ]
288 | }
--------------------------------------------------------------------------------
/resources/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hamstah/Orca/cd4f96db307dbdcc1d4f687f7f70ed47dfd0bbe7/resources/logo.png
--------------------------------------------------------------------------------
/resources/logo.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resources/preview.hardware.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hamstah/Orca/cd4f96db307dbdcc1d4f687f7f70ed47dfd0bbe7/resources/preview.hardware.jpg
--------------------------------------------------------------------------------
/resources/preview.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hamstah/Orca/cd4f96db307dbdcc1d4f687f7f70ed47dfd0bbe7/resources/preview.jpg
--------------------------------------------------------------------------------