@tialro2/rnbokit 1.0.15 → 1.0.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +242 -242
- package/dist/RNBO.css +113 -113
- package/dist/RNBO.svelte +230 -230
- package/dist/RNBOcomponents/AudioDropIn.svelte +125 -125
- package/dist/RNBOcomponents/ExtMidiIn.svelte +85 -85
- package/dist/RNBOcomponents/ExtMidiOut.svelte +85 -85
- package/dist/RNBOcomponents/MicIn.svelte +80 -80
- package/dist/RNBOcomponents/RNBOInlet.svelte +66 -66
- package/dist/RNBOcomponents/RNBOInport.svelte +21 -21
- package/dist/RNBOcomponents/RNBOMidiIn.svelte +63 -63
- package/dist/RNBOcomponents/RNBOMidiOut.svelte +22 -22
- package/dist/RNBOcomponents/RNBOOutport.svelte +36 -36
- package/dist/RNBOcomponents/RNBOParam.svelte +37 -37
- package/dist/RNBOcomponents/XYMidiIn.svelte +93 -93
- package/dist/UIcomponents/Controls.svelte +12 -12
- package/dist/UIcomponents/FileDropZone.svelte +118 -118
- package/dist/UIcomponents/ProgressBar.svelte +35 -35
- package/dist/UIcomponents/RadioGroup.svelte +27 -27
- package/dist/UIcomponents/RadioItem.svelte +96 -96
- package/dist/index.js +20 -20
- package/package.json +10 -10
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
<script>
|
|
2
|
-
//A file drop in/media player for audio
|
|
3
|
-
import { flip } from 'svelte/animate';
|
|
4
|
-
import { crossfade } from 'svelte/transition';
|
|
5
|
-
const [send, receive] = crossfade({
|
|
6
|
-
duration: (d) => Math.sqrt(d * 200)
|
|
7
|
-
});
|
|
8
|
-
|
|
9
|
-
import FileDropZone from '../UIcomponents/FileDropZone.svelte';
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
1
|
+
<script>
|
|
2
|
+
//A file drop in/media player for audio
|
|
3
|
+
import { flip } from 'svelte/animate';
|
|
4
|
+
import { crossfade } from 'svelte/transition';
|
|
5
|
+
const [send, receive] = crossfade({
|
|
6
|
+
duration: (d) => Math.sqrt(d * 200)
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
import FileDropZone from '../UIcomponents/FileDropZone.svelte';
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
13
|
/**
|
|
14
14
|
* @typedef {Object} Props
|
|
15
15
|
* @property {AudioContext} context
|
|
@@ -18,116 +18,116 @@
|
|
|
18
18
|
|
|
19
19
|
/** @type {Props & { [key: string]: any }} */
|
|
20
20
|
let { context, audio = $bindable(), ...rest } = $props();
|
|
21
|
-
|
|
22
|
-
/** @type {Array<File>} */
|
|
23
|
-
let files = $state([]);
|
|
24
|
-
/** @type {HTMLMediaElement[]} */
|
|
25
|
-
let audioElements = $state([]);
|
|
26
|
-
|
|
27
|
-
/** @type {HTMLMediaElement|undefined} */
|
|
28
|
-
let current;
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* pause other running audio and connect new playing source on play
|
|
32
|
-
* @param {Event} e
|
|
33
|
-
*/
|
|
34
|
-
function onPlay(e) {
|
|
35
|
-
if (current === e.target) return;
|
|
36
|
-
|
|
37
|
-
for (const audioElement of audioElements) {
|
|
38
|
-
if (audioElement !== e.target) {
|
|
39
|
-
// console.log('pause');
|
|
40
|
-
audioElement.pause();
|
|
41
|
-
continue;
|
|
42
|
-
}
|
|
43
|
-
// console.log('connect');
|
|
44
|
-
current = audioElement;
|
|
45
|
-
}
|
|
46
|
-
try {
|
|
47
|
-
audio = context.createMediaElementSource(current);
|
|
48
|
-
} catch (e) {
|
|
49
|
-
//ignore DOMexception error, as the correct source will still be used,
|
|
50
|
-
// no easy way around arror (need to investigate)
|
|
51
|
-
console.log('failed to (re)connect MediaElementSource');
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* put files in an array, so we can do array operations like splice. e.target.files is read-only
|
|
57
|
-
* @param {Event} e
|
|
58
|
-
*/
|
|
59
|
-
function loadFiles(e) {
|
|
60
|
-
// @ts-expect-error - quick fix for: TS2339: Property 'files' does not exist on type 'Event'.
|
|
61
|
-
files = [...e.target.files];
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* remove a file from the files array when we click the 'x'. If no more files,
|
|
66
|
-
* show audio drop in again
|
|
67
|
-
* @param {Number} index
|
|
68
|
-
*/
|
|
69
|
-
function removeFile(index) {
|
|
70
|
-
if (!files) return;
|
|
71
|
-
audioElements = [];
|
|
72
|
-
|
|
73
|
-
files.splice(index, 1);
|
|
74
|
-
files = files;
|
|
75
|
-
if (files.length === 0) {
|
|
76
|
-
files = [];
|
|
77
|
-
audioElements = [];
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
</script>
|
|
81
|
-
|
|
82
|
-
<div class="RNBOsubcomponent" {...rest}>
|
|
83
|
-
{#if files.length === 0}
|
|
84
|
-
<FileDropZone name="audio files" on:change={loadFiles} multiple accept="audio/*" />
|
|
85
|
-
{:else}
|
|
86
|
-
{#each files as file, i (file)}
|
|
87
|
-
<div
|
|
88
|
-
class="RNBOsection RNBOaudio"
|
|
89
|
-
in:receive={{ key: file }}
|
|
90
|
-
out:send={{ key: file }}
|
|
91
|
-
animate:flip={{ duration: 200 }}
|
|
92
|
-
>
|
|
93
|
-
<p class="RNBOtext">{file.name}</p>
|
|
94
|
-
<audio
|
|
95
|
-
src={URL.createObjectURL(file)}
|
|
96
|
-
bind:this={audioElements[i]}
|
|
97
|
-
onplay={onPlay}
|
|
98
|
-
controls
|
|
99
|
-
></audio>
|
|
100
|
-
<button
|
|
101
|
-
type="button"
|
|
102
|
-
class="RNBObtn RNBOclose"
|
|
103
|
-
onclick={() => removeFile(i)}
|
|
104
|
-
onkeydown={() => removeFile(i)}
|
|
105
|
-
>
|
|
106
|
-
x
|
|
107
|
-
</button>
|
|
108
|
-
</div>
|
|
109
|
-
{/each}
|
|
110
|
-
{/if}
|
|
111
|
-
</div>
|
|
112
|
-
|
|
113
|
-
<style>
|
|
114
|
-
.RNBOclose {
|
|
115
|
-
position: absolute;
|
|
116
|
-
top: -0.5rem;
|
|
117
|
-
right: -0.5rem;
|
|
118
|
-
padding-top: 0.2rem;
|
|
119
|
-
padding-bottom: 0.2rem;
|
|
120
|
-
padding-left: 0.5rem;
|
|
121
|
-
padding-right: 0.5rem;
|
|
122
|
-
cursor: pointer;
|
|
123
|
-
border-radius: var(--local-rounded-base);
|
|
124
|
-
border-style: none;
|
|
125
|
-
background-color: rgb(var(--local-accent-color));
|
|
126
|
-
}
|
|
127
|
-
.RNBOaudio {
|
|
128
|
-
position: relative;
|
|
129
|
-
display: inline-block;
|
|
130
|
-
padding: 0.5rem;
|
|
131
|
-
margin: 0.5rem;
|
|
132
|
-
}
|
|
133
|
-
</style>
|
|
21
|
+
|
|
22
|
+
/** @type {Array<File>} */
|
|
23
|
+
let files = $state([]);
|
|
24
|
+
/** @type {HTMLMediaElement[]} */
|
|
25
|
+
let audioElements = $state([]);
|
|
26
|
+
|
|
27
|
+
/** @type {HTMLMediaElement|undefined} */
|
|
28
|
+
let current;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* pause other running audio and connect new playing source on play
|
|
32
|
+
* @param {Event} e
|
|
33
|
+
*/
|
|
34
|
+
function onPlay(e) {
|
|
35
|
+
if (current === e.target) return;
|
|
36
|
+
|
|
37
|
+
for (const audioElement of audioElements) {
|
|
38
|
+
if (audioElement !== e.target) {
|
|
39
|
+
// console.log('pause');
|
|
40
|
+
audioElement.pause();
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
// console.log('connect');
|
|
44
|
+
current = audioElement;
|
|
45
|
+
}
|
|
46
|
+
try {
|
|
47
|
+
audio = context.createMediaElementSource(current);
|
|
48
|
+
} catch (e) {
|
|
49
|
+
//ignore DOMexception error, as the correct source will still be used,
|
|
50
|
+
// no easy way around arror (need to investigate)
|
|
51
|
+
console.log('failed to (re)connect MediaElementSource');
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* put files in an array, so we can do array operations like splice. e.target.files is read-only
|
|
57
|
+
* @param {Event} e
|
|
58
|
+
*/
|
|
59
|
+
function loadFiles(e) {
|
|
60
|
+
// @ts-expect-error - quick fix for: TS2339: Property 'files' does not exist on type 'Event'.
|
|
61
|
+
files = [...e.target.files];
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* remove a file from the files array when we click the 'x'. If no more files,
|
|
66
|
+
* show audio drop in again
|
|
67
|
+
* @param {Number} index
|
|
68
|
+
*/
|
|
69
|
+
function removeFile(index) {
|
|
70
|
+
if (!files) return;
|
|
71
|
+
audioElements = [];
|
|
72
|
+
|
|
73
|
+
files.splice(index, 1);
|
|
74
|
+
files = files;
|
|
75
|
+
if (files.length === 0) {
|
|
76
|
+
files = [];
|
|
77
|
+
audioElements = [];
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
</script>
|
|
81
|
+
|
|
82
|
+
<div class="RNBOsubcomponent" {...rest}>
|
|
83
|
+
{#if files.length === 0}
|
|
84
|
+
<FileDropZone name="audio files" on:change={loadFiles} multiple accept="audio/*" />
|
|
85
|
+
{:else}
|
|
86
|
+
{#each files as file, i (file)}
|
|
87
|
+
<div
|
|
88
|
+
class="RNBOsection RNBOaudio"
|
|
89
|
+
in:receive={{ key: file }}
|
|
90
|
+
out:send={{ key: file }}
|
|
91
|
+
animate:flip={{ duration: 200 }}
|
|
92
|
+
>
|
|
93
|
+
<p class="RNBOtext">{file.name}</p>
|
|
94
|
+
<audio
|
|
95
|
+
src={URL.createObjectURL(file)}
|
|
96
|
+
bind:this={audioElements[i]}
|
|
97
|
+
onplay={onPlay}
|
|
98
|
+
controls
|
|
99
|
+
></audio>
|
|
100
|
+
<button
|
|
101
|
+
type="button"
|
|
102
|
+
class="RNBObtn RNBOclose"
|
|
103
|
+
onclick={() => removeFile(i)}
|
|
104
|
+
onkeydown={() => removeFile(i)}
|
|
105
|
+
>
|
|
106
|
+
x
|
|
107
|
+
</button>
|
|
108
|
+
</div>
|
|
109
|
+
{/each}
|
|
110
|
+
{/if}
|
|
111
|
+
</div>
|
|
112
|
+
|
|
113
|
+
<style>
|
|
114
|
+
.RNBOclose {
|
|
115
|
+
position: absolute;
|
|
116
|
+
top: -0.5rem;
|
|
117
|
+
right: -0.5rem;
|
|
118
|
+
padding-top: 0.2rem;
|
|
119
|
+
padding-bottom: 0.2rem;
|
|
120
|
+
padding-left: 0.5rem;
|
|
121
|
+
padding-right: 0.5rem;
|
|
122
|
+
cursor: pointer;
|
|
123
|
+
border-radius: var(--local-rounded-base);
|
|
124
|
+
border-style: none;
|
|
125
|
+
background-color: rgb(var(--local-accent-color));
|
|
126
|
+
}
|
|
127
|
+
.RNBOaudio {
|
|
128
|
+
position: relative;
|
|
129
|
+
display: inline-block;
|
|
130
|
+
padding: 0.5rem;
|
|
131
|
+
margin: 0.5rem;
|
|
132
|
+
}
|
|
133
|
+
</style>
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
<script>
|
|
2
|
-
import RadioGroup from '../UIcomponents/RadioGroup.svelte';
|
|
3
|
-
import RadioItem from '../UIcomponents/RadioItem.svelte';
|
|
4
|
-
/** @type {MIDIAccess|null|false} */
|
|
5
|
-
let midi = $state(null); // global MIDIAccess object
|
|
6
|
-
/**@type {MIDIInputMap|null} */
|
|
7
|
-
let inports = $state(null); // available MIDI inports
|
|
8
|
-
|
|
9
|
-
//TODO: choose port by name rather than index
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
/** @type {MIDIInput|null} */
|
|
13
|
-
let inport = null;
|
|
14
|
-
|
|
1
|
+
<script>
|
|
2
|
+
import RadioGroup from '../UIcomponents/RadioGroup.svelte';
|
|
3
|
+
import RadioItem from '../UIcomponents/RadioItem.svelte';
|
|
4
|
+
/** @type {MIDIAccess|null|false} */
|
|
5
|
+
let midi = $state(null); // global MIDIAccess object
|
|
6
|
+
/**@type {MIDIInputMap|null} */
|
|
7
|
+
let inports = $state(null); // available MIDI inports
|
|
8
|
+
|
|
9
|
+
//TODO: choose port by name rather than index
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
/** @type {MIDIInput|null} */
|
|
13
|
+
let inport = null;
|
|
14
|
+
|
|
15
15
|
/**
|
|
16
16
|
* @typedef {Object} Props
|
|
17
17
|
* @property {number|null} [port]
|
|
@@ -20,74 +20,74 @@
|
|
|
20
20
|
|
|
21
21
|
/** @type {Props} */
|
|
22
22
|
let { port = $bindable(null), midiMessage = $bindable() } = $props();
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* set the midi access point and get the midi input port
|
|
26
|
-
* @param {MIDIAccess} midiAccess
|
|
27
|
-
*/
|
|
28
|
-
function onMIDISuccess(midiAccess) {
|
|
29
|
-
midi = midiAccess;
|
|
30
|
-
inports = midi.inputs; // store in the global (in real usage, would probably keep in an object instance)
|
|
31
|
-
if (port) {
|
|
32
|
-
setPort();
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* handle if external MIDI not available
|
|
38
|
-
* @param {string} msg
|
|
39
|
-
*/
|
|
40
|
-
function onMIDIFailure(msg) {
|
|
41
|
-
console.error(`Failed to get MIDI access - ${msg}`);
|
|
42
|
-
midi = false;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* set the input port when selected
|
|
47
|
-
*/
|
|
48
|
-
function setPort() {
|
|
49
|
-
if (inports === null || port === null) return;
|
|
50
|
-
|
|
51
|
-
// @ts-ignore - ts getting their types wrong...
|
|
52
|
-
inport = [...inports][port];
|
|
53
|
-
console.log(
|
|
54
|
-
// @ts-ignore - because inports will always exist, since we use the #if block
|
|
55
|
-
'connecting to MIDI input port: %c' + inports.get(inport[0]).name,
|
|
56
|
-
'font-style:italic'
|
|
57
|
-
);
|
|
58
|
-
// @ts-ignore - see previous comment
|
|
59
|
-
inports.get(inport[0]).onmidimessage = onMIDIMessage;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/** @param {MIDIMessageEvent} event */
|
|
63
|
-
function onMIDIMessage(event) {
|
|
64
|
-
midiMessage = event.data;
|
|
65
|
-
console.log(
|
|
66
|
-
'MIDI message from %c' + event.target.name + ': ' + midiMessage,
|
|
67
|
-
'font-style:italic'
|
|
68
|
-
);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
navigator.requestMIDIAccess().then(onMIDISuccess, onMIDIFailure);
|
|
72
|
-
</script>
|
|
73
|
-
|
|
74
|
-
<div class="RNBOsubcomponent">
|
|
75
|
-
<p class="RNBOtext">External MIDI inputs</p>
|
|
76
|
-
|
|
77
|
-
{#if midi && inports}
|
|
78
|
-
<!-- <slot {midi} {inports} {port}> -->
|
|
79
|
-
<RadioGroup>
|
|
80
|
-
{#each [...inports.entries()] as input, i}
|
|
81
|
-
<!-- first index of the input array is the id, second the object -->
|
|
82
|
-
<RadioItem bind:group={port} name="inports" value={i} on:change={setPort}
|
|
83
|
-
>{input[1].name}
|
|
84
|
-
</RadioItem>
|
|
85
|
-
{/each}
|
|
86
|
-
</RadioGroup>
|
|
87
|
-
<!-- </slot> -->
|
|
88
|
-
{:else if midi === false}
|
|
89
|
-
<p>MIDI access failed, please try in a different browser</p>
|
|
90
|
-
{:else}
|
|
91
|
-
<p>loading MIDI ports</p>
|
|
92
|
-
{/if}
|
|
93
|
-
</div>
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* set the midi access point and get the midi input port
|
|
26
|
+
* @param {MIDIAccess} midiAccess
|
|
27
|
+
*/
|
|
28
|
+
function onMIDISuccess(midiAccess) {
|
|
29
|
+
midi = midiAccess;
|
|
30
|
+
inports = midi.inputs; // store in the global (in real usage, would probably keep in an object instance)
|
|
31
|
+
if (port) {
|
|
32
|
+
setPort();
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* handle if external MIDI not available
|
|
38
|
+
* @param {string} msg
|
|
39
|
+
*/
|
|
40
|
+
function onMIDIFailure(msg) {
|
|
41
|
+
console.error(`Failed to get MIDI access - ${msg}`);
|
|
42
|
+
midi = false;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* set the input port when selected
|
|
47
|
+
*/
|
|
48
|
+
function setPort() {
|
|
49
|
+
if (inports === null || port === null) return;
|
|
50
|
+
|
|
51
|
+
// @ts-ignore - ts getting their types wrong...
|
|
52
|
+
inport = [...inports][port];
|
|
53
|
+
console.log(
|
|
54
|
+
// @ts-ignore - because inports will always exist, since we use the #if block
|
|
55
|
+
'connecting to MIDI input port: %c' + inports.get(inport[0]).name,
|
|
56
|
+
'font-style:italic'
|
|
57
|
+
);
|
|
58
|
+
// @ts-ignore - see previous comment
|
|
59
|
+
inports.get(inport[0]).onmidimessage = onMIDIMessage;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** @param {MIDIMessageEvent} event */
|
|
63
|
+
function onMIDIMessage(event) {
|
|
64
|
+
midiMessage = event.data;
|
|
65
|
+
console.log(
|
|
66
|
+
'MIDI message from %c' + event.target.name + ': ' + midiMessage,
|
|
67
|
+
'font-style:italic'
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
navigator.requestMIDIAccess().then(onMIDISuccess, onMIDIFailure);
|
|
72
|
+
</script>
|
|
73
|
+
|
|
74
|
+
<div class="RNBOsubcomponent">
|
|
75
|
+
<p class="RNBOtext">External MIDI inputs</p>
|
|
76
|
+
|
|
77
|
+
{#if midi && inports}
|
|
78
|
+
<!-- <slot {midi} {inports} {port}> -->
|
|
79
|
+
<RadioGroup>
|
|
80
|
+
{#each [...inports.entries()] as input, i}
|
|
81
|
+
<!-- first index of the input array is the id, second the object -->
|
|
82
|
+
<RadioItem bind:group={port} name="inports" value={i} on:change={setPort}
|
|
83
|
+
>{input[1].name}
|
|
84
|
+
</RadioItem>
|
|
85
|
+
{/each}
|
|
86
|
+
</RadioGroup>
|
|
87
|
+
<!-- </slot> -->
|
|
88
|
+
{:else if midi === false}
|
|
89
|
+
<p>MIDI access failed, please try in a different browser</p>
|
|
90
|
+
{:else}
|
|
91
|
+
<p>loading MIDI ports</p>
|
|
92
|
+
{/if}
|
|
93
|
+
</div>
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
<script>
|
|
2
|
-
import RadioGroup from '../UIcomponents/RadioGroup.svelte';
|
|
3
|
-
import RadioItem from '../UIcomponents/RadioItem.svelte';
|
|
4
|
-
/** @type {MIDIAccess|null|false} */
|
|
5
|
-
let midi = $state(null); // global MIDIAccess object
|
|
6
|
-
/**@type {MIDIInputMap|null} */
|
|
7
|
-
let outports = $state(null); // available MIDI outports
|
|
8
|
-
|
|
9
|
-
//TODO: choose port by name rather than index
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
/** @type {MIDIInput|null} */
|
|
13
|
-
let outport = null;
|
|
14
|
-
|
|
1
|
+
<script>
|
|
2
|
+
import RadioGroup from '../UIcomponents/RadioGroup.svelte';
|
|
3
|
+
import RadioItem from '../UIcomponents/RadioItem.svelte';
|
|
4
|
+
/** @type {MIDIAccess|null|false} */
|
|
5
|
+
let midi = $state(null); // global MIDIAccess object
|
|
6
|
+
/**@type {MIDIInputMap|null} */
|
|
7
|
+
let outports = $state(null); // available MIDI outports
|
|
8
|
+
|
|
9
|
+
//TODO: choose port by name rather than index
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
/** @type {MIDIInput|null} */
|
|
13
|
+
let outport = null;
|
|
14
|
+
|
|
15
15
|
/**
|
|
16
16
|
* @typedef {Object} Props
|
|
17
17
|
* @property {number|null} [port]
|
|
@@ -20,74 +20,74 @@
|
|
|
20
20
|
|
|
21
21
|
/** @type {Props} */
|
|
22
22
|
let { port = $bindable(null), midiMessage = $bindable() } = $props();
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* set the midi access point and get the midi output port
|
|
26
|
-
* @param {MIDIAccess} midiAccess
|
|
27
|
-
*/
|
|
28
|
-
function onMIDISuccess(midiAccess) {
|
|
29
|
-
midi = midiAccess;
|
|
30
|
-
outports = midi.outputs; // store in the global (in real usage, would probably keep in an object instance)
|
|
31
|
-
if (port) {
|
|
32
|
-
setPort();
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* handle if external MIDI not available
|
|
38
|
-
* @param {string} msg
|
|
39
|
-
*/
|
|
40
|
-
function onMIDIFailure(msg) {
|
|
41
|
-
console.error(`Failed to get MIDI access - ${msg}`);
|
|
42
|
-
midi = false;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* set the output port when selected
|
|
47
|
-
*/
|
|
48
|
-
function setPort() {
|
|
49
|
-
if (!outports || !port) return;
|
|
50
|
-
|
|
51
|
-
// @ts-ignore - ts getting their types wrong...
|
|
52
|
-
outport = [...outports][port];
|
|
53
|
-
console.log(
|
|
54
|
-
// @ts-ignore - because outports will always exist, since we use the #if block
|
|
55
|
-
'connecting to MIDI output port: %c' + outports.get(outport[0]).name,
|
|
56
|
-
'font-style:italic'
|
|
57
|
-
);
|
|
58
|
-
// @ts-ignore - see previous comment
|
|
59
|
-
outports.get(outport[0]).onmidimessage = onMIDIMessage;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/** @param {MIDIMessageEvent} event */
|
|
63
|
-
function onMIDIMessage(event) {
|
|
64
|
-
midiMessage = event.data;
|
|
65
|
-
console.log(
|
|
66
|
-
'MIDI message from %c' + event.target.name + ': ' + midiMessage,
|
|
67
|
-
'font-style:italic'
|
|
68
|
-
);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
navigator.requestMIDIAccess().then(onMIDISuccess, onMIDIFailure);
|
|
72
|
-
</script>
|
|
73
|
-
|
|
74
|
-
<div class="RNBOsubcomponent">
|
|
75
|
-
<p class="RNBOtext">External MIDI outputs</p>
|
|
76
|
-
|
|
77
|
-
{#if midi && outports}
|
|
78
|
-
<!-- <slot {midi} {outports} {port}> -->
|
|
79
|
-
<RadioGroup>
|
|
80
|
-
{#each [...outports.entries()] as output, i}
|
|
81
|
-
<!-- first index of the output array is the id, second the object -->
|
|
82
|
-
<RadioItem bind:group={port} name="outports" value={i} on:change={setPort}
|
|
83
|
-
>{output[1].name}
|
|
84
|
-
</RadioItem>
|
|
85
|
-
{/each}
|
|
86
|
-
</RadioGroup>
|
|
87
|
-
<!-- </slot> -->
|
|
88
|
-
{:else if midi === false}
|
|
89
|
-
<p>MIDI access failed, please try in a different browser</p>
|
|
90
|
-
{:else}
|
|
91
|
-
<p>loading MIDI ports</p>
|
|
92
|
-
{/if}
|
|
93
|
-
</div>
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* set the midi access point and get the midi output port
|
|
26
|
+
* @param {MIDIAccess} midiAccess
|
|
27
|
+
*/
|
|
28
|
+
function onMIDISuccess(midiAccess) {
|
|
29
|
+
midi = midiAccess;
|
|
30
|
+
outports = midi.outputs; // store in the global (in real usage, would probably keep in an object instance)
|
|
31
|
+
if (port) {
|
|
32
|
+
setPort();
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* handle if external MIDI not available
|
|
38
|
+
* @param {string} msg
|
|
39
|
+
*/
|
|
40
|
+
function onMIDIFailure(msg) {
|
|
41
|
+
console.error(`Failed to get MIDI access - ${msg}`);
|
|
42
|
+
midi = false;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* set the output port when selected
|
|
47
|
+
*/
|
|
48
|
+
function setPort() {
|
|
49
|
+
if (!outports || !port) return;
|
|
50
|
+
|
|
51
|
+
// @ts-ignore - ts getting their types wrong...
|
|
52
|
+
outport = [...outports][port];
|
|
53
|
+
console.log(
|
|
54
|
+
// @ts-ignore - because outports will always exist, since we use the #if block
|
|
55
|
+
'connecting to MIDI output port: %c' + outports.get(outport[0]).name,
|
|
56
|
+
'font-style:italic'
|
|
57
|
+
);
|
|
58
|
+
// @ts-ignore - see previous comment
|
|
59
|
+
outports.get(outport[0]).onmidimessage = onMIDIMessage;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** @param {MIDIMessageEvent} event */
|
|
63
|
+
function onMIDIMessage(event) {
|
|
64
|
+
midiMessage = event.data;
|
|
65
|
+
console.log(
|
|
66
|
+
'MIDI message from %c' + event.target.name + ': ' + midiMessage,
|
|
67
|
+
'font-style:italic'
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
navigator.requestMIDIAccess().then(onMIDISuccess, onMIDIFailure);
|
|
72
|
+
</script>
|
|
73
|
+
|
|
74
|
+
<div class="RNBOsubcomponent">
|
|
75
|
+
<p class="RNBOtext">External MIDI outputs</p>
|
|
76
|
+
|
|
77
|
+
{#if midi && outports}
|
|
78
|
+
<!-- <slot {midi} {outports} {port}> -->
|
|
79
|
+
<RadioGroup>
|
|
80
|
+
{#each [...outports.entries()] as output, i}
|
|
81
|
+
<!-- first index of the output array is the id, second the object -->
|
|
82
|
+
<RadioItem bind:group={port} name="outports" value={i} on:change={setPort}
|
|
83
|
+
>{output[1].name}
|
|
84
|
+
</RadioItem>
|
|
85
|
+
{/each}
|
|
86
|
+
</RadioGroup>
|
|
87
|
+
<!-- </slot> -->
|
|
88
|
+
{:else if midi === false}
|
|
89
|
+
<p>MIDI access failed, please try in a different browser</p>
|
|
90
|
+
{:else}
|
|
91
|
+
<p>loading MIDI ports</p>
|
|
92
|
+
{/if}
|
|
93
|
+
</div>
|