diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b5ce96d --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +build/ +node_modules/ + +*.swp +*.swo +*.bak + +.DS_Store diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..cfec10b --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,19 @@ +Copyright (c) 2016 Griffin Moe + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..c2cb177 --- /dev/null +++ b/README.md @@ -0,0 +1,32 @@ +# In C - Score Progress + +This is a simple Electron app for displaying score progress on a projector +during laptop performances of [Terry Riley's *In C*][inC]. It is designed to be +used with [Max][max], but it could be used with other software (let me know if +you do!). Supports Windows, macOS, and Linux. + +![screenshot](img/screenshot.png "In C - In Action") + +## Usage + +This app works by having each performer report a identification number unique +to their computer and the phrase they are currently performing. In Max this is +sent as a list of two integers, specifically the ID number followed by the +phrase number. All messages should be sent to port number `41234` on the +computer hosting this app. Below is an example Max patch that sends a message +to the correct port on your local machine, assuming you are hosting the app: + +![max-patch](img/max-patch.png "Example Max patch for communicating with this app") + +## Downloads + +TODO + +## About + +Created for the Loyola University (Chicago) Technology Ensemble. Fall 2016 + +[License](LICENSE.md) + +[inC]: https://en.wikipedia.org/wiki/In_C +[max]: https://cycling74.com/max7/ diff --git a/app/index.html b/app/index.html new file mode 100644 index 0000000..ceb8fa5 --- /dev/null +++ b/app/index.html @@ -0,0 +1,16 @@ + + + + + In C - Score Progress + + + + + + + diff --git a/app/js/renderer.js b/app/js/renderer.js new file mode 100644 index 0000000..61ddc8b --- /dev/null +++ b/app/js/renderer.js @@ -0,0 +1,48 @@ +'use strict'; + +const d3 = require('d3'); + +const NUM_PHRASES = 53; + +const addPhraseSection = (parent, phraseNum) => { + parent.append('section') + .attr('class', 'phrase-section') + .append('img') + .attr('src', `phrases/Sco${phraseNum}.png`); +} + +const colorById = (cid) => { + const hue = (cid * 100) % 355; + return d3.hsl(hue, 0.4, 0.6); +} + +module.exports.start = () => { + let body = d3.select('body'); + for(let i=1; i <= NUM_PHRASES; ++i) { + addPhraseSection(body, i); + } +} + +module.exports.update = (playerMatrix) => { + //Wipe existing player ids + d3.selectAll('section.phrase-section') + .selectAll('div.players').remove(); + + //Join list of players to list of phrases + let divPlayers = d3.selectAll('section.phrase-section') + .data(playerMatrix) + .append('div') + .attr('class', 'players'); + + //Join players to phrase + let playerIds = divPlayers.selectAll('span') + .data((d) => { return d; }) + .enter() + .insert('span') + .attr('class', 'player') + .style('background-color', (d) => { + return colorById(d).toString(); + }) + .insert('span') + .text((d) => { return d; }); +} diff --git a/app/js/server.js b/app/js/server.js new file mode 100644 index 0000000..c4a13e4 --- /dev/null +++ b/app/js/server.js @@ -0,0 +1,69 @@ +'use strict'; + +const NUM_PHRASES = 53; + +module.exports = (renderer) => { + + const dgram = require('dgram'); + const server = dgram.createSocket('udp4'); + + var playerMatrix = (() => { + let matrix = [ ]; + for(let i=0; i < NUM_PHRASES; ++i) { + matrix[i] = []; + } + return matrix; + })(); + + const arraySort = (a,b) => { return a - b; } + + const updateMatrix = (matrix,data) => { + const cidExists = matrix.reduce((a,b) => { + let index = Math.max(a.index, b.indexOf(data.cid)); + return { + "phrase": (index==-1) ? a.phrase+1 : a.phrase, + "index": index + }; + }, {"phrase": 0, "index": -1}); + + if(cidExists.index == -1) { + matrix[data.phrase].push(data.cid); + matrix[data.phrase].sort(arraySort); + } else { + matrix[cidExists.phrase].splice(cidExists.index, 1); + matrix[cidExists.phrase].sort(arraySort); + matrix[data.phrase].push(data.cid); + matrix[data.phrase].sort(arraySort); + } + + } + + const processMaxListPacket = (buffer) => { + let data = buffer.slice(12); + let cid = data.readInt32BE(); + let phrase = data.readInt32BE(4); + return { 'cid': cid, 'phrase': phrase-1 }; + } + + server.on('error', (err) => { + console.log(`server error:\n${err.stack}`); + server.close(); + }); + + server.on('message', (msg, rinfo) => { + let data = processMaxListPacket(msg); + console.log(`server got: [${data.cid} ${data.phrase}] from ${rinfo.address}:${rinfo.port}`); + + updateMatrix(playerMatrix, data); + renderer.update(playerMatrix); + }); + + server.on('listening', () => { + let address = server.address(); + console.log(`server listening on: ${address.address}:${address.port}`); + renderer.start(); + }); + + server.bind(41234); // server listening 0.0.0.0:41234 + +} diff --git a/app/phrases/Sco1.png b/app/phrases/Sco1.png new file mode 100644 index 0000000..085ea12 Binary files /dev/null and b/app/phrases/Sco1.png differ diff --git a/app/phrases/Sco10.png b/app/phrases/Sco10.png new file mode 100644 index 0000000..450d8fd Binary files /dev/null and b/app/phrases/Sco10.png differ diff --git a/app/phrases/Sco11.png b/app/phrases/Sco11.png new file mode 100644 index 0000000..1d83db8 Binary files /dev/null and b/app/phrases/Sco11.png differ diff --git a/app/phrases/Sco12.png b/app/phrases/Sco12.png new file mode 100644 index 0000000..e646858 Binary files /dev/null and b/app/phrases/Sco12.png differ diff --git a/app/phrases/Sco13.png b/app/phrases/Sco13.png new file mode 100644 index 0000000..940917f Binary files /dev/null and b/app/phrases/Sco13.png differ diff --git a/app/phrases/Sco14.png b/app/phrases/Sco14.png new file mode 100644 index 0000000..345ec33 Binary files /dev/null and b/app/phrases/Sco14.png differ diff --git a/app/phrases/Sco15.png b/app/phrases/Sco15.png new file mode 100644 index 0000000..f55e281 Binary files /dev/null and b/app/phrases/Sco15.png differ diff --git a/app/phrases/Sco16.png b/app/phrases/Sco16.png new file mode 100644 index 0000000..7cb09dd Binary files /dev/null and b/app/phrases/Sco16.png differ diff --git a/app/phrases/Sco17.png b/app/phrases/Sco17.png new file mode 100644 index 0000000..8bde1f6 Binary files /dev/null and b/app/phrases/Sco17.png differ diff --git a/app/phrases/Sco18.png b/app/phrases/Sco18.png new file mode 100644 index 0000000..b70a422 Binary files /dev/null and b/app/phrases/Sco18.png differ diff --git a/app/phrases/Sco19.png b/app/phrases/Sco19.png new file mode 100644 index 0000000..a35ab73 Binary files /dev/null and b/app/phrases/Sco19.png differ diff --git a/app/phrases/Sco2.png b/app/phrases/Sco2.png new file mode 100644 index 0000000..8fdab59 Binary files /dev/null and b/app/phrases/Sco2.png differ diff --git a/app/phrases/Sco20.png b/app/phrases/Sco20.png new file mode 100644 index 0000000..c8b7cf9 Binary files /dev/null and b/app/phrases/Sco20.png differ diff --git a/app/phrases/Sco21.png b/app/phrases/Sco21.png new file mode 100644 index 0000000..0c94e63 Binary files /dev/null and b/app/phrases/Sco21.png differ diff --git a/app/phrases/Sco22.png b/app/phrases/Sco22.png new file mode 100644 index 0000000..86c14b5 Binary files /dev/null and b/app/phrases/Sco22.png differ diff --git a/app/phrases/Sco23.png b/app/phrases/Sco23.png new file mode 100644 index 0000000..99764b3 Binary files /dev/null and b/app/phrases/Sco23.png differ diff --git a/app/phrases/Sco24.png b/app/phrases/Sco24.png new file mode 100644 index 0000000..1219c2a Binary files /dev/null and b/app/phrases/Sco24.png differ diff --git a/app/phrases/Sco25.png b/app/phrases/Sco25.png new file mode 100644 index 0000000..a5e67da Binary files /dev/null and b/app/phrases/Sco25.png differ diff --git a/app/phrases/Sco26.png b/app/phrases/Sco26.png new file mode 100644 index 0000000..1806b70 Binary files /dev/null and b/app/phrases/Sco26.png differ diff --git a/app/phrases/Sco27.png b/app/phrases/Sco27.png new file mode 100644 index 0000000..c35bef6 Binary files /dev/null and b/app/phrases/Sco27.png differ diff --git a/app/phrases/Sco28.png b/app/phrases/Sco28.png new file mode 100644 index 0000000..332f53b Binary files /dev/null and b/app/phrases/Sco28.png differ diff --git a/app/phrases/Sco29.png b/app/phrases/Sco29.png new file mode 100644 index 0000000..3d6c576 Binary files /dev/null and b/app/phrases/Sco29.png differ diff --git a/app/phrases/Sco3.png b/app/phrases/Sco3.png new file mode 100644 index 0000000..65a6433 Binary files /dev/null and b/app/phrases/Sco3.png differ diff --git a/app/phrases/Sco30.png b/app/phrases/Sco30.png new file mode 100644 index 0000000..1e5b189 Binary files /dev/null and b/app/phrases/Sco30.png differ diff --git a/app/phrases/Sco31.png b/app/phrases/Sco31.png new file mode 100644 index 0000000..7dd3bf6 Binary files /dev/null and b/app/phrases/Sco31.png differ diff --git a/app/phrases/Sco32.png b/app/phrases/Sco32.png new file mode 100644 index 0000000..d4b6cf0 Binary files /dev/null and b/app/phrases/Sco32.png differ diff --git a/app/phrases/Sco33.png b/app/phrases/Sco33.png new file mode 100644 index 0000000..7133ad5 Binary files /dev/null and b/app/phrases/Sco33.png differ diff --git a/app/phrases/Sco34.png b/app/phrases/Sco34.png new file mode 100644 index 0000000..e626a53 Binary files /dev/null and b/app/phrases/Sco34.png differ diff --git a/app/phrases/Sco35.png b/app/phrases/Sco35.png new file mode 100644 index 0000000..0c45f94 Binary files /dev/null and b/app/phrases/Sco35.png differ diff --git a/app/phrases/Sco36.png b/app/phrases/Sco36.png new file mode 100644 index 0000000..9b34c29 Binary files /dev/null and b/app/phrases/Sco36.png differ diff --git a/app/phrases/Sco37.png b/app/phrases/Sco37.png new file mode 100644 index 0000000..99ed3e5 Binary files /dev/null and b/app/phrases/Sco37.png differ diff --git a/app/phrases/Sco38.png b/app/phrases/Sco38.png new file mode 100644 index 0000000..6881c75 Binary files /dev/null and b/app/phrases/Sco38.png differ diff --git a/app/phrases/Sco39.png b/app/phrases/Sco39.png new file mode 100644 index 0000000..b8d4004 Binary files /dev/null and b/app/phrases/Sco39.png differ diff --git a/app/phrases/Sco4.png b/app/phrases/Sco4.png new file mode 100644 index 0000000..131813f Binary files /dev/null and b/app/phrases/Sco4.png differ diff --git a/app/phrases/Sco40.png b/app/phrases/Sco40.png new file mode 100644 index 0000000..6bd96d3 Binary files /dev/null and b/app/phrases/Sco40.png differ diff --git a/app/phrases/Sco41.png b/app/phrases/Sco41.png new file mode 100644 index 0000000..e8a2618 Binary files /dev/null and b/app/phrases/Sco41.png differ diff --git a/app/phrases/Sco42.png b/app/phrases/Sco42.png new file mode 100644 index 0000000..eb8cd27 Binary files /dev/null and b/app/phrases/Sco42.png differ diff --git a/app/phrases/Sco43.png b/app/phrases/Sco43.png new file mode 100644 index 0000000..3ab2832 Binary files /dev/null and b/app/phrases/Sco43.png differ diff --git a/app/phrases/Sco44.png b/app/phrases/Sco44.png new file mode 100644 index 0000000..b087bb4 Binary files /dev/null and b/app/phrases/Sco44.png differ diff --git a/app/phrases/Sco45.png b/app/phrases/Sco45.png new file mode 100644 index 0000000..e293b28 Binary files /dev/null and b/app/phrases/Sco45.png differ diff --git a/app/phrases/Sco46.png b/app/phrases/Sco46.png new file mode 100644 index 0000000..f79f5be Binary files /dev/null and b/app/phrases/Sco46.png differ diff --git a/app/phrases/Sco47.png b/app/phrases/Sco47.png new file mode 100644 index 0000000..c3b3117 Binary files /dev/null and b/app/phrases/Sco47.png differ diff --git a/app/phrases/Sco48.png b/app/phrases/Sco48.png new file mode 100644 index 0000000..2f1fa2d Binary files /dev/null and b/app/phrases/Sco48.png differ diff --git a/app/phrases/Sco49.png b/app/phrases/Sco49.png new file mode 100644 index 0000000..49b86b7 Binary files /dev/null and b/app/phrases/Sco49.png differ diff --git a/app/phrases/Sco5.png b/app/phrases/Sco5.png new file mode 100644 index 0000000..224b330 Binary files /dev/null and b/app/phrases/Sco5.png differ diff --git a/app/phrases/Sco50.png b/app/phrases/Sco50.png new file mode 100644 index 0000000..74b4c55 Binary files /dev/null and b/app/phrases/Sco50.png differ diff --git a/app/phrases/Sco51.png b/app/phrases/Sco51.png new file mode 100644 index 0000000..38ab5bb Binary files /dev/null and b/app/phrases/Sco51.png differ diff --git a/app/phrases/Sco52.png b/app/phrases/Sco52.png new file mode 100644 index 0000000..d9c2a92 Binary files /dev/null and b/app/phrases/Sco52.png differ diff --git a/app/phrases/Sco53.png b/app/phrases/Sco53.png new file mode 100644 index 0000000..2f1b300 Binary files /dev/null and b/app/phrases/Sco53.png differ diff --git a/app/phrases/Sco6.png b/app/phrases/Sco6.png new file mode 100644 index 0000000..3f972d1 Binary files /dev/null and b/app/phrases/Sco6.png differ diff --git a/app/phrases/Sco7.png b/app/phrases/Sco7.png new file mode 100644 index 0000000..c968894 Binary files /dev/null and b/app/phrases/Sco7.png differ diff --git a/app/phrases/Sco8.png b/app/phrases/Sco8.png new file mode 100644 index 0000000..5d9df70 Binary files /dev/null and b/app/phrases/Sco8.png differ diff --git a/app/phrases/Sco9.png b/app/phrases/Sco9.png new file mode 100644 index 0000000..c7bac66 Binary files /dev/null and b/app/phrases/Sco9.png differ diff --git a/app/style.css b/app/style.css new file mode 100644 index 0000000..6e73c49 --- /dev/null +++ b/app/style.css @@ -0,0 +1,46 @@ +body { + font-family: Helvetica, Arial, sans-serif; + font-weight: 500; + background-color: #ddd; + color: white; +} + +.phrase-section { + display: flex; + flex-wrap: wrap; + margin: 30px; + padding: 15px; + background-color: #fff; + box-shadow: 2px 3px 5px #999; +} + +.phrase-section > img { + max-width: 100%; + height: auto; + margin: 5px; +} + +.players { + display: flex; + flex-wrap: wrap; +} + +.player { + display: flex; + float: left; + font-size: 1.25rem; + margin: 5px; + padding: 5px; + width: 30px; + height: 30px; +} + +.player > span { + width: 100%; + align-self: center; + text-align: center; +} + +::-webkit-scrollbar { + display: none; +} diff --git a/img/max-patch.png b/img/max-patch.png new file mode 100644 index 0000000..7212d59 Binary files /dev/null and b/img/max-patch.png differ diff --git a/img/screenshot.png b/img/screenshot.png new file mode 100644 index 0000000..1678901 Binary files /dev/null and b/img/screenshot.png differ diff --git a/main.js b/main.js new file mode 100644 index 0000000..18a4773 --- /dev/null +++ b/main.js @@ -0,0 +1,29 @@ +const electron = require('electron') +const app = electron.app +const BrowserWindow = electron.BrowserWindow + +const path = require('path') +const url = require('url') + +let mainWindow + +app.on('ready', () => { + mainWindow = new BrowserWindow({ + width: 1200, + height: 800, + }) + + mainWindow.loadURL(url.format({ + pathname: path.join(__dirname, 'app/index.html'), + protocol: 'file:', + slashes: true + })) + + mainWindow.on('closed', () => { + mainWindow = null + }) +}) + +app.on('window-all-closed', () => { + app.quit() +}) diff --git a/package.json b/package.json new file mode 100644 index 0000000..16cf146 --- /dev/null +++ b/package.json @@ -0,0 +1,29 @@ +{ + "name": "in-c-score-progress", + "productName": "InCScoreProgress", + "version": "1.0.0", + "description": "App for displaying performers' progress of Terry Riley's \"In C\".", + "keywords": ["electron", "max", "msp", "Max 7", "In C", "Terry Riley"], + "main": "main.js", + "scripts": { + "start": "electron .", + "app": "electron-packager . --all --out build/" + }, + "author": "Griffin Moe", + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/gmoe/in-c-score-progress.git" + }, + "bugs": { + "url": "https://github.com/gmoe/my_package/issues" + }, + "homepage": "https://github.com/gmoe/in-c-score-progress", + "dependencies": { + "d3": "^4.3.0", + "electron": "^1.4.7" + }, + "devDependencies": { + "electron-packager": "^8.3.0" + } +}