Skip to content
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

Add support for SMF files (resolves #5). #7

Open
wants to merge 30 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
7b0b38e
GH-6: Add `es6` as a linting environment.
duhrer Jan 26, 2023
88b0a09
GH-5: Initial implementation of SMF parsing.
duhrer Jan 26, 2023
7780613
GH-5: Added test MIDI files.
duhrer Jan 26, 2023
45794af
GH-5: Added functional tests for SMF file handling.
duhrer Jan 30, 2023
928e121
GH-5: Added unit tests for SMF parsing functions.
duhrer Feb 1, 2023
a37201d
GH-5: Simplified channel prefix parsing.
duhrer Feb 1, 2023
9e2b6b5
NOGH: Added coverage reporting to CI config.
duhrer Feb 1, 2023
a0944d5
NOGH: Tweaked testem config to include Firefox and exclude Chrome var…
duhrer Feb 1, 2023
4d13097
GH-5: Tidied up 'chunk' variable names based on reread of standard.
duhrer Feb 2, 2023
08b5b27
GH-5: Added initial docs for SMF file handling and new events.
duhrer Feb 2, 2023
37d76a4
GH-5: Updated to use 'subarray' rather than 'slice' in SMF parsing.
duhrer Feb 3, 2023
fdeb0b9
GH-8: Added support for quarter-frame MTC messages.
duhrer Feb 3, 2023
034b0cf
GH-8: Added JSDocs for MTC types and improved tests.
duhrer Feb 3, 2023
4fad637
GH-8: Added documentation and examples for quarter frame MTC messages.
duhrer Feb 7, 2023
1db62d2
GH-8: Added demos for sending/receiving MTC quarter frame messages.
duhrer Feb 7, 2023
72ba1a1
GH-8: Updated quarter frame send demo to use audio context scheduler.
duhrer Feb 8, 2023
2f7e77a
GH-5: Tidied up smpte offset and quarter frame handling.
duhrer Feb 13, 2023
02637f7
GH-5: Standardised variable names and improved documentation around t…
duhrer Feb 13, 2023
4b7794e
GH-5: Initial demo for SMF player.
duhrer Feb 13, 2023
79d6879
GH-5: Simplified scheduler init and removed wrapping 'start' button.
duhrer Feb 14, 2023
51d9a20
GH-5: Added support for "MIDI port" meta events observed in "the wild".
duhrer Feb 15, 2023
ccae0d9
GH-5: Fixed timing for multi-track SMF files.
duhrer Feb 15, 2023
b3c5e5f
GH-5: Saved work in progress on 'on-the-fly' SMF player.
duhrer Feb 17, 2023
e04a161
GH-5: Removed frame-rate model relay code to improve performance.
duhrer Feb 20, 2023
ba56bf6
GH-5: Fixed song length calculation.
duhrer Feb 20, 2023
4302d6a
NOGH: Updated GH actions versions to avoid Node 12.x warnings.
duhrer Feb 21, 2023
9ea406e
GH-5: Improved SMF file metadata for viewer and player demos.
duhrer Feb 21, 2023
7030bca
GH-5: Updated to released version of bergson with AAC scheduler fix.
duhrer Mar 8, 2023
af0f178
GH-5: Removed outdated cruft from previous testing with player demo.
duhrer Mar 8, 2023
a6a21c5
GH-5: Fixed styling of controls in SMF player demo.
duhrer Mar 8, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
{
"extends": "eslint-config-fluid",
"env": {
"browser": true
"browser": true,
"es6": true
},
"parserOptions": {
"ecmaVersion": 8
Expand Down
4 changes: 4 additions & 0 deletions .fluidlintallrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@
"./tests/**/*",
"./*",
"!./audit-resolve.json"
],
"excludes": [
"./tests/midi/**/*.mid",
"./tests/midi/**/*.syx"
]
}
}
Expand Down
15 changes: 11 additions & 4 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,21 +19,28 @@ jobs:
HEADLESS: true

steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3.3.0

- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
uses: actions/setup-node@v3.6.0
with:
node-version: ${{ matrix.node-version }}

- name: Install Node.js dependencies
run: npm install

