aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--TUTORIAL.md8
-rw-r--r--desktop/core/io.js (renamed from desktop/sources/scripts/io.js)8
-rw-r--r--desktop/core/io/cc.js (renamed from desktop/sources/scripts/io.cc.js)0
-rw-r--r--desktop/core/io/midi.js (renamed from desktop/sources/scripts/io.midi.js)4
-rw-r--r--desktop/core/io/osc.js (renamed from desktop/sources/scripts/io.osc.js)0
-rw-r--r--desktop/core/io/udp.js (renamed from desktop/sources/scripts/io.udp.js)2
-rw-r--r--desktop/sources/index.html14
-rw-r--r--desktop/sources/scripts/clock.js89
-rw-r--r--desktop/sources/scripts/io.midi.clock.js85
-rw-r--r--desktop/sources/scripts/io.osc-standalone.js123
-rw-r--r--desktop/sources/scripts/keyboard.js6
-rw-r--r--desktop/sources/scripts/lib/theme.js2
-rw-r--r--desktop/sources/scripts/source.js12
-rw-r--r--desktop/sources/scripts/terminal.js85
14 files changed, 89 insertions, 349 deletions
diff --git a/TUTORIAL.md b/TUTORIAL.md
index 34d81eb..393d1db 100644
--- a/TUTORIAL.md
+++ b/TUTORIAL.md
@@ -6,14 +6,6 @@ If this is your first time trying out **Orca**, watch this [introduction video](
If you are on Windows, use something like [loopMidi](http://www.tobias-erichsen.de/software/loopmidi.html) to help routing midi signal across applications.
-#### Using MIDI beat clock instead of the built in clock
-
-Orca comes with its own internal clock but you can configure it to receive its clock signal from a MIDI input.
-Press `Ctrl+Space` to cycle through available clocks (built in or MIDI inputs).
-The MIDI clock listens for the START and STOP signals from the midi device to run.
-
-*Warning*: Note length when using the MIDI clock is currently based on note length at 120 BPM.
-
## MIDI CC
#### Easy Binding
diff --git a/desktop/sources/scripts/io.js b/desktop/core/io.js
index a92710a..3f3e19a 100644
--- a/desktop/sources/scripts/io.js
+++ b/desktop/core/io.js
@@ -1,9 +1,9 @@
'use strict'
-const Midi = require('./io.midi')
-const MidiCC = require('./io.cc')
-const Udp = require('./io.udp')
-const Osc = require('./io.osc')
+const Midi = require('./io/midi')
+const MidiCC = require('./io/cc')
+const Udp = require('./io/udp')
+const Osc = require('./io/osc')
function IO (terminal) {
this.midi = new Midi(terminal)
diff --git a/desktop/sources/scripts/io.cc.js b/desktop/core/io/cc.js
index 5355d65..5355d65 100644
--- a/desktop/sources/scripts/io.cc.js
+++ b/desktop/core/io/cc.js
diff --git a/desktop/sources/scripts/io.midi.js b/desktop/core/io/midi.js
index 271336d..593ac3c 100644
--- a/desktop/sources/scripts/io.midi.js
+++ b/desktop/core/io/midi.js
@@ -1,17 +1,13 @@
'use strict'
-const MidiClock = require('./io.midi.clock')
-
function Midi (terminal) {
this.index = 0
this.devices = []
this.stack = []
- this.clock = new MidiClock(terminal)
this.start = function () {
console.info('Midi Starting..')
this.setup()
- this.clock.start()
}
this.clear = function () {
diff --git a/desktop/sources/scripts/io.osc.js b/desktop/core/io/osc.js
index c761ced..c761ced 100644
--- a/desktop/sources/scripts/io.osc.js
+++ b/desktop/core/io/osc.js
diff --git a/desktop/sources/scripts/io.udp.js b/desktop/core/io/udp.js
index cb595ec..2a4f371 100644
--- a/desktop/sources/scripts/io.udp.js
+++ b/desktop/core/io/udp.js
@@ -71,7 +71,7 @@ function Udp (terminal) {
const val = `${msg}`.substr(1)
const int = parseInt(`${msg}`.substr(1))
if (key === 'p') {
- terminal.play()
+ terminal.clock.play()
} else if (key === 's') {
terminal.stop()
} else if (key === 'r') {
diff --git a/desktop/sources/index.html b/desktop/sources/index.html
index 8f573cc..59eae2f 100644
--- a/desktop/sources/index.html
+++ b/desktop/sources/index.html
@@ -43,17 +43,17 @@
terminal.controller.add("default","Edit","Undo",() => { terminal.history.undo() },"CmdOrCtrl+Z")
terminal.controller.add("default","Edit","Redo",() => { terminal.history.redo() },"CmdOrCtrl+Shift+Z")
- terminal.controller.add("default","Program","Play/Pause",() => { terminal.togglePlay() },"Space")
- terminal.controller.add("default","Program","Reset Frame",() => { terminal.orca.f = 0 },"CmdOrCtrl+Shift+N")
- terminal.controller.add("default","Program","Prev Frame",() => { terminal.prevFrame() },"CmdOrCtrl+Shift+F")
- terminal.controller.add("default","Program","Next Frame",() => { terminal.nextFrame() },"CmdOrCtrl+F")
- terminal.controller.add("default","Program","Incr. Speed",() => { terminal.modSpeed(1) },">")
- terminal.controller.add("default","Program","Decr. Speed",() => { terminal.modSpeed(-1) },"<")
terminal.controller.add("default","Program","Incr. Col",() => { terminal.modGrid(1,0) },"]")
terminal.controller.add("default","Program","Decr. Col",() => { terminal.modGrid(-1,0) },"[")
terminal.controller.add("default","Program","Incr. Row",() => { terminal.modGrid(0,1) },"}")
terminal.controller.add("default","Program","Decr. Row",() => { terminal.modGrid(0,-1) },"{")
- terminal.controller.add("default","Program","Next Clock", () => { terminal.nextClock() }, "Ctrl+Space")
+
+ terminal.controller.add("default","Clock","Play/Pause",() => { terminal.clock.togglePlay() },"Space")
+ terminal.controller.add("default","Clock","Reset Frame",() => { terminal.clock.resetFrame() },"CmdOrCtrl+Shift+N")
+ terminal.controller.add("default","Clock","Incr. Speed",() => { terminal.clock.modSpeed(1) },">")
+ terminal.controller.add("default","Clock","Decr. Speed",() => { terminal.clock.modSpeed(-1) },"<")
+ terminal.controller.add("default","Clock","Incr. Speed(10x)",() => { terminal.clock.modSpeed(10,true) },"cmdOrCtrl+>")
+ terminal.controller.add("default","Clock","Decr. Speed(10x)",() => { terminal.clock.modSpeed(-10,true) },"cmdOrCtrl+<")
terminal.controller.add("default","View","Zoom In",() => { terminal.modZoom(0.25) },"CmdOrCtrl+=")
terminal.controller.add("default","View","Zoom Out",() => { terminal.modZoom(-0.25) },"CmdOrCtrl+-")
diff --git a/desktop/sources/scripts/clock.js b/desktop/sources/scripts/clock.js
index e1c0fda..b2b826f 100644
--- a/desktop/sources/scripts/clock.js
+++ b/desktop/sources/scripts/clock.js
@@ -1,56 +1,87 @@
'use strict'
-class Clock {
- constructor (bpm, callback) {
- this.bpm = 0
- this.callback = () => {}
- this.timer = null
- this.running = false
- this.setBpm(bpm)
+function Clock (terminal) {
+ this.isPaused = true
+ this.timer = null
+
+ this.speed = { value: 120, target: 120 }
+
+ this.start = function () {
+ this.setTimer(120)
+ this.play()
}
- setCallback (callback) {
- this.callback = callback
+ this.update = function () {
+ if (this.speed.target === this.speed.value) { return }
+
+ this.setTimer(this.speed.value)
+
+ if (this.speed.value < this.speed.target) { this.speed.value++ }
+ if (this.speed.value > this.speed.target) { this.speed.value-- }
}
- canSetBpm () {
- return true
+ this.togglePlay = function () {
+ if (this.isPaused === true) {
+ this.play()
+ } else {
+ this.stop()
+ }
}
- getBpm () {
- return this.bpm
+ this.play = function () {
+ if (!this.isPaused) { console.warn('Already playing'); return }
+ console.log('Play')
+ this.isPaused = false
+ this.setTimer(this.speed.target)
}
- setBpm (bpm) {
- this.bpm = bpm
- this.reset()
+ this.stop = function () {
+ if (this.isPaused) { console.warn('Already stopped'); return }
+ console.log('Stop')
+ terminal.io.midi.silence()
+ this.isPaused = true
+ this.clearTimer()
}
- reset () {
+ this.clearTimer = function () {
if (this.timer) {
clearInterval(this.timer)
}
+ }
- if (this.running) {
- this.timer = setInterval(() => { this.callback() }, (60000 / this.bpm) / 4)
- }
+ this.setTimer = function (bpm) {
+ this.speed.value = bpm
+ this.clearTimer()
+ this.timer = setInterval(() => { terminal.run(); this.update() }, (60000 / bpm) / 4)
}
- setRunning (running) {
- this.running = running
- this.reset()
+ this.setSpeed = function (bpm, animate = false) {
+ if (animate) {
+ this.speed.target = bpm
+ } else {
+ this.setTimer(bpm)
+ }
}
- start () {
- this.setRunning(true)
+ this.modSpeed = function (mod = 0, animate = false) {
+ if (animate === true) {
+ this.speed.target += mod
+ } else {
+ this.setTimer(this.speed.value + mod)
+ this.speed.target = this.speed.value
+ terminal.update()
+ }
}
- stop () {
- this.setRunning(false)
+ this.resetFrame = function () {
+ terminal.orca.f = 0
}
- toString () {
- return `${this.bpm}`
+ this.toString = function () {
+ const diff = this.speed.target - this.speed.value
+ const _offset = diff > 0 ? `+${diff}` : diff < 0 ? diff : ''
+ const _beat = diff === 0 && terminal.orca.f % 4 === 0 ? '*' : ''
+ return `${this.speed.value}${_offset}${_beat}`
}
}
diff --git a/desktop/sources/scripts/io.midi.clock.js b/desktop/sources/scripts/io.midi.clock.js
deleted file mode 100644
index e9bd786..0000000
--- a/desktop/sources/scripts/io.midi.clock.js
+++ /dev/null
@@ -1,85 +0,0 @@
-'use strict'
-
-class WrappedClock {
- constructor (device) {
- this.device = device
- this.running = false
- this.callback = () => {}
- this.count = 0
- this.started = false
- this.signals = {
- CLOCK: 0xF8,
- START: 0xFA,
- STOP: 0xFC
- }
- }
-
- canSetBpm () {
- return false
- }
-
- setCallback (callback) {
- this.callback = callback
- }
-
- setRunning (running) {
- this.running = running
- this.reset()
- }
-
- reset () {
- if (this.running) {
- this.device.onmidimessage = (message) => { this.onMIDIMessage(message) }
- } else {
- this.device.onmidimessage = null
- }
- }
-
- toString () {
- return `${this.device.name}`
- }
-
- onMIDIMessage (message) {
- switch (message.data[0]) {
- case this.signals.CLOCK:
- this.count = (this.count + 1) % 6
- if (this.count === 0 && this.started) {
- this.callback()
- }
- break
- case this.signals.START:
- this.started = true
- break
- case this.signals.STOP:
- this.started = false
- break
- }
- }
-}
-
-class MidiClock {
- constructor (terminal) {
- this.terminal = terminal
- }
-
- start () {
- console.info('Midi Clock Starting..')
- this.setup()
- }
-
- setup () {
- if (!navigator.requestMIDIAccess) { return }
- navigator.requestMIDIAccess({ sysex: false }).then((midiAccess) => { this.onMIDIAccess(midiAccess) }, (err) => {
- console.warn('No Midi', err)
- })
- }
-
- onMIDIAccess (midiAccess) {
- const iter = midiAccess.inputs.values()
- for (let i = iter.next(); i && !i.done; i = iter.next()) {
- this.terminal.clocks.push(new WrappedClock(i.value))
- }
- }
-}
-
-module.exports = MidiClock
diff --git a/desktop/sources/scripts/io.osc-standalone.js b/desktop/sources/scripts/io.osc-standalone.js
deleted file mode 100644
index f8b3fd1..0000000
--- a/desktop/sources/scripts/io.osc-standalone.js
+++ /dev/null
@@ -1,123 +0,0 @@
-'use strict'
-
-function Osc (terminal) {
- this.index = 0
- this.routes = []
- this.stack = []
-
- this.start = function () {
- console.info('Starting OSC..')
- this.setup()
- }
-
- this.clear = function () {
- this.stack = []
- }
-
- this.run = function () {
- for (const id in this.stack) {
- this.play(this.stack[id])
- }
- }
-
- this.send = function (msg) {
- this.stack.push(msg)
- }
-
- this.play = function (data) {
- // see io.osc.js
-
- // const args = data.split('.').filter(d => d !== '')
- // if (args.length !== 0) {
- // const key = args[0]
- // const def = this.config.defs[key]
- // const pattern = def.pattern
-
- // if(pattern.length !== args.length - 1) {
- // console.log(`Number of arguments provided does not match the pattern length of this def`)
- // return
- // }
-
- // const values = []
- // for(let i = 0, l = pattern.length; i < l; i++) {
- // const type = pattern[i]
- // if (type !== 'f' && type !== 'i' && type !== 's') {
- // console.log(`Don't know how to send OSC argument with type '${type}'`)
- // return
- // }
-
- // const value =
- // type === 'f' ? parseInt(split[1]) / 10.0
- // : type === 'i' ? parseInt(split[1])
- // /* type === 's' ? */ : split[1]
-
- // function nextMultipleOf4 (x) {
- // const rem = x % 4
- // return rem === 0 ? x : (x + 4 - rem)
- // }
-
- // function writeOscString (val, buf, pos) {
- // let localPos = pos
- // for (let i = 0; i < val.length; i++) {
- // const ch = val.charCodeAt(i)
- // localPos = buf.writeUInt8(ch & 0xFF, localPos)
- // }
- // // Add length, terminating 0 and pad to multiple of 4
- // return nextMultipleOf4(pos + val.length + 1)
- // }
-
- // let msglen = 0
- // { // Calculate message length
- // // Zero-terminated address string
- // msglen += nextMultipleOf4(address.length + 1)
- // // Type tag with two args arg: comma, letter (key), letter (value), terminating 0
- // msglen += 4
- // // Zero-terminated key string
- // msglen += nextMultipleOf4(key.length + 1)
- // if (type === 'f' || type === 'i') {
- // // 32-bit float or int
- // msglen += 4
- // } else if (type === 's') {
- // // Zero terminated value string
- // msglen += nextMultipleOf4(value.length + 1)
- // }
- // }
-
- // // Get buffer cleared to 0
- // const buf = Buffer.alloc(msglen)
- // let pos = 0
-
- // pos = writeOscString(address, buf, pos)
- // pos = writeOscString(`,s${type}`, buf, pos)
- // pos = writeOscString(key, buf, pos)
-
- // if (type === 'f') {
- // pos = buf.writeFloatBE(value, pos)
- // } else if (type === 'i') {
- // pos = buf.writeInt32BE(value, pos)
- // } else if (type === 's') {
- // pos = writeOscString(value, buf, pos)
- // }
- // }
-
- // this.port.send(buf, def.port, def.address, (err) => {
- // if (err) { console.log(err) }
- // })
- }
-
- this.setup = function () {
- this.config = require('../../core/bridge/oscConfig')
- this.clients = {}
- for (const key in this.config.defs) {
- const def = this.config.defs[key]
- const address = def.address
- const port = def.port
- if (!this.clients[`${address}:${port}`]) {
- this.clients[`${address}:${port}`] = new osc.Client(address, port)
- console.log(`OSC client ${address}:${port} created`)
- }
- }
- }
-}
-
-module.exports = Osc
diff --git a/desktop/sources/scripts/keyboard.js b/desktop/sources/scripts/keyboard.js
index e7444cc..90a6139 100644
--- a/desktop/sources/scripts/keyboard.js
+++ b/desktop/sources/scripts/keyboard.js
@@ -29,15 +29,15 @@ function Keyboard (terminal) {
if (event.ctrlKey) { return }
if (event.key === 'Backspace' || event.key === '.') { terminal.cursor.erase(true); return }
- if (event.key === ' ' && terminal.cursor.mode === 0) { terminal.togglePlay(); event.preventDefault(); return }
+ if (event.key === ' ' && terminal.cursor.mode === 0) { terminal.clock.togglePlay(); event.preventDefault(); return }
if (event.key === 'Escape') { terminal.clear(); terminal.isPaused = false; terminal.cursor.reset(); 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.modSpeed(1); event.preventDefault(); return }
- if (event.key === '<') { terminal.modSpeed(-1); event.preventDefault(); return }
+ if (event.key === '>') { terminal.clock.modSpeed(1); event.preventDefault(); return }
+ if (event.key === '<') { terminal.clock.modSpeed(-1); event.preventDefault(); return }
if (event.key.length === 1) {
terminal.cursor.write(event.key)
diff --git a/desktop/sources/scripts/lib/theme.js b/desktop/sources/scripts/lib/theme.js
index 6fb3c41..87e3ab3 100644
--- a/desktop/sources/scripts/lib/theme.js
+++ b/desktop/sources/scripts/lib/theme.js
@@ -29,7 +29,7 @@ function Theme (_default) {
this.load = function (data) {
const theme = parse(data)
if (!validate(theme)) { console.warn('Theme', 'Not a theme', theme); return }
- console.log('Theme', `Load theme, background: ${theme.background}.`)
+ 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))
this.active = theme
diff --git a/desktop/sources/scripts/source.js b/desktop/sources/scripts/source.js
index 9c7912e..4eef97d 100644
--- a/desktop/sources/scripts/source.js
+++ b/desktop/sources/scripts/source.js
@@ -11,23 +11,23 @@ function Source (terminal) {
}
this.new = function () {
- console.log('Source', 'New File')
+ console.log('Source', 'Make a new file..')
this.path = null
terminal.orca.reset()
terminal.resize()
terminal.history.reset()
- terminal.play()
+ terminal.clock.play()
}
this.open = function () {
- console.log('Source', 'Open File')
+ console.log('Source', 'Open a file..')
let paths = dialog.showOpenDialog(app.win, { properties: ['openFile'], filters: [{ name: 'Orca Machines', extensions: ['orca'] }] })
if (!paths) { console.log('Nothing to load') }
this.read(paths[0])
}
this.save = function (as = false) {
- console.log('Source', 'Save File')
+ console.log('Source', 'Save a file..')
if (this.path && !as) {
this.write(this.path)
} else {
@@ -35,7 +35,7 @@ function Source (terminal) {
}
}
this.saveAs = function () {
- console.log('Source', 'Save File As')
+ console.log('Source', 'Save a file as..')
dialog.showSaveDialog((path) => {
if (path === undefined) { return }
if (path.indexOf('.orca') < 0) { path += '.orca' }
@@ -46,7 +46,7 @@ function Source (terminal) {
this.revert = function () {
if (!this.path) { return }
- console.log('Source', 'Revert File')
+ console.log('Source', 'Revert a file..')
this.read(this.path)
}
diff --git a/desktop/sources/scripts/terminal.js b/desktop/sources/scripts/terminal.js
index 6b96068..74837be 100644
--- a/desktop/sources/scripts/terminal.js
+++ b/desktop/sources/scripts/terminal.js
@@ -2,24 +2,24 @@
function Terminal () {
const Orca = require('../../core/orca')
+ const IO = require('../../core/io')
const Cursor = require('./cursor')
const Source = require('./source')
const History = require('./history')
const Keyboard = require('./keyboard')
- const IO = require('./io')
const Clock = require('./clock')
this.library = require('../../core/library')
+ this.history = new History()
+ this.controller = new Controller()
+
this.orca = new Orca()
this.io = new IO(this)
this.cursor = new Cursor(this)
this.source = new Source(this)
this.keyboard = new Keyboard(this)
- this.history = new History()
- this.controller = new Controller()
- this.clocks = [new Clock(120)]
- this.selectedClock = 0
+ this.clock = new Clock(this)
// 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' })
@@ -32,8 +32,6 @@ function Terminal () {
this.tile = { w: 10, h: 15 }
this.scale = window.devicePixelRatio
- this.isPaused = false
-
this.install = function (host) {
host.appendChild(this.el)
this.theme.install(host)
@@ -45,7 +43,7 @@ function Terminal () {
this.source.start()
this.history.bind(this.orca, 's')
this.history.record(this.orca.s)
- this.nextClock()
+ this.clock.start()
this.update()
this.el.className = 'ready'
}
@@ -57,21 +55,6 @@ function Terminal () {
this.update()
}
- this.play = function () {
- console.log('Play')
- this.isPaused = false
- this.update()
- this.clock().setRunning(true)
- }
-
- this.stop = function () {
- console.log('Stop')
- this.io.midi.silence()
- this.isPaused = true
- this.update()
- this.clock().setRunning(false)
- }
-
this.load = function (orca, frame = 0) {
this.history.reset()
this.orca = orca
@@ -94,46 +77,6 @@ function Terminal () {
this.theme.reset()
}
- this.prevFrame = function () {
- this.orca.f -= 2
- this.stop()
- this.run()
- }
-
- this.nextFrame = function () {
- this.stop()
- this.run()
- }
-
- // Clock
-
- this.clock = function () {
- return this.clocks[this.selectedClock]
- }
-
- this.nextClock = function () {
- const previousClock = this.clock()
- if (previousClock) {
- previousClock.setRunning(false)
- previousClock.setCallback(() => {})
- }
- this.selectedClock = (this.selectedClock + 1) % this.clocks.length
- this.clock().setRunning(!this.isPaused)
- this.clock().setCallback(() => this.run())
-
- console.log('Select clock:', this.clock())
- this.update()
- }
-
- this.setSpeed = function (bpm) {
- if (this.clock().canSetBpm()) {
- bpm = clamp(bpm, 60, 300)
- console.log(`Change Speed: ${bpm}.`)
- this.clock().setBpm(bpm)
- this.update()
- }
- }
-
this.setGrid = function (w, h) {
this.grid.w = w
this.grid.h = h
@@ -151,20 +94,6 @@ function Terminal () {
this.resize(true)
}
- this.togglePlay = function () {
- if (this.isPaused === true) {
- this.play()
- } else {
- this.stop()
- }
- }
-
- this.modSpeed = function (mod = 0) {
- if (this.clock().canSetBpm()) {
- this.setSpeed(this.clock().getBpm() + mod)
- }
- }
-
this.modGrid = function (x = 0, y = 0) {
const w = clamp(this.grid.w + x, 4, 16)
const h = clamp(this.grid.h + y, 4, 16)
@@ -246,7 +175,7 @@ function Terminal () {
this.write(`${this.orca.w}x${this.orca.h}`, col * 0, 0, this.grid.w)
this.write(`${this.grid.w}/${this.grid.h}`, col * 1, 0, this.grid.w)
this.write(`${this.source}`, col * 2, 0, this.grid.w)
- this.write(`${this.clock()}${this.orca.f % 4 === 0 ? '*' : ''}`, col * 3, 0, this.grid.w)
+ this.write(`${this.clock}`, col * 3, 0, this.grid.w)
this.write(`${this.io.inspect(this.grid.w)}`, col * 4, 0, this.grid.w)
if (this.orca.f < 25) {