Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add preset saving and loading #44

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions desktop/sources/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
controller.add("default","*","Reset",() => { pilot.mixer.reset() },"CmdOrCtrl+Backspace")
controller.add("default","*","Quit",() => { app.exit() },"CmdOrCtrl+Q")

controller.add("default","File","Open",() => { pilot.open() },"CmdOrCtrl+O")
controller.add("default","File","Save",() => { pilot.save() },"CmdOrCtrl+S")
controller.add("default","File","Record",() => { pilot.recorder.toggle() },"CmdOrCtrl+R")
controller.add("default","File","Stop Recording",() => { pilot.recorder.stop() },"Escape")

Expand Down
8 changes: 7 additions & 1 deletion desktop/sources/scripts/interface.channel.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,13 @@ export default function ChannelInterface (pilot, id, node) {
this.updateOsc(data)
}

this.toString = function () {
const osc = 'osc' + (this.node.oscillator ? wavCode(this.node.oscillator.type) : '') + (this.node.modulation ? wavCode(this.node.modulation.type) : '')
const env = 'env' + to16(this.node.envelope.attack) + to16(this.node.envelope.decay) + to16(this.node.envelope.sustain) + to16(this.node.envelope.release)
const idStr = str36(id)
return idStr + osc + ';' + idStr + env + ';'
}

// Updates

this.updateAll = function (data, force = false) {
Expand Down Expand Up @@ -193,7 +200,6 @@ export default function ChannelInterface (pilot, id, node) {
}

// Helpers
function letterValue (c) { return c.toLowerCase().charCodeAt(0) - 97 }
function isUpperCase (s) { return `${s}`.toUpperCase() === `${s}` }
function from16 (str) { return (int36(str) / 15) }
function to16 (float) { return str36(Math.floor(float * 15)) }
Expand Down
19 changes: 15 additions & 4 deletions desktop/sources/scripts/interface.effect.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,20 @@ export default function EffectInterface (pilot, id, node) {
if (pilot.animate !== true) { return }
if (force !== true && (!data || !data.isEffect)) { return }

if (this.node.wet) {
setContent(this.val_el, `${to16(this.node.wet.value)}${to16(this.depth())}`)
}
}

this.toString = function () {
let str = ''
if (this.node.wet) {
str = id + to16(this.node.wet.value) + to16(this.depth()) + ';'
}
return str
}

this.depth = function () {
let value = 0
if (id === 'rev') {
value = this.node.roomSize.value
Expand All @@ -114,10 +128,7 @@ export default function EffectInterface (pilot, id, node) {
} else if (id === 'che') {
value = this.node.order / 100
}

if (this.node.wet) {
setContent(this.val_el, `${to16(this.node.wet.value)}${to16(value)}`)
}
return value
}

// Parsers
Expand Down
103 changes: 103 additions & 0 deletions desktop/sources/scripts/lib/source.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
'use strict'

/* global FileReader */
/* global MouseEvent */
/* global document */
/* global window */

export default function Source () {
this.cache = {}

this.install = () => {
}

this.start = () => {
this.new()
}

this.new = () => {
console.log('Source', 'New file..')
this.cache = {}
}

this.open = (ext, callback) => {
console.log('Source', 'Open file..')
const input = document.createElement('input')
input.type = 'file'
input.onchange = (e) => {
const file = e.target.files[0]
if (file.name.indexOf('.' + ext) < 0) { console.warn('Source', `Skipped ${file.name}`); return }
this.read(file, callback)
}
input.click()
}

this.load = (ext, callback) => {
console.log('Source', 'Load files..')
const input = document.createElement('input')
input.type = 'file'
input.setAttribute('multiple', 'multiple')
input.onchange = (e) => {
for (const file of e.target.files) {
if (file.name.indexOf('.' + ext) < 0) { console.warn('Source', `Skipped ${file.name}`); return }
this.read(file, this.store)
}
}
input.click()
}

this.store = (file, content) => {
console.info('Source', 'Stored ' + file.name)
this.cache[file.name] = content
}

this.save = (name, content, type = 'text/plain', callback) => {
this.saveAs(name, content, type, callback)
}

this.saveAs = (name, ext, content, type = 'text/plain', callback) => {
console.log('Source', 'Save new file..')
this.write(name, ext, content, type, callback)
}

// I/O

this.read = (file, callback) => {
const reader = new FileReader()
reader.onload = (event) => {
const res = event.target.result
if (callback) { callback(file, res) }
}
reader.readAsText(file, 'UTF-8')
}

this.write = (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 }))
}

function timestamp (d = new Date(), e = new Date(d)) {
return `${arvelie()}-${neralie()}`
}

function arvelie (date = new Date()) {
const start = new Date(date.getFullYear(), 0, 0)
const diff = (date - start) + ((start.getTimezoneOffset() - date.getTimezoneOffset()) * 60 * 1000)
const doty = Math.floor(diff / 86400000) - 1
const y = date.getFullYear().toString().substr(2, 2)
const m = doty === 364 || doty === 365 ? '+' : String.fromCharCode(97 + Math.floor(doty / 14)).toUpperCase()
const d = `${(doty === 365 ? 1 : doty === 366 ? 2 : (doty % 14)) + 1}`.padStart(2, '0')
return `${y}${m}${d}`
}

function neralie (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)
}
}
11 changes: 11 additions & 0 deletions desktop/sources/scripts/mixer.js
Original file line number Diff line number Diff line change
Expand Up @@ -176,5 +176,16 @@ export default function Mixer (pilot) {
this.run('BIT07;DIS00;WAH0F;CHE07;FEE00;TRE07;REV00;PHA0F;VIB01;CHO07')
}

this.state = function () {
let state = ''
for (const channel of this.channels) {
state += channel.toString()
}
for (const key in this.effects) {
state += this.effects[key].toString()
}
return state
}

function clamp (v, min, max) { return v < min ? min : v > max ? max : v }
}
17 changes: 17 additions & 0 deletions desktop/sources/scripts/pilot.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@ import Listener from './listener.js'
import Mixer from './mixer.js'
import Recorder from './recorder.js'
import Commander from './commander.js'
import Source from './lib/source.js'
import Theme from './lib/theme.js'

export default function Pilot () {
this.listener = null
this.mixer = null
this.recorder = null
this.commander = null
this.source = new Source()
this.theme = new Theme({ background: '#000000', f_high: '#ffffff', f_med: '#777777', f_low: '#444444', f_inv: '#000000', b_high: '#eeeeee', b_med: '#333', b_low: '#444444', b_inv: '#fff' })

this.el = document.createElement('div')
Expand Down Expand Up @@ -48,4 +50,19 @@ export default function Pilot () {
const currentZoomFactor = webFrame.getZoomFactor()
webFrame.setZoomFactor(set ? mod : currentZoomFactor + mod)
}

this.open = function () {
this.source.open('pilot', this.whenOpen)
}

this.whenOpen = (file, text) => {
const lines = text.trim().split('\n')
for (const line of lines) {
this.mixer.run(line)
}
}

this.save = function () {
this.source.write('pilot', 'pilot', this.mixer.state(), 'text/plain')
}
}