-
Notifications
You must be signed in to change notification settings - Fork 79
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
Web MIDI support. #47
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wow, this is awesome! Thanks a lot!
I have only played a tiny little bit with wasm so far, so there is a lot of things here that I don't have a good understanding for, but I'll try my best.
One thing that's a bit unfortunate is that I have a branch in development (#38) which is almost finished and ready to be merged, which changes the API. So all backends need to be adapted. Do you think that you can rebase the Web MIDI support on that branch?
It might even make the code leaner and cleaner because ports are no longer identified by the index and it seems that your DeviceSet
might become simpler or superfluous then.
Concerning the asychronicity:
The issue seems to be in how to handle js_sys::Promise
, right? I think the only way to really fix this is to introduce Rust's new async
into midir's API. Which is probably a good idea anyway, but out of scope for this PR. (Can js_sys::Promise
interoperate with async
?)
You can open a follow-up issue so we don't forget about it, and that also serves as documentation about this "known issue" (i.e. that messages might be lost because the asynchronous port opening has not completed yet).
I have left some more comments inline.
input: web_sys::MidiInput, | ||
user_data: Arc<Mutex<Option<T>>>, | ||
#[allow(dead_code)] // Must be kept alive until we decide to unregister from input | ||
closure: Closure<dyn FnMut(MidiMessageEvent)>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If that is how you have to do things for event handlers in js_sys
, that seems a bit unsafe to me ... but probably it's the only way?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just found https://rustwasm.github.io/wasm-bindgen/api/wasm_bindgen/closure/struct.Closure.html which explain this a bit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I don't have a great alternative here. Dropping the closure will cause the JS function to start throwing exceptions/panicing when called. Fortunately, this starts happening immediately, so it's easy to test/catch if mistakes are made.
My pleasure 👍
Feel free to ask questions, I'm happy to chime in.
Sure! It's what I get for my PR first, ask questions later style :). I've subscribed to #38 so I should get a notification for when that lands as well.
Looks like it, yeah, I should be able to simply lookup in the map.
Yes.
That would be one of the more solid options I think, yeah.
I believe so - I've mucked with
Sounds good! #48
Will address and rebase 👍 |
One more thing: We should add the wasm target to the CI configuration. I'm not sure which host platform should be used to build it, though. If you're not familiar with Azure Pipelines, that's fine and I can do it as a follow-up. |
I'm not sure which host should be used either. Maybe windows, under the assumption that it's the best supported by azure pipelines...? On travis I've generally used linux hosts for faster boot... And then you've got two options: Cheap, fastrustup target add wasm32-unknown-unknown
cargo build --target=wasm32-unknown-unknown Test the entire CI setup, taking a few minutes to install wasm-packcargo install wasm-pack
cd examples\browser
wasm-pack build --target=no-modules --dev (EDIT: cargo install, not rustup install) |
5a59ec1
to
ab30c2b
Compare
ab30c2b
to
e36019c
Compare
Rebased... also squashed. Was able to delete a good chunk of code. I think I addressed everything but the azure pipelines configuration. |
Okay, than this is blocked on getting #38 merged (which is blocked on chris-zen/coremidi#14) ... by the way, have you checked that your structs all implement Because #38 contains unit tests that check for this. |
Most of them don't implement Send. AFAIK wasm threads are implemented as web workers sharing a memory buffer but not sharing JS execution contexts, nor having any sort of access to the DOM, or anything else fun. I could get them implementing Send by storing String s instead I guess, but all API calls would still fail unless on the main/ui/tab thread, so I'm not sure if that's actually a good idea. I suppose it might be possible to workaround that with message queues and setInterval or requestAnimationFrame draining said message queue on the main thread...? |
Okay, I guess it's fine to live with the fact that |
So I have a changeset to get:
compiling (and running, not that there's anything to run). The most awkward bit is the need to duplicate MidiInput::connect in common.rs to have a non-Send variation in order for test_forward.rs to compile, as otherwise it needs conn_out (MidiOutput) to be Send. I can either commit that as-is to this branch (this commit if you want to see it for yourself: MaulingMonkey@6c76a9b ), or I can take a stab at doing the message queue thing to make things Send able. Any preference...? |
Hm, I see ... so in Web MIDI the input callback is guaranteed to be called on the main thread, i.e. on the (only) thread that you can also send messages from? Is there prior experience with threading on WebAssembly (in conjunction with Also, these trait bounds may need to be reconsidered anyway when we tackle #48, so I would be fine to just disable the stuff that doesn't work yet (including |
As I understand it, yes.
It's still kinda early but there's at least a multithreaded ray tracing demo out there. Chrome WASM threads are still behind a chrome://flags gate as I understand it:
Fair.
Me either 😄 |
7b865ed
to
39ed62e
Compare
I now merged #38 and have changed the base branch of this PR back to master. Can you please rebase your commits? Furthermore, I tried |
Will do.
Nothing! Currently, wasm tests also need to be marked #[wasm_bindgen_test] to run. I can mark common.rs 's test_trait_impls with it if you want, but since the whole point of the test is just to ensure it compiles, I left it alone, I didn't see much need. It'll still log the same message for virtual.rs - where we intentionally #[cfg(...)] out the entire module due to missing virtual port support. Ideally wasm-pack wouldn't try to run tests for that file at all... |
5bfc04d
to
af473ab
Compare
Ahh, I should probably actually test my rebase shouldn't I... |
Rebase tested, works on my machine (tm) 👍 |
@MaulingMonkey Thanks again for the PR! I added CI integration in 109a884. |
Thanks for providing the solid base for me to contribute to! :) |
Concerns
Web MIDI is all kinds of asyncronous. Devices won't be available if you try to block request them immediately. It's possible that sending a MIDI device input immediately after opening it, if that input device requires system exclusive access, may not work. It'd perhaps be possible to buffer data until the promise for opening the device resolves...
Testing
Note that existing chrome instances may interfere with using command line flags - you may prefer to use the msjsdiag.debugger-for-chrome extension instead. Snippets from my local .vscode config:
.vscode\tasks.json
.vscode\launch.json
Screenshots