1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
//! The bottom of the stack: moving bytes to and from the device.
//!
//! Everything above this trait is pure logic, so the whole protocol can be built and
//! tested against committed captures with no hardware attached — the same property
//! that makes [`nord_format`] trustworthy.
use crateResult;
pub use UsbTransport;
// ⚠️ `web-sys` emits WebUSB only under the unstable cfg supplied for wasm targets.
pub use WebUsbTransport;
// Same gate as the desktop backend: it taps that transport and needs a filesystem.
pub use Recorder;
pub use ;
/// Clavia DMI AB. Read off the device descriptor in a firmware-update capture.
pub const VENDOR_ID: u16 = 0x0ffc;
/// Nord Electro 5.
pub const PRODUCT_ID_ELECTRO5: u16 = 0x0027;
/// USB vendor-specific interface class. The protocol rides this; the instrument's
/// other interface is USB-MIDI (audio class), which every backend must leave alone so
/// CoreMIDI/ALSA keep working — and which the browser would refuse to claim anyway.
pub const CLASS_VENDOR_SPECIFIC: u8 = 0xff;
/// Vendor bulk IN endpoint (device → host). Settled across every corpus capture.
pub const EP_IN: u8 = 0x82;
/// Vendor bulk OUT endpoint (host → device).
pub const EP_OUT: u8 = 0x03;
/// The read buffer NSM posts. The device answers with ~32KB chunks; the size is the
/// device's choice, not a USB constraint (the link is Full Speed, 64-byte packets).
pub const READ_BUFFER: usize = 49152;
/// A bidirectional byte pipe to the device.
///
/// # Why this shape
///
/// **No `Send` bounds.** WASM is single-threaded and `web-sys` types are `!Send`, so
/// requiring `Send` futures — which `#[async_trait]` adds by default, and which
/// `tokio::spawn` demands — would make the WebUSB backend impossible, and the
/// requirement would infect every generic bound above this one. The
/// `async_fn_in_trait` lint fires precisely because callers *cannot* add a `Send`
/// bound here; that is the intent, so it is allowed deliberately. Desktop callers
/// needing `Send` should bound on a `SendTransport` marker rather than changing this.
///
/// **Separate directions, not request/response.** Several operations send multiple
/// OUTs before any IN (`delete` is `O36 O26 I30`), so a `send_and_receive()` primitive
/// would be a lie.
///
/// **Owned buffers.** WebUSB hands back an `ArrayBuffer`; a borrowed `&[u8]` return
/// cannot be honored.
///
/// **No timeout parameter.** WebUSB has no native transfer timeout — callers wrap.
/// Opt-in marker for desktop callers that need to move a transport across threads.
/// Deliberately *not* a supertrait of [`Transport`] — see the note there.