- name: Node Tests
- name: Browser Tests
run: xvfb-run --auto-servernum npm test

- name: Archive Code Coverage Report
continue-on-error: true
uses: actions/[email protected]
with:
name: Code Coverage Report
path: reports/

- name: Cleanup after xvfb
uses: bcomnes/cleanup-xvfb@v1
uses: bcomnes/cleanup-xvfb@v1.0.8

- name: Security Audit
run: npm audit --omit dev
Expand Down
10 changes: 10 additions & 0 deletions demos/css/sendQuarterFrame.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/*
* Copyright 2023, Tony Atkins
*
* Licensed under the MIT license, see LICENSE for details.
*/
.start-button,
.stop-button {
border-radius: 0.25rem;
padding: 1rem;
}
37 changes: 37 additions & 0 deletions demos/css/smfMetadata.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* Copyright 2023, Tony Atkins
*
* Licensed under the MIT license, see LICENSE for details.
*/
.smf-metadata {
margin-top: 1rem;
padding-left: 2rem;
}

.smf-metadata-container {
display: flex;
flex-direction: column;
width: 100%;
}

.metadata-header {
display: flex;
flex-direction: column;
width: 100%;
}

.metadata-header > .name {
align-content: flex-start;
font-weight: bold;
width: 100%;
}

.metadata-header > .copyright {
align-content: flex-end;
width: 100%;
}

.text {
font-style: italic;
margin-top: 1rem;
}
23 changes: 23 additions & 0 deletions demos/css/smfPlayer.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* Copyright 2023, Tony Atkins
*
* Licensed under the MIT license, see LICENSE for details.
*/

.main-panel {
display: none;
}

.controls {
column-gap: 1rem;
display: flex;
flex-direction: row;
width: 100%;
}

.controls button {
border-radius: 1rem;
font-size: 1.5rem;
padding: 1rem;
width: 50%;
}
25 changes: 25 additions & 0 deletions demos/css/smfViewer.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* Copyright 2023, Tony Atkins
*
* Licensed under the MIT license, see LICENSE for details.
*/

.smf-demo-output {
font-family: monospace;
font-size: 1.25rem;
padding-left: 2rem;
}

.smf-demo-error {
background-color: #fcc;
border: 1px solid red;
border-radius: 0.33rem;
color: black;
display: none;
font-size: 1.5rem;
padding: 2rem;
}

.smf-demo-error.has-error {
display: inherit;
}
23 changes: 23 additions & 0 deletions demos/css/timestamp.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* Copyright 2023, Tony Atkins
*
* Licensed under the MIT license, see LICENSE for details.
*/

.timestamp {
align-items: stretch;
column-gap: 2rem;
display: flex;
flex-direction: row;
font-size: 10rem;
padding: 1rem;
}

.timestamp > * {
align-content: center;
border: 1px solid #969696;
border-radius: 0.5rem;
font-family: monospace;
text-align: center;
width: 100%;
}
38 changes: 22 additions & 16 deletions demos/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,23 +12,29 @@
<link type="text/css" rel="stylesheet" href="../src/css/youme.css"/>
</head>
<body>
<h3>"Youme" Demos</h3>
<h3>"Youme" Demos</h3>

<p>The pages below demonstrate various components provided by this package.</p>
<p>The pages below demonstrate various components provided by this package.</p>

