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

Dynamically loadable language libraries #248

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 2 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
27 changes: 14 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,13 +70,13 @@ To display the list of operators inside of Orca, use `CmdOrCtrl+G`.

## MIDI

The [MIDI](https://en.wikipedia.org/wiki/MIDI) operator `:` takes up to 5 inputs('channel, 'octave, 'note, velocity, length).
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Editor ate trailing spaces, sorry.

The [MIDI](https://en.wikipedia.org/wiki/MIDI) operator `:` takes up to 5 inputs('channel, 'octave, 'note, velocity, length).

For example, `:25C`, is a **C note, on the 5th octave, through the 3rd MIDI channel**, `:04c`, is a **C# note, on the 4th octave, through the 1st MIDI channel**. Velocity is an optional value from `0`(0/127) to `g`(127/127). Note length is the number of frames during which a note remains active. See it in action with [midi.orca](https://git.sr.ht/~rabbits/orca-examples/tree/master/basics/_midi.orca).

## MIDI MONO

The [MONO](https://en.wikipedia.org/wiki/Monophony) operator `%` takes up to 5 inputs('channel, 'octave, 'note, velocity, length).
The [MONO](https://en.wikipedia.org/wiki/Monophony) operator `%` takes up to 5 inputs('channel, 'octave, 'note, velocity, length).

This operator is very similar to the default Midi operator, but **each new note will stop the previously playing note**, would its length overlap with the new one. Making certain that only a single note is ever played at once, this is ideal for monophonic analog synthetisers that might struggle to dealing with chords and note overlaps.

Expand All @@ -94,9 +94,9 @@ It sends two different values **between 0-127**, where the value is calculated a

## MIDI BANK SELECT / PROGRAM CHANGE

This is a command (see below) rather than an operator and it combines the [MIDI program change and bank select functions](https://www.sweetwater.com/sweetcare/articles/6-what-msb-lsb-refer-for-changing-banks-andprograms/).
This is a command (see below) rather than an operator and it combines the [MIDI program change and bank select functions](https://www.sweetwater.com/sweetcare/articles/6-what-msb-lsb-refer-for-changing-banks-andprograms/).

The syntax is `pg:channel;msb;lsb;program`. Channel is 0-15, msb/lsb/program are 0-127, but program will automatically be translated to 1-128 by the MIDI driver. `program` typically correspondes to a "patch" selection on a synth. Note that `msb` may also be identified as "bank" and `lsb` as "sub" in some applications (like Ableton Live).
The syntax is `pg:channel;msb;lsb;program`. Channel is 0-15, msb/lsb/program are 0-127, but program will automatically be translated to 1-128 by the MIDI driver. `program` typically correspondes to a "patch" selection on a synth. Note that `msb` may also be identified as "bank" and `lsb` as "sub" in some applications (like Ableton Live).

`msb` and `lsb` can be left blank if you only want to send a simple program change. For example, `pg:0;;;63` will set the synth to patch number 64 (without changing the bank)

Expand Down Expand Up @@ -149,30 +149,31 @@ All commands have a shorthand equivalent to their first two characters, for exam
- `midi:1;2` Set Midi output device to `#1`, and input device to `#2`.
- `udp:1234;5678` Set UDP output port to `1234`, and input port to `5678`.
- `osc:1234` Set OSC output port to `1234`.
- `lang:clr;default` Incrementally load language interpreters (`clr` clears the language library entirely). Multiple languages can be combined.

## Base36 Table

Orca operates on a base of **36 increments**. Operators using numeric values will typically also operate on letters and convert them into values as per the following table. For instance `Do` will bang every *24th frame*.
Orca operates on a base of **36 increments**. Operators using numeric values will typically also operate on letters and convert them into values as per the following table. For instance `Do` will bang every *24th frame*.

| **0** | **1** | **2** | **3** | **4** | **5** | **6** | **7** | **8** | **9** | **A** | **B** |
| :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: |
| **0** | **1** | **2** | **3** | **4** | **5** | **6** | **7** | **8** | **9** | **A** | **B** |
| :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: |
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
| **C** | **D** | **E** | **F** | **G** | **H** | **I** | **J** | **K** | **L** | **M** | **N** |
| 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 |
| **O** | **P** | **Q** | **R** | **S** | **T** | **U** | **V** | **W** | **X** | **Y** | **Z** |
| **O** | **P** | **Q** | **R** | **S** | **T** | **U** | **V** | **W** | **X** | **Y** | **Z** |
| 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 |

## Transpose Table

The midi operator interprets any letter above the chromatic scale as a transpose value, for instance `3H`, is equivalent to `4A`.

| **0** | **1** | **2** | **3** | **4** | **5** | **6** | **7** | **8** | **9** | **A** | **B** |
| :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: |
| **0** | **1** | **2** | **3** | **4** | **5** | **6** | **7** | **8** | **9** | **A** | **B** |
| :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: |
| _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | A0 | B0 |
| **C** | **D** | **E** | **F** | **G** | **H** | **I** | **J** | **K** | **L** | **M** | **N** |
| C0 | D0 | E0 | F0 | G0 | A0 | B0 | C1 | D1 | E1 | F1 | G1 |
| **O** | **P** | **Q** | **R** | **S** | **T** | **U** | **V** | **W** | **X** | **Y** | **Z** |
| A1 | B1 | C2 | D2 | E2 | F2 | G2 | A2 | B2 | C3 | D3 | E3 |
| C0 | D0 | E0 | F0 | G0 | A0 | B0 | C1 | D1 | E1 | F1 | G1 |
| **O** | **P** | **Q** | **R** | **S** | **T** | **U** | **V** | **W** | **X** | **Y** | **Z** |
| A1 | B1 | C2 | D2 | E2 | F2 | G2 | A2 | B2 | C3 | D3 | E3 |

## Companion Applications

Expand Down
6 changes: 4 additions & 2 deletions desktop/sources/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@
<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/lib/source.js"></script>
<script type="text/javascript" src="scripts/core/library.js"></script>
<script type="text/javascript" src="scripts/core/library/library.js"></script>
<script type="text/javascript" src="scripts/core/library/base.js"></script>
<script type="text/javascript" src="scripts/core/library/default.js"></script>
Copy link
Contributor Author

@unthingable unthingable Oct 25, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One of the uglier parts. Is there a better way to organize and load these so that new definitions can be added without modifying index.html? Can one JS file import another?

Ideally this would be user loadable.

<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>
Expand All @@ -30,7 +32,7 @@

client.install(document.body)

window.addEventListener('load', () => {
window.addEventListener('load', () => {
client.start()
client.acels.inject('Orca')
})
Expand Down
13 changes: 10 additions & 3 deletions desktop/sources/scripts/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@
/* global Theme */

function Client () {
this.version = 176
this.library = library
this.version = 177
this.libraryName = 'default'
this.library = library[this.libraryName]

this.theme = new Theme(this)
this.acels = new Acels(this)
Expand Down Expand Up @@ -331,7 +332,13 @@ function Client () {
} else {
this.write(this.orca.f < 25 ? `ver${this.version}` : `${Object.keys(this.source.cache).length} mods`, this.grid.w * 0, this.orca.h + 1, this.grid.w)
this.write(`${this.orca.w}x${this.orca.h}`, this.grid.w * 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) : ''}`, this.grid.w * 2, this.orca.h + 1, this.grid.w)
this.write(
this.orca.f < 25
? `${this.libraryName}`
: `${this.grid.w}/${this.grid.h}${this.tile.w !== 10 ? ' ' + (this.tile.w / 10).toFixed(1) : ''}`,
this.grid.w * 2,
this.orca.h + 1,
this.grid.w)
this.write(`${this.clock}`, this.grid.w * 3, this.orca.h + 1, this.grid.w, this.clock.isPuppet ? 3 : this.io.midi.isClock ? 11 : this.clock.isPaused ? 20 : 2)
this.write(`${display(Object.keys(this.orca.variables).join(''), this.orca.f, this.grid.w - 1)}`, this.grid.w * 4, this.orca.h + 1, this.grid.w - 1)
this.write(this.orca.f < 250 ? `> ${this.io.midi.toOutputString()}` : '', this.grid.w * 5, this.orca.h + 1, this.grid.w * 4)
Expand Down
25 changes: 24 additions & 1 deletion desktop/sources/scripts/commander.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
'use strict'

/* global library */

function Commander (client) {
this.isActive = false
this.query = ''
Expand Down Expand Up @@ -70,7 +72,28 @@ function Commander (client) {
},
write: (p) => {
client.orca.writeBlock(p._x || client.cursor.x, p._y || client.cursor.y, p._str)
}
},
// Language
lang: (p) => {
p.parts.forEach(l => {
if (l === 'clr') {
console.log('Clearing lang'),
client.library = {}
client.libraryName = '---'
} else {
if (l in library) {
console.log(`Incrementally loading lang: ${l}`)
client.library = Object.assign({}, client.library, library[l])
client.libraryName = l
} else {
console.error(`Lang ${l} is not defined`)
return
}
}
client.orca.library = client.library
client.clock.setFrame(0)
})
},
}

// Make shorthands
Expand Down
36 changes: 36 additions & 0 deletions desktop/sources/scripts/core/library/base.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
`use strict`

/* global Operator */
/* global library */

library.base = {}

library.base['#'] = 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)
}
}

for (let i = 0; i <= 9; i++) {
library.base[`${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) {

}
}
}
Loading