Skip to content

Commit

Permalink
c2js - midi output and device select (#204)
Browse files Browse the repository at this point in the history
* update c2js template for midi device selection

* wasm midi_out implemented, no test

* scriptprocessornode

* clean up  shared code

* midi_utils

* consistency

* revert attempt to remove dublicate code, channel bugfix, cleanup

* consistency

* consistency

* changelog and channel

---------

Co-authored-by: Reinissance <reinissancey@gmail.com>
  • Loading branch information
dromer and Reinissance authored Oct 14, 2024
1 parent 250a1a1 commit 8759c49
Show file tree
Hide file tree
Showing 5 changed files with 438 additions and 201 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ Bugfixes:

* Daisy template newline

* JS: midi out and device select

0.12.1
-----

Expand Down
221 changes: 150 additions & 71 deletions hvcc/generators/c2js/template/hv_worklet.js
Original file line number Diff line number Diff line change
Expand Up @@ -108,13 +108,22 @@ class {{name}}_AudioLibWorklet extends AudioWorkletProcessor {
var self = this;
// typedef void (HvSendHook_t) (HeavyContextInterface *context, const char *sendName, hv_uint32_t sendHash, const HvMessage *msg);
var sendHook = addFunction(function(context, sendName, sendHash, msg) {
// Filter out MIDI messages
const midiMessage = sendMidiOut(UTF8ToString(sendName), msg);
if (midiMessage.length > 0) {
self.port.postMessage({
type: 'midiOut',
payload: midiMessage
});
} else {
// Converts sendhook callback to (sendName, float) message
self.port.postMessage({
type: 'sendHook',
payload: [UTF8ToString(sendName), _hv_msg_getFloat(msg, 0)]
});
},
"viiii"
}
},
"viiii"
);
_hv_setSendHook(this.heavyContext, sendHook);
}
Expand All @@ -132,73 +141,7 @@ class {{name}}_AudioLibWorklet extends AudioWorkletProcessor {
}

sendMidi(message) {
if (this.heavyContext) {
var command = message[0] & 0xF0;
var channel = message[0] & 0x0F;
var data1 = message[1];
var data2 = message[2];

// all events to [midiin]
for (var i = 1; i <= 2; i++) {
_hv_sendMessageToReceiverFF(this.heavyContext, HV_HASH_MIDIIN, 0,
message[i],
channel
);
}

// realtime events to [midirealtimein]
if (MIDI_REALTIME.includes(message[0])) {
_hv_sendMessageToReceiverFF(this.heavyContext, HV_HASH_MIDIREALTIMEIN, 0,
message[0]
);
}

switch(command) {
case 0x80: // note off
_hv_sendMessageToReceiverFFF(this.heavyContext, HV_HASH_NOTEIN, 0,
data1,
0,
channel);
break;
case 0x90: // note on
_hv_sendMessageToReceiverFFF(this.heavyContext, HV_HASH_NOTEIN, 0,
data1,
data2,
channel);
break;
case 0xA0: // polyphonic aftertouch
_hv_sendMessageToReceiverFFF(this.heavyContext, HV_HASH_POLYTOUCHIN, 0,
data2, // pressure
data1, // note
channel);
break;
case 0xB0: // control change
_hv_sendMessageToReceiverFFF(this.heavyContext, HV_HASH_CTLIN, 0,
data2, // value
data1, // cc number
channel);
break;
case 0xC0: // program change
_hv_sendMessageToReceiverFF(this.heavyContext, HV_HASH_PGMIN, 0,
data1,
channel);
break;
case 0xD0: // aftertouch
_hv_sendMessageToReceiverFF(this.heavyContext, HV_HASH_TOUCHIN, 0,
data1,
channel);
break;
case 0xE0: // pitch bend
// combine 7bit lsb and msb into 32bit int
var value = (data2 << 7) | data1;
_hv_sendMessageToReceiverFF(this.heavyContext, HV_HASH_BENDIN, 0,
value,
channel);
break;
default:
// console.error('No handler for midi message: ', message);
}
}
sendMidiIn(this.heavyContext, message);
}

