midi-communications-windows 0.0.3 → 0.1.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d7c6d6e900a9daa9c9a95c48a2c5b68b97bf02cd35694a0a5110cbe5ac9f1f9b
4
- data.tar.gz: b2135a883c9648f77e6dbe99a5f1b25941c595f39c28dba3a5968d85f6b4d598
3
+ metadata.gz: fab76aff1317f582ff061ecac55ad7bdf25f27ed0ad1c55508f7481f88ae159a
4
+ data.tar.gz: b8d67bd3c739c80b5373ef1f6834ed73c20ccfec7301d539706d13703381d98b
5
5
  SHA512:
6
- metadata.gz: 294cfb3185f4fb694d5769fb43643260632772e9e7eea8be47691b5be92f65a64e51bf5f31b087a85a7e780d98532eca59a7311dec5d1b477cbc375b4836c884
7
- data.tar.gz: bd6e9bc0bf14f7607d7d014f45e833311c874f56e58082c16bc7191030d050f8a33b4e7817b80dc8c92baa161f9c45754969b2ae837f2d37170a0a44193a2f8e
6
+ metadata.gz: bd3861ebb4b96e659894b35810a5db436be4901a631ce13f06ae7401d72846d25b32b408f5607cb35020045756ba0e20bc375f4c57947f73f3a45bd303dad8ae
7
+ data.tar.gz: 559595e2a885245f981d4d8bd90376fc584a4d15ebd475c5e5391b81dee1aeafb5b3ea82551af4cae31f717d0f5d940d3b23d5d76984eb158fbd0f55697740b0
@@ -0,0 +1,17 @@
1
+ name: Notify Plugin Rebuild
2
+
3
+ on:
4
+ push:
5
+ branches: [master]
6
+
7
+ jobs:
8
+ notify:
9
+ runs-on: ubuntu-latest
10
+ steps:
11
+ - name: Trigger nota-plugin rebuild
12
+ uses: peter-evans/repository-dispatch@v3
13
+ with:
14
+ token: ${{ secrets.PLUGIN_REBUILD_PAT }}
15
+ repository: javier-sy/nota-plugin
16
+ event-type: source-updated
17
+ client-payload: '{"repo": "${{ github.repository }}", "sha": "${{ github.sha }}"}'
data/.yardoc/checksums CHANGED
@@ -4,5 +4,5 @@ lib/midi-communications-windows/input.rb 36e58891d1c604dd4b2f333382a4010660d4786
4
4
  lib/midi-communications-windows/device.rb 9f151193d144c298c064592ee21d44111f968d01
5
5
  lib/midi-communications-windows/output.rb 3069d46892268c529d999363bd05fac891e5f4fc
6
6
  lib/midi-communications-windows/message.rb 2390946620b244ec12a6b373e003304ef9c29e4d
7
- lib/midi-communications-windows/version.rb 3dbf5650d0b320f6164b3791f859d2551162dc0a
7
+ lib/midi-communications-windows/version.rb 902ae38c68bbfd2670740b7d7bb6a342f77cbb68
8
8
  lib/midi-communications-windows/type_conversion.rb dae7dc5109d955f4693920fa173f5c143dcb7bf1
Binary file
data/.yardopts CHANGED
@@ -4,5 +4,3 @@
4
4
  --no-private
5
5
  --embed-mixins
6
6
  lib/**/*.rb
