Skip to content
Permalink
Browse files

Merge pull request #125 from hundredrabbits/MidiLogic

Implemented multi-channel mono operation
  • Loading branch information
neauoire committed Jun 1, 2019
2 parents dbf1d79 + 06ed9a9 commit 221e94afd3c3b3cbdfd92d599ff51f462efc5b9c
@@ -62,10 +62,6 @@ npm start
- `;` **udp**: Sends UDP message.
- `=` **osc**(*path*): Sends OSC message.

#### Receive

- `&` **mono**: Receive MIDI note.

## MIDI

The [MIDI](https://en.wikipedia.org/wiki/MIDI) operator `:` takes up to 5 inputs('channel, 'octave, 'note, velocity, length).
@@ -44,7 +44,7 @@ export default function IO (terminal) {
}

this.length = function () {
return this.midi.stack.length + this.cc.stack.length + this.udp.stack.length + this.osc.stack.length + this.mono.stack.length
return this.midi.length() + this.mono.length() + this.cc.stack.length + this.udp.stack.length + this.osc.stack.length
}

this.inspect = function (limit = terminal.grid.w) {
@@ -1,5 +1,7 @@
'use strict'

import transpose from '../transpose.js'

export default function Midi (terminal) {
this.mode = 0

@@ -21,6 +23,62 @@ export default function Midi (terminal) {

}

this.run = function () {
for (const id in this.stack) {
if (this.stack[id].isPlayed === false) {
this.press(this.stack[id])
}
if (this.stack[id].length <= 1) {
this.release(this.stack[id])
}
if (this.stack[id]) {
this.stack[id].length--
}
}

this.stack = this.stack.filter((item) => { return item.length > 0 })
}

this.trigger = function (item, down) {
if (!this.outputDevice()) { console.warn('Midi', 'No midi output!'); return }

const transposed = this.transpose(item.note, item.octave)
const channel = terminal.orca.valueOf(item.channel)

const c = down === true ? 0x90 + channel : 0x80 + channel
const n = transposed.id
const v = parseInt((item.velocity / 16) * 127)

this.outputDevice().send([c, n, v])
}

this.press = function (item) {
if (!item) { return }
this.trigger(item, true)
item.isPlayed = true
}

this.release = function (item) {
if (!item) { return }
this.trigger(item, false)
}

this.silence = function () {
for (const id in this.stack) {
this.release(this.stack[id])
}
}

this.send = function (channel, octave, note, velocity, length, isPlayed = false) {
// Stop duplicates
for (const id in this.stack) {
if (this.stack[id].channel === channel) { return }
if (this.stack[id].octave === octave) { return }
if (this.stack[id].note === note) { return }
}
this.stack.push({ channel, octave, note, velocity, length, isPlayed })
}

this.update = function () {
terminal.controller.clearCat('default', 'Midi')
terminal.controller.add('default', 'Midi', `Refresh Device List`, () => { terminal.io.midi.setup(); terminal.io.midi.update() })
@@ -50,58 +108,13 @@ export default function Midi (terminal) {
terminal.controller.commit()
}

this.run = function () {
this.stack = this.stack.filter((item) => {
const alive = item[4] > 0
const played = item[5]
if (alive !== true) {
this.trigger(item, false)
} else if (played !== true) {
this.trigger(item, true)
}
item[4]--
return alive
})
}

this.trigger = function (item, down) {
if (!this.outputDevice()) { console.warn('Midi', 'No midi output!'); return }

const channel = down === true ? 0x90 + item[0] : 0x80 + item[0]
const note = clamp(24 + (item[1] * 12) + item[2], 0, 127)
const velocity = clamp(item[3], 0, 127)

this.outputDevice().send([channel, note, velocity])
item[5] = true
}

this.send = function (channel, octave, note, velocity, length, played = false) {
for (const id in this.stack) {
const item = this.stack[id]
if (item[0] === channel && item[1] === octave && item[2] === note) {
item[3] = velocity
item[4] = length
item[5] = played
return
}
}
this.stack.push([channel, octave, note, velocity, length, played])
}

this.silence = function () {
this.stack = this.stack.filter((item) => {
this.trigger(item, false)
return false
})
}

// Keys

this.press = function (key) {
this.keyDown = function (key) {
this.key = parseInt(key)
}

this.release = function () {
this.keyUp = function () {
this.key = null
}

@@ -128,10 +141,10 @@ export default function Midi (terminal) {
switch (msg.data[0]) {
// Keys
case 0x90:
this.press(msg.data[1])
this.keyDown(msg.data[1])
break
case 0x80:
this.release()
this.keyUp()
break
// Clock
case 0xF8:
@@ -205,9 +218,23 @@ export default function Midi (terminal) {

// UI

this.transpose = function (n, o = 3) {
if (!transpose[n]) { return { note: n, octave: o } }
const note = transpose[n].charAt(0)
const octave = clamp(parseInt(transpose[n].charAt(1)) + o, 0, 8)
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)
const real = id < 89 ? Object.keys(transpose)[id - 45] : null
return { id, value, note, octave, real }
}

this.toString = function () {
return this.outputDevice() ? `${this.outputDevice().name}` : 'No Midi'
}

this.length = function () {
return this.stack.length
}

function clamp (v, min, max) { return v < min ? min : v > max ? max : v }
}
@@ -1,65 +1,56 @@
'use strict'

export default function Mono (terminal) {
this.queue = null
this.stack = []
this.stack = {}

this.start = function () {
console.info('MidiMono Starting..')
}

this.clear = function () {

}

this.run = function () {
if (this.stack[0]) {
if (this.stack[0].length <= 1) {
this.release()
} else {
this.stack[0].length--
for (const id in this.stack) {
if (this.stack[id].isPlayed === false) {
this.press(this.stack[id])
}
if (this.stack[id].length <= 1) {
this.release(this.stack[id])
}
if (this.stack[id]) {
this.stack[id].length--
}
}

if (this.queue) {
this.press()
}
}

this.press = function (item = this.queue) {
this.press = function (item) {
if (!item) { return }
if (this.stack[0]) { this.release() }
this.trigger(item, true)
this.stack[0] = item
this.queue = null
terminal.io.midi.trigger(item, true)
item.isPlayed = true
}

this.release = function (item = this.stack[0]) {
this.release = function (item) {
if (!item) { return }
this.trigger(this.stack[0], false)
this.stack = []
terminal.io.midi.trigger(item, false)
delete this.stack[item.channel]
}

this.clear = function () {

}

this.trigger = function (item, down) {
if (!terminal.io.midi.outputDevice()) { console.warn('MidiMono', 'No midi output!'); return }
if (!item) { return }

const channel = down === true ? 0x90 + item.channel : 0x80 + item.channel
const note = clamp(24 + (item.octave * 12) + item.note, 0, 127)
const velocity = clamp(item.velocity, 0, 127)

terminal.io.midi.outputDevice().send([channel, note, velocity])
this.silence = function () {
for (const id in this.stack) {
this.release(this.stack[id])
}
}

this.send = function (channel, octave, note, velocity, length) {
this.queue = { channel, octave, note, velocity, length }
this.send = function (channel, octave, note, velocity, length, isPlayed = false) {
if (this.stack[channel]) {
this.release(this.stack[channel])
}
this.stack[channel] = { channel, octave, note, velocity, length, isPlayed }
}

this.silence = function () {
this.release()
this.length = function () {
return Object.keys(this.stack).length
}

// UI

function clamp (v, min, max) { return v < min ? min : v > max ? max : v }
}
@@ -34,7 +34,6 @@ import _mono from './library/_mono.js'
import _cc from './library/_cc.js'
import _udp from './library/_udp.js'
import _osc from './library/_osc.js'
import _keys from './library/_keys.js'

export default {
'0': _null,
@@ -79,6 +78,5 @@ export default {
'%': _mono,
'!': _cc,
';': _udp,
'=': _osc,
'&': _keys
'=': _osc
}

This file was deleted.

@@ -17,32 +17,22 @@ export default function OperatorMidi (orca, x, y, passive) {
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 }

const channel = this.listen(this.ports.channel, true)
const rawOctave = this.listen(this.ports.octave, true)
const rawNote = this.listen(this.ports.note)
const rawVelocity = this.listen(this.ports.velocity, true)
const channel = this.listen(this.ports.channel)
if (channel === '.') { return }
const octave = this.listen(this.ports.octave)
if (octave === '.') { return }
const note = this.listen(this.ports.note)
if (note === '.') { return }

const velocity = this.listen(this.ports.velocity, true)
const length = this.listen(this.ports.length, true)

if (!isNaN(rawNote)) { return }

const transposed = this.transpose(rawNote, rawOctave)
// 1 - 8
const octave = transposed.octave
// 0 - 11
const note = transposed.value
// 0 - G(127)
const velocity = parseInt((rawVelocity / 16) * 127)

this.draw = false

terminal.io.midi.send(channel, octave, note, velocity, length)

if (force === true) {
terminal.io.midi.run()
}

this.draw = false
}
}

0 comments on commit 221e94a

Please sign in to comment.