<ul>
<li>
<a href="./passthrough.html">"Passthrough": Relay messages from a single input to a single output.</a>
</li>
<li>
<a href="./multi-passthrough.html">"Multi-Passthrough": Relay messages from one or more inputs to one or more outputs.</a>
</li>
<li>
<a href="./message-monitor.html">"Message Monitor": Display MIDI messages received from one or more inputs.</a>
</li>
<li>
<a href="./midi-console.html">"MIDI Console": Convert MIDI messages between hex and JSON, send them to an output.</a>
</li>
</ul>
<ul>
<li>
<a href="./passthrough.html">"Passthrough": Relay messages from a single input to a single output.</a>
</li>
<li>
<a href="./multi-passthrough.html">"Multi-Passthrough": Relay messages from one or more inputs to one or more outputs.</a>
</li>
<li>
<a href="./message-monitor.html">"Message Monitor": Display MIDI messages received from one or more inputs.</a>
</li>
<li>
<a href="./midi-console.html">"MIDI Console": Convert MIDI messages between hex and JSON, send them to an output.</a>
</li>
<li>
<a href="./receive-quarter-frame.html">"Quarter Frame Receiver": Update a local clock based on external quarter frame MTC messages.</a>
</li>
<li>
<a href="./receive-quarter-frame.html">"Quarter Frame Sender": Send quarter frame MTC messages to an external receiver to control its clock.</a>
</li>
</ul>
</body>
</html>
103 changes: 103 additions & 0 deletions demos/js/receiveQuarterFrame.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/*
* Copyright 2023, Tony Atkins
*
* Licensed under the MIT license, see LICENSE for details.
*/
(function (fluid) {
"use strict";
var youme = fluid.registerNamespace("youme");
fluid.defaults("youme.demos.quarterFrame.receive", {
gradeNames: ["youme.templateRenderer"],
markup: {
container: "<div class='quarter-frame'><div class='timestamp'></div><div class='input'></div></div>"
},
selectors: {
input: ".input",
timestamp: ".timestamp"
},
model: {
rate: 3,
hour: 0,
minute: 0,
second: 0,
frame: 0
},

components: {
timestamp: {
type: "youme.demos.timestamp",
container: "{that}.dom.timestamp",
options: {
model: {
hour: "{youme.demos.quarterFrame.receive}.model.hour",
minute: "{youme.demos.quarterFrame.receive}.model.minute",
second: "{youme.demos.quarterFrame.receive}.model.second"
}
}
},
input: {
type: "youme.portSelectorView.input",
container: "{that}.dom.input",
options: {
desiredPortSpec: { name: "IAC Driver Bus.+" },
listeners: {
"onMessage.handleMessage": {
funcName: "youme.demos.quarterFrame.receive.handleMessage",
args: ["{youme.demos.quarterFrame.receive}", "{arguments}.0"] // message
}
}
}
}
}
});

youme.demos.quarterFrame.receive.handleMessage = function (that, message) {
if (message.type === "quarterFrameMTC") {
switch (message.piece) {
case 0:
var oldHighFrameNibble = that.model.frame & 16;
var frameValueWithNewLowNibble = oldHighFrameNibble + (message.frame & 15);
that.applier.change("frame", frameValueWithNewLowNibble);
break;
case 1:
var oldLowFrameNibble = that.model.frame & 15;
var frameValueWithNewHighNibble = (message.frame & 16) + oldLowFrameNibble;
that.applier.change("frame", frameValueWithNewHighNibble);
break;
case 2:
var oldHighSecondNibble = that.model.second & 48;
var secondValueWithNewLowNibble = oldHighSecondNibble + (message.second & 15);
that.applier.change("second", secondValueWithNewLowNibble);
break;
case 3:
var oldLowSecondNibble = that.model.second & 15;
var secondValueWithNewHighNibble = (message.second & 48) + oldLowSecondNibble;
that.applier.change("second", secondValueWithNewHighNibble);
break;
case 4:
var oldHighMinuteNibble = that.model.minute & 48;
var minuteValueWithNewLowNibble = oldHighMinuteNibble + (message.minute & 15);
that.applier.change("minute", minuteValueWithNewLowNibble);
break;
case 5:
var oldLowMinuteNibble = that.model.minute & 15;
var minuteValueWithNewHighNibble = (message.minute & 48) + oldLowMinuteNibble;
that.applier.change("minute", minuteValueWithNewHighNibble);
break;
case 6:
var oldHighHourNibble = that.model.hour & 16;
var hourValueWithNewLowNibble = oldHighHourNibble + (message.hour & 15);
that.applier.change("hour", hourValueWithNewLowNibble);
break;
case 7:
var oldLowHourNibble = that.model.hour & 15;
var hourValueWithNewHighNibble = (message.hour & 16) + oldLowHourNibble;
that.applier.change("hour", hourValueWithNewHighNibble);
that.applier.change("rate", message.rate);
default:
fluid.log(fluid.logLevel.ERROR, "Invalid piece number: " + message.piece);
}

}
};
})(fluid);
Loading