7
- -
8
- docs/testing-on-windows.md
data/README.md CHANGED
@@ -19,68 +19,31 @@ This library is part of a suite of Ruby libraries for MIDI:
19
19
  | Low level MIDI interface to Linux | **TO DO** (by now [MIDI Communications](https://github.com/javier-sy/midi-communications) uses [alsa-rawmidi](http://github.com/arirusso/alsa-rawmidi)) |
20
20
  | Low level MIDI interface to JRuby | **TO DO** (by now [MIDI Communications](https://github.com/javier-sy/midi-communications) uses [midi-jruby](http://github.com/arirusso/midi-jruby)) |
21
21
 
22
- ## Status
23
-
24
- **Early.** Everything is written and has been exercised end to end on Windows 11
25
- 25H2 against system loopback endpoints: enumeration, short messages in both
26
- directions, System Exclusive in both directions including a message larger than
27
- the whole buffer queue, twenty open/close cycles, and the error path. What has
28
- not been exercised is anything needing real hardware — a physical interface slow
29
- enough to make `Output`'s System Exclusive wait mean something, and a port
30
- appearing or disappearing while the program runs.
31
-
32
- The version stays in the 0.0.x series because that was a virtual machine with no
33
- MIDI hardware in it, not because anything is known to be missing. It will not be
34
- published to RubyGems until a physical MIDI interface has closed the items
35
- [`docs/testing-on-windows.md`](docs/testing-on-windows.md) lists as untestable
36
- without one.
37
-
38
- That document is also how to rebuild the test environment: it is the procedure
39
- these measurements were taken with, including how to make two ports collide in
40
- WinMM's 31 characters of name.
41
-
42
- ### One thing worth knowing before you use it
43
-
44
- `Input#gets` **waits**. It does not return an empty array when nothing has
45
- arrived; it blocks until something does, and then returns everything that
46
- accumulated. Calling it on a quiet port looks exactly like a hung program. That
47
- is deliberate — `Musa::Clock::InputMidiClock` reads in a loop with no delay of
48
- its own and relies on it — but it will surprise anyone arriving from an API that
49
- polls.
22
+ You will normally reach it through
23
+ [MIDI Communications](https://github.com/javier-sy/midi-communications), which
24
+ depends on it and selects it on Windows. It implements that gem's physical layer
25
+ contract; anything about how ports behave is documented there, in
26
+ `MIDICommunications::PhysicalLayer`.
50
27
 
51
- ## Requirements
52
-
53
- * [ffi](http://github.com/ffi/ffi)
28
+ ## Features
54
29
 
55
- Nothing else. `winmm.dll` is part of Windows, so this gem binds a library that
56
- is already on the machine and ships no compiled artifact of its own.
30
+ * Simplified API
31
+ * Input and output on multiple devices concurrently
32
+ * Generalized handling of different MIDI Message types (including SysEx)
33
+ * Timestamped input events
34
+ * Patch MIDI via software to other programs using a loopback endpoint
35
+ * No compiled artifact: `winmm.dll` is part of Windows
57
36
 
58
- ### Which versions of Windows
37
+ Runnable examples of the API are in [`examples/`](examples).
59
38
 
60
- **By construction, old ones.** Everything this gem calls is the oldest MIDI API
61
- Windows has — `midiInOpen`, `midiOutShortMsg`, `midiOutLongMsg` and their
62
- neighbours — plus three functions for a thread's message queue, `GetMessageW`,
63
- `PeekMessageW` and `PostThreadMessageW`. All of it, the Unicode entry points
64
- included, dates from the NT era. Nothing here calls Windows MIDI Services, which
65
- means nothing here needs Windows 11.
66
-
67
- What changes on an older system is not whether the gem works but what the
68
- platform gives it. Before Windows MIDI Services a MIDI port is **exclusive** —
69
- one program at a time — and there are no system loopback endpoints, so routing
70
- MIDI between applications on one machine needs a third-party driver such as
71
- loopMIDI. The same code, a poorer platform.
39
+ ## Status
72
40
 
73
- A 32-bit Ruby should also be fine: the two size checks that only hold on 64-bit
74
- Windows are guarded, and the two that are checked everywhere describe structures
75
- whose layout does not depend on the word size.
41
+ **Early.** Tested on Windows 11 without external MIDI devices. Everything works
42
+ against loopback ports; running it against real hardware is still pending.
76
43
 
77
- **None of which has been run.** The only system this has ever executed on is
78
- Windows 11 25H2, in a virtual machine, on an x64 Ruby under ARM emulation. The
79
- paragraphs above say what the code asks of Windows, not what has been observed;
80
- treat them as a reason to expect it to work rather than as a report that it does.
44
+ ## Requirements
81
45
 
82
- Where the floor actually sits is a question about Ruby, not about this gem:
83
- RubyInstaller recommends Windows 10 or 11 and publishes no hard cutoff.
46
+ * [ffi](http://github.com/ffi/ffi)
84
47
 
85
48
  ## Installation
86
49
 
@@ -94,78 +57,7 @@ Otherwise
94
57
 
95
58
  ## Documentation
96
59
 
97
- [rdoc](http://rubydoc.info/github/javier-sy/midi-communications-windows)
98
-
99
- ## Why WinMM and not one of the newer Windows MIDI APIs
100
-
101
- Windows has three MIDI APIs a program could reach for, and as of February 2026
102
- the oldest is the right one for Ruby.
103
-
104
- **Windows MIDI Services** became generally available in Windows 11 in February
105
- 2026, replacing the MIDI stack underneath. Rather than retiring the older APIs,
106
- Microsoft reconnected them to the new service, so a WinMM client needs nothing
107
- installed to reach what the new stack provides — including the loopback
108
- endpoints the system now creates itself, which is what previously required a
109
- third-party driver.
110
-
111
- Multi-client access arrives the same way, but **per endpoint, not per API**.
112
- Measured on Windows 11 25H2 through this library: two clients opened the same
113
- loopback input at once and both received every message, while a second open of
114
- the classic `wdmaud` software synthesiser was refused with "The specified device
115
- is already in use". Endpoints carried by the new transports are shared;
116
- endpoints still on the old drivers are exclusive, as they always were. On
117
- Windows 10 there is no Windows MIDI Services at all.
118
-
119
- **The Windows MIDI Services App SDK** offers MIDI 2.0 and UMP, neither of which
120
- this library needs: `midi-communications` and MusaDSL are MIDI 1.0 throughout.
121
- It is published only as WinRT, and Microsoft's guidance is that other languages
122
- obtain a WinRT projection from their toolchain. Ruby has none.
123
-
124
- **WinRT `Windows.Devices.Midi`** is, under the new stack, another compatibility
125
- layer onto the same service. It offers what WinMM offers, in exchange for
126
- hand-written COM.
127
-
128
- ## Differences from the macOS layer
129
-
130
- The two libraries implement the same contract over platforms that do not have
131
- the same shape. Where they differ, they differ because the platforms do:
132
-
133
- * **`manufacturer` and `model` are `nil`.** WinMM reports `wMid` and `wPid`,
134
- numeric codes from a manufacturer registry that stopped being maintained in
135
- the 1990s and that class-compliant USB devices almost all answer with
136
- Microsoft's. Core MIDI reports real strings. Inventing text from the codes
137
- would describe the code table, not the hardware.
138
- * **`display_name` is the port name.** On macOS it is composed as
139
- "manufacturer model (name)", which here would be a name wrapped in the
140
- punctuation of two absent fields.
141
- * **Port ids are unique within a direction, not across both.** A WinMM port is
142
- identified by its index among inputs or among outputs, and that index is what
143
- is passed to `midiInOpen`. Core MIDI numbers endpoints of both directions from
144
- one counter. Input 0 and output 0 are both valid here, and unrelated.
145
- * **Port names are truncated to 31 characters, and do not identify a port.**
146
- That is all WinMM stores, and it drops the rest silently. Two loopback
147
- endpoints whose names differed only past character 31 came back identical in
148
- every field of `MIDIINCAPSW` — same name, same `wMid`, same `wPid`, same
149
- `wTechnology` — distinguishable only by index. Core MIDI names are neither
150
- truncated nor, in practice, ambiguous.
151
- * **Enumeration is not cached, but wrappers are reused.** The macOS layer reads
152
- the device list once and keeps it, so a device plugged in later is never seen.
153
- Here WinMM is asked on every call, and a port still present comes back as the
154
- same object it was before, so opening a port and then reading from it works
155
- whether or not the caller kept the reference.
156
- * **There is no packet-list parsing.** Core MIDI delivers a list of packets that
157
- has to be walked; WinMM delivers one complete short message at a time, with
158
- running status already resolved by the driver.
159
-
160
- ## Relationship to midi-winmm
161
-
162
- This library is **not** derived from [midi-winmm](http://github.com/arirusso/midi-winmm),
163
- which was written in 2011 for 32-bit Ruby. Windows is LLP64: on a 64-bit Ruby,
164
- `unsigned long` is 32 bits while a `HANDLE` is 64, so that library's
165
- `typedef :ulong, :HANDLE` truncates every handle it obtains. It also reads port
166
- names through the ANSI entry points, which mangle any name that is not ASCII.
167
- Both are addressed here by construction; see the notes in
168
- `lib/midi-communications-windows/api.rb`.
60
+ [rdoc](https://www.rubydoc.info/gems/midi-communications-windows)
169
61
 
170
62
  ## Author
171
63
 
@@ -134,7 +134,7 @@ WinMM there expects.</p>
134
134
  </div>
135
135
 
136
136
  <div id="footer">
137
- Generated on Sun Sep 6 21:20:52 2026 by
137
+ Generated on Mon Sep 7 01:25:12 2026 by
138
138
  <a href="https://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
139
139
  0.9.45 (ruby-3.4.7).
140
140
  </div>
@@ -132,7 +132,7 @@ declared as <code>:uint16</code> so that reading it cannot split a character in
132
132
  </div>
133
133
 
134
134
  <div id="footer">
135
- Generated on Sun Sep 6 21:20:52 2026 by
135
+ Generated on Mon Sep 7 01:25:12 2026 by
136
136
  <a href="https://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
137
137
  0.9.45 (ruby-3.4.7).
138
138
  </div>
@@ -130,7 +130,7 @@
130
130
  </div>
131
131
 
132
132
  <div id="footer">
133
- Generated on Sun Sep 6 21:20:52 2026 by
133
+ Generated on Mon Sep 7 01:25:12 2026 by
134
134
  <a href="https://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
135
135
  0.9.45 (ruby-3.4.7).
136
136
  </div>
@@ -133,7 +133,7 @@ is 48 bytes on 64-bit Windows, which is what the queue functions expect.</p>
133
133
  </div>
134
134
 
135
135
  <div id="footer">
136
- Generated on Sun Sep 6 21:20:52 2026 by
136
+ Generated on Mon Sep 7 01:25:12 2026 by
137
137
  <a href="https://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
138
138
  0.9.45 (ruby-3.4.7).
139
139
  </div>
@@ -971,7 +971,7 @@ than showing a replacement character.</p>
971
971
  </div>
972
972
 
973
973
  <div id="footer">
974
- Generated on Sun Sep 6 21:20:52 2026 by
974
+ Generated on Mon Sep 7 01:25:12 2026 by
975
975
  <a href="https://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
976
976
  0.9.45 (ruby-3.4.7).
977
977
  </div>
@@ -355,7 +355,7 @@ back as the same object as before; see <span class='object_link'><a href="../Dev
355
355
  </div>
356
356
 
357
357
  <div id="footer">
358
- Generated on Sun Sep 6 21:20:52 2026 by
358
+ Generated on Mon Sep 7 01:25:12 2026 by
359
359
  <a href="https://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
360
360
  0.9.45 (ruby-3.4.7).
361
361
  </div>
@@ -1086,7 +1086,7 @@ may already hold.</p>
1086
1086
  </div>
1087
1087
 
1088
1088
  <div id="footer">
1089
- Generated on Sun Sep 6 21:20:52 2026 by
1089
+ Generated on Mon Sep 7 01:25:12 2026 by
1090
1090
  <a href="https://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
1091
1091
  0.9.45 (ruby-3.4.7).
1092
1092
  </div>
@@ -978,7 +978,7 @@ the reserved id <code>-1</code> and does not count among its devices.</p>
978
978
  </div>
979
979
 
980
980
  <div id="footer">
981
- Generated on Sun Sep 6 21:20:52 2026 by
981
+ Generated on Mon Sep 7 01:25:12 2026 by
982
982
  <a href="https://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
983
983
  0.9.45 (ruby-3.4.7).
984
984
  </div>
@@ -428,7 +428,7 @@ for instance</p></div>
428
428
  </div>
429
429
 
430
430
  <div id="footer">
431
- Generated on Sun Sep 6 21:20:52 2026 by
431
+ Generated on Mon Sep 7 01:25:12 2026 by
432
432
  <a href="https://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
433
433
  0.9.45 (ruby-3.4.7).
434
434
  </div>
@@ -1544,7 +1544,7 @@ may already hold.</p>
1544
1544
  </div>
1545
1545
 
1546
1546
  <div id="footer">
1547
- Generated on Sun Sep 6 21:20:52 2026 by
1547
+ Generated on Mon Sep 7 01:25:12 2026 by
1548
1548
  <a href="https://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
1549
1549
  0.9.45 (ruby-3.4.7).
1550
1550
  </div>
@@ -690,7 +690,7 @@ byte calls for</p></div>
690
690
  </div>
691
691
 
692
692
  <div id="footer">
693
- Generated on Sun Sep 6 21:20:52 2026 by
693
+ Generated on Mon Sep 7 01:25:12 2026 by
694
694
  <a href="https://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
695
695
  0.9.45 (ruby-3.4.7).
696
696
  </div>
@@ -1687,7 +1687,7 @@ else, and this is where the two part company.</p>
1687
1687
  </div>
1688
1688
 
1689
1689
  <div id="footer">
1690
- Generated on Sun Sep 6 21:20:53 2026 by
1690
+ Generated on Mon Sep 7 01:25:12 2026 by
1691
1691
  <a href="https://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
1692
1692
  0.9.45 (ruby-3.4.7).
1693
1693
  </div>
@@ -359,7 +359,7 @@
359
359
  </div>
360
360
 
361
361
  <div id="footer">
362
- Generated on Sun Sep 6 21:20:52 2026 by
362
+ Generated on Mon Sep 7 01:25:12 2026 by
363
363
  <a href="https://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
364
364
  0.9.45 (ruby-3.4.7).
365
365
  </div>
@@ -184,7 +184,7 @@ RubyGems is where installations break; there is nothing here to break.</p>
184
184
 
185
185
  </div>
186
186
  </dt>
187
- <dd><pre class="code"><span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>0.0.3</span><span class='tstring_end'>&#39;</span></span><span class='period'>.</span><span class='id identifier rubyid_freeze'>freeze</span></pre></dd>
187
+ <dd><pre class="code"><span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>0.1.0</span><span class='tstring_end'>&#39;</span></span><span class='period'>.</span><span class='id identifier rubyid_freeze'>freeze</span></pre></dd>
188
188
 
189
189
  </dl>
190
190
 
@@ -200,7 +200,7 @@ RubyGems is where installations break; there is nothing here to break.</p>
200
200
  </div>
201
201
 
202
202
  <div id="footer">
203
- Generated on Sun Sep 6 21:20:52 2026 by
203
+ Generated on Mon Sep 7 01:25:12 2026 by
204
204
  <a href="https://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
205
205
  0.9.45 (ruby-3.4.7).
206
206
  </div>
data/doc/_index.html CHANGED
@@ -65,9 +65,6 @@
65
65
  <li class="r1"><a href="index.html" title="README">README</a></li>
66
66
 
67
67
 
68
- <li class="r2"><a href="file.testing-on-windows.html" title="testing-on-windows">testing-on-windows</a></li>
69
-
70
-
71
68
  </ul>
72
69
 
73
70
  <div class="clear"></div>
@@ -252,7 +249,7 @@
252
249
  </div>
253
250
 
254
251
  <div id="footer">
255
- Generated on Sun Sep 6 21:20:52 2026 by
252
+ Generated on Mon Sep 7 01:25:12 2026 by
256
253
  <a href="https://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
257
254
  0.9.45 (ruby-3.4.7).
258
255
  </div>
data/doc/file.README.html CHANGED
@@ -103,125 +103,35 @@
103
103
  </tr>
104
104
  </tbody>
105
105
  </table>
106
+ <p>You will normally reach it through
107
+ <a href="https://github.com/javier-sy/midi-communications">MIDI Communications</a>, which
108
+ depends on it and selects it on Windows. It implements that gem's physical layer
109
+ contract; anything about how ports behave is documented there, in
110
+ <code>MIDICommunications::PhysicalLayer</code>.</p>
111
+ <h2 id="Features">Features</h2>
112
+ <ul>
113
+ <li>Simplified API</li>
114
+ <li>Input and output on multiple devices concurrently</li>
115
+ <li>Generalized handling of different MIDI Message types (including SysEx)</li>
116
+ <li>Timestamped input events</li>
117
+ <li>Patch MIDI via software to other programs using a loopback endpoint</li>
118
+ <li>No compiled artifact: <code>winmm.dll</code> is part of Windows</li>
119
+ </ul>
120
+ <p>Runnable examples of the API are in <a href="examples"><code>examples/</code></a>.</p>
106
121
  <h2 id="Status">Status</h2>
107
- <p><strong>Early.</strong> Everything is written and has been exercised end to end on Windows 11
108
- 25H2 against system loopback endpoints: enumeration, short messages in both
109
- directions, System Exclusive in both directions including a message larger than
110
- the whole buffer queue, twenty open/close cycles, and the error path. What has
111
- not been exercised is anything needing real hardware — a physical interface slow
112
- enough to make <code>Output</code>'s System Exclusive wait mean something, and a port
113
- appearing or disappearing while the program runs.</p>
114
- <p>The version stays in the 0.0.x series because that was a virtual machine with no
115
- MIDI hardware in it, not because anything is known to be missing. It will not be
116
- published to RubyGems until a physical MIDI interface has closed the items
117
- <a href="docs/testing-on-windows.md"><code>docs/testing-on-windows.md</code></a> lists as untestable
118
- without one.</p>
119
- <p>That document is also how to rebuild the test environment: it is the procedure
120
- these measurements were taken with, including how to make two ports collide in
121
- WinMM's 31 characters of name.</p>
122
- <h3 id="One_thing_worth_knowing_before_you_use_it">One thing worth knowing before you use it</h3>
123
- <p><code>Input#gets</code> <strong>waits</strong>. It does not return an empty array when nothing has
124
- arrived; it blocks until something does, and then returns everything that
125
- accumulated. Calling it on a quiet port looks exactly like a hung program. That
126
- is deliberate — <code>Musa::Clock::InputMidiClock</code> reads in a loop with no delay of
127
- its own and relies on it — but it will surprise anyone arriving from an API that
128
- polls.</p>
122
+ <p><strong>Early.</strong> Tested on Windows 11 without external MIDI devices. Everything works
123
+ against loopback ports; running it against real hardware is still pending.</p>
129
124
  <h2 id="Requirements">Requirements</h2>
130
125
  <ul>
131
126
  <li><a href="http://github.com/ffi/ffi">ffi</a></li>
132
127
  </ul>
133
- <p>Nothing else. <code>winmm.dll</code> is part of Windows, so this gem binds a library that
134
- is already on the machine and ships no compiled artifact of its own.</p>
135
- <h3 id="Which_versions_of_Windows">Which versions of Windows</h3>
136
- <p><strong>By construction, old ones.</strong> Everything this gem calls is the oldest MIDI API
137
- Windows has — <code>midiInOpen</code>, <code>midiOutShortMsg</code>, <code>midiOutLongMsg</code> and their
138
- neighbours — plus three functions for a thread's message queue, <code>GetMessageW</code>,
139
- <code>PeekMessageW</code> and <code>PostThreadMessageW</code>. All of it, the Unicode entry points
140
- included, dates from the NT era. Nothing here calls Windows MIDI Services, which
141
- means nothing here needs Windows 11.</p>
142
- <p>What changes on an older system is not whether the gem works but what the
143
- platform gives it. Before Windows MIDI Services a MIDI port is <strong>exclusive</strong> —
144
- one program at a time — and there are no system loopback endpoints, so routing
145
- MIDI between applications on one machine needs a third-party driver such as
146
- loopMIDI. The same code, a poorer platform.</p>
147
- <p>A 32-bit Ruby should also be fine: the two size checks that only hold on 64-bit
148
- Windows are guarded, and the two that are checked everywhere describe structures
149
- whose layout does not depend on the word size.</p>
150
- <p><strong>None of which has been run.</strong> The only system this has ever executed on is
151
- Windows 11 25H2, in a virtual machine, on an x64 Ruby under ARM emulation. The
152
- paragraphs above say what the code asks of Windows, not what has been observed;
153
- treat them as a reason to expect it to work rather than as a report that it does.</p>
154
- <p>Where the floor actually sits is a question about Ruby, not about this gem:
155
- RubyInstaller recommends Windows 10 or 11 and publishes no hard cutoff.</p>
156
128
  <h2 id="Installation">Installation</h2>
157
129
  <p>If you're using Bundler, add this line to your application's Gemfile:</p>
158
130
  <p><code>gem &quot;midi-communications-windows&quot;</code></p>
159
131
  <p>Otherwise</p>
160
132
  <p><code>gem install midi-communications-windows</code></p>
161
133
  <h2 id="Documentation">Documentation</h2>
162
- <p><a href="http://rubydoc.info/github/javier-sy/midi-communications-windows">rdoc</a></p>
163
- <h2 id="Why_WinMM_and_not_one_of_the_newer_Windows_MIDI_APIs">Why WinMM and not one of the newer Windows MIDI APIs</h2>
164
- <p>Windows has three MIDI APIs a program could reach for, and as of February 2026
165
- the oldest is the right one for Ruby.</p>
166
- <p><strong>Windows MIDI Services</strong> became generally available in Windows 11 in February
167
- 2026, replacing the MIDI stack underneath. Rather than retiring the older APIs,
168
- Microsoft reconnected them to the new service, so a WinMM client needs nothing
169
- installed to reach what the new stack provides — including the loopback
170
- endpoints the system now creates itself, which is what previously required a
171
- third-party driver.</p>
172
- <p>Multi-client access arrives the same way, but <strong>per endpoint, not per API</strong>.
173
- Measured on Windows 11 25H2 through this library: two clients opened the same
174
- loopback input at once and both received every message, while a second open of
175
- the classic <code>wdmaud</code> software synthesiser was refused with &quot;The specified device
176
- is already in use&quot;. Endpoints carried by the new transports are shared;
177
- endpoints still on the old drivers are exclusive, as they always were. On
178
- Windows 10 there is no Windows MIDI Services at all.</p>
179
- <p><strong>The Windows MIDI Services App SDK</strong> offers MIDI 2.0 and UMP, neither of which
180
- this library needs: <code>midi-communications</code> and MusaDSL are MIDI 1.0 throughout.
181
- It is published only as WinRT, and Microsoft's guidance is that other languages
182
- obtain a WinRT projection from their toolchain. Ruby has none.</p>
183
- <p><strong>WinRT <code>Windows.Devices.Midi</code></strong> is, under the new stack, another compatibility
184
- layer onto the same service. It offers what WinMM offers, in exchange for
185
- hand-written COM.</p>
186
- <h2 id="Differences_from_the_macOS_layer">Differences from the macOS layer</h2>
187
- <p>The two libraries implement the same contract over platforms that do not have
188
- the same shape. Where they differ, they differ because the platforms do:</p>
189
- <ul>
190
- <li><strong><code>manufacturer</code> and <code>model</code> are <code>nil</code>.</strong> WinMM reports <code>wMid</code> and <code>wPid</code>,
191
- numeric codes from a manufacturer registry that stopped being maintained in
192
- the 1990s and that class-compliant USB devices almost all answer with
193
- Microsoft's. Core MIDI reports real strings. Inventing text from the codes
194
- would describe the code table, not the hardware.</li>
195
- <li><strong><code>display_name</code> is the port name.</strong> On macOS it is composed as
196
- &quot;manufacturer model (name)&quot;, which here would be a name wrapped in the
197
- punctuation of two absent fields.</li>
198
- <li><strong>Port ids are unique within a direction, not across both.</strong> A WinMM port is
199
- identified by its index among inputs or among outputs, and that index is what
200
- is passed to <code>midiInOpen</code>. Core MIDI numbers endpoints of both directions from
201
- one counter. Input 0 and output 0 are both valid here, and unrelated.</li>
202
- <li><strong>Port names are truncated to 31 characters, and do not identify a port.</strong>
203
- That is all WinMM stores, and it drops the rest silently. Two loopback
204
- endpoints whose names differed only past character 31 came back identical in
205
- every field of <code>MIDIINCAPSW</code> — same name, same <code>wMid</code>, same <code>wPid</code>, same
206
- <code>wTechnology</code> — distinguishable only by index. Core MIDI names are neither
207
- truncated nor, in practice, ambiguous.</li>
208
- <li><strong>Enumeration is not cached, but wrappers are reused.</strong> The macOS layer reads
209
- the device list once and keeps it, so a device plugged in later is never seen.
210
- Here WinMM is asked on every call, and a port still present comes back as the
211
- same object it was before, so opening a port and then reading from it works
212
- whether or not the caller kept the reference.</li>
213
- <li><strong>There is no packet-list parsing.</strong> Core MIDI delivers a list of packets that
214
- has to be walked; WinMM delivers one complete short message at a time, with
215
- running status already resolved by the driver.</li>
216
- </ul>
217
- <h2 id="Relationship_to_midi_winmm">Relationship to midi-winmm</h2>
218
- <p>This library is <strong>not</strong> derived from <a href="http://github.com/arirusso/midi-winmm">midi-winmm</a>,
219
- which was written in 2011 for 32-bit Ruby. Windows is LLP64: on a 64-bit Ruby,
220
- <code>unsigned long</code> is 32 bits while a <code>HANDLE</code> is 64, so that library's
221
- <code>typedef :ulong, :HANDLE</code> truncates every handle it obtains. It also reads port
222
- names through the ANSI entry points, which mangle any name that is not ASCII.
223
- Both are addressed here by construction; see the notes in
224
- <code>lib/midi-communications-windows/api.rb</code>.</p>
134
+ <p><a href="https://www.rubydoc.info/gems/midi-communications-windows">rdoc</a></p>
225
135
  <h2 id="Author">Author</h2>
226
136
  <ul>
227
137
  <li><a href="https://github.com/javier-sy">Javier Sánchez Yeste</a></li>
@@ -230,7 +140,7 @@ Both are addressed here by construction; see the notes in
230
140
  <p><a href="https://github.com/javier-sy/midi-communications-windows">MIDI Communications Windows Layer</a> Copyright (c) 2026 <a href="https://yeste.studio">Javier Sánchez Yeste</a>, licensed under LGPL 3.0 License</p></div></div>
231
141
 
232
142
  <div id="footer">
233
- Generated on Sun Sep 6 21:20:52 2026 by
143
+ Generated on Mon Sep 7 01:25:12 2026 by
234
144
  <a href="https://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
235
145
  0.9.45 (ruby-3.4.7).
236
146
  </div>
data/doc/file_list.html CHANGED
@@ -52,11 +52,6 @@
52
52
  </li>
53
53
 
54
54
 
55
- <li id="object_testing-on-windows" class="even">
56
- <div class="item"><span class="object_link"><a href="file.testing-on-windows.html" title="testing-on-windows">testing-on-windows</a></span></div>
57
- </li>
58
-
59
-
60
55
 
61
56
  </ul>
62
57
  </div>