diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml
new file mode 100644
index 00000000..a7930a7b
--- /dev/null
+++ b/.github/workflows/pages.yml
@@ -0,0 +1,71 @@
+# This workflow uses actions that are not certified by GitHub.
+# They are provided by a third-party and are governed by
+# separate terms of service, privacy policy, and support
+# documentation.
+
+# Sample workflow for building and deploying a Jekyll site to GitHub Pages
+name: Deploy Jekyll site to Pages
+
+on:
+ push:
+ branches:
+ - "main"
+ paths:
+ - "docs/**"
+
+ # Allows you to run this workflow manually from the Actions tab
+ workflow_dispatch:
+
+# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
+permissions:
+ contents: read
+ pages: write
+ id-token: write
+
+# Allow one concurrent deployment
+concurrency:
+ group: "pages"
+ cancel-in-progress: true
+
+jobs:
+ # Build job
+ build:
+ runs-on: ubuntu-latest
+ defaults:
+ run:
+ working-directory: docs
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v3
+ - name: Setup Ruby
+ uses: ruby/setup-ruby@v1
+ with:
+ ruby-version: '3.1' # Not needed with a .ruby-version file
+ bundler-cache: true # runs 'bundle install' and caches installed gems automatically
+ cache-version: 0 # Increment this number if you need to re-download cached gems
+ working-directory: '${{ github.workspace }}/docs'
+ - name: Setup Pages
+ id: pages
+ uses: actions/configure-pages@v3
+ - name: Build with Jekyll
+ # Outputs to the './_site' directory by default
+ run: bundle exec jekyll build --baseurl "${{ steps.pages.outputs.base_path }}"
+ env:
+ JEKYLL_ENV: production
+ - name: Upload artifact
+ # Automatically uploads an artifact from the './_site' directory by default
+ uses: actions/upload-pages-artifact@v1
+ with:
+ path: "docs/_site/"
+
+ # Deployment job
+ deploy:
+ environment:
+ name: github-pages
+ url: ${{ steps.deployment.outputs.page_url }}
+ runs-on: ubuntu-latest
+ needs: build
+ steps:
+ - name: Deploy to GitHub Pages
+ id: deployment
+ uses: actions/deploy-pages@v2
diff --git a/build/staging/version/BundleInfo.wxi b/build/staging/version/BundleInfo.wxi
index a68f4269..8b223f2c 100644
--- a/build/staging/version/BundleInfo.wxi
+++ b/build/staging/version/BundleInfo.wxi
@@ -1,4 +1,4 @@
" %}{% assign _pres_after = "" %}{% if _pres.size != 0 %}{% if site.compress_html.blanklines %}{% assign _lines = _pres.last | split: _LINE_FEED %}{% capture _pres_after %}{% for _line in _lines %}{% assign _trimmed = _line | split: " " | join: " " %}{% if _trimmed != empty or forloop.last %}{% unless forloop.first %}{{ _LINE_FEED }}{% endunless %}{{ _line }}{% endif %}{% endfor %}{% endcapture %}{% else %}{% assign _pres_after = _pres.last | split: " " | join: " " %}{% endif %}{% endif %}{% capture _content %}{{ _content }}{% if _pre_before contains "" %}
{% endif %}{% unless _pre_before contains "" and _pres.size == 1 %}{{ _pres_after }}{% endunless %}{% endcapture %}{% endfor %}{% if _profile %}{% assign _profile_collapse = _content | size | plus: 1 %}{% endif %}{% if site.compress_html.clippings == "all" %}{% assign _clippings = "html head title base link meta style body article section nav aside h1 h2 h3 h4 h5 h6 hgroup header footer address p hr blockquote ol ul li dl dt dd figure figcaption main div table caption colgroup col tbody thead tfoot tr td th" | split: " " %}{% else %}{% assign _clippings = site.compress_html.clippings %}{% endif %}{% for _element in _clippings %}{% assign _edges = "
Step | Bytes |
raw | {{ content | size }}{% if _profile_endings %} |
endings | {{ _profile_endings }}{% endif %}{% if _profile_startings %} |
startings | {{ _profile_startings }}{% endif %}{% if _profile_comments %} |
comments | {{ _profile_comments }}{% endif %}{% if _profile_collapse %} |
collapse | {{ _profile_collapse }}{% endif %}{% if _profile_clippings %} |
clippings | {{ _profile_clippings }}{% endif %} |
It’s best to use the Settings application and the transport / processing plugins for Settings to manipulate the file. However, if you edit it by hand, here are some notes.
The JSON configuration files are all stored in %allusersprofile%\Microsoft\MIDI
which typically resolves to C:\ProgramData\Microsoft\MIDI
. For security reasons, we don’t allow the file to be stored in any other location. However, you can have as many files in that folder as you want, and switch between them as needed.
The default config file is typically named Default.midiconfig.json
. The actual name is stored in the registry under HKLM\SOFTWARE\Microsoft\Windows MIDI Services
in the CurrentConfig
value. This value must not contain any non-filename path characters (no backslashes, colons, etc.).
JSON is typically case-sensitive for all keys. The Windows.Data.Json parser used by Windows MIDI Services is case-sensitive with no option to ignore case. That includes GUID values. For example, the following two values are not equivalent JSON keys:
"{26FA740D-469C-4D33-BEB1-3885DE7D6DF1}":
+ {
+ "_comment": "KS MIDI (USB etc.)"
+ },
+
and
"{26fa740d-469c-4d33-beb1-3885de7d6df1}":
+ {
+ "_comment": "KS MIDI (USB etc.)"
+ },
+
The JSON config file is such that each transport owns its own schema within the bucket associated with its class ID (GUID). We do not impose a schema on the transports or other plugins. Therefore there is no formal JSON Schema for this file.
Here’s an example of a bare-bones file, with sections for three different transports.
{
+ "header":
+ {
+ "_comment": "NOTE: All json keys are case-sensitive, including GUIDs.",
+ "product" : "Windows MIDI Services",
+ "fileVersion": 1.0
+ },
+
+ "endpointTransportPluginSettings":
+ {
+ "{26FA740D-469C-4D33-BEB1-3885DE7D6DF1}":
+ {
+ "_comment": "KS MIDI (USB etc.)"
+ },
+ "{C95DCD1F-CDE3-4C2D-913C-528CB8A4CBE6}":
+ {
+ "_comment": "Network MIDI"
+ },
+ "{8FEAAD91-70E1-4A19-997A-377720A719C1}":
+ {
+ "_comment": "Virtual MIDI"
+ }
+
+ },
+ "endpointProcessingPluginSettings":
+ {
+
+ }
+}
+
The basics of this are identical for each transport. We’ll use KS (USB) as an example
"{26FA740D-469C-4D33-BEB1-3885DE7D6DF1}":
+{
+ "_comment": "KS MIDI (USB etc.)"
+ "SWD: \\\\?\\SWD#MIDISRV#MIDIU_KS_BIDI_6799286025327820155_OUTPIN.0_INPIN.2#{e7cce071-3c03-423f-88d3-f1045d02552b}":
+ {
+ "userSuppliedName" : "Pete's Kontrol S61",
+ "userSuppliedDescription" : "This is my most favorite MIDI 2.0 controller in the whole world!"
+ }
+ ...
+},
+
Of those, the identification method SWD
is the most important. This controls how we identify a matching device. In cases where the manufacturer doesn’t supply a unique iSerialNumber in USB, unplugging your device from one USB port and plugging it into another can result in a new Id. Similarly, if you have two or more of the same device, and they do not have unique serial numbers, it can be impossible for Windows to distinguish between them.
Valid values for the identification method prefix
SWD:
: (The colon and trailing space are required). Use the full Windows Endpoint Device Interface Id. For example \\\\?\\SWD#MIDISRV#MIDIU_KS_BIDI_16024944077548273316_OUTPIN.0_INPIN.2#{e7cce071-3c03-423f-88d3-f1045d02552b}
. (Note how the backslashes have to be escaped with additional backslashes.) If the device has an iSerialNumber
or you never move it between USB ports, this tends to work fine.Valid properties you can set across all supported endpoints
Property | Type | Description |
---|---|---|
userSuppliedName | Quoted Text | The name you want to use for the endpoint. This will override the name displayed in correctly-coded applications, but won’t necessarily change what you see in Device Manager. These names should be relatively short so they display fully in all/most applications, but meaningful to you. |
userSuppliedDescription | Quoted Text | A text description and/or notes about the endpoint. Applications may or may not use this data |
forceSingleClientOnly | Boolean true/false (no quotes) | Most endpoints are multi-client (more than one application can use them simultaneously) by default. This setting is for forcing an endpoint to be single-client only (a value of true). It’s unusual to need this, but a typical use may be to disable multi-client for a device which has a custom driver which doesn’t gracefully handle multiple client applications at the same time. |
This is not an exhaustive list, because the transport and processing plugins may be created by anyone.
Virtual MIDI includes three different sections inside its transport bucket.
"{8FEAAD91-70E1-4A19-997A-377720A719C1}":
+{
+ "_comment": "Virtual MIDI",
+ "add":
+ {
+ },
+ "update":
+ {
+ },
+ "remove":
+ {
+
+ }
+
+}
+
For the persistent configuration file, typically “add” is all that is specified, as it doesn’t make sense to update or remove endpoints or routing on service start.
NOTE: This document is not yet complete. We’ll add more details as the schemas are finalized
TODO: Show how to update endpoint names and provide other properties here