aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--browser/mock/buffer.js3
-rw-r--r--browser/mock/dgram.js10
-rw-r--r--browser/mock/electron.js5
-rw-r--r--browser/mock/fs.js0
-rw-r--r--browser/mock/osc.js3
-rw-r--r--browser/mock/path.js0
-rw-r--r--browser/mock/require.js19
-rw-r--r--desktop/core/io/udp.js72
-rw-r--r--desktop/core/library.js86
-rw-r--r--desktop/core/library/_bang.js16
-rw-r--r--desktop/core/library/_cc.js32
-rw-r--r--desktop/core/library/_comment.js19
-rw-r--r--desktop/core/library/_midi.js37
-rw-r--r--desktop/core/library/_mono.js37
-rw-r--r--desktop/core/library/_null.js16
-rw-r--r--desktop/core/library/_osc.js36
-rw-r--r--desktop/core/library/_pb.js33
-rw-r--r--desktop/core/library/_self.js26
-rw-r--r--desktop/core/library/_udp.js30
-rw-r--r--desktop/core/library/a.js20
-rw-r--r--desktop/core/library/b.js21
-rw-r--r--desktop/core/library/c.js21
-rw-r--r--desktop/core/library/d.js21
-rw-r--r--desktop/core/library/e.js16
-rw-r--r--desktop/core/library/f.js20
-rw-r--r--desktop/core/library/g.js28
-rw-r--r--desktop/core/library/h.js17
-rw-r--r--desktop/core/library/i.js21
-rw-r--r--desktop/core/library/j.js18
-rw-r--r--desktop/core/library/k.js27
-rw-r--r--desktop/core/library/l.js30
-rw-r--r--desktop/core/library/m.js20
-rw-r--r--desktop/core/library/n.js16
-rw-r--r--desktop/core/library/o.js21
-rw-r--r--desktop/core/library/p.js24
-rw-r--r--desktop/core/library/q.js28
-rw-r--r--desktop/core/library/r.js21
-rw-r--r--desktop/core/library/s.js16
-rw-r--r--desktop/core/library/t.js24
-rw-r--r--desktop/core/library/u.js21
-rw-r--r--desktop/core/library/v.js26
-rw-r--r--desktop/core/library/w.js16
-rw-r--r--desktop/core/library/x.js21
-rw-r--r--desktop/core/library/y.js18
-rw-r--r--desktop/core/library/z.js22
-rw-r--r--desktop/main.js45
-rw-r--r--desktop/sources/index.html32
-rw-r--r--desktop/sources/scripts/clock.js15
-rw-r--r--desktop/sources/scripts/commander.js134
-rw-r--r--desktop/sources/scripts/core/io.js (renamed from desktop/core/io.js)8
-rw-r--r--desktop/sources/scripts/core/io/cc.js (renamed from desktop/core/io/cc.js)2
-rw-r--r--desktop/sources/scripts/core/io/midi.js (renamed from desktop/core/io/midi.js)67
-rw-r--r--desktop/sources/scripts/core/io/mono.js (renamed from desktop/core/io/mono.js)2
-rw-r--r--desktop/sources/scripts/core/io/osc.js (renamed from desktop/core/io/osc.js)13
-rw-r--r--desktop/sources/scripts/core/io/udp.js61
-rw-r--r--desktop/sources/scripts/core/library.js740
-rw-r--r--desktop/sources/scripts/core/operator.js (renamed from desktop/core/operator.js)2
-rw-r--r--desktop/sources/scripts/core/orca.js (renamed from desktop/core/orca.js)4
-rw-r--r--desktop/sources/scripts/core/transpose.js (renamed from desktop/core/transpose.js)2
-rw-r--r--desktop/sources/scripts/cursor.js84
-rw-r--r--desktop/sources/scripts/lib/acels.js123
-rw-r--r--desktop/sources/scripts/lib/controller.js81
-rw-r--r--desktop/sources/scripts/lib/history.js (renamed from desktop/sources/scripts/history.js)2
-rw-r--r--desktop/sources/scripts/lib/theme.js58
-rw-r--r--desktop/sources/scripts/source.js31
-rw-r--r--desktop/sources/scripts/terminal.js214
-rw-r--r--desktop/sources/scripts/timer.js6
-rw-r--r--index.html67
68 files changed, 1298 insertions, 1529 deletions
diff --git a/browser/mock/buffer.js b/browser/mock/buffer.js
deleted file mode 100644
index 5aa0b69..0000000
--- a/browser/mock/buffer.js
+++ /dev/null
@@ -1,3 +0,0 @@
-export default class Buffer {
- static from (str) { return str }
-}
diff --git a/browser/mock/dgram.js b/browser/mock/dgram.js
deleted file mode 100644
index 18ffeb8..0000000
--- a/browser/mock/dgram.js
+++ /dev/null
@@ -1,10 +0,0 @@
-class Socket {
- on () {}
- bind () {}
- close () {}
- send () {}
-}
-
-export function createSocket () {
- return new Socket()
-}
diff --git a/browser/mock/electron.js b/browser/mock/electron.js
deleted file mode 100644
index 4b2e8e6..0000000
--- a/browser/mock/electron.js
+++ /dev/null
@@ -1,5 +0,0 @@
-export let remote = {
- app: {
- injectMenu () {}
- }
-}
diff --git a/browser/mock/fs.js b/browser/mock/fs.js
deleted file mode 100644
index e69de29..0000000
--- a/browser/mock/fs.js
+++ /dev/null
diff --git a/browser/mock/osc.js b/browser/mock/osc.js
deleted file mode 100644
index 7a2906f..0000000
--- a/browser/mock/osc.js
+++ /dev/null
@@ -1,3 +0,0 @@
-export class Client {
- close () {}
-}
diff --git a/browser/mock/path.js b/browser/mock/path.js
deleted file mode 100644
index e69de29..0000000
--- a/browser/mock/path.js
+++ /dev/null
diff --git a/browser/mock/require.js b/browser/mock/require.js
deleted file mode 100644
index 7fcc38b..0000000
--- a/browser/mock/require.js
+++ /dev/null
@@ -1,19 +0,0 @@
-import * as fs from './fs.js'
-import * as path from './path.js'
-import * as osc from './osc.js'
-import * as electron from './electron.js'
-import * as dgram from './dgram.js'
-
-import Buffer from './buffer.js'
-window.Buffer = Buffer
-
-window.require = function (what) {
- switch (what) {
- case 'dgram': return dgram; break
- case 'fs': return fs; break
- case 'path': return path; break
- case 'node-osc': return osc; break
- case 'electron': return electron; break
- default: console.log(what); break
- }
-}
diff --git a/desktop/core/io/udp.js b/desktop/core/io/udp.js
deleted file mode 100644
index f438ac5..0000000
--- a/desktop/core/io/udp.js
+++ /dev/null
@@ -1,72 +0,0 @@
-'use strict'
-
-const dgram = require('dgram')
-
-export default function Udp (terminal) {
- this.stack = []
- this.port = null
- this.options = { default: 49161, orca: 49160 }
-
- this.start = function () {
- console.info('UDP', 'Starting..')
- this.select()
- }
-
- this.clear = function () {
- this.stack = []
- }
-
- this.run = function () {
- for (const id in this.stack) {
- this.play(this.stack[id])
- }
- }
-
- this.push = function (msg) {
- this.stack.push(msg)
- }
-
- this.play = function (data) {
- this.client.send(Buffer.from(`${data}`), this.port, terminal.io.ip, (err) => {
- if (err) { console.warn(err) }
- })
- }
-
- this.select = function (port = this.options.default) {
- if (parseInt(port) === this.port) { console.warn('UDP', 'Already selected'); return }
- if (isNaN(port) || port < 1000) { console.warn('UDP', 'Unavailable port'); return }
- console.info('UDP', `Selected port: ${port}`)
- this.port = parseInt(port)
- this.update()
- }
-
- this.update = function () {
- terminal.controller.clearCat('default', 'UDP')
- for (const id in this.options) {
- terminal.controller.add('default', 'UDP', `${id.charAt(0).toUpperCase() + id.substr(1)}(${this.options[id]}) ${this.port === this.options[id] ? ' — Active' : ''}`, () => { terminal.io.udp.select(this.options[id]) }, '')
- }
- terminal.controller.add('default', 'UDP', 'Choose Custom Port', () => { terminal.commander.start('udp:') }, '')
- terminal.controller.commit()
- }
-
- this.client = dgram.createSocket('udp4')
- this.listener = dgram.createSocket('udp4')
-
- // Input
-
- this.listener.on('message', (msg, rinfo) => {
- terminal.commander.trigger(`${msg}`, false)
- })
-
- this.listener.on('listening', () => {
- const address = this.listener.address()
- console.info('UDP', `Started client at ${address.address}:${address.port}`)
- })
-
- this.listener.on('error', (err) => {
- console.warn('UDP', `Server error:\n ${err.stack}`)
- this.listener.close()
- })
-
- this.listener.bind(49160)
-}
diff --git a/desktop/core/library.js b/desktop/core/library.js
deleted file mode 100644
index 4eb92e0..0000000
--- a/desktop/core/library.js
+++ /dev/null
@@ -1,86 +0,0 @@
-'use strict'
-
-import _null from './library/_null.js'
-import a from './library/a.js'
-import b from './library/b.js'
-import c from './library/c.js'
-import d from './library/d.js'
-import e from './library/e.js'
-import f from './library/f.js'
-import g from './library/g.js'
-import h from './library/h.js'
-import i from './library/i.js'
-import j from './library/j.js'
-import k from './library/k.js'
-import l from './library/l.js'
-import m from './library/m.js'
-import n from './library/n.js'
-import o from './library/o.js'
-import p from './library/p.js'
-import q from './library/q.js'
-import r from './library/r.js'
-import s from './library/s.js'
-import t from './library/t.js'
-import u from './library/u.js'
-import v from './library/v.js'
-import w from './library/w.js'
-import x from './library/x.js'
-import y from './library/y.js'
-import z from './library/z.js'
-import _bang from './library/_bang.js'
-import _comment from './library/_comment.js'
-import _midi from './library/_midi.js'
-import _mono from './library/_mono.js'
-import _cc from './library/_cc.js'
-import _pb from './library/_pb.js'
-import _udp from './library/_udp.js'
-import _osc from './library/_osc.js'
-import _self from './library/_self.js'
-
-export default {
- 0: _null,
- 1: _null,
- 2: _null,
- 3: _null,
- 4: _null,
- 5: _null,
- 6: _null,
- 7: _null,
- 8: _null,
- 9: _null,
- a,
- b,
- c,
- d,
- e,
- f,
- g,
- h,
- i,
- j,
- k,
- l,
- m,
- n,
- o,
- p,
- q,
- r,
- s,
- t,
- u,
- v,
- w,
- x,
- y,
- z,
- '*': _bang,
- '#': _comment,
- ':': _midi,
- '%': _mono,
- '!': _cc,
- '?': _pb,
- ';': _udp,
- '=': _osc,
- $: _self
-}
diff --git a/desktop/core/library/_bang.js b/desktop/core/library/_bang.js
deleted file mode 100644
index 1599cca..0000000
--- a/desktop/core/library/_bang.js
+++ /dev/null
@@ -1,16 +0,0 @@
-'use strict'
-
-import Operator from '../operator.js'
-
-export default function OperatorBang (orca, x, y, passive) {
- Operator.call(this, orca, x, y, '*', true)
-
- this.name = 'bang'
- this.info = 'Bangs neighboring operands'
- this.draw = false
-
- this.run = function (force = false) {
- this.draw = false
- this.erase()
- }
-}
diff --git a/desktop/core/library/_cc.js b/desktop/core/library/_cc.js
deleted file mode 100644
index d70571e..0000000
--- a/desktop/core/library/_cc.js
+++ /dev/null
@@ -1,32 +0,0 @@
-'use strict'
-
-import Operator from '../operator.js'
-
-export default function OperatorCC (orca, x, y) {
- Operator.call(this, orca, x, y, '!', true)
-
- this.name = 'cc'
- this.info = 'Sends MIDI control change'
- this.ports.channel = { x: 1, y: 0, clamp: { min: 0, max: 15 } }
- this.ports.knob = { x: 2, y: 0, clamp: { min: 0 } }
- this.ports.value = { x: 3, y: 0, clamp: { min: 0 } }
-
- this.operation = function (force = false) {
- if (!this.hasNeighbor('*') && force === false) { return }
- if (this.listen(this.ports.channel) === '.') { return }
- if (this.listen(this.ports.knob) === '.') { return }
-
- const channel = this.listen(this.ports.channel, true)
- const knob = this.listen(this.ports.knob, true)
- const rawValue = this.listen(this.ports.value, true)
- const value = Math.ceil((127 * rawValue) / 35)
-
- terminal.io.cc.stack.push({ channel, knob, value, type: 'cc' })
-
- this.draw = false
-
- if (force === true) {
- terminal.io.cc.run()
- }
- }
-}
diff --git a/desktop/core/library/_comment.js b/desktop/core/library/_comment.js
deleted file mode 100644
index 8dcf0ae..0000000
--- a/desktop/core/library/_comment.js
+++ /dev/null
@@ -1,19 +0,0 @@
-'use strict'
-
-import Operator from '../operator.js'
-
-export default function OperatorComment (orca, x, y, passive) {
- Operator.call(this, orca, x, y, '#', true)
-
- this.name = 'comment'
- this.info = 'Halts line'
- this.draw = false
-
- this.operation = function () {
- for (let x = this.x + 1; x <= orca.w; x++) {
- orca.lock(x, this.y)
- if (orca.glyphAt(x, this.y) === this.glyph) { break }
- }
- orca.lock(this.x, this.y)
- }
-}
diff --git a/desktop/core/library/_midi.js b/desktop/core/library/_midi.js
deleted file mode 100644
index 9fc614a..0000000
--- a/desktop/core/library/_midi.js
+++ /dev/null
@@ -1,37 +0,0 @@
-'use strict'
-
-import Operator from '../operator.js'
-
-export default function OperatorMidi (orca, x, y, passive) {
- Operator.call(this, orca, x, y, ':', true)
-
- this.name = 'midi'
- this.info = 'Sends MIDI note'
- this.ports.channel = { x: 1, y: 0, clamp: { min: 0, max: 16 } }
- this.ports.octave = { x: 2, y: 0, clamp: { min: 0, max: 8 } }
- this.ports.note = { x: 3, y: 0 }
- this.ports.velocity = { x: 4, y: 0, default: 'f', clamp: { min: 0, max: 16 } }
- this.ports.length = { x: 5, y: 0, default: '1', clamp: { min: 0, max: 16 } }
-
- this.operation = function (force = false) {
- if (!this.hasNeighbor('*') && force === false) { return }
- if (this.listen(this.ports.channel) === '.') { return }
- if (this.listen(this.ports.octave) === '.') { return }
- if (this.listen(this.ports.note) === '.') { return }
- if (!isNaN(this.listen(this.ports.note))) { return }
-
- const channel = this.listen(this.ports.channel, true)
- const octave = this.listen(this.ports.octave, true)
- const note = this.listen(this.ports.note)
- const velocity = this.listen(this.ports.velocity, true)
- const length = this.listen(this.ports.length, true)
-
- terminal.io.midi.push(channel, octave, note, velocity, length)
-
- if (force === true) {
- terminal.io.midi.run()
- }
-
- this.draw = false
- }
-}
diff --git a/desktop/core/library/_mono.js b/desktop/core/library/_mono.js
deleted file mode 100644
index db9d1fc..0000000
--- a/desktop/core/library/_mono.js
+++ /dev/null
@@ -1,37 +0,0 @@
-'use strict'
-
-import Operator from '../operator.js'
-
-export default function OperatorMono (orca, x, y, passive) {
- Operator.call(this, orca, x, y, '%', true)
-
- this.name = 'mono'
- this.info = 'Sends MIDI monophonic note'
- this.ports.channel = { x: 1, y: 0, clamp: { min: 0, max: 16 } }
- this.ports.octave = { x: 2, y: 0, clamp: { min: 0, max: 8 } }
- this.ports.note = { x: 3, y: 0 }
- this.ports.velocity = { x: 4, y: 0, default: 'f', clamp: { min: 0, max: 16 } }
- this.ports.length = { x: 5, y: 0, default: '1', clamp: { min: 0, max: 16 } }
-
- this.operation = function (force = false) {
- if (!this.hasNeighbor('*') && force === false) { return }
- if (this.listen(this.ports.channel) === '.') { return }
- if (this.listen(this.ports.octave) === '.') { return }
- if (this.listen(this.ports.note) === '.') { return }
- if (!isNaN(this.listen(this.ports.note))) { return }
-
- const channel = this.listen(this.ports.channel, true)
- const octave = this.listen(this.ports.octave, true)
- const note = this.listen(this.ports.note)
- const velocity = this.listen(this.ports.velocity, true)
- const length = this.listen(this.ports.length, true)
-
- terminal.io.mono.push(channel, octave, note, velocity, length)
-
- if (force === true) {
- terminal.io.mono.run()
- }
-
- this.draw = false
- }
-}
diff --git a/desktop/core/library/_null.js b/desktop/core/library/_null.js
deleted file mode 100644
index 30dd5c3..0000000
--- a/desktop/core/library/_null.js
+++ /dev/null
@@ -1,16 +0,0 @@
-'use strict'
-
-import Operator from '../operator.js'
-
-export default function OperatorNull (orca, x, y, passive) {
- Operator.call(this, orca, x, y, '.', false)
-
- this.name = 'null'
- this.info = 'empty'
-
- // Overwrite run, to disable draw.
-
- this.run = function (force = false) {
-
- }
-}
diff --git a/desktop/core/library/_osc.js b/desktop/core/library/_osc.js
deleted file mode 100644
index 2b7af97..0000000
--- a/desktop/core/library/_osc.js
+++ /dev/null
@@ -1,36 +0,0 @@
-'use strict'
-
-import Operator from '../operator.js'
-
-export default function OperatorOsc (orca, x, y, passive) {
- Operator.call(this, orca, x, y, '=', true)
-
- this.name = 'osc'
- this.info = 'Sends OSC message'
-
- this.ports.path = { x: 1, y: 0 }
-
- this.operation = function (force = false) {
- let msg = ''
- for (let x = 2; x <= 36; x++) {
- const g = orca.glyphAt(this.x + x, this.y)
- orca.lock(this.x + x, this.y)
- if (g === '.') { break }
- msg += g
- }
-
- if (!this.hasNeighbor('*') && force === false) { return }
- if (msg === '') { return }
-
- const path = this.listen(this.ports.path)
-
- if (!path || path === '.') { return }
-
- this.draw = false
- terminal.io.osc.push('/' + path, msg)
-
- if (force === true) {
- terminal.io.osc.run()
- }
- }
-}
diff --git a/desktop/core/library/_pb.js b/desktop/core/library/_pb.js
deleted file mode 100644
index 6b6c96b..0000000
--- a/desktop/core/library/_pb.js
+++ /dev/null
@@ -1,33 +0,0 @@
-'use strict'
-
-import Operator from '../operator.js'
-
-export default function OperatorPB (orca, x, y) {
- Operator.call(this, orca, x, y, '?', true)
-
- this.name = 'cc'
- this.info = 'Sends MIDI pitch bend'
- this.ports.channel = { x: 1, y: 0, clamp: { min: 0, max: 15 } }
- this.ports.lsb = { x: 2, y: 0, clamp: { min: 0 } }
- this.ports.msb = { x: 3, y: 0, clamp: { min: 0 } }
-
- this.operation = function (force = false) {
- if (!this.hasNeighbor('*') && force === false) { return }
- if (this.listen(this.ports.channel) === '.') { return }
- if (this.listen(this.ports.lsb) === '.') { return }
-
- const channel = this.listen(this.ports.channel, true)
- const rawlsb = this.listen(this.ports.lsb, true)
- const lsb = Math.ceil((127 * rawlsb) / 35)
- const rawmsb = this.listen(this.ports.msb, true)
- const msb = Math.ceil((127 * rawmsb) / 35)
-
- terminal.io.cc.stack.push({ channel, lsb, msb, type: 'pb' })
-
- this.draw = false
-
- if (force === true) {
- terminal.io.cc.run()
- }
- }
-}
diff --git a/desktop/core/library/_self.js b/desktop/core/library/_self.js
deleted file mode 100644
index 67b144e..0000000
--- a/desktop/core/library/_self.js
+++ /dev/null
@@ -1,26 +0,0 @@
-'use strict'
-
-import Operator from '../operator.js'
-
-export default function OperatorSelf (orca, x, y, passive) {
- Operator.call(this, orca, x, y, '*', true)
-
- this.name = 'self'
- this.info = 'Send command to itself'
-
- this.run = function (force = false) {
- let msg = ''
- for (let x = 1; x <= 36; x++) {
- const g = orca.glyphAt(this.x + x, this.y)
- orca.lock(this.x + x, this.y)
- if (g === '.') { break }
- msg += g
- }
-
- if (!this.hasNeighbor('*') && force === false) { return }
- if (msg === '') { return }
-
- this.draw = false
- terminal.commander.trigger(`${msg}`)
- }
-}
diff --git a/desktop/core/library/_udp.js b/desktop/core/library/_udp.js
deleted file mode 100644
index fd04d24..0000000
--- a/desktop/core/library/_udp.js
+++ /dev/null
@@ -1,30 +0,0 @@
-'use strict'
-
-import Operator from '../operator.js'
-
-export default function OperatorUdp (orca, x, y, passive) {
- Operator.call(this, orca, x, y, ';', true)
-
- this.name = 'udp'
- this.info = 'Sends UDP message'
-
- this.operation = function (force = false) {
- let msg = ''
- for (let x = 1; x <= 36; x++) {
- const g = orca.glyphAt(this.x + x, this.y)
- orca.lock(this.x + x, this.y)
- if (g === '.') { break }
- msg += g
- }
-
- if (!this.hasNeighbor('*') && force === false) { return }
- if (msg === '') { return }
-
- this.draw = false
- terminal.io.udp.push(msg)
-
- if (force === true) {
- terminal.io.udp.run()
- }
- }
-}
diff --git a/desktop/core/library/a.js b/desktop/core/library/a.js
deleted file mode 100644
index c2c66e5..0000000
--- a/desktop/core/library/a.js
+++ /dev/null
@@ -1,20 +0,0 @@
-'use strict'
-
-import Operator from '../operator.js'
-
-export default function OperatorA (orca, x, y, passive) {
- Operator.call(this, orca, x, y, 'a', passive)
-
- this.name = 'add'
- this.info = 'Outputs sum of inputs'
-
- this.ports.a = { x: -1, y: 0 }
- this.ports.b = { x: 1, y: 0 }
- this.ports.output = { x: 0, y: 1, sensitive: true }
-
- this.operation = function (force = false) {
- const a = this.listen(this.ports.a, true)
- const b = this.listen(this.ports.b, true)
- return orca.keyOf(a + b)
- }
-}
diff --git a/desktop/core/library/b.js b/desktop/core/library/b.js
deleted file mode 100644
index a3bf23a..0000000
--- a/desktop/core/library/b.js
+++ /dev/null
@@ -1,21 +0,0 @@
-'use strict'
-
-import Operator from '../operator.js'
-
-export default function OperatorB (orca, x, y, passive) {
- Operator.call(this, orca, x, y, 'b', passive)
-
- this.name = 'bounce'
- this.info = 'Outputs values between inputs'
-
- this.ports.rate = { x: -1, y: 0, clamp: { min: 1 } }
- this.ports.mod = { x: 1, y: 0, default: '8' }
- this.ports.output = { x: 0, y: 1, sensitive: true }
-
- this.operation = function (force = false) {
- const rate = this.listen(this.ports.rate, true)
- const mod = this.listen(this.ports.mod, true) - 1
- const key = Math.floor(orca.f / rate) % (mod * 2)
- return orca.keyOf(key <= mod ? key : mod - (key - mod))
- }
-}
diff --git a/desktop/core/library/c.js b/desktop/core/library/c.js
deleted file mode 100644
index 38dc20e..0000000
--- a/desktop/core/library/c.js
+++ /dev/null
@@ -1,21 +0,0 @@
-'use strict'
-
-import Operator from '../operator.js'
-
-export default function OperatorC (orca, x, y, passive) {
- Operator.call(this, orca, x, y, 'c', passive)
-
- this.name = 'clock'
- this.info = 'Outputs modulo of frame'
-
- this.ports.rate = { x: -1, y: 0, clamp: { min: 1 } }
- this.ports.mod = { x: 1, y: 0, default: '8' }
- this.ports.output = { x: 0, y: 1, sensitive: true }
-
- this.operation = function (force = false) {
- const rate = this.listen(this.ports.rate, true)
- const mod = this.listen(this.ports.mod, true)
- const val = Math.floor(orca.f / rate) % mod
- return orca.keyOf(val)
- }
-}
diff --git a/desktop/core/library/d.js b/desktop/core/library/d.js
deleted file mode 100644
index 90cad15..0000000
--- a/desktop/core/library/d.js
+++ /dev/null
@@ -1,21 +0,0 @@
-'use strict'
-
-import Operator from '../operator.js'
-
-export default function OperatorD (orca, x, y, passive) {
- Operator.call(this, orca, x, y, 'd', passive)
-
- this.name = 'delay'
- this.info = 'Bangs on modulo of frame'
-
- this.ports.rate = { x: -1, y: 0, clamp: { min: 1 } }
- this.ports.mod = { x: 1, y: 0, default: '8' }
- this.ports.output = { x: 0, y: 1, bang: true }
-
- this.operation = function (force = false) {
- const rate = this.listen(this.ports.rate, true)
- const mod = this.listen(this.ports.mod, true)
- const res = orca.f % (mod * rate)
- return res === 0 || mod === 1
- }
-}
diff --git a/desktop/core/library/e.js b/desktop/core/library/e.js
deleted file mode 100644
index dab6b39..0000000
--- a/desktop/core/library/e.js
+++ /dev/null
@@ -1,16 +0,0 @@
-'use strict'
-
-import Operator from '../operator.js'
-
-export default function OperatorE (orca, x, y, passive) {
- Operator.call(this, orca, x, y, 'e', passive)
-
- this.name = 'east'
- this.info = 'Moves eastward, or bangs'
- this.draw = false
-
- this.operation = function () {
- this.move(1, 0)
- this.passive = false
- }
-}
diff --git a/desktop/core/library/f.js b/desktop/core/library/f.js
deleted file mode 100644
index 9566562..0000000
--- a/desktop/core/library/f.js
+++ /dev/null
@@ -1,20 +0,0 @@
-'use strict'
-
-import Operator from '../operator.js'
-
-export default function OperatorF (orca, x, y, passive) {
- Operator.call(this, orca, x, y, 'f', passive)
-
- this.name = 'if'
- this.info = 'Bangs if inputs are equal'
-
- this.ports.a = { x: -1, y: 0 }
- this.ports.b = { x: 1, y: 0 }
- this.ports.output = { x: 0, y: 1, bang: true }
-
- this.operation = function (force = false) {
- const a = this.listen(this.ports.a)
- const b = this.listen(this.ports.b)
- return a === b && a !== '.'
- }
-}
diff --git a/desktop/core/library/g.js b/desktop/core/library/g.js
deleted file mode 100644
index bc08aef..0000000
--- a/desktop/core/library/g.js
+++ /dev/null
@@ -1,28 +0,0 @@
-'use strict'
-
-import Operator from '../operator.js'
-
-export default function OperatorG (orca, x, y, passive) {
- Operator.call(this, orca, x, y, 'g', passive)
-
- this.name = 'generator'
- this.info = 'Writes operands with offset'
-
- this.ports.x = { x: -3, y: 0 }
- this.ports.y = { x: -2, y: 0 }
- this.ports.len = { x: -1, y: 0, clamp: { min: 1 } }
-
- this.operation = function (force = false) {
- const len = this.listen(this.ports.len, true)
- const x = this.listen(this.ports.x, true)
- const y = this.listen(this.ports.y, true) + 1
- for (let offset = 0; offset < len; offset++) {
- const inPort = { x: offset + 1, y: 0 }
- const outPort = { x: x + offset, y: y, output: true }
- this.addPort(`in${offset}`, inPort)
- this.addPort(`out${offset}`, outPort)
- const res = this.listen(inPort)
- this.output(`${res}`, outPort)
- }
- }
-}
diff --git a/desktop/core/library/h.js b/desktop/core/library/h.js
deleted file mode 100644
index 24b1184..0000000
--- a/desktop/core/library/h.js
+++ /dev/null
@@ -1,17 +0,0 @@
-'use strict'
-
-import Operator from '../operator.js'
-
-export default function OperatorH (orca, x, y, passive) {
- Operator.call(this, orca, x, y, 'h', passive)
-
- this.name = 'halt'
- this.info = 'Halts southward operand'
-
- this.ports.output = { x: 0, y: 1, reader: true }
-
- this.operation = function (force = false) {
- orca.lock(this.x + this.ports.output.x, this.y + this.ports.output.y)
- return this.listen(this.ports.output, true)
- }
-}
diff --git a/desktop/core/library/i.js b/desktop/core/library/i.js
deleted file mode 100644
index f896f25..0000000
--- a/desktop/core/library/i.js
+++ /dev/null
@@ -1,21 +0,0 @@
-'use strict'
-
-import Operator from '../operator.js'
-
-export default function OperatorI (orca, x, y, passive) {
- Operator.call(this, orca, x, y, 'i', passive)
-
- this.name = 'increment'
- this.info = 'Increments southward operand'
-
- this.ports.step = { x: -1, y: 0, default: '1' }
- this.ports.mod = { x: 1, y: 0 }
- this.ports.output = { x: 0, y: 1, sensitive: true, reader: true }
-
- this.operation = function (force = false) {
- const step = this.listen(this.ports.step, true)
- const mod = this.listen(this.ports.mod, true)
- const val = this.listen(this.ports.output, true)
- return orca.keyOf((val + step) % (mod > 0 ? mod : 36))
- }
-}
diff --git a/desktop/core/library/j.js b/desktop/core/library/j.js
deleted file mode 100644
index 0c7e68d..0000000
--- a/desktop/core/library/j.js
+++ /dev/null
@@ -1,18 +0,0 @@
-'use strict'
-
-import Operator from '../operator.js'
-
-export default function OperatorJ (orca, x, y, passive) {
- Operator.call(this, orca, x, y, 'j', passive)
-
- this.name = 'jumper'
- this.info = 'Outputs northward operand'
-
- this.ports.val = { x: 0, y: -1 }
- this.ports.output = { x: 0, y: 1 }
-
- this.operation = function (force = false) {
- orca.lock(this.x, this.y + 1)
- return this.listen(this.ports.val)
- }
-}
diff --git a/desktop/core/library/k.js b/desktop/core/library/k.js
deleted file mode 100644
index 0163bb5..0000000
--- a/desktop/core/library/k.js
+++ /dev/null
@@ -1,27 +0,0 @@
-'use strict'
-
-import Operator from '../operator.js'
-
-export default function OperatorK (orca, x, y, passive) {
- Operator.call(this, orca, x, y, 'k', passive)
-
- this.name = 'konkat'
- this.info = 'Reads multiple variables'
-
- this.ports.len = { x: -1, y: 0, clamp: { min: 1 } }
-
- this.operation = function (force = false) {
- this.len = this.listen(this.ports.len, true)
- for (let offset = 0; offset < this.len; offset++) {
- const key = orca.glyphAt(this.x + offset + 1, this.y)
- orca.lock(this.x + offset + 1, this.y)
- if (key === '.') { continue }
- const inPort = { x: offset + 1, y: 0 }
- const outPort = { x: offset + 1, y: 1, output: true }
- this.addPort(`in${offset}`, inPort)
- this.addPort(`out${offset}`, outPort)
- const res = orca.valueIn(key)
- this.output(`${res}`, outPort)
- }
- }
-}
diff --git a/desktop/core/library/l.js b/desktop/core/library/l.js
deleted file mode 100644
index 518c2ec..0000000
--- a/desktop/core/library/l.js
+++ /dev/null
@@ -1,30 +0,0 @@
-'use strict'
-
-import Operator from '../operator.js'
-
-export default function OperatorL (orca, x, y, passive) {
- Operator.call(this, orca, x, y, 'l', passive)
-
- this.name = 'loop'
- this.info = 'Moves eastward operands'
-
- this.ports.step = { x: -2, y: 0, default: '1' }
- this.ports.len = { x: -1, y: 0 }
- this.ports.val = { x: 1, y: 0 }
- this.ports.output = { x: 0, y: 1 }
-
- this.operation = function (force = false) {
- const len = this.listen(this.ports.len, true)
- const step = this.listen(this.ports.step, true)
- const index = orca.indexAt(this.x + 1, this.y)
- const seg = orca.s.substr(index, len)
- const res = seg.substr(len - step, step) + seg.substr(0, len - step)
- for (let offset = 0; offset <= len; offset++) {
- if (offset > 0) {
- orca.lock(this.x + offset, this.y)
- }
- orca.write(this.x + offset + 1, this.y, res.charAt(offset))
- }
- return this.listen(this.ports.val)
- }
-}
diff --git a/desktop/core/library/m.js b/desktop/core/library/m.js
deleted file mode 100644
index 5986708..0000000
--- a/desktop/core/library/m.js
+++ /dev/null
@@ -1,20 +0,0 @@
-'use strict'
-
-import Operator from '../operator.js'
-
-export default function OperatorM (orca, x, y, passive) {
- Operator.call(this, orca, x, y, 'm', passive)
-
- this.name = 'multiply'
- this.info = 'Outputs product of inputs'
-
- this.ports.a = { x: -1, y: 0 }
- this.ports.b = { x: 1, y: 0 }
- this.ports.output = { x: 0, y: 1, sensitive: true }
-
- this.operation = function (force = false) {
- const a = this.listen(this.ports.a, true)
- const b = this.listen(this.ports.b, true)
- return orca.keyOf(a * b)
- }
-}
diff --git a/desktop/core/library/n.js b/desktop/core/library/n.js
deleted file mode 100644
index 1f1f290..0000000
--- a/desktop/core/library/n.js
+++ /dev/null
@@ -1,16 +0,0 @@
-'use strict'
-
-import Operator from '../operator.js'
-
-export default function OperatorN (orca, x, y, passive) {
- Operator.call(this, orca, x, y, 'n', passive)
-
- this.name = 'north'
- this.info = 'Moves Northward, or bangs'
- this.draw = false
-
- this.operation = function () {
- this.move(0, -1)
- this.passive = false
- }
-}
diff --git a/desktop/core/library/o.js b/desktop/core/library/o.js
deleted file mode 100644
index 7a126ce..0000000
--- a/desktop/core/library/o.js
+++ /dev/null
@@ -1,21 +0,0 @@
-'use strict'
-
-import Operator from '../operator.js'
-
-export default function OperatorO (orca, x, y, passive) {
- Operator.call(this, orca, x, y, 'o', passive)
-
- this.name = 'read'
- this.info = 'Reads operand with offset'
-
- this.ports.x = { x: -2, y: 0 }
- this.ports.y = { x: -1, y: 0 }
- this.ports.output = { x: 0, y: 1 }
-
- this.operation = function (force = false) {
- const x = this.listen(this.ports.x, true)
- const y = this.listen(this.ports.y, true)
- this.addPort('read', { x: x + 1, y: y })
- return this.listen(this.ports.read)
- }
-}
diff --git a/desktop/core/library/p.js b/desktop/core/library/p.js
deleted file mode 100644
index 2d42745..0000000
--- a/desktop/core/library/p.js
+++ /dev/null
@@ -1,24 +0,0 @@
-'use strict'
-
-import Operator from '../operator.js'
-
-export default function OperatorP (orca, x, y, passive) {
- Operator.call(this, orca, x, y, 'p', passive)
-
- this.name = 'push'
- this.info = 'Writes eastward operand'
-
- this.ports.key = { x: -2, y: 0 }
- this.ports.len = { x: -1, y: 0, clamp: { min: 1 } }
- this.ports.val = { x: 1, y: 0 }
-
- this.operation = function (force = false) {
- const len = this.listen(this.ports.len, true)
- const key = this.listen(this.ports.key, true)
- for (let offset = 0; offset < len; offset++) {
- orca.lock(this.x + offset, this.y + 1)
- }
- this.ports.output = { x: (key % len), y: 1 }
- return this.listen(this.ports.val)
- }
-}
diff --git a/desktop/core/library/q.js b/desktop/core/library/q.js
deleted file mode 100644
index af12331..0000000
--- a/desktop/core/library/q.js
+++ /dev/null
@@ -1,28 +0,0 @@
-'use strict'
-
-import Operator from '../operator.js'
-
-export default function OperatorQ (orca, x, y, passive) {
- Operator.call(this, orca, x, y, 'q', passive)
-
- this.name = 'query'
- this.info = 'Reads operands with offset'
-
- this.ports.x = { x: -3, y: 0 }
- this.ports.y = { x: -2, y: 0 }
- this.ports.len = { x: -1, y: 0, clamp: { min: 1 } }
-
- this.operation = function (force = false) {
- const len = this.listen(this.ports.len, true)
- const x = this.listen(this.ports.x, true)
- const y = this.listen(this.ports.y, true)
- for (let offset = 0; offset < len; offset++) {
- const inPort = { x: x + offset + 1, y: y }
- const outPort = { x: offset - len + 1, y: 1, output: true }
- this.addPort(`in${offset}`, inPort)
- this.addPort(`out${offset}`, outPort)
- const res = this.listen(inPort)
- this.output(`${res}`, outPort)
- }
- }
-}
diff --git a/desktop/core/library/r.js b/desktop/core/library/r.js
deleted file mode 100644
index 591717a..0000000
--- a/desktop/core/library/r.js
+++ /dev/null
@@ -1,21 +0,0 @@
-'use strict'
-
-import Operator from '../operator.js'
-
-export default function OperatorR (orca, x, y, passive) {
- Operator.call(this, orca, x, y, 'r', passive)
-
- this.name = 'random'
- this.info = 'Outputs random value'
-
- this.ports.min = { x: -1, y: 0 }
- this.ports.max = { x: 1, y: 0 }
- this.ports.output = { x: 0, y: 1, sensitive: true }
-
- this.operation = function (force = false) {
- const min = this.listen(this.ports.min, true)
- const max = this.listen(this.ports.max, true)
- const val = parseInt((Math.random() * ((max > 0 ? max : 36) - min)) + min)
- return orca.keyOf(val)
- }
-}
diff --git a/desktop/core/library/s.js b/desktop/core/library/s.js
deleted file mode 100644
index 0c13a28..0000000
--- a/desktop/core/library/s.js
+++ /dev/null
@@ -1,16 +0,0 @@
-'use strict'
-
-import Operator from '../operator.js'
-
-export default function OperatorS (orca, x, y, passive) {
- Operator.call(this, orca, x, y, 's', passive)
-
- this.name = 'south'
- this.info = 'Moves southward, or bangs'
- this.draw = false
-
- this.operation = function () {
- this.move(0, 1)
- this.passive = false
- }
-}
diff --git a/desktop/core/library/t.js b/desktop/core/library/t.js
deleted file mode 100644
index 0e51cfe..0000000
--- a/desktop/core/library/t.js
+++ /dev/null
@@ -1,24 +0,0 @@
-'use strict'
-
-import Operator from '../operator.js'
-
-export default function OperatorT (orca, x, y, passive) {
- Operator.call(this, orca, x, y, 't', passive)
-
- this.name = 'track'
- this.info = 'Reads eastward operand'
-
- this.ports.key = { x: -2, y: 0 }
- this.ports.len = { x: -1, y: 0, clamp: { min: 1 } }
- this.ports.output = { x: 0, y: 1 }
-
- this.operation = function (force = false) {
- const len = this.listen(this.ports.len, true)
- const key = this.listen(this.ports.key, true)
- for (let offset = 0; offset < len; offset++) {
- orca.lock(this.x + offset + 1, this.y)
- }
- this.ports.val = { x: (key % len) + 1, y: 0 }
- return this.listen(this.ports.val)
- }
-}
diff --git a/desktop/core/library/u.js b/desktop/core/library/u.js
deleted file mode 100644
index 4dc50e2..0000000
--- a/desktop/core/library/u.js
+++ /dev/null
@@ -1,21 +0,0 @@
-'use strict'
-
-import Operator from '../operator.js'
-
-export default function OperatorU (orca, x, y, passive) {
- Operator.call(this, orca, x, y, 'u', passive)
-
- this.name = 'uclid'
- this.info = 'Bangs on Euclidean rhythm'
-
- this.ports.step = { x: -1, y: 0, clamp: { min: 0 }, default: '1' }
- this.ports.max = { x: 1, y: 0, clamp: { min: 1 }, default: '8' }
- this.ports.output = { x: 0, y: 1, bang: true }
-
- this.operation = function (force = false) {
- const step = this.listen(this.ports.step, true)
- const max = this.listen(this.ports.max, true)
- const bucket = (step * (orca.f + max - 1)) % max + step
- return bucket >= max
- }
-}
diff --git a/desktop/core/library/v.js b/desktop/core/library/v.js
deleted file mode 100644
index 187a5cd..0000000
--- a/desktop/core/library/v.js
+++ /dev/null
@@ -1,26 +0,0 @@
-'use strict'
-
-import Operator from '../operator.js'
-
-export default function OperatorV (orca, x, y, passive) {
- Operator.call(this, orca, x, y, 'v', passive)
-
- this.name = 'variable'
- this.info = 'Reads and writes variable'
-
- this.ports.write = { x: -1, y: 0 }
- this.ports.read = { x: 1, y: 0 }
-
- this.operation = function (force = false) {
- const write = this.listen(this.ports.write)
- const read = this.listen(this.ports.read)
- if (write === '.' && read !== '.') {
- this.addPort('output', { x: 0, y: 1 })
- }
- if (write !== '.') {
- orca.variables[write] = read
- return
- }
- return orca.valueIn(read)
- }
-}
diff --git a/desktop/core/library/w.js b/desktop/core/library/w.js
deleted file mode 100644
index aae8615..0000000
--- a/desktop/core/library/w.js
+++ /dev/null
@@ -1,16 +0,0 @@
-'use strict'
-
-import Operator from '../operator.js'
-
-export default function OperatorW (orca, x, y, passive) {
- Operator.call(this, orca, x, y, 'w', passive)
-
- this.name = 'west'
- this.info = 'Moves westward, or bangs'
- this.draw = false
-
- this.operation = function () {
- this.move(-1, 0)
- this.passive = false
- }
-}
diff --git a/desktop/core/library/x.js b/desktop/core/library/x.js
deleted file mode 100644
index 1230d8a..0000000
--- a/desktop/core/library/x.js
+++ /dev/null
@@ -1,21 +0,0 @@
-'use strict'
-
-import Operator from '../operator.js'
-
-export default function OperatorX (orca, x, y, passive) {
- Operator.call(this, orca, x, y, 'x', passive)
-
- this.name = 'write'
- this.info = 'Writes operand with offset'
-
- this.ports.x = { x: -2, y: 0 }
- this.ports.y = { x: -1, y: 0 }
- this.ports.val = { x: 1, y: 0 }
-
- this.operation = function (force = false) {
- const x = this.listen(this.ports.x, true)
- const y = this.listen(this.ports.y, true) + 1
- this.addPort('output', { x: x, y: y })
- return this.listen(this.ports.val)
- }
-}
diff --git a/desktop/core/library/y.js b/desktop/core/library/y.js
deleted file mode 100644
index a0ae7c9..0000000
--- a/desktop/core/library/y.js
+++ /dev/null
@@ -1,18 +0,0 @@
-'use strict'
-
-import Operator from '../operator.js'
-
-export default function OperatorY (orca, x, y, passive) {
- Operator.call(this, orca, x, y, 'y', passive)
-
- this.name = 'jymper'
- this.info = 'Outputs westward operand'
-
- this.ports.val = { x: -1, y: 0 }
- this.ports.output = { x: 1, y: 0 }
-
- this.operation = function (force = false) {
- orca.lock(this.x + 1, this.y)
- return this.listen(this.ports.val)
- }
-}
diff --git a/desktop/core/library/z.js b/desktop/core/library/z.js
deleted file mode 100644
index b91cde4..0000000
--- a/desktop/core/library/z.js
+++ /dev/null
@@ -1,22 +0,0 @@
-'use strict'
-
-import Operator from '../operator.js'
-
-export default function OperatorZ (orca, x, y, passive) {
- Operator.call(this, orca, x, y, 'z', passive)
-
- this.name = 'lerp'
- this.info = 'Transitions operand to target'
-
- this.ports.rate = { x: -1, y: 0, default: '1' }
- this.ports.target = { x: 1, y: 0 }
- this.ports.output = { x: 0, y: 1, sensitive: true, reader: true }
-
- this.operation = function (force = false) {
- const rate = this.listen(this.ports.rate, true)
- const target = this.listen(this.ports.target, true)
- const val = this.listen(this.ports.output, true)
- const mod = val <= target - rate ? rate : val >= target + rate ? -rate : target - val
- return orca.keyOf(val + mod)
- }
-}
diff --git a/desktop/main.js b/desktop/main.js
index b0017b6..ecedde7 100644
--- a/desktop/main.js
+++ b/desktop/main.js
@@ -1,32 +1,20 @@
-const { app, BrowserWindow, webFrame, Menu } = require('electron')
-const path = require('path')
+'use strict'
-require('electron').protocol.registerSchemesAsPrivileged([
- { scheme: 'js', privileges: { standard: true, secure: true } }
-])
+/* global createWindow */
-function protocolHandler (request, respond) {
- try {
- const pathname = request.url.replace(/^js:\/*/, '')
- const filename = path.resolve(app.getAppPath(), pathname)
- respond({ mimeType: 'text/javascript', data: require('fs').readFileSync(filename) })
- } catch (e) {
- console.error(e, request)
- }
-}
+const { app, BrowserWindow, Menu } = require('electron')
+const path = require('path')
let isShown = true
app.win = null
app.on('ready', () => {
- require('electron').protocol.registerBufferProtocol('js', protocolHandler)
-
app.win = new BrowserWindow({
- width: 710,
- height: 470,
- minWidth: 310,
- minHeight: 350,
+ width: 780,
+ height: 462,
+ minWidth: 380,
+ minHeight: 360,
backgroundColor: '#000',
icon: path.join(__dirname, { darwin: 'icon.icns', linux: 'icon.png', win32: 'icon.ico' }[process.platform] || 'icon.ico'),
resizable: true,
@@ -37,10 +25,9 @@ app.on('ready', () => {
})
app.win.loadURL(`file://${__dirname}/sources/index.html`)
- // app.inspect()
+ app.inspect()
app.win.on('closed', () => {
- win = null
app.quit()
})
@@ -69,19 +56,19 @@ app.inspect = function () {
app.win.toggleDevTools()
}
-app.toggleMenubar = function () {
- app.win.setMenuBarVisibility(!app.win.isMenuBarVisible())
-}
-
app.toggleFullscreen = function () {
app.win.setFullScreen(!app.win.isFullScreen())
}
+app.toggleMenubar = function () {
+ app.win.setMenuBarVisibility(!app.win.isMenuBarVisible())
+}
+
app.toggleVisible = function () {
- if (process.platform === 'darwin') {
- if (isShown && !app.win.isFullScreen()) { app.win.hide() } else { app.win.show() }
- } else {
+ if (process.platform === 'win32') {
if (!app.win.isMinimized()) { app.win.minimize() } else { app.win.restore() }
+ } else {
+ if (isShown && !app.win.isFullScreen()) { app.win.hide() } else { app.win.show() }
}
}
diff --git a/desktop/sources/index.html b/desktop/sources/index.html
index 2f4d665..d2d361c 100644
--- a/desktop/sources/index.html
+++ b/desktop/sources/index.html
@@ -1,26 +1,38 @@
-<!DOCTYPE html>
-<html lang='en'>
+<html>
<head>
<meta charset='utf-8'>
<link rel="stylesheet" type="text/css" href="links/style.css"/>
+ <script type="text/javascript" src="scripts/lib/acels.js"></script>
+ <script type="text/javascript" src="scripts/lib/theme.js"></script>
+ <script type="text/javascript" src="scripts/lib/history.js"></script>
+ <script type="text/javascript" src="scripts/core/library.js"></script>
+ <script type="text/javascript" src="scripts/core/io.js"></script>
+ <script type="text/javascript" src="scripts/core/operator.js"></script>
+ <script type="text/javascript" src="scripts/core/orca.js"></script>
+ <script type="text/javascript" src="scripts/core/transpose.js"></script>
+ <script type="text/javascript" src="scripts/core/io/cc.js"></script>
+ <script type="text/javascript" src="scripts/core/io/midi.js"></script>
+ <script type="text/javascript" src="scripts/core/io/mono.js"></script>
+ <script type="text/javascript" src="scripts/core/io/osc.js"></script>
+ <script type="text/javascript" src="scripts/core/io/udp.js"></script>
+ <script type="text/javascript" src="scripts/clock.js"></script>
+ <script type="text/javascript" src="scripts/commander.js"></script>
+ <script type="text/javascript" src="scripts/cursor.js"></script>
+ <script type="text/javascript" src="scripts/source.js"></script>
+ <script type="text/javascript" src="scripts/terminal.js"></script>
<title>Orca</title>
</head>
<body>
- <script type="module">
+ <script>
'use strict'
-
- console.clear()
-
- import Terminal from "js:./sources/scripts/terminal.js";
const terminal = new Terminal()
- window.terminal = terminal // global availability for e.g. udp
-
terminal.install(document.body)
window.addEventListener('load', () => {
- terminal.start();
+ terminal.start()
+ terminal.acels.inject('Orca')
})
</script>
</body>
diff --git a/desktop/sources/scripts/clock.js b/desktop/sources/scripts/clock.js
index 9baecd8..a1d1bc1 100644
--- a/desktop/sources/scripts/clock.js
+++ b/desktop/sources/scripts/clock.js
@@ -1,6 +1,10 @@
'use strict'
-export default function Clock (terminal) {
+/* global Blob */
+
+function Clock (terminal) {
+ const worker = 'onmessage = (e) => { setInterval(() => { postMessage(true) }, e.data)}'
+
this.isPaused = true
this.timer = null
this.isPuppet = false
@@ -50,7 +54,7 @@ export default function Clock (terminal) {
this.play = function (msg = false) {
console.log('Clock', 'Play')
- if (this.isPaused === false) { console.warn('Clock', 'Already playing'); return }
+ if (this.isPaused === false) { return }
if (this.isPuppet === true) { console.warn('Clock', 'External Midi control'); return }
this.isPaused = false
if (msg === true) { terminal.io.midi.sendClockStart() }
@@ -105,9 +109,12 @@ export default function Clock (terminal) {
this.setTimer = function (bpm) {
console.log('Clock', 'New Timer ' + bpm + 'bpm')
this.clearTimer()
- this.timer = new Worker(`${__dirname}/scripts/timer.js`)
+ this.timer = new Worker(window.URL.createObjectURL(new Blob([worker], { type: 'text/javascript' })))
this.timer.postMessage((60000 / bpm) / 4)
- this.timer.onmessage = (event) => { terminal.io.midi.sendClock(); terminal.run() }
+ this.timer.onmessage = (event) => {
+ terminal.io.midi.sendClock()
+ terminal.run()
+ }
}
this.clearTimer = function () {
diff --git a/desktop/sources/scripts/commander.js b/desktop/sources/scripts/commander.js
index 4fd4372..f1ceb93 100644
--- a/desktop/sources/scripts/commander.js
+++ b/desktop/sources/scripts/commander.js
@@ -1,6 +1,6 @@
'use strict'
-export default function Commander (terminal) {
+function Commander (terminal) {
this.isActive = false
this.query = ''
this.history = []
@@ -72,13 +72,16 @@ export default function Commander (terminal) {
// Begin
- this.start = function (q = '') {
+ this.start = (q = '') => {
+ document.onkeydown = (event) => { this.onKeyDown(event) }
+ document.onkeyup = (event) => { this.onKeyUp(event) }
+
this.isActive = true
this.query = q
terminal.update()
}
- this.stop = function () {
+ this.stop = () => {
this.isActive = false
this.query = ''
this.historyIndex = this.history.length
@@ -90,8 +93,10 @@ export default function Commander (terminal) {
this.preview()
}
- this.write = function (key) {
- if (key.length !== 1) { return }
+ this.write = (key) => {
+ if (key === 'Backspace') { this.erase(); return }
+ if (key === 'Enter') { this.run(); return }
+ if (key === 'Escape') { this.stop(); return }
this.query += key
this.preview()
}
@@ -124,123 +129,16 @@ export default function Commander (terminal) {
// Events
- this.onKeyDown = function (event) {
- // Reset
- if ((event.metaKey || event.ctrlKey) && event.key === 'Backspace') {
- terminal.reset()
- event.preventDefault()
- return
- }
-
- if (event.keyCode === 191 && (event.metaKey || event.ctrlKey)) { terminal.cursor.comment(); event.preventDefault(); return }
-
- // Copy/Paste
- if (event.keyCode === 67 && (event.metaKey || event.ctrlKey)) { terminal.cursor.copy(); event.preventDefault(); return }
- if (event.keyCode === 88 && (event.metaKey || event.ctrlKey)) { terminal.cursor.cut(); event.preventDefault(); return }
- if (event.keyCode === 86 && (event.metaKey || event.ctrlKey) && event.shiftKey) { terminal.cursor.paste(true); event.preventDefault(); return }
- if (event.keyCode === 86 && (event.metaKey || event.ctrlKey)) { terminal.cursor.paste(false); event.preventDefault(); return }
- if (event.keyCode === 65 && (event.metaKey || event.ctrlKey)) { terminal.cursor.selectAll(); event.preventDefault(); return }
-
- // Undo/Redo
- if (event.keyCode === 90 && (event.metaKey || event.ctrlKey) && event.shiftKey) { terminal.history.redo(); event.preventDefault(); return }
- if (event.keyCode === 90 && (event.metaKey || event.ctrlKey)) { terminal.history.undo(); event.preventDefault(); return }
-
- if (event.keyCode === 38) { this.onArrowUp(event.shiftKey, (event.metaKey || event.ctrlKey), event.altKey); return }
- if (event.keyCode === 40) { this.onArrowDown(event.shiftKey, (event.metaKey || event.ctrlKey), event.altKey); return }
- if (event.keyCode === 37) { this.onArrowLeft(event.shiftKey, (event.metaKey || event.ctrlKey), event.altKey); return }
- if (event.keyCode === 39) { this.onArrowRight(event.shiftKey, (event.metaKey || event.ctrlKey), event.altKey); return }
-
- if (event.keyCode === 9) { terminal.toggleHardmode(); event.preventDefault(); return }
-
- if (event.metaKey) { return }
- if (event.ctrlKey) { return }
-
- if (event.key === ' ' && terminal.cursor.mode === 0) { terminal.clock.togglePlay(event.shiftKey); event.preventDefault(); return }
- if (event.key === ' ' && terminal.cursor.mode === 1) { terminal.cursor.move(1, 0); event.preventDefault(); return }
-
- if (event.key === 'Escape') { terminal.toggleGuide(false); terminal.commander.stop(); terminal.clear(); terminal.isPaused = false; terminal.cursor.reset(); return }
- if (event.key === 'Backspace') { terminal[this.isActive === true ? 'commander' : 'cursor'].erase(); event.preventDefault(); return }
-
- if (event.key === ']') { terminal.modGrid(1, 0); event.preventDefault(); return }
- if (event.key === '[') { terminal.modGrid(-1, 0); event.preventDefault(); return }
- if (event.key === '}') { terminal.modGrid(0, 1); event.preventDefault(); return }
- if (event.key === '{') { terminal.modGrid(0, -1); event.preventDefault(); return }
- if (event.key === '>') { terminal.clock.modSpeed(1); event.preventDefault(); return }
- if (event.key === '<') { terminal.clock.modSpeed(-1); event.preventDefault(); return }
-
- // Route key to Operator or Cursor
- terminal[this.isActive === true ? 'commander' : 'cursor'].write(event.key)
- }
-
- this.onKeyUp = function (event) {
- terminal.update()
- }
-
- this.onArrowUp = function (mod = false, skip = false, drag = false) {
- // Navigate History
- if (this.isActive === true) {
- this.historyIndex -= this.historyIndex > 0 ? 1 : 0
- this.start(this.history[this.historyIndex])
- return
- }
- const leap = skip ? terminal.grid.h : 1
- terminal.toggleGuide(false)
- if (drag) {
- terminal.cursor.drag(0, leap)
- } else if (mod) {
- terminal.cursor.scale(0, leap)
- } else {
- terminal.cursor.move(0, leap)
- }
+ this.onKeyDown = (e) => {
+ if (e.ctrlKey || e.metaKey || e.altKey) { return }
+ terminal[this.isActive === true ? 'commander' : 'cursor'].write(e.key)
+ e.stopPropagation()
}
- this.onArrowDown = function (mod = false, skip = false, drag = false) {
- // Navigate History
- if (this.isActive === true) {
- this.historyIndex += this.historyIndex < this.history.length ? 1 : 0
- this.start(this.history[this.historyIndex])
- return
- }
- const leap = skip ? terminal.grid.h : 1
- terminal.toggleGuide(false)
- if (drag) {
- terminal.cursor.drag(0, -leap)
- } else if (mod) {
- terminal.cursor.scale(0, -leap)
- } else {
- terminal.cursor.move(0, -leap)
- }
+ this.onKeyUp = (e) => {
+ // terminal.update()
}
- this.onArrowLeft = function (mod = false, skip = false, drag = false) {
- const leap = skip ? terminal.grid.w : 1
- terminal.toggleGuide(false)
- if (drag) {
- terminal.cursor.drag(-leap, 0)
- } else if (mod) {
- terminal.cursor.scale(-leap, 0)
- } else {
- terminal.cursor.move(-leap, 0)
- }
- }
-
- this.onArrowRight = function (mod = false, skip = false, drag = false) {
- const leap = skip ? terminal.grid.w : 1
- terminal.toggleGuide(false)
- if (drag) {
- terminal.cursor.drag(leap, 0)
- } else if (mod) {
- terminal.cursor.scale(leap, 0)
- } else {
- terminal.cursor.move(leap, 0)
- }
- }
-
- // Events
-
- document.onkeydown = (event) => { this.onKeyDown(event) }
- document.onkeyup = (event) => { this.onKeyUp(event) }
-
// UI
this.toString = function () {
diff --git a/desktop/core/io.js b/desktop/sources/scripts/core/io.js
index 96cacb1..6e3704a 100644
--- a/desktop/core/io.js
+++ b/desktop/sources/scripts/core/io.js
@@ -1,12 +1,6 @@
'use strict'
-import Midi from './io/midi.js'
-import MidiCC from './io/cc.js'
-import Mono from './io/mono.js'
-import Udp from './io/udp.js'
-import Osc from './io/osc.js'
-
-export default function IO (terminal) {
+function IO (terminal) {
this.ip = '127.0.0.1'
this.midi = new Midi(terminal)
diff --git a/desktop/core/io/cc.js b/desktop/sources/scripts/core/io/cc.js
index f617ea7..630d3d9 100644
--- a/desktop/core/io/cc.js
+++ b/desktop/sources/scripts/core/io/cc.js
@@ -1,6 +1,6 @@
'use strict'
-export default function MidiCC (terminal) {
+function MidiCC (terminal) {
this.stack = []
this.offset = 64
diff --git a/desktop/core/io/midi.js b/desktop/sources/scripts/core/io/midi.js
index 9ccf764..7062a3c 100644
--- a/desktop/core/io/midi.js
+++ b/desktop/sources/scripts/core/io/midi.js
@@ -1,8 +1,8 @@
'use strict'
-import transpose from '../transpose.js'
+/* global transposeTable */
-export default function Midi (terminal) {
+function Midi (terminal) {
this.mode = 0
this.isClock = false
@@ -15,7 +15,7 @@ export default function Midi (terminal) {
this.start = function () {
console.info('Midi Starting..')
- this.setup()
+ this.refresh()
}
this.clear = function () {
@@ -79,37 +79,6 @@ export default function Midi (terminal) {
this.stack.push(item)
}
- this.update = () => {
- terminal.controller.clearCat('default', 'Midi')
- terminal.controller.add('default', 'Midi', 'Play/Pause Message', () => { this.toggleClock(true); this.update() }, 'shift+space')
- terminal.controller.add('default', 'Midi', `MIDI Send Clock ${this.isClock === true ? ' — On' : ' — Off'}`, () => { this.toggleClock(); this.update() }, '')
- terminal.controller.add('default', 'Midi', 'Refresh Device List', () => { this.setup(); this.update() })
- terminal.controller.addSpacer('default', 'Midi', 'spacer1')
-
- // Outputs
- if (this.outputs.length < 1) {
- terminal.controller.add('default', 'Midi', 'No Midi Outputs')
- } else {
- for (const id in this.outputs) {
- terminal.controller.add('default', 'Midi', `${this.outputs[id].name} Output ${this.outputIndex === parseInt(id) ? ' — Active' : ''}`, () => { this.selectOutput(id) }, '')
- }
- terminal.controller.add('default', 'Midi', `No Output ${this.outputIndex === -1 ? ' — Active' : ''}`, () => { this.selectOutput(-1) }, '')
- terminal.controller.addSpacer('default', 'Midi', 'spacer2')
- }
-
- // Inputs
- if (this.inputs.length < 1) {
- terminal.controller.add('default', 'Midi', 'No Midi Inputs')
- } else {
- for (const id in this.inputs) {
- terminal.controller.add('default', 'Midi', `${this.inputs[id].name} Input ${this.inputIndex === parseInt(id) ? ' — Active' : ''}`, () => { this.selectInput(id) }, '')
- }
- terminal.controller.add('default', 'Midi', `No Input ${this.inputIndex === -1 ? ' — Active' : ''}`, () => { this.selectInput(-1) }, '')
- }
-
- terminal.controller.commit()
- }
-
this.allNotesOff = function () {
if (!this.outputDevice()) { return }
console.log('MIDI', 'All Notes Off')
@@ -191,23 +160,21 @@ export default function Midi (terminal) {
// Tools
this.selectOutput = function (id) {
- if (id === -1) { this.outputIndex = -1; console.log('MIDI', 'Select Output Device: None'); this.update(); return }
+ if (id === -1) { this.outputIndex = -1; console.log('MIDI', 'Select Output Device: None'); return }
if (!this.outputs[id]) { return }
this.outputIndex = parseInt(id)
console.log('MIDI', `Select Output Device: ${this.outputDevice().name}`)
- this.update()
}
this.selectInput = function (id) {
if (this.inputDevice()) { this.inputDevice().onmidimessage = null }
- if (id === -1) { this.inputIndex = -1; console.log('MIDI', 'Select Input Device: None'); this.update(); return }
+ if (id === -1) { this.inputIndex = -1; console.log('MIDI', 'Select Input Device: None'); return }
if (!this.inputs[id]) { return }
this.inputIndex = parseInt(id)
this.inputDevice().onmidimessage = (msg) => { this.receive(msg) }
console.log('MIDI', `Select Input Device: ${this.inputDevice().name}`)
- this.update()
}
this.outputDevice = function () {
@@ -218,11 +185,21 @@ export default function Midi (terminal) {
return this.inputs[this.inputIndex]
}
+ this.selectNextOutput = () => {
+ this.outputIndex = this.outputIndex < this.outputs.length ? this.outputIndex + 1 : 0
+ terminal.update()
+ }
+
+ this.selectNextInput = () => {
+ this.inputIndex = this.inputIndex < this.inputs.length ? this.inputIndex + 1 : 0
+ terminal.update()
+ }
+
// Setup
- this.setup = function () {
+ this.refresh = function () {
if (!navigator.requestMIDIAccess) { return }
- navigator.requestMIDIAccess({ sysex: false }).then(this.access, (err) => {
+ navigator.requestMIDIAccess().then(this.access, (err) => {
console.warn('No Midi', err)
})
}
@@ -246,9 +223,9 @@ export default function Midi (terminal) {
// UI
this.transpose = function (n, o = 3) {
- if (!transpose[n]) { return null }
- const octave = clamp(parseInt(o) + parseInt(transpose[n].charAt(1)), 0, 8)
- const note = transpose[n].charAt(0)
+ if (!transposeTable[n]) { return null }
+ const octave = clamp(parseInt(o) + parseInt(transposeTable[n].charAt(1)), 0, 8)
+ const note = transposeTable[n].charAt(0)
const value = ['C', 'c', 'D', 'd', 'E', 'F', 'f', 'G', 'g', 'A', 'a', 'B'].indexOf(note)
const id = clamp((octave * 12) + value + 24, 0, 127)
return { id, value, note, octave }
@@ -258,8 +235,8 @@ export default function Midi (terminal) {
const note = ['C', 'c', 'D', 'd', 'E', 'F', 'f', 'G', 'g', 'A', 'a', 'B'][id % 12]
const octave = Math.floor(id / 12) - 5
const name = `${note}${octave}`
- const key = Object.values(transpose).indexOf(name)
- return Object.keys(transpose)[key]
+ const key = Object.values(transposeTable).indexOf(name)
+ return Object.keys(transposeTable)[key]
}
this.toString = function () {
diff --git a/desktop/core/io/mono.js b/desktop/sources/scripts/core/io/mono.js
index 4386fac..903036b 100644
--- a/desktop/core/io/mono.js
+++ b/desktop/sources/scripts/core/io/mono.js
@@ -1,6 +1,6 @@
'use strict'
-export default function Mono (terminal) {
+function Mono (terminal) {
this.stack = {}
this.start = function () {
diff --git a/desktop/core/io/osc.js b/desktop/sources/scripts/core/io/osc.js
index 4409158..346decf 100644
--- a/desktop/core/io/osc.js
+++ b/desktop/sources/scripts/core/io/osc.js
@@ -2,12 +2,13 @@
const osc = require('node-osc')
-export default function Osc (terminal) {
+function Osc (terminal) {
this.stack = []
this.port = null
this.options = { default: 49162, tidalCycles: 6010, sonicPi: 4559, superCollider: 57120, norns: 10111 }
this.start = function () {
+ if (!osc) { console.warn('OSC', 'Could not start.'); return }
console.info('OSC', 'Starting..')
this.setup()
this.select()
@@ -45,16 +46,6 @@ export default function Osc (terminal) {
console.info('OSC', `Selected port: ${port}`)
this.port = parseInt(port)
this.setup()
- this.update()
- }
-
- this.update = () => {
- terminal.controller.clearCat('default', 'OSC')
- for (const id in this.options) {
- terminal.controller.add('default', 'OSC', `${id.charAt(0).toUpperCase() + id.substr(1)}(${this.options[id]}) ${this.port === this.options[id] ? ' — Active' : ''}`, () => { this.select(this.options[id]) }, '')
- }
- terminal.controller.add('default', 'OSC', 'Choose Custom Port', () => { terminal.commander.start('osc:') }, '')
- terminal.controller.commit()
}
this.setup = function () {
diff --git a/desktop/sources/scripts/core/io/udp.js b/desktop/sources/scripts/core/io/udp.js
new file mode 100644
index 0000000..11fe0fd
--- /dev/null
+++ b/desktop/sources/scripts/core/io/udp.js
@@ -0,0 +1,61 @@
+'use strict'
+
+const dgram = require('dgram')
+
+function Udp (terminal) {
+ this.stack = []
+ this.port = null
+ this.options = { default: 49161, orca: 49160 }
+ this.client = dgram ? dgram.createSocket('udp4') : null
+ this.listener = dgram ? dgram.createSocket('udp4') : null
+
+ this.start = function () {
+ if (!this.client || !this.listener) { console.warn('UDP', 'Could not start.'); return }
+ console.info('UDP', 'Starting..')
+
+ this.listener.on('message', (msg, rinfo) => {
+ terminal.commander.trigger(`${msg}`, false)
+ })
+
+ this.listener.on('listening', () => {
+ const address = this.listener.address()
+ console.info('UDP', `Started client at ${address.address}:${address.port}`)
+ })
+
+ this.listener.on('error', (err) => {
+ console.warn('UDP', `Server error:\n ${err.stack}`)
+ this.listener.close()
+ })
+
+ this.listener.bind(49160)
+
+ this.select()
+ }
+
+ this.clear = function () {
+ this.stack = []
+ }
+
+ this.run = function () {
+ for (const id in this.stack) {
+ this.play(this.stack[id])
+ }
+ }
+
+ this.push = function (msg) {
+ this.stack.push(msg)
+ }
+
+ this.play = function (data) {
+ this.client.send(Buffer.from(`${data}`), this.port, terminal.io.ip, (err) => {
+ if (err) { console.warn(err) }
+ })
+ }
+
+ this.select = function (port = this.options.default) {
+ if (parseInt(port) === this.port) { console.warn('UDP', 'Already selected'); return }
+ if (isNaN(port) || port < 1000) { console.warn('UDP', 'Unavailable port'); return }
+ console.info('UDP', `Selected port: ${port}`)
+ this.port = parseInt(port)
+ }
+}
diff --git a/desktop/sources/scripts/core/library.js b/desktop/sources/scripts/core/library.js
new file mode 100644
index 0000000..1e6a272
--- /dev/null
+++ b/desktop/sources/scripts/core/library.js
@@ -0,0 +1,740 @@
+'use strict'
+
+/* global Operator */
+
+const library = {}
+
+library.a = function OperatorA (orca, x, y, passive) {
+ Operator.call(this, orca, x, y, 'a', passive)
+
+ this.name = 'add'
+ this.info = 'Outputs sum of inputs'
+
+ this.ports.a = { x: -1, y: 0 }
+ this.ports.b = { x: 1, y: 0 }
+ this.ports.output = { x: 0, y: 1, sensitive: true }
+
+ this.operation = function (force = false) {
+ const a = this.listen(this.ports.a, true)
+ const b = this.listen(this.ports.b, true)
+ return orca.keyOf(a + b)
+ }
+}
+
+library.b = function OperatorB (orca, x, y, passive) {
+ Operator.call(this, orca, x, y, 'b', passive)
+
+ this.name = 'bounce'
+ this.info = 'Outputs values between inputs'
+
+ this.ports.rate = { x: -1, y: 0, clamp: { min: 1 } }
+ this.ports.mod = { x: 1, y: 0, default: '8' }
+ this.ports.output = { x: 0, y: 1, sensitive: true }
+
+ this.operation = function (force = false) {
+ const rate = this.listen(this.ports.rate, true)
+ const mod = this.listen(this.ports.mod, true) - 1
+ const key = Math.floor(orca.f / rate) % (mod * 2)
+ return orca.keyOf(key <= mod ? key : mod - (key - mod))
+ }
+}
+
+library.c = function OperatorC (orca, x, y, passive) {
+ Operator.call(this, orca, x, y, 'c', passive)
+
+ this.name = 'clock'
+ this.info = 'Outputs modulo of frame'
+
+ this.ports.rate = { x: -1, y: 0, clamp: { min: 1 } }
+ this.ports.mod = { x: 1, y: 0, default: '8' }
+ this.ports.output = { x: 0, y: 1, sensitive: true }
+
+ this.operation = function (force = false) {
+ const rate = this.listen(this.ports.rate, true)
+ const mod = this.listen(this.ports.mod, true)
+ const val = Math.floor(orca.f / rate) % mod
+ return orca.keyOf(val)
+ }
+}
+
+library.d = function OperatorD (orca, x, y, passive) {
+ Operator.call(this, orca, x, y, 'd', passive)
+
+ this.name = 'delay'
+ this.info = 'Bangs on modulo of frame'
+
+ this.ports.rate = { x: -1, y: 0, clamp: { min: 1 } }
+ this.ports.mod = { x: 1, y: 0, default: '8' }
+ this.ports.output = { x: 0, y: 1, bang: true }
+
+ this.operation = function (force = false) {
+ const rate = this.listen(this.ports.rate, true)
+ const mod = this.listen(this.ports.mod, true)
+ const res = orca.f % (mod * rate)
+ return res === 0 || mod === 1
+ }
+}
+
+library.e = function OperatorE (orca, x, y, passive) {
+ Operator.call(this, orca, x, y, 'e', passive)
+
+ this.name = 'east'
+ this.info = 'Moves eastward, or bangs'
+ this.draw = false
+
+ this.operation = function () {
+ this.move(1, 0)
+ this.passive = false
+ }
+}
+
+library.f = function OperatorF (orca, x, y, passive) {
+ Operator.call(this, orca, x, y, 'f', passive)
+
+ this.name = 'if'
+ this.info = 'Bangs if inputs are equal'
+
+ this.ports.a = { x: -1, y: 0 }
+ this.ports.b = { x: 1, y: 0 }
+ this.ports.output = { x: 0, y: 1, bang: true }
+
+ this.operation = function (force = false) {
+ const a = this.listen(this.ports.a)
+ const b = this.listen(this.ports.b)
+ return a === b && a !== '.'
+ }
+}
+
+library.g = function OperatorG (orca, x, y, passive) {
+ Operator.call(this, orca, x, y, 'g', passive)
+
+ this.name = 'generator'
+ this.info = 'Writes operands with offset'
+
+ this.ports.x = { x: -3, y: 0 }
+ this.ports.y = { x: -2, y: 0 }
+ this.ports.len = { x: -1, y: 0, clamp: { min: 1 } }
+
+ this.operation = function (force = false) {
+ const len = this.listen(this.ports.len, true)
+ const x = this.listen(this.ports.x, true)
+ const y = this.listen(this.ports.y, true) + 1
+ for (let offset = 0; offset < len; offset++) {
+ const inPort = { x: offset + 1, y: 0 }
+ const outPort = { x: x + offset, y: y, output: true }
+ this.addPort(`in${offset}`, inPort)
+ this.addPort(`out${offset}`, outPort)
+ const res = this.listen(inPort)
+ this.output(`${res}`, outPort)
+ }
+ }
+}
+
+library.h = function OperatorH (orca, x, y, passive) {
+ Operator.call(this, orca, x, y, 'h', passive)
+
+ this.name = 'halt'
+ this.info = 'Halts southward operand'
+
+ this.ports.output = { x: 0, y: 1, reader: true }
+
+ this.operation = function (force = false) {
+ orca.lock(this.x + this.ports.output.x, this.y + this.ports.output.y)
+ return this.listen(this.ports.output, true)
+ }
+}
+
+library.i = function OperatorI (orca, x, y, passive) {
+ Operator.call(this, orca, x, y, 'i', passive)
+
+ this.name = 'increment'
+ this.info = 'Increments southward operand'
+
+ this.ports.step = { x: -1, y: 0, default: '1' }
+ this.ports.mod = { x: 1, y: 0 }
+ this.ports.output = { x: 0, y: 1, sensitive: true, reader: true }
+
+ this.operation = function (force = false) {
+ const step = this.listen(this.ports.step, true)
+ const mod = this.listen(this.ports.mod, true)
+ const val = this.listen(this.ports.output, true)
+ return orca.keyOf((val + step) % (mod > 0 ? mod : 36))
+ }
+}
+
+library.j = function OperatorJ (orca, x, y, passive) {
+ Operator.call(this, orca, x, y, 'j', passive)
+
+ this.name = 'jumper'
+ this.info = 'Outputs northward operand'
+
+ this.ports.val = { x: 0, y: -1 }
+ this.ports.output = { x: 0, y: 1 }
+
+ this.operation = function (force = false) {
+ orca.lock(this.x, this.y + 1)
+ return this.listen(this.ports.val)
+ }
+}
+
+library.k = function OperatorK (orca, x, y, passive) {
+ Operator.call(this, orca, x, y, 'k', passive)
+
+ this.name = 'konkat'
+ this.info = 'Reads multiple variables'
+
+ this.ports.len = { x: -1, y: 0, clamp: { min: 1 } }
+
+ this.operation = function (force = false) {
+ this.len = this.listen(this.ports.len, true)
+ for (let offset = 0; offset < this.len; offset++) {
+ const key = orca.glyphAt(this.x + offset + 1, this.y)
+ orca.lock(this.x + offset + 1, this.y)
+ if (key === '.') { continue }
+ const inPort = { x: offset + 1, y: 0 }
+ const outPort = { x: offset + 1, y: 1, output: true }
+ this.addPort(`in${offset}`, inPort)
+ this.addPort(`out${offset}`, outPort)
+ const res = orca.valueIn(key)
+ this.output(`${res}`, outPort)
+ }
+ }
+}
+
+library.l = function OperatorL (orca, x, y, passive) {
+ Operator.call(this, orca, x, y, 'l', passive)
+
+ this.name = 'loop'
+ this.info = 'Moves eastward operands'
+
+ this.ports.step = { x: -2, y: 0, default: '1' }
+ this.ports.len = { x: -1, y: 0 }
+ this.ports.val = { x: 1, y: 0 }
+ this.ports.output = { x: 0, y: 1 }
+
+ this.operation = function (force = false) {
+ const len = this.listen(this.ports.len, true)
+ const step = this.listen(this.ports.step, true)
+ const index = orca.indexAt(this.x + 1, this.y)
+ const seg = orca.s.substr(index, len)
+ const res = seg.substr(len - step, step) + seg.substr(0, len - step)
+ for (let offset = 0; offset <= len; offset++) {
+ if (offset > 0) {
+ orca.lock(this.x + offset, this.y)
+ }
+ orca.write(this.x + offset + 1, this.y, res.charAt(offset))
+ }
+ return this.listen(this.ports.val)
+ }
+}
+
+library.m = function OperatorM (orca, x, y, passive) {
+ Operator.call(this, orca, x, y, 'm', passive)
+
+ this.name = 'multiply'
+ this.info = 'Outputs product of inputs'
+
+ this.ports.a = { x: -1, y: 0 }
+ this.ports.b = { x: 1, y: 0 }
+ this.ports.output = { x: 0, y: 1, sensitive: true }
+
+ this.operation = function (force = false) {
+ const a = this.listen(this.ports.a, true)
+ const b = this.listen(this.ports.b, true)
+ return orca.keyOf(a * b)
+ }
+}
+
+library.n = function OperatorN (orca, x, y, passive) {
+ Operator.call(this, orca, x, y, 'n', passive)
+
+ this.name = 'north'
+ this.info = 'Moves Northward, or bangs'
+ this.draw = false
+
+ this.operation = function () {
+ this.move(0, -1)
+ this.passive = false
+ }
+}
+
+library.o = function OperatorO (orca, x, y, passive) {
+ Operator.call(this, orca, x, y, 'o', passive)
+
+ this.name = 'read'
+ this.info = 'Reads operand with offset'
+
+ this.ports.x = { x: -2, y: 0 }
+ this.ports.y = { x: -1, y: 0 }
+ this.ports.output = { x: 0, y: 1 }
+
+ this.operation = function (force = false) {
+ const x = this.listen(this.ports.x, true)
+ const y = this.listen(this.ports.y, true)
+ this.addPort('read', { x: x + 1, y: y })
+ return this.listen(this.ports.read)
+ }
+}
+
+library.p = function OperatorP (orca, x, y, passive) {
+ Operator.call(this, orca, x, y, 'p', passive)
+
+ this.name = 'push'
+ this.info = 'Writes eastward operand'
+
+ this.ports.key = { x: -2, y: 0 }
+ this.ports.len = { x: -1, y: 0, clamp: { min: 1 } }
+ this.ports.val = { x: 1, y: 0 }
+
+ this.operation = function (force = false) {
+ const len = this.listen(this.ports.len, true)
+ const key = this.listen(this.ports.key, true)
+ for (let offset = 0; offset < len; offset++) {
+ orca.lock(this.x + offset, this.y + 1)
+ }
+ this.ports.output = { x: (key % len), y: 1 }
+ return this.listen(this.ports.val)
+ }
+}
+
+library.q = function OperatorQ (orca, x, y, passive) {
+ Operator.call(this, orca, x, y, 'q', passive)
+
+ this.name = 'query'
+ this.info = 'Reads operands with offset'
+
+ this.ports.x = { x: -3, y: 0 }
+ this.ports.y = { x: -2, y: 0 }
+ this.ports.len = { x: -1, y: 0, clamp: { min: 1 } }
+
+ this.operation = function (force = false) {
+ const len = this.listen(this.ports.len, true)
+ const x = this.listen(this.ports.x, true)
+ const y = this.listen(this.ports.y, true)
+ for (let offset = 0; offset < len; offset++) {
+ const inPort = { x: x + offset + 1, y: y }
+ const outPort = { x: offset - len + 1, y: 1, output: true }
+ this.addPort(`in${offset}`, inPort)
+ this.addPort(`out${offset}`, outPort)
+ const res = this.listen(inPort)
+ this.output(`${res}`, outPort)
+ }
+ }
+}
+
+library.r = function OperatorR (orca, x, y, passive) {
+ Operator.call(this, orca, x, y, 'r', passive)
+
+ this.name = 'random'
+ this.info = 'Outputs random value'
+
+ this.ports.min = { x: -1, y: 0 }
+ this.ports.max = { x: 1, y: 0 }
+ this.ports.output = { x: 0, y: 1, sensitive: true }
+
+ this.operation = function (force = false) {
+ const min = this.listen(this.ports.min, true)
+ const max = this.listen(this.ports.max, true)
+ const val = parseInt((Math.random() * ((max > 0 ? max : 36) - min)) + min)
+ return orca.keyOf(val)
+ }
+}
+
+library.s = function OperatorS (orca, x, y, passive) {
+ Operator.call(this, orca, x, y, 's', passive)
+
+ this.name = 'south'
+ this.info = 'Moves southward, or bangs'
+ this.draw = false
+
+ this.operation = function () {
+ this.move(0, 1)
+ this.passive = false
+ }
+}
+
+library.t = function OperatorT (orca, x, y, passive) {
+ Operator.call(this, orca, x, y, 't', passive)
+
+ this.name = 'track'
+ this.info = 'Reads eastward operand'
+
+ this.ports.key = { x: -2, y: 0 }
+ this.ports.len = { x: -1, y: 0, clamp: { min: 1 } }
+ this.ports.output = { x: 0, y: 1 }
+
+ this.operation = function (force = false) {
+ const len = this.listen(this.ports.len, true)
+ const key = this.listen(this.ports.key, true)
+ for (let offset = 0; offset < len; offset++) {
+ orca.lock(this.x + offset + 1, this.y)
+ }
+ this.ports.val = { x: (key % len) + 1, y: 0 }
+ return this.listen(this.ports.val)
+ }
+}
+
+library.u = function OperatorU (orca, x, y, passive) {
+ Operator.call(this, orca, x, y, 'u', passive)
+
+ this.name = 'uclid'
+ this.info = 'Bangs on Euclidean rhythm'
+
+ this.ports.step = { x: -1, y: 0, clamp: { min: 0 }, default: '1' }
+ this.ports.max = { x: 1, y: 0, clamp: { min: 1 }, default: '8' }
+ this.ports.output = { x: 0, y: 1, bang: true }
+
+ this.operation = function (force = false) {
+ const step = this.listen(this.ports.step, true)
+ const max = this.listen(this.ports.max, true)
+ const bucket = (step * (orca.f + max - 1)) % max + step
+ return bucket >= max
+ }
+}
+
+library.v = function OperatorV (orca, x, y, passive) {
+ Operator.call(this, orca, x, y, 'v', passive)
+
+ this.name = 'variable'
+ this.info = 'Reads and writes variable'
+
+ this.ports.write = { x: -1, y: 0 }
+ this.ports.read = { x: 1, y: 0 }
+
+ this.operation = function (force = false) {
+ const write = this.listen(this.ports.write)
+ const read = this.listen(this.ports.read)
+ if (write === '.' && read !== '.') {
+ this.addPort('output', { x: 0, y: 1 })
+ }
+ if (write !== '.') {
+ orca.variables[write] = read
+ return
+ }
+ return orca.valueIn(read)
+ }
+}
+
+library.w = function OperatorW (orca, x, y, passive) {
+ Operator.call(this, orca, x, y, 'w', passive)
+
+ this.name = 'west'
+ this.info = 'Moves westward, or bangs'
+ this.draw = false
+
+ this.operation = function () {
+ this.move(-1, 0)
+ this.passive = false
+ }
+}
+
+library.x = function OperatorX (orca, x, y, passive) {
+ Operator.call(this, orca, x, y, 'x', passive)
+
+ this.name = 'write'
+ this.info = 'Writes operand with offset'
+
+ this.ports.x = { x: -2, y: 0 }
+ this.ports.y = { x: -1, y: 0 }
+ this.ports.val = { x: 1, y: 0 }
+
+ this.operation = function (force = false) {
+ const x = this.listen(this.ports.x, true)
+ const y = this.listen(this.ports.y, true) + 1
+ this.addPort('output', { x: x, y: y })
+ return this.listen(this.ports.val)
+ }
+}
+
+library.y = function OperatorY (orca, x, y, passive) {
+ Operator.call(this, orca, x, y, 'y', passive)
+
+ this.name = 'jymper'
+ this.info = 'Outputs westward operand'
+
+ this.ports.val = { x: -1, y: 0 }
+ this.ports.output = { x: 1, y: 0 }
+
+ this.operation = function (force = false) {
+ orca.lock(this.x + 1, this.y)
+ return this.listen(this.ports.val)
+ }
+}
+
+library.z = function OperatorZ (orca, x, y, passive) {
+ Operator.call(this, orca, x, y, 'z', passive)
+
+ this.name = 'lerp'
+ this.info = 'Transitions operand to target'
+
+ this.ports.rate = { x: -1, y: 0, default: '1' }
+ this.ports.target = { x: 1, y: 0 }
+ this.ports.output = { x: 0, y: 1, sensitive: true, reader: true }
+
+ this.operation = function (force = false) {
+ const rate = this.listen(this.ports.rate, true)
+ const target = this.listen(this.ports.target, true)
+ const val = this.listen(this.ports.output, true)
+ const mod = val <= target - rate ? rate : val >= target + rate ? -rate : target - val
+ return orca.keyOf(val + mod)
+ }
+}
+
+// Specials
+
+library['*'] = function OperatorBang (orca, x, y, passive) {
+ Operator.call(this, orca, x, y, '*', true)
+
+ this.name = 'bang'
+ this.info = 'Bangs neighboring operands'
+ this.draw = false
+
+ this.run = function (force = false) {
+ this.draw = false
+ this.erase()
+ }
+}
+
+library['#'] = function OperatorComment (orca, x, y, passive) {
+ Operator.call(this, orca, x, y, '#', true)
+
+ this.name = 'comment'
+ this.info = 'Halts line'
+ this.draw = false
+
+ this.operation = function () {
+ for (let x = this.x + 1; x <= orca.w; x++) {
+ orca.lock(x, this.y)
+ if (orca.glyphAt(x, this.y) === this.glyph) { break }
+ }
+ orca.lock(this.x, this.y)
+ }
+}
+
+// IO
+
+library.$ = function OperatorSelf (orca, x, y, passive) {
+ Operator.call(this, orca, x, y, '*', true)
+
+ this.name = 'self'
+ this.info = 'Send command to itself'
+
+ this.run = function (force = false) {
+ let msg = ''
+ for (let x = 1; x <= 36; x++) {
+ const g = orca.glyphAt(this.x + x, this.y)
+ orca.lock(this.x + x, this.y)
+ if (g === '.') { break }
+ msg += g
+ }
+
+ if (!this.hasNeighbor('*') && force === false) { return }
+ if (msg === '') { return }
+
+ this.draw = false
+ terminal.commander.trigger(`${msg}`)
+ }
+}
+
+library['!'] = function OperatorCC (orca, x, y) {
+ Operator.call(this, orca, x, y, '!', true)
+
+ this.name = 'cc'
+ this.info = 'Sends MIDI control change'
+ this.ports.channel = { x: 1, y: 0, clamp: { min: 0, max: 15 } }
+ this.ports.knob = { x: 2, y: 0, clamp: { min: 0 } }
+ this.ports.value = { x: 3, y: 0, clamp: { min: 0 } }
+
+ this.operation = function (force = false) {
+ if (!this.hasNeighbor('*') && force === false) { return }
+ if (this.listen(this.ports.channel) === '.') { return }
+ if (this.listen(this.ports.knob) === '.') { return }
+
+ const channel = this.listen(this.ports.channel, true)
+ const knob = this.listen(this.ports.knob, true)
+ const rawValue = this.listen(this.ports.value, true)
+ const value = Math.ceil((127 * rawValue) / 35)
+
+ terminal.io.cc.stack.push({ channel, knob, value, type: 'cc' })
+
+ this.draw = false
+
+ if (force === true) {
+ terminal.io.cc.run()
+ }
+ }
+}
+
+library[':'] = function OperatorMidi (orca, x, y, passive) {
+ Operator.call(this, orca, x, y, ':', true)
+
+ this.name = 'midi'
+ this.info = 'Sends MIDI note'
+ this.ports.channel = { x: 1, y: 0, clamp: { min: 0, max: 16 } }
+ this.ports.octave = { x: 2, y: 0, clamp: { min: 0, max: 8 } }
+ this.ports.note = { x: 3, y: 0 }
+ this.ports.velocity = { x: 4, y: 0, default: 'f', clamp: { min: 0, max: 16 } }
+ this.ports.length = { x: 5, y: 0, default: '1', clamp: { min: 0, max: 16 } }
+
+ this.operation = function (force = false) {
+ if (!this.hasNeighbor('*') && force === false) { return }
+ if (this.listen(this.ports.channel) === '.') { return }
+ if (this.listen(this.ports.octave) === '.') { return }
+ if (this.listen(this.ports.note) === '.') { return }
+ if (!isNaN(this.listen(this.ports.note))) { return }
+
+ const channel = this.listen(this.ports.channel, true)
+ const octave = this.listen(this.ports.octave, true)
+ const note = this.listen(this.ports.note)
+ const velocity = this.listen(this.ports.velocity, true)
+ const length = this.listen(this.ports.length, true)
+
+ terminal.io.midi.push(channel, octave, note, velocity, length)
+
+ if (force === true) {
+ terminal.io.midi.run()
+ }
+
+ this.draw = false
+ }
+}
+
+library['%'] = function OperatorMono (orca, x, y, passive) {
+ Operator.call(this, orca, x, y, '%', true)
+
+ this.name = 'mono'
+ this.info = 'Sends MIDI monophonic note'
+ this.ports.channel = { x: 1, y: 0, clamp: { min: 0, max: 16 } }
+ this.ports.octave = { x: 2, y: 0, clamp: { min: 0, max: 8 } }
+ this.ports.note = { x: 3, y: 0 }
+ this.ports.velocity = { x: 4, y: 0, default: 'f', clamp: { min: 0, max: 16 } }
+ this.ports.length = { x: 5, y: 0, default: '1', clamp: { min: 0, max: 16 } }
+
+ this.operation = function (force = false) {
+ if (!this.hasNeighbor('*') && force === false) { return }
+ if (this.listen(this.ports.channel) === '.') { return }
+ if (this.listen(this.ports.octave) === '.') { return }
+ if (this.listen(this.ports.note) === '.') { return }
+ if (!isNaN(this.listen(this.ports.note))) { return }
+
+ const channel = this.listen(this.ports.channel, true)
+ const octave = this.listen(this.ports.octave, true)
+ const note = this.listen(this.ports.note)
+ const velocity = this.listen(this.ports.velocity, true)
+ const length = this.listen(this.ports.length, true)
+
+ terminal.io.mono.push(channel, octave, note, velocity, length)
+
+ if (force === true) {
+ terminal.io.mono.run()
+ }
+
+ this.draw = false
+ }
+}
+
+library['='] = function OperatorOsc (orca, x, y, passive) {
+ Operator.call(this, orca, x, y, '=', true)
+
+ this.name = 'osc'
+ this.info = 'Sends OSC message'
+
+ this.ports.path = { x: 1, y: 0 }
+
+ this.operation = function (force = false) {
+ let msg = ''
+ for (let x = 2; x <= 36; x++) {
+ const g = orca.glyphAt(this.x + x, this.y)
+ orca.lock(this.x + x, this.y)
+ if (g === '.') { break }
+ msg += g
+ }
+
+ if (!this.hasNeighbor('*') && force === false) { return }
+ if (msg === '') { return }
+
+ const path = this.listen(this.ports.path)
+
+ if (!path || path === '.') { return }
+
+ this.draw = false
+ terminal.io.osc.push('/' + path, msg)
+
+ if (force === true) {
+ terminal.io.osc.run()
+ }
+ }
+}
+
+library['?'] = function OperatorPB (orca, x, y) {
+ Operator.call(this, orca, x, y, '?', true)
+
+ this.name = 'cc'
+ this.info = 'Sends MIDI pitch bend'
+ this.ports.channel = { x: 1, y: 0, clamp: { min: 0, max: 15 } }
+ this.ports.lsb = { x: 2, y: 0, clamp: { min: 0 } }
+ this.ports.msb = { x: 3, y: 0, clamp: { min: 0 } }
+
+ this.operation = function (force = false) {
+ if (!this.hasNeighbor('*') && force === false) { return }
+ if (this.listen(this.ports.channel) === '.') { return }
+ if (this.listen(this.ports.lsb) === '.') { return }
+
+ const channel = this.listen(this.ports.channel, true)
+ const rawlsb = this.listen(this.ports.lsb, true)
+ const lsb = Math.ceil((127 * rawlsb) / 35)
+ const rawmsb = this.listen(this.ports.msb, true)
+ const msb = Math.ceil((127 * rawmsb) / 35)
+
+ terminal.io.cc.stack.push({ channel, lsb, msb, type: 'pb' })
+
+ this.draw = false
+
+ if (force === true) {
+ terminal.io.cc.run()
+ }
+ }
+}
+
+library[';'] = function OperatorUdp (orca, x, y, passive) {
+ Operator.call(this, orca, x, y, ';', true)
+
+ this.name = 'udp'
+ this.info = 'Sends UDP message'
+
+ this.operation = function (force = false) {
+ let msg = ''
+ for (let x = 1; x <= 36; x++) {
+ const g = orca.glyphAt(this.x + x, this.y)
+ orca.lock(this.x + x, this.y)
+ if (g === '.') { break }
+ msg += g
+ }
+
+ if (!this.hasNeighbor('*') && force === false) { return }
+ if (msg === '') { return }
+
+ this.draw = false
+ terminal.io.udp.push(msg)
+
+ if (force === true) {
+ terminal.io.udp.run()
+ }
+ }
+}
+
+// Add numbers
+
+for (let i = 0; i <= 9; i++) {
+ library[`${i}`] = function OperatorNull (orca, x, y, passive) {
+ Operator.call(this, orca, x, y, '.', false)
+
+ this.name = 'null'
+ this.info = 'empty'
+
+ // Overwrite run, to disable draw.
+ this.run = function (force = false) {
+
+ }
+ }
+}
diff --git a/desktop/core/operator.js b/desktop/sources/scripts/core/operator.js
index 58a6d5c..b4d3c6c 100644
--- a/desktop/core/operator.js
+++ b/desktop/sources/scripts/core/operator.js
@@ -1,6 +1,6 @@
'use strict'
-export default function Operator (orca, x, y, glyph = '.', passive = false) {
+function Operator (orca, x, y, glyph = '.', passive = false) {
this.name = 'unknown'
this.x = x
this.y = y
diff --git a/desktop/core/orca.js b/desktop/sources/scripts/core/orca.js
index ef55ab6..bb23ebc 100644
--- a/desktop/core/orca.js
+++ b/desktop/sources/scripts/core/orca.js
@@ -1,8 +1,6 @@
'use strict'
-import library from './library.js'
-
-export default function Orca () {
+function Orca (library) {
this.keys = Object.keys(library).slice(0, 36)
this.w = 1 // Default Width
diff --git a/desktop/core/transpose.js b/desktop/sources/scripts/core/transpose.js
index 448fc38..6925240 100644
--- a/desktop/core/transpose.js
+++ b/desktop/sources/scripts/core/transpose.js
@@ -1,6 +1,6 @@
'use strict'
-export default {
+const transposeTable = {
A: 'A0',
a: 'a0',
B: 'B0',
diff --git a/desktop/sources/scripts/cursor.js b/desktop/sources/scripts/cursor.js
index ca3659e..cf3d0f4 100644
--- a/desktop/sources/scripts/cursor.js
+++ b/desktop/sources/scripts/cursor.js
@@ -1,8 +1,6 @@
'use strict'
-const { clipboard } = require('electron')
-
-export default function Cursor (terminal) {
+function Cursor (terminal) {
this.x = 0
this.y = 0
this.w = 0
@@ -15,12 +13,22 @@ export default function Cursor (terminal) {
this.mode = 0
+ this.start = () => {
+ document.onmousedown = (e) => { this.onMouseDown(e) }
+ document.onmouseup = (e) => { this.onMouseUp(e) }
+ document.onmousemove = (e) => { this.onMouseMove(e) }
+ document.oncopy = (e) => { this.onCopy(e) }
+ document.oncut = (e) => { this.onCut(e) }
+ document.onpaste = (e) => { this.onPaste(e) }
+ }
+
this.move = function (x, y) {
if (isNaN(x) || isNaN(y)) { return }
this.x = clamp(this.x + parseInt(x), 0, terminal.orca.w - 1)
this.y = clamp(this.y - parseInt(y), 0, terminal.orca.h - 1)
this.calculateBounds()
+ terminal.toggleGuide(false)
terminal.update()
}
@@ -30,6 +38,7 @@ export default function Cursor (terminal) {
this.y = clamp(parseInt(y), 0, terminal.orca.h - 1)
this.calculateBounds()
+ terminal.toggleGuide(false)
terminal.update()
}
@@ -63,9 +72,10 @@ export default function Cursor (terminal) {
this.drag = function (x, y) {
if (isNaN(x) || isNaN(y)) { return }
this.mode = 0
- this.cut()
+ const block = this.getBlock()
+ this.erase()
this.move(x, y)
- this.paste()
+ this.writeBlock(block)
}
this.selectAll = function () {
@@ -100,21 +110,15 @@ export default function Cursor (terminal) {
}
this.copy = function () {
- const block = this.getBlock()
- var rows = []
- for (var i = 0; i < block.length; i++) {
- rows.push(block[i].join(''))
- }
- clipboard.writeText(rows.join('\n'))
+ document.execCommand('copy')
}
this.cut = function () {
- this.copy()
- this.erase()
+ document.execCommand('cut')
}
this.paste = function (overlap = false) {
- this.writeBlock(clipboard.readText().split(/\r?\n/), overlap)
+ document.execCommand('paste')
}
this.read = function () {
@@ -122,6 +126,7 @@ export default function Cursor (terminal) {
}
this.write = function (g) {
+ if (!terminal.orca.isAllowed(g)) { return }
if (terminal.orca.write(this.x, this.y, g) && this.mode === 1) {
this.move(1, 0)
}
@@ -246,6 +251,57 @@ export default function Cursor (terminal) {
)
}
+ this.mouseFrom = null
+
+ this.onMouseDown = (e) => {
+ const pos = this.tilePos(e.clientX, e.clientY)
+ this.select(pos.x, pos.y, 0, 0)
+ this.mouseFrom = pos
+ }
+
+ this.onMouseUp = (e) => {
+ if (this.mouseFrom) {
+ const pos = this.tilePos(e.clientX, e.clientY)
+ this.select(this.mouseFrom.x, this.mouseFrom.y, pos.x - this.mouseFrom.x, pos.y - this.mouseFrom.y)
+ }
+ this.mouseFrom = null
+ }
+
+ this.onMouseMove = (e) => {
+ if (!this.mouseFrom) { return }
+ const pos = this.tilePos(e.clientX, e.clientY)
+ this.select(this.mouseFrom.x, this.mouseFrom.y, pos.x - this.mouseFrom.x, pos.y - this.mouseFrom.y)
+ }
+
+ this.onCopy = (e) => {
+ const block = this.getBlock()
+ var rows = []
+ for (var i = 0; i < block.length; i++) {
+ rows.push(block[i].join(''))
+ }
+ const content = rows.join('\n')
+ const clipboard = e.clipboardData
+ e.clipboardData.setData('text/plain', content)
+ e.clipboardData.setData('text/source', content)
+ e.preventDefault()
+ }
+
+ this.onCut = (e) => {
+ this.onCopy(e)
+ this.erase()
+ }
+
+ this.onPaste = (e) => {
+ const data = e.clipboardData.getData('text/source')
+ this.writeBlock(data.split(/\r?\n/), false)
+ this.scaleTo(data.split('\n')[0].length, data.split('\n').length)
+ e.preventDefault()
+ }
+
+ this.tilePos = (x, y, w = terminal.tile.w, h = terminal.tile.h) => {
+ return { x: parseInt((x - 30) / w), y: parseInt((y - 30) / h) }
+ }
+
function sense (s) { return s === s.toUpperCase() && s.toLowerCase() !== s.toUpperCase() }
function clamp (v, min, max) { return v < min ? min : v > max ? max : v }
}
diff --git a/desktop/sources/scripts/lib/acels.js b/desktop/sources/scripts/lib/acels.js
new file mode 100644
index 0000000..962d58e
--- /dev/null
+++ b/desktop/sources/scripts/lib/acels.js
@@ -0,0 +1,123 @@
+'use strict'
+
+function Acels () {
+ this.all = {}
+ this.pipe = null
+
+ this.install = (host = window) => {
+ host.addEventListener('keydown', this.onKeyDown, false)
+ host.addEventListener('keyup', this.onKeyUp, false)
+ }
+
+ this.set = (cat, name, accelerator, downfn, upfn) => {
+ if (this.all[accelerator]) { console.warn('Acels', `Trying to overwrite ${this.all[accelerator].name}, with ${name}.`) }
+ this.all[accelerator] = { cat, name, downfn, upfn, accelerator }
+ }
+
+ this.get = (accelerator) => {
+ return this.all[accelerator]
+ }
+
+ this.sort = () => {
+ const h = {}
+ for (const item of Object.values(this.all)) {
+ if (!h[item.cat]) { h[item.cat] = [] }
+ h[item.cat].push(item)
+ }
+ return h
+ }
+
+ this.convert = (event) => {
+ const accelerator = event.key === ' ' ? 'Space' : event.key.substr(0, 1).toUpperCase() + event.key.substr(1)
+ if ((event.ctrlKey || event.metaKey) && event.shiftKey) {
+ return `CmdOrCtrl+Shift+${accelerator}`
+ }
+ if (event.shiftKey) {
+ return `Shift+${accelerator}`
+ }
+ if (event.altKey) {
+ return `Alt+${accelerator}`
+ }
+ if (event.ctrlKey || event.metaKey) {
+ return `CmdOrCtrl+${accelerator}`
+ }
+ return accelerator
+ }
+
+ this.pipe = (obj) => {
+ this.pipe = obj
+ }
+
+ this.onKeyDown = (e) => {
+ const target = this.get(this.convert(e))
+ if (!target || !target.downfn) { return this.pipe ? this.pipe.onKeyDown(e) : null }
+ target.downfn()
+ e.preventDefault()
+ }
+
+ this.onKeyUp = (e) => {
+ const target = this.get(this.convert(e))
+ if (!target || !target.upfn) { return this.pipe ? this.pipe.onKeyUp(e) : null }
+ target.upfn()
+ e.preventDefault()
+ }
+
+ this.toMarkdown = () => {
+ const cats = this.sort()
+ let text = ''
+ for (const cat in cats) {
+ text += `\n### ${cat}\n\n`
+ for (const item of cats[cat]) {
+ text += `- \`${item.accelerator}\`: ${item.info}\n`
+ }
+ }
+ return text.trim()
+ }
+
+ this.toString = () => {
+ const cats = this.sort()
+ let text = ''
+ for (const cat in cats) {
+ for (const item of cats[cat]) {
+ text += `${cat}: ${item.name} | ${item.accelerator}\n`
+ }
+ }
+ return text.trim()
+ }
+
+ // Electron specifics
+
+ this.inject = (name = 'Untitled') => {
+ const app = require('electron').remote.app
+ const injection = []
+
+ injection.push({
+ label: name,
+ submenu: [
+ { label: 'About', click: () => { require('electron').shell.openExternal('https://github.com/hundredrabbits/' + name) } },
+ { label: 'Download Themes', click: () => { require('electron').shell.openExternal('https://github.com/hundredrabbits/Themes') } },
+ { label: 'Fullscreen', accelerator: 'CmdOrCtrl+Enter', click: () => { app.toggleFullscreen() } },
+ { label: 'Hide', accelerator: 'CmdOrCtrl+H', click: () => { app.toggleVisible() } },
+ { label: 'Toggle Menubar', accelerator: 'Alt+H', click: () => { app.toggleMenubar() } },
+ { label: 'Inspect', accelerator: 'CmdOrCtrl+.', click: () => { app.inspect() } },
+ { label: 'Quit', accelerator: 'CmdOrCtrl+Q', click: () => { app.exit() } }
+ ]
+ })
+
+ const sorted = this.sort()
+ for (const cat of Object.keys(sorted)) {
+ const submenu = []
+ for (const option of sorted[cat]) {
+ if (option.role) {
+ submenu.push({ role: option.role })
+ } else if (option.type) {
+ submenu.push({ type: option.type })
+ } else {
+ submenu.push({ label: option.name, accelerator: option.accelerator, click: option.downfn })
+ }
+ }
+ injection.push({ label: cat, submenu: submenu })
+ }
+ app.injectMenu(injection)
+ }
+}
diff --git a/desktop/sources/scripts/lib/controller.js b/desktop/sources/scripts/lib/controller.js
deleted file mode 100644
index 6b81027..0000000
--- a/desktop/sources/scripts/lib/controller.js
+++ /dev/null
@@ -1,81 +0,0 @@
-'use strict'
-
-export default function Controller () {
- this.menu = { default: {} }
- this.mode = 'default'
- this.app = require('electron').remote.app
-
- this.start = function () {
- }
-
- this.add = function (mode, cat, label, fn, accelerator) {
- if (!this.menu[mode]) { this.menu[mode] = {} }
- if (!this.menu[mode][cat]) { this.menu[mode][cat] = {} }
- this.menu[mode][cat][label] = {
- fn: function (_menuItem, browserWindow) {
- browserWindow.webContents.focus()
- fn.apply(this, arguments)
- },
- accelerator: accelerator
- }
- }
-
- this.addRole = function (mode, cat, label) {
- if (!this.menu[mode]) { this.menu[mode] = {} }
- if (!this.menu[mode][cat]) { this.menu[mode][cat] = {} }
- this.menu[mode][cat][label] = { role: label }
- }
-
- this.addSpacer = function (mode, cat, label, type = 'separator') {
- if (!this.menu[mode]) { this.menu[mode] = {} }
- if (!this.menu[mode][cat]) { this.menu[mode][cat] = {} }
- this.menu[mode][cat][label] = { type: type }
- }
-
- this.clearCat = function (mode, cat) {
- if (this.menu[mode]) { this.menu[mode][cat] = {} }
- }
-
- this.set = function (mode = 'default') {
- this.mode = mode
- this.commit()
- }
-
- this.format = function () {
- const f = []
- const m = this.menu[this.mode]
- for (const cat in m) {
- const submenu = []
- for (const name in m[cat]) {
- const option = m[cat][name]
- if (option.role) {
- submenu.push({ role: option.role })
- } else if (option.type) {
- submenu.push({ type: option.type })
- } else {
- submenu.push({ label: name, accelerator: option.accelerator, click: option.fn })
- }
- }
- f.push({ label: cat, submenu: submenu })
- }
- return f
- }
-
- this.commit = function () {
- console.log('Controller', 'Changing..')
- this.app.injectMenu(this.format())
- }
-
- this.accelerator = function (key, menu) {
- const acc = { basic: null, ctrl: null }
- for (const cat in menu) {
- const options = menu[cat]
- for (const id in options.submenu) {
- const option = options.submenu[id]; if (option.role) { continue }
- acc.basic = (option.accelerator.toLowerCase() === key.toLowerCase()) ? option.label.toUpperCase().replace('TOGGLE ', '').substr(0, 8).trim() : acc.basic
- acc.ctrl = (option.accelerator.toLowerCase() === ('CmdOrCtrl+' + key).toLowerCase()) ? option.label.toUpperCase().replace('TOGGLE ', '').substr(0, 8).trim() : acc.ctrl
- }
- }
- return acc
- }
-}
diff --git a/desktop/sources/scripts/history.js b/desktop/sources/scripts/lib/history.js
index 1d77a58..1bbf0ae 100644
--- a/desktop/sources/scripts/history.js
+++ b/desktop/sources/scripts/lib/history.js
@@ -1,6 +1,6 @@
'use strict'
-export default function History () {
+function History () {
this.index = 0
this.frames = []
this.host = null
diff --git a/desktop/sources/scripts/lib/theme.js b/desktop/sources/scripts/lib/theme.js
index a2777fe..94061ed 100644
--- a/desktop/sources/scripts/lib/theme.js
+++ b/desktop/sources/scripts/lib/theme.js
@@ -1,20 +1,25 @@
'use strict'
-export default function Theme (_default) {
- const fs = require('fs')
- const url = require('url')
+/* global localStorage */
+/* global FileReader */
+/* global DOMParser */
- this.active = _default
+function Theme () {
+ const themer = this
+
+ this.default = { background: '#eee', f_high: '#000', f_med: '#999', f_low: '#ccc', f_inv: '#000', b_high: '#000', b_med: '#888', b_low: '#aaa', b_inv: '#ffb545' }
+ this.active = {}
this.el = document.createElement('style')
this.el.type = 'text/css'
- this.install = function (host = document.body, callback) {
+ this.install = (host = document.body, callback) => {
host.appendChild(this.el)
this.callback = callback
}
- this.start = function () {
+ this.start = () => {
+ this.active = this.default
console.log('Theme', 'Starting..')
if (isJson(localStorage.theme)) {
const storage = JSON.parse(localStorage.theme)
@@ -24,12 +29,12 @@ export default function Theme (_default) {
return
}
}
- this.load(_default)
+ this.load(this.active)
}
- this.load = function (data) {
+ this.load = (data) => {
const theme = parse(data)
- if (!validate(theme)) { console.warn('Theme', 'Not a theme', theme); return }
+ if (!validate(theme)) { return }
console.log('Theme', 'Loaded theme!')
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}; }`
localStorage.setItem('theme', JSON.stringify(theme))
@@ -39,18 +44,12 @@ export default function Theme (_default) {
}
}
- this.reset = function () {
- this.load(_default)
- }
-
- this.setImage = function (path) {
- document.body.style.backgroundImage = path && fs.existsSync(path) && document.body.style.backgroundImage !== `url(${url.pathToFileURL(path)})` ? `url(${url.pathToFileURL(path)})` : ''
+ this.reset = () => {
+ this.load(this.default)
}
- this.set = function (key, value) {
- if (!this.active[key]) { console.warn('Theme', 'Unknown key ' + key); return }
- if (!isColor(value)) { console.warn('Theme', 'Not a color ' + value); return }
- this.active[key] = '#' + value
+ this.get = (key) => {
+ return this.active[key]
}
function parse (any) {
@@ -60,7 +59,7 @@ export default function Theme (_default) {
// Drag
- this.drag = function (e) {
+ this.drag = (e) => {
e.stopPropagation()
e.preventDefault()
e.dataTransfer.dropEffect = 'copy'
@@ -71,10 +70,10 @@ export default function Theme (_default) {
e.stopPropagation()
const file = e.dataTransfer.files[0]
if (!file || !file.name) { console.warn('Theme', 'Unnamed file.'); return }
- if (file.name.indexOf('.thm') < 0 && file.name.indexOf('.svg') < 0) { console.warn('Theme', 'Skipped, not a theme'); return }
+ if (file.name.indexOf('.thm') < 0 && file.name.indexOf('.svg') < 0) { return }
const reader = new FileReader()
- reader.onload = (e) => {
- this.load(e.target.result)
+ reader.onload = function (e) {
+ themer.load(e.target.result)
}
reader.readAsText(file)
}
@@ -82,11 +81,12 @@ export default function Theme (_default) {
this.open = () => {
const fs = require('fs')
const { dialog, app } = require('electron').remote
- const paths = dialog.showOpenDialogSync(app.win, { properties: ['openFile'], filters: [{ name: 'Themes', extensions: ['svg'] }] })
+ const paths = dialog.showOpenDialog(app.win, { properties: ['openFile'], filters: [{ name: 'Themes', extensions: ['svg'] }] })
if (!paths) { console.log('Nothing to load'); return }
- const data = fs.readFileSync(paths[0], 'utf8')
- if (!data) { return }
- this.load(data)
+ fs.readFile(paths[0], 'utf8', function (err, data) {
+ if (err) throw err
+ themer.load(data)
+ })
}
window.addEventListener('dragover', this.drag)
@@ -131,10 +131,6 @@ export default function Theme (_default) {
try { JSON.parse(text); return true } catch (error) { return false }
}
- function isColor (str) {
- return /(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test('#' + str)
- }
-
function isHtml (text) {
try { new DOMParser().parseFromString(text, 'text/xml'); return true } catch (error) { return false }
}
diff --git a/desktop/sources/scripts/source.js b/desktop/sources/scripts/source.js
index 25a4095..61097b4 100644
--- a/desktop/sources/scripts/source.js
+++ b/desktop/sources/scripts/source.js
@@ -1,9 +1,11 @@
'use strict'
-export default function Source (terminal) {
+function Source (terminal) {
const fs = require('fs')
const path = require('path')
- const { dialog, app } = require('electron').remote
+ const electron = require('electron')
+ const dialog = electron ? electron.remote.dialog : null
+ const app = electron ? electron.remote.app : null
this.path = null
this.queue = []
@@ -29,11 +31,14 @@ export default function Source (terminal) {
const paths = dialog.showOpenDialogSync(app.win, { properties: ['openFile'], filters: [{ name: 'Orca Machines', extensions: ['orca'] }] })
if (!paths) { console.log('Nothing to load'); return }
this.read(paths[0])
+ terminal.toggleGuide(false)
}
this.save = function (quitAfter = false) {
console.log('Source', 'Saving file..')
- if (this.path) {
+ if (!require('electron')) {
+ this.download('orca', 'orca', this.generate(), 'text/plain')
+ } else if (this.path) {
this.write(this.path, this.generate(), quitAfter)
} else {
this.saveAs(quitAfter)
@@ -49,6 +54,17 @@ export default function Source (terminal) {
this.path = path
}
+ this.download = (name, ext, content, type, settings = 'charset=utf-8') => {
+ const link = document.createElement('a')
+ link.setAttribute('download', `${name}-${timestamp()}.${ext}`)
+ if (type === 'image/png' || type === 'image/jpeg') {
+ link.setAttribute('href', content)
+ } else {
+ link.setAttribute('href', 'data:' + type + ';' + settings + ',' + encodeURIComponent(content))
+ }
+ link.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true, view: window }))
+ }
+
this.revert = function () {
if (!this.path) { return }
console.log('Source', 'Revert a file..')
@@ -81,8 +97,10 @@ export default function Source (terminal) {
}
}
- this.read = function (loc = this.path) {
+ this.read = function (loc = this.path, content = '') {
if (!loc) { return }
+ if (!fs && !content) { console.warn('Source', 'FileSystem unavailable'); return }
+ if (!fs && content) { this.load(content); return }
if (!fs.existsSync(loc)) { console.warn('Source', 'File does not exist: ' + loc); return }
console.log('Source', 'Reading ' + loc)
this.path = loc
@@ -230,4 +248,9 @@ export default function Source (terminal) {
}
return c
}
+
+ function timestamp (d = new Date(), e = new Date(d)) {
+ const ms = e - d.setHours(0, 0, 0, 0)
+ return (ms / 8640 / 10000).toFixed(6).substr(2, 6)
+ }
}
diff --git a/desktop/sources/scripts/terminal.js b/desktop/sources/scripts/terminal.js
index 603cab2..3bb46ec 100644
--- a/desktop/sources/scripts/terminal.js
+++ b/desktop/sources/scripts/terminal.js
@@ -1,31 +1,23 @@
'use strict'
-import Orca from '../../core/orca.js'
-import IO from '../../core/io.js'
-import Cursor from './cursor.js'
-import Source from './source.js'
-import History from './history.js'
-import Commander from './commander.js'
-import Clock from './clock.js'
-import Theme from './lib/theme.js'
-import Controller from './lib/controller.js'
-import library from '../../core/library.js'
-
-export default function Terminal () {
- this.version = 145
+/* global library */
+
+function Terminal () {
+ this.version = 146
this.library = library
- this.orca = new Orca()
+ this.acels = new Acels()
+ this.orca = new Orca(this.library)
this.io = new IO(this)
this.cursor = new Cursor(this)
this.source = new Source(this)
this.commander = new Commander(this)
this.clock = new Clock(this)
this.history = new History()
- this.controller = new Controller()
// Themes
- 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' })
+ this.theme = new Theme()
+ this.theme.default = { 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' }
this.el = document.createElement('canvas')
this.context = this.el.getContext('2d')
@@ -44,82 +36,105 @@ export default function Terminal () {
host.appendChild(this.el)
this.theme.install(host)
- this.controller.add('default', '*', 'About', () => { require('electron').shell.openExternal('https://github.com/hundredrabbits/Orca') }, 'CmdOrCtrl+,')
- this.controller.add('default', '*', 'Fullscreen', () => { require('electron').remote.app.toggleFullscreen() }, 'CmdOrCtrl+Enter')
- this.controller.add('default', '*', 'Hide', () => { require('electron').remote.app.toggleVisible() }, 'CmdOrCtrl+H')
- this.controller.add('default', '*', 'Toggle Menubar', () => { require('electron').remote.app.toggleMenubar() }, 'Alt+H')
- this.controller.add('default', '*', 'Inspect', () => { require('electron').remote.app.inspect() }, 'CmdOrCtrl+.')
- this.controller.add('default', '*', 'Reset', () => { this.reset() }, 'CmdOrCtrl+Backspace')
- this.controller.add('default', '*', 'Quit', () => { this.io.silence(); this.source.quit() }, 'CmdOrCtrl+Q')
-
- this.controller.add('default', 'File', 'New', () => { this.source.new() }, 'CmdOrCtrl+N')
- this.controller.add('default', 'File', 'Save', () => { this.source.save() }, 'CmdOrCtrl+S')
- this.controller.add('default', 'File', 'Save As', () => { this.source.saveAs() }, 'CmdOrCtrl+Shift+S')
- this.controller.add('default', 'File', 'Open', () => { this.source.open() }, 'CmdOrCtrl+O')
- this.controller.add('default', 'File', 'Resume', () => { this.source.resume() })
- this.controller.add('default', 'File', 'Revert', () => { this.source.revert() }, 'CmdOrCtrl+W')
-
- this.controller.add('default', 'Edit', 'Toggle Insert Mode', () => { this.cursor.toggleMode(1) }, 'CmdOrCtrl+I')
- this.controller.add('default', 'Edit', 'Block Comment', () => { this.cursor.comment() }, 'CmdOrCtrl+/')
- this.controller.add('default', 'Edit', 'Find', () => { this.commander.start('find:') }, 'CmdOrCtrl+P')
- this.controller.add('default', 'Edit', 'Inject', () => { this.commander.start('inject:') }, 'CmdOrCtrl+J')
- this.controller.add('default', 'Edit', 'Trigger Operator', () => { this.cursor.trigger() }, 'CmdOrCtrl+B')
- this.controller.addSpacer('default', 'Edit', 'selection')
- this.controller.add('default', 'Edit', 'Select All', () => { this.cursor.selectAll() }, 'CmdOrCtrl+A')
- this.controller.add('default', 'Edit', 'Erase Selection', () => { this.cursor.erase() }, 'Backspace')
- this.controller.add('default', 'Edit', 'Copy Selection', () => { this.cursor.copy() }, 'CmdOrCtrl+C')
- this.controller.add('default', 'Edit', 'Cut Selection', () => { this.cursor.cut() }, 'CmdOrCtrl+X')
- this.controller.add('default', 'Edit', 'Paste Selection', () => { this.cursor.paste(false) }, 'CmdOrCtrl+V')
- this.controller.add('default', 'Edit', 'Paste Over', () => { this.cursor.paste(true) }, 'CmdOrCtrl+Shift+V')
- this.controller.add('default', 'Edit', 'Undo', () => { this.history.undo() }, 'CmdOrCtrl+Z')
- this.controller.add('default', 'Edit', 'Redo', () => { this.history.redo() }, 'CmdOrCtrl+Shift+Z')
-
- this.controller.add('default', 'Clock', 'Play/Pause', () => { this.clock.togglePlay(false) }, 'Space')
- this.controller.add('default', 'Clock', 'Frame By Frame', () => { this.clock.touch() }, 'CmdOrCtrl+F')
- this.controller.add('default', 'Clock', 'Reset Frame', () => { this.clock.resetFrame() }, 'CmdOrCtrl+R')
- this.controller.add('default', 'Clock', 'Incr. Speed', () => { this.clock.modSpeed(1) }, '>')
- this.controller.add('default', 'Clock', 'Decr. Speed', () => { this.clock.modSpeed(-1) }, '<')
- this.controller.add('default', 'Clock', 'Incr. Speed(10x)', () => { this.clock.modSpeed(10, true) }, 'CmdOrCtrl+>')
- this.controller.add('default', 'Clock', 'Decr. Speed(10x)', () => { this.clock.modSpeed(-10, true) }, 'CmdOrCtrl+<')
-
- this.controller.add('default', 'View', 'Zoom In', () => { this.modZoom(0.0625) }, 'CmdOrCtrl+=')
- this.controller.add('default', 'View', 'Zoom Out', () => { this.modZoom(-0.0625) }, 'CmdOrCtrl+-')
- this.controller.add('default', 'View', 'Zoom Reset', () => { this.modZoom(1, true) }, 'CmdOrCtrl+0')
- this.controller.add('default', 'View', 'Toggle Retina', () => { this.toggleRetina() }, '`')
- this.controller.add('default', 'View', 'Toggle Hardmode', () => { this.toggleHardmode() }, 'Tab')
- this.controller.add('default', 'View', 'Toggle Guide', () => { this.toggleGuide() }, 'CmdOrCtrl+G')
- this.controller.addSpacer('default', 'View', 'commander')
- this.controller.add('default', 'View', 'Toggle Commander', () => { this.commander.start() }, 'CmdOrCtrl+K')
- this.controller.add('default', 'View', 'Run Commander', () => { this.commander.run() }, 'Enter')
- this.controller.addSpacer('default', 'View', 'sizes')
- this.controller.add('default', 'View', 'Incr. Col', () => { this.modGrid(1, 0) }, ']')
- this.controller.add('default', 'View', 'Decr. Col', () => { this.modGrid(-1, 0) }, '[')
- this.controller.add('default', 'View', 'Incr. Row', () => { this.modGrid(0, 1) }, '}')
- this.controller.add('default', 'View', 'Decr. Row', () => { this.modGrid(0, -1) }, '{')
-
- this.controller.add('default', 'Midi', 'Default')
- this.controller.add('default', 'UDP', 'Default')
- this.controller.add('default', 'OSC', 'Default')
-
- this.controller.add('default', 'Theme', 'Open Theme', () => { this.theme.open() }, 'CmdOrCtrl+Shift+O')
- this.controller.add('default', 'Theme', 'Reset Theme', () => { this.theme.reset() }, 'CmdOrCtrl+Shift+Backspace')
- this.controller.addSpacer('default', 'Theme', 'Download')
- this.controller.add('default', 'Theme', 'Download Themes..', () => { require('electron').shell.openExternal('https://github.com/hundredrabbits/Themes') })
-
- this.controller.commit()
+ this.acels.set('File', 'New', 'CmdOrCtrl+N', () => { this.source.new() })
+ this.acels.set('File', 'Save', 'CmdOrCtrl+S', () => { this.source.save() })
+ this.acels.set('File', 'Save', 'CmdOrCtrl+Shift+S', () => { this.source.saveAs() })
+ this.acels.set('File', 'Open', 'CmdOrCtrl+O', () => { this.source.open() })
+ this.acels.set('File', 'Revert', 'CmdOrCtrl+W', () => { this.source.revert() })
+
+ this.acels.set('Edit', 'Select All', 'CmdOrCtrl+A', () => { this.cursor.selectAll() })
+ this.acels.set('Edit', 'Erase Selection', 'Backspace', () => { this.cursor.erase() })
+ // this.acels.set('Edit', 'Copy Selection', 'CmdOrCtrl+C', () => { this.cursor.copy() })
+ // this.acels.set('Edit', 'Cut Selection', 'CmdOrCtrl+X', () => { this.cursor.cut() })
+ // this.acels.set('Edit', 'Paste Selection', 'CmdOrCtrl+V', () => { this.cursor.paste(false) })
+ // this.acels.set('Edit', 'Paste Over', 'CmdOrCtrl+Shift+V', () => { this.cursor.paste(true) })
+ this.acels.set('Edit', 'Undo', 'CmdOrCtrl+Z', () => { this.history.undo() })
+ this.acels.set('Edit', 'Redo', 'CmdOrCtrl+Shift+Z', () => { this.history.redo() })
+
+ this.acels.set('Project', 'Find', 'CmdOrCtrl+J', () => { this.commander.start('find:') })
+ this.acels.set('Project', 'Inject', 'CmdOrCtrl+B', () => { this.commander.start('inject:') })
+ this.acels.set('Project', 'Toggle Commander', 'CmdOrCtrl+K', () => { this.commander.start() })
+ this.acels.set('Project', 'Run Commander', 'Enter', () => { this.commander.run() })
+
+ this.acels.set('Cursor', 'Toggle Insert Mode', 'CmdOrCtrl+I', () => { this.cursor.toggleMode(1) })
+ this.acels.set('Cursor', 'Toggle Block Comment', 'CmdOrCtrl+/', () => { this.cursor.comment() })
+ this.acels.set('Cursor', 'Trigger Operator', 'CmdOrCtrl+P', () => { this.cursor.trigger() })
+ this.acels.set('Cursor', 'Reset', 'Escape', () => { terminal.toggleGuide(false); terminal.commander.stop(); terminal.clear(); terminal.isPaused = false; terminal.cursor.reset() })
+
+ this.acels.set('Move', 'Move North', 'ArrowUp', () => { terminal.cursor.move(0, 1) })
+ this.acels.set('Move', 'Move East', 'ArrowRight', () => { terminal.cursor.move(1, 0) })
+ this.acels.set('Move', 'Move South', 'ArrowDown', () => { terminal.cursor.move(0, -1) })
+ this.acels.set('Move', 'Move West', 'ArrowLeft', () => { terminal.cursor.move(-1, 0) })
+ this.acels.set('Move', 'Scale North', 'Shift+ArrowUp', () => { terminal.cursor.scale(0, 1) })
+ this.acels.set('Move', 'Scale East', 'Shift+ArrowRight', () => { terminal.cursor.scale(1, 0) })
+ this.acels.set('Move', 'Scale South', 'Shift+ArrowDown', () => { terminal.cursor.scale(0, -1) })
+ this.acels.set('Move', 'Scale West', 'Shift+ArrowLeft', () => { terminal.cursor.scale(-1, 0) })
+ this.acels.set('Move', 'Drag North', 'Alt+ArrowUp', () => { terminal.cursor.drag(0, 1) })
+ this.acels.set('Move', 'Drag East', 'Alt+ArrowRight', () => { terminal.cursor.drag(1, 0) })
+ this.acels.set('Move', 'Drag South', 'Alt+ArrowDown', () => { terminal.cursor.drag(0, -1) })
+ this.acels.set('Move', 'Drag West', 'Alt+ArrowLeft', () => { terminal.cursor.drag(-1, 0) })
+ this.acels.set('Move', 'Move North(Leap)', 'CmdOrCtrl+ArrowUp', () => { terminal.cursor.move(0, this.grid.h) })
+ this.acels.set('Move', 'Move East(Leap)', 'CmdOrCtrl+ArrowRight', () => { terminal.cursor.move(this.grid.w, 0) })
+ this.acels.set('Move', 'Move South(Leap)', 'CmdOrCtrl+ArrowDown', () => { terminal.cursor.move(0, -this.grid.h) })
+ this.acels.set('Move', 'Move West(Leap)', 'CmdOrCtrl+ArrowLeft', () => { terminal.cursor.move(-this.grid.w, 0) })
+ this.acels.set('Move', 'Scale North(Leap)', 'CmdOrCtrl+Shift+ArrowUp', () => { terminal.cursor.scale(0, this.grid.h) })
+ this.acels.set('Move', 'Scale East(Leap)', 'CmdOrCtrl+Shift+ArrowRight', () => { terminal.cursor.scale(this.grid.w, 0) })
+ this.acels.set('Move', 'Scale South(Leap)', 'CmdOrCtrl+Shift+ArrowDown', () => { terminal.cursor.scale(0, -this.grid.h) })
+ this.acels.set('Move', 'Scale West(Leap)', 'CmdOrCtrl+Shift+ArrowLeft', () => { terminal.cursor.scale(-this.grid.w, 0) })
+ this.acels.set('Move', 'Drag North(Leap)', 'CmdOrCtrl+Alt+ArrowUp', () => { terminal.cursor.drag(0, this.grid.h) })
+ this.acels.set('Move', 'Drag East(Leap)', 'CmdOrCtrl+Alt+ArrowRight', () => { terminal.cursor.drag(this.grid.w, 0) })
+ this.acels.set('Move', 'Drag South(Leap)', 'CmdOrCtrl+Alt+ArrowDown', () => { terminal.cursor.drag(0, -this.grid.h) })
+ this.acels.set('Move', 'Drag West(Leap)', 'CmdOrCtrl+Alt+ArrowLeft', () => { terminal.cursor.drag(-this.grid.w, 0) })
+
+ this.acels.set('Clock', 'Play/Pause', 'Space', () => { this.clock.togglePlay() })
+ this.acels.set('Clock', 'Frame By Frame', 'CmdOrCtrl+F', () => { this.clock.touch() })
+ this.acels.set('Clock', 'Reset Frame', 'CmdOrCtrl+Shift+R', () => { this.clock.resetFrame() })
+ this.acels.set('Clock', 'Incr. Speed', 'Shift+>', () => { this.clock.modSpeed(1) })
+ this.acels.set('Clock', 'Decr. Speed', 'Shift+<', () => { this.clock.modSpeed(-1) })
+ this.acels.set('Clock', 'Incr. Speed(10x)', 'CmdOrCtrl+>', () => { this.clock.modSpeed(10, true) })
+ this.acels.set('Clock', 'Decr. Speed(10x)', 'CmdOrCtrl+<', () => { this.clock.modSpeed(-10, true) })
+
+ this.acels.set('View', 'Toggle Retina', '`', () => { this.toggleRetina() })
+ this.acels.set('View', 'Toggle Hardmode', 'Tab', () => { this.toggleHardmode() })
+ this.acels.set('View', 'Toggle Guide', 'CmdOrCtrl+G', () => { this.toggleGuide() })
+ this.acels.set('View', 'Incr. Col', ']', () => { this.modGrid(1, 0) })
+ this.acels.set('View', 'Decr. Col', '[', () => { this.modGrid(-1, 0) })
+ this.acels.set('View', 'Incr. Row', '}', () => { this.modGrid(0, 1) })
+ this.acels.set('View', 'Decr. Row', '{', () => { this.modGrid(0, -1) })
+ this.acels.set('View', 'Zoom In', 'CmdOrCtrl+=', () => { this.modZoom(0.0625) })
+ this.acels.set('View', 'Zoom Out', 'CmdOrCtrl+-', () => { this.modZoom(-0.0625) })
+ this.acels.set('View', 'Zoom Reset', 'CmdOrCtrl+0', () => { this.modZoom(1, true) })
+
+ this.acels.set('Midi', 'Play/Pause Midi', 'Shift+Space', () => { this.clock.togglePlay(true) })
+ this.acels.set('Midi', 'Next Input Device', 'CmdOrCtrl+}', () => { this.io.midi.selectNextInput() })
+ this.acels.set('Midi', 'Next Output Device', 'CmdOrCtrl+]', () => { this.io.midi.selectNextOutput() })
+ this.acels.set('Midi', 'Refresh Devices', 'CmdOrCtrl+Shift+M', () => { this.io.midi.refresh() })
+
+ this.acels.set('Communication', 'Choose OSC Port', 'CmdOrCtrl+Shift+O', () => { this.commander.start('osc:') })
+ this.acels.set('Communication', 'Choose UDP Port', 'CmdOrCtrl+Shift+U', () => { this.commander.start('udp:') })
+
+ this.acels.install(window)
+ this.acels.pipe(this.commander)
}
this.start = () => {
+ console.info('Terminal', 'Starting..')
+ console.info(`${this.acels}`)
this.theme.start()
this.io.start()
this.source.start()
this.history.bind(this.orca, 's')
this.history.record(this.orca.s)
this.clock.start()
+ this.cursor.start()
this.update()
this.el.className = 'ready'
- this.toggleGuide(this.reqGuide() === true)
+ this.toggleGuide()
+ }
+
+ this.whenOpen = (file) => {
+
}
this.run = () => {
@@ -306,26 +321,24 @@ export default function Terminal () {
const col = this.grid.w
const variables = Object.keys(this.orca.variables).join('')
- if (this.commander.isActive === true) {
- this.write(`${this.commander.query}${this.orca.f % 2 === 0 ? '_' : ''}`, col * 0, this.orca.h + 1, this.grid.w * 4)
- } else {
- this.write(`${this.cursor.x},${this.cursor.y}${this.cursor.mode === 1 ? '+' : ''}`, col * 0, this.orca.h + 1, this.grid.w, this.cursor.mode === 1 ? 1 : 2)
- this.write(`${this.cursor.w}:${this.cursor.h}`, col * 1, this.orca.h + 1, this.grid.w)
- this.write(`${this.cursor.inspect()}`, col * 2, this.orca.h + 1, this.grid.w)
- this.write(`${this.orca.f}f${this.isPaused ? '*' : ''}`, col * 3, this.orca.h + 1, this.grid.w)
- }
+ // Top Row(cursor)
+
+ this.write(this.orca.f < 15 ? `ver${this.version}` : `${this.cursor.inspect()}`, col * 0, this.orca.h, this.grid.w)
+ this.write(`${this.cursor.x},${this.cursor.y}${this.cursor.mode === 1 ? '+' : ''}`, col * 1, this.orca.h, this.grid.w, this.cursor.mode === 1 ? 1 : 2)
+ this.write(`${this.cursor.w}:${this.cursor.h}`, col * 2, this.orca.h, this.grid.w)
+ this.write(`${this.orca.f}f${this.isPaused ? '*' : ''}`, col * 3, this.orca.h, this.grid.w)
+ this.write(`${this.io.inspect(this.grid.w)}`, col * 4, this.orca.h, this.grid.w)
- this.write(`${this.orca.w}x${this.orca.h}`, col * 0, this.orca.h, this.grid.w)
- this.write(`${this.grid.w}/${this.grid.h}${this.tile.w !== 10 ? ' ' + (this.tile.w / 10).toFixed(1) : ''}`, col * 1, this.orca.h, this.grid.w)
- this.write(`${this.source}`, col * 2, this.orca.h, this.grid.w, this.source.queue.length > this.orca.f ? 3 : 2)
- this.write(`${this.clock}`, col * 3, this.orca.h, this.grid.w, this.clock.isPuppet === true ? 3 : 2)
+ // Low Row(project)
- if (this.orca.f < 15) {
- this.write(`${this.io.midi}`, col * 4, this.orca.h, this.grid.w * 2)
- this.write(`Version ${this.version}`, col * 4, this.orca.h + 1, this.grid.w * 2)
+ if (this.commander.isActive === true) {
+ this.write(`${this.commander.query}${this.orca.f % 2 === 0 ? '_' : ''}`, col * 0, this.orca.h + 1, this.grid.w * 4)
} else {
- this.write(`${this.io.inspect(this.grid.w)}`, col * 4, this.orca.h, this.grid.w)
- this.write(`${display(variables, this.orca.f, this.grid.w)}`, col * 4, this.orca.h + 1, this.grid.w)
+ this.write(`${this.source}`, col * 0, this.orca.h + 1, this.grid.w, this.source.queue.length > this.orca.f ? 3 : 2)
+ this.write(`${this.orca.w}x${this.orca.h}`, col * 1, this.orca.h + 1, this.grid.w)
+ this.write(`${this.grid.w}/${this.grid.h}${this.tile.w !== 10 ? ' ' + (this.tile.w / 10).toFixed(1) : ''}`, col * 2, this.orca.h + 1, this.grid.w)
+ this.write(`${this.clock}`, col * 3, this.orca.h + 1, this.grid.w, this.clock.isPuppet === true ? 3 : 2)
+ this.write(`${this.io.midi}`, col * 4, this.orca.h + 1, this.grid.w * 4)
}
}
@@ -369,6 +382,7 @@ export default function Terminal () {
// Resize tools
this.fit = () => {
+ if (!require('electron')) { return }
const size = { w: (this.orca.w * this.tile.w) + 60, h: (this.orca.h * this.tile.h) + 60 + (2 * this.tile.h) }
const win = require('electron').remote.getCurrentWindow()
const winSize = win.getSize()
@@ -457,7 +471,11 @@ export default function Terminal () {
if (!path || path.indexOf('.orca') < 0) { console.log('Orca', 'Not a orca file'); return }
- this.source.read(path)
+ const reader = new FileReader()
+ reader.onload = (event) => {
+ this.source.read(path, event.target.result)
+ }
+ reader.readAsText(file, 'UTF-8')
})
window.onresize = (event) => {
diff --git a/desktop/sources/scripts/timer.js b/desktop/sources/scripts/timer.js
deleted file mode 100644
index 823094f..0000000
--- a/desktop/sources/scripts/timer.js
+++ /dev/null
@@ -1,6 +0,0 @@
-'use strict'
-
-onmessage = (event) => {
- console.log('Timer', 'New Interval ' + event.data + 'ms')
- setInterval(() => { postMessage(true) }, event.data)
-}
diff --git a/index.html b/index.html
index 18ce528..849596e 100644
--- a/index.html
+++ b/index.html
@@ -1,40 +1,49 @@
<html>
<head>
- <meta charset='utf-8'>
- <!-- Basic -->
- <meta name='author' content='Devine Lu Linvega'>
- <meta name='description' content='Orca: Esoteric Programming Language'/>
- <meta name='keywords' content='Orca, livecoding, programming language, lisp, udp, midi, ide' />
- <meta name='license' content='name=BY-NC-SA(4.0), url=https://creativecommons.org/licenses/by-nc-sa/4.0/'/>
- <meta name='thumbnail' content='https://wiki.xxiivv.com/media/services/thumbnail.jpg' />
- <!-- Twitter -->
- <meta name='twitter:card' content='summary'>
- <meta name='twitter:site' content='@neauoire'>
- <meta name='twitter:title' content='Orca'>
- <meta name='twitter:description' content='An Esoteric Programming Language'>
- <meta name='twitter:creator' content='@neauoire'>
- <meta name='twitter:image' content='https://wiki.xxiivv.com/media/services/rss.jpg'>
- <!-- Facebook -->
- <meta property='og:title' content='Orca' />
- <meta property='og:type' content='article' />
- <meta property='og:url' content='http://wiki.xxiivv.com/' />
- <meta property='og:image' content='https://wiki.xxiivv.com/media/services/rss.jpg' />
- <meta property='og:description' content='An Esoteric Programming Language' />
- <meta property='og:site_name' content='XXIIVV' />
- <!-- Defaults -->
+ <meta charset='utf-8'>
<link rel="stylesheet" type="text/css" href="desktop/sources/links/style.css"/>
+
+ <script type="text/javascript">
+ function require(name){
+ console.warn('Failed to require '+name)
+ }
+ </script>
+
+ <script type="text/javascript" src="desktop/sources/scripts/lib/acels.js"></script>
+ <script type="text/javascript" src="desktop/sources/scripts/lib/theme.js"></script>
+ <script type="text/javascript" src="desktop/sources/scripts/lib/history.js"></script>
+
+ <script type="text/javascript" src="desktop/sources/scripts/core/library.js"></script>
+ <script type="text/javascript" src="desktop/sources/scripts/core/io.js"></script>
+ <script type="text/javascript" src="desktop/sources/scripts/core/operator.js"></script>
+ <script type="text/javascript" src="desktop/sources/scripts/core/orca.js"></script>
+ <script type="text/javascript" src="desktop/sources/scripts/core/transpose.js"></script>
+
+ <script type="text/javascript" src="desktop/sources/scripts/core/io/cc.js"></script>
+ <script type="text/javascript" src="desktop/sources/scripts/core/io/midi.js"></script>
+ <script type="text/javascript" src="desktop/sources/scripts/core/io/mono.js"></script>
+ <script type="text/javascript" src="desktop/sources/scripts/core/io/osc.js"></script>
+ <script type="text/javascript" src="desktop/sources/scripts/core/io/udp.js"></script>
+
+ <script type="text/javascript" src="desktop/sources/scripts/clock.js"></script>
+ <script type="text/javascript" src="desktop/sources/scripts/commander.js"></script>
+ <script type="text/javascript" src="desktop/sources/scripts/cursor.js"></script>
+ <script type="text/javascript" src="desktop/sources/scripts/source.js"></script>
+ <script type="text/javascript" src="desktop/sources/scripts/terminal.js"></script>
+
<title>Orca — Web</title>
</head>
<body>
- <script type="module" src="browser/mock/require.js"></script>
- <script type="module">
- console.clear()
- import Terminal from "./desktop/sources/scripts/terminal.js";
+ <script>
+ 'use strict'
+
const terminal = new Terminal()
- window.__dirname = "desktop/sources";
- window.terminal = terminal
+
terminal.install(document.body)
- terminal.start()
+
+ window.addEventListener('load', () => {
+ terminal.start()
+ })
</script>
</body>
</html>