sendStringToReceiver(name, message) {
Expand Down Expand Up @@ -265,9 +208,145 @@ var tableHashes = {
registerProcessor("{{name}}_AudioLibWorklet", {{name}}_AudioLibWorklet);


// midi_utils

function sendMidiIn(hv_context, message) {
if (hv_context) {
var command = message[0] & 0xF0;
var channel = message[0] & 0x0F;
var data1 = message[1];
var data2 = message[2];

// all events to [midiin]
for (var i = 1; i <= 2; i++) {
_hv_sendMessageToReceiverFF(hv_context, HV_HASH_MIDIIN, 0,
message[i],
channel
);
}

// realtime events to [midirealtimein]
if (MIDI_REALTIME.includes(message[0])) {
_hv_sendMessageToReceiverFF(hv_context, HV_HASH_MIDIREALTIMEIN, 0,
message[0]
);
}

switch(command) {
case 0x80: // note off
_hv_sendMessageToReceiverFFF(hv_context, HV_HASH_NOTEIN, 0,
data1,
0,
channel);
break;
case 0x90: // note on
_hv_sendMessageToReceiverFFF(hv_context, HV_HASH_NOTEIN, 0,
data1,
data2,
channel);
break;
case 0xA0: // polyphonic aftertouch
_hv_sendMessageToReceiverFFF(hv_context, HV_HASH_POLYTOUCHIN, 0,
data2, // pressure
data1, // note
channel);
break;
case 0xB0: // control change
_hv_sendMessageToReceiverFFF(hv_context, HV_HASH_CTLIN, 0,
data2, // value
data1, // cc number
channel);
break;
case 0xC0: // program change
_hv_sendMessageToReceiverFF(hv_context, HV_HASH_PGMIN, 0,
data1,
channel);
break;
case 0xD0: // aftertouch
_hv_sendMessageToReceiverFF(hv_context, HV_HASH_TOUCHIN, 0,
data1,
channel);
break;
case 0xE0: // pitch bend
// combine 7bit lsb and msb into 32bit int
var value = (data2 << 7) | data1;
_hv_sendMessageToReceiverFF(hv_context, HV_HASH_BENDIN, 0,
value,
channel);
break;
default:
// console.error('No handler for midi message: ', message);
}
}
}

function sendMidiOut(sendName, msg) {
switch (sendName) {
case "__hv_noteout":
var note = _hv_msg_getFloat(msg, 0);
var velocity = _hv_msg_getFloat(msg, 1);
var channel = _hv_msg_getFloat(msg, 2) % 16; // no pd midi ports
return [
((velocity > 0) ? 144 : 128) | channel,
note,
velocity
]
case "__hv_ctlout":
var value = _hv_msg_getFloat(msg, 0);
var cc = _hv_msg_getFloat(msg, 1);
var channel = _hv_msg_getFloat(msg, 2) % 16; // no pd midi ports
return [
176 | channel,
cc,
value
]
case "__hv_pgmout":
var program = _hv_msg_getFloat(msg, 0);
var channel = _hv_msg_getFloat(msg, 1) % 16; // no pd midi ports
return [
192 | channel,
program
]
case "__hv_touchout":
var pressure = _hv_msg_getFloat(msg, 0);
var channel = _hv_msg_getFloat(msg, 1) % 16; // no pd midi ports
return [
208 | channel,
pressure,
]
case "__hv_polytouchout":
var value = _hv_msg_getFloat(msg, 0);
var note = _hv_msg_getFloat(msg, 1);
var channel = _hv_msg_getFloat(msg, 2) % 16; // no pd midi ports
return[
160 | channel,
note,
value
]
case "__hv_bendout":
var value = _hv_msg_getFloat(msg, 0);
let lsb = value & 0x7F;
let msb = (value >> 7) & 0x7F;
var channel = _hv_msg_getFloat(msg, 1) % 16; // no pd midi ports
return [
224 | channel,
lsb,
msb
]
case "__hv_midiout":
let firstByte = _hv_msg_getFloat(msg, 0);
return (firstByte === 192 || firstByte === 208) ?
[_hv_msg_getFloat(msg, 0), _hv_msg_getFloat(msg, 1)] :
[_hv_msg_getFloat(msg, 0), _hv_msg_getFloat(msg, 1), _hv_msg_getFloat(msg, 2)];
default:
console.warn(`Unhandled sendName: ${sendName}`);
return [];
}
}

/*
* MIDI Constants
*/
* MIDI Constants
*/

const HV_HASH_NOTEIN = 0x67E37CA3;
const HV_HASH_CTLIN = 0x41BE0f9C;
Expand Down
2 changes: 1 addition & 1 deletion hvcc/generators/c2js/template/hv_worklet_start.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ var self = {

function importScripts(){
console.warn('importScripts should not be called in an AudioWorklet', arguments);
}
}
Loading

0 comments on commit 8759c49

Please sign in to comment.