Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
16 changes: 8 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,19 @@ See it in action at http://www.performer.io/
Performer takes any MIDI file and determines the best piano fingering to use for that particular song. It then visualizes two virtual hands performing the piece in 3D.

##How it works
-Performer has sophisticated cost algorithms to determine the "price" of any of the ~200k piano movement options. That is, it answers the question, "What does it 'cost' to move from note A with finger X to note B with finger Y."
- Performer has sophisticated cost algorithms to determine the "price" of any of the ~200k piano movement options. That is, it answers the question, "What does it 'cost' to move from note A with finger X to note B with finger Y."

-When a MIDI file is uploaded, it parses the file to know what notes are in the song.
- When a MIDI file is uploaded, it parses the file to know what notes are in the song.

-It then uses **Viterbi's algorithm** to determine the lowest cost path among the trillions of possible fingering choices. Thanks to Viterbi's, this process runs in linear time as a function of the number of notes in a song.
- It then uses **Viterbi's algorithm** to determine the lowest cost path among the trillions of possible fingering choices. Thanks to Viterbi's, this process runs in linear time as a function of the number of notes in a song.

-Once the path has been determined, the data is processed and used to orchestrate the 'fingers' moving in sync with the audio playback
- Once the path has been determined, the data is processed and used to orchestrate the 'fingers' moving in sync with the audio playback

##The tech behind it
-**JavaScript** powered all the algorithms.
- **JavaScript** powered all the algorithms

-MIDI file parsing and playback is done with the help of a slightly modified version of the **MIDI.js** library
- MIDI file parsing and playback is done with the help of a slightly modified version of the **MIDI.js** library

-**Three.js** in conjunction with Tween.js was used for creating and animating the 3D hands and piano
- **Three.js** in conjunction with **Tween.js** to create and animate the 3D hands and piano

-The backend was doing using **Node**, **Express**, and **MongoDB**.
- The backend was done doing using **Node**, **Express**, and **MongoDB**
4 changes: 2 additions & 2 deletions public/build.js

Large diffs are not rendered by default.

24 changes: 14 additions & 10 deletions public/bundle.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
;(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
var params = require('./CostAlgorithmParameters.js');
var helpers = require('./CostAlgorithmHelpers.js');

Expand Down Expand Up @@ -338,7 +338,7 @@ module.exports.FingeringAlgorithm = function(midiData) {

var dataWithStarts = helpers.addStartTimes(midiData);
// This checks if we already have the best path data for that song on the client.
// Well aware this is a janky way to do it. Didn't have time to implement better back-end data response obj.
// TODO: Refactor into better response object that wouldn't need iteration
for (var i = 0; i < app.preComputed.length; i++) {
if (app.preComputed[i].title === app.currentSong) {
var bestPath = app.preComputed[i].BestPathObj;
Expand All @@ -349,10 +349,13 @@ module.exports.FingeringAlgorithm = function(midiData) {
var noteTrellis = helpers.makeNoteTrellis(dataWithStarts);

// Traversing forward, computing costs and leaving our best path trail
for (var layer = 1; layer < noteTrellis.length; layer++) { // Go through each layer (starting at 2nd, because first is just endCap)
for (var node1 = 0; node1 < noteTrellis[layer].length ; node1++) { // Go through each node in each layer
// Go through each layer (starting at 2nd, because first is just endCap)
for (var layer = 1; layer < noteTrellis.length; layer++) {
// Go through each node in each layer
for (var node1 = 0; node1 < noteTrellis[layer].length ; node1++) {
var min = Infinity;
for (var node2 = 0; node2 < noteTrellis[layer-1].length; node2++) { // Go through each node in prev layer.
// Go through each node in prev layer.
for (var node2 = 0; node2 < noteTrellis[layer-1].length; node2++) {
var curNode = noteTrellis[layer][node1];
var prevNode = noteTrellis[layer-1][node2];
var totalCost = prevNode.nodeScore || 0;
Expand Down Expand Up @@ -2389,11 +2392,13 @@ module.exports.Scene = function(container) {
var scene = new THREE.Scene();

// Create camera
var view_angle = 85;
var aspect = width/height;
var left = width / -200;
var right = width / 200;
var top = height / 200;
var bottom = height / -200;
var near = 0.001;
var far = 1000;
var camera = new THREE.PerspectiveCamera(view_angle, aspect, near, far);
var camera = new THREE.OrthographicCamera(left, right, top, bottom, near, far);
camera.position.set(0, 3.0, 1.2);
camera.lookAt(new THREE.Vector3(10,50,5));

Expand Down Expand Up @@ -2451,5 +2456,4 @@ module.exports.Scene = function(container) {
_this.renderer.render(_this.scene, _this.camera);
};
};
},{}]},{},[8])
;
},{}]},{},[8])
4 changes: 2 additions & 2 deletions public/bundle.min.js

Large diffs are not rendered by default.

8 changes: 5 additions & 3 deletions src/Visuals/Scene.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,13 @@ module.exports.Scene = function(container) {
var scene = new THREE.Scene();

// Create camera
var view_angle = 85;
var aspect = width/height;
var left = width / -200;
var right = width / 200;
var top = height / 200;
var bottom = height / -200;
var near = 0.001;
var far = 1000;
var camera = new THREE.PerspectiveCamera(view_angle, aspect, near, far);
var camera = new THREE.OrthographicCamera(left, right, top, bottom, near, far);
camera.position.set(0, 3.0, 1.2);
camera.lookAt(new THREE.Vector3(10,50,5));

Expand Down