paulwalko.github.io/music/index.html

117 lines
6.2 KiB
HTML
Raw Permalink Normal View History

2018-10-21 18:23:31 -04:00
<!DOCTYPE html>
<html>
<head>
2018-10-22 09:50:12 -04:00
<meta charset='UTF-8'>
2018-10-21 18:23:31 -04:00
<title>Paul Walko - MUS 3064 Midterm Project</title>
2018-10-23 11:36:17 -04:00
<script type='text/javascript' src='js/helperFunctions.js'></script>
2018-10-22 09:50:12 -04:00
<script type='text/javascript' src='https://tonejs.github.io/build/Tone.min.js'></script>
2018-10-21 18:23:31 -04:00
</head>
<body>
2018-10-23 11:36:17 -04:00
Select 1 or more tracks to play, then press 'Play/Pause':<br />
2018-10-21 18:23:31 -04:00
<br />
2018-10-23 11:36:17 -04:00
<input type='checkbox' id='at'>Appalachain Trail</input> <br />
2018-10-22 09:50:12 -04:00
<input type='checkbox' id='pilotmtn'>Pilot Mountain</input> <br />
2018-10-23 11:36:17 -04:00
<input type='checkbox' id='huck'>Huckleberry Trail</input> <br />
2018-10-22 09:50:12 -04:00
<br />
<button id='PlayPause'/>Play/Pause</button> <br />
2018-10-21 18:23:31 -04:00
<script>
2018-10-23 11:36:17 -04:00
let hz_lookup = {'2n': 120, '4n': 60, '8n': 30, '16n': 15, '32n': 7.5};
let tracks = {'at': {'bpm_counter': 0, 'point_counter': 0, 'bpm': 0, 'frequency': 0, 'content': [], 'synth': new Tone.PolySynth(3).toMaster(), 'duration': '32n'},
'pilotmtn': {'bpm_counter': 0, 'point_counter': 0, 'bpm': 0, 'frequency': 0, 'content': [], 'synth': new Tone.MembraneSynth().toMaster(), 'duration': '4n'},
'huck': {'bpm_counter': 0, 'point_counter': 0, 'bpm': 0, 'frequency': 0, 'content': [], 'synth': new Tone.DuoSynth().toMaster(), 'duration': '8n'}};
// Cycles trough different bpms every 5 seconds
let cycle_counter = 0;
2018-10-21 18:23:31 -04:00
2018-10-22 09:50:12 -04:00
function mySetup() {
// Process track data
for (track in tracks) {
// Load tracks
2018-10-21 18:23:31 -04:00
let xmlhttp = new XMLHttpRequest();
2018-10-22 09:50:12 -04:00
xmlhttp.open('GET', 'gpx/' + track + '.xml', false);
2018-10-21 18:23:31 -04:00
xmlhttp.send();
2018-10-22 09:50:12 -04:00
// Parse tracks
let points = xmlhttp.responseXML.getElementsByTagName('trkpt');
for (let j = 1; j < points.length; j++) {
// Get distance since last point
let prevlat = points[j - 1].attributes.lat.value;
let prevlon = points[j - 1].attributes.lon.value;
let lat = points[j].attributes.lat.value;
let lon = points[j].attributes.lon.value;
let distance = getDistance(prevlat, prevlon, lat, lon, 'M');
// Time since last track
let prevtime = (new Date(points[j - 1]
.children[1].textContent)).getTime() / 3600000;
let time = (new Date(points[j].children[1]
.textContent)).getTime() / 3600000;
time = time - prevtime;
// Get speed & elevation then add to dict
//// Avg speed is about 10 MPH, so to make this usable
2018-10-23 11:36:17 -04:00
//// everything is scaled by x20, which is used as the
2018-10-22 09:50:12 -04:00
//// BPM
2018-10-23 11:36:17 -04:00
let speed = scale(distance / time, 0, 50, 100, 200);
2018-10-25 13:32:25 -04:00
//let elevation = scale(parseInt(points[j].children[0].textContent), 500, 700, 3000, 4000);
let elevation = Math.floor(scale(parseInt(points[j].children[0].textContent), 500, 700, 100, 110));
2018-10-22 09:50:12 -04:00
// TODO calculate direction
tracks[track]['content'].push({/*'direction': direction, */
'speed': speed, 'elevation': elevation});
}
// This should always be true but it doesn't hurt to make sure
if (tracks[track]['content'].length > 0) {
2018-10-23 11:36:17 -04:00
tracks[track]['bpm'] = tracks[track]['content'][0]['speed'];
tracks[track]['frequency'] = tracks[track]['content'][0]['elevation'];
2018-10-22 09:50:12 -04:00
}
2018-10-21 18:23:31 -04:00
}
2018-10-22 09:50:12 -04:00
// Overall BPM is 200, but the actual tracks don't always play on
// every beat.
// For example with a 150 BPM tune, the counter for that tune
// plays a beat every 200 / 150 beats.
2018-10-23 11:36:17 -04:00
Tone.Transport.bpm.value = 300;
2018-10-22 09:50:12 -04:00
loopBeat = new Tone.Loop(beats, '16n');
loopBeat.start(0);
2018-10-21 18:23:31 -04:00
2018-10-23 11:36:17 -04:00
//bassSynth = new Tone.MembraneSynth().toMaster();
2018-10-22 09:50:12 -04:00
//Tone.Transport.start();
2018-10-21 18:23:31 -04:00
2018-10-22 09:50:12 -04:00
document.querySelector("#PlayPause").addEventListener("click", function(){
Tone.Transport.toggle();
});
2018-10-21 18:23:31 -04:00
}
2018-10-22 09:50:12 -04:00
function beats(time) {
2018-10-23 11:36:17 -04:00
// Update 5 second cycle counter
let seconds = 1;
cycle_counter = Math.floor((cycle_counter + 1) % Math.round(Tone.Transport.bpm.value / hz_lookup['16n'] * seconds));
for (track in tracks) {
// Don't play track if checkbox is unchecked
if (document.getElementById(track).checked == false) {
continue;
}
let track_data = tracks[track];
// Play each synth if bpm counter is ready
if (track_data['bpm_counter'] == 0) {
2018-10-25 13:32:25 -04:00
track_data['synth'].triggerAttackRelease(Tone.Frequency(track['frequency'], 'midi'), track_data['duration'], time, 0.8);
2018-10-23 11:36:17 -04:00
}
// Update each bpm counter
tracks[track]['bpm_counter'] = (track_data['bpm_counter'] + 1) % Math.round(Tone.Transport.bpm.value / track_data['bpm']);
// Indicates 5 seconds has passed, so cycle to next point in data
if (cycle_counter == 0) {
2018-10-25 13:32:25 -04:00
console.log(track + ' BPM: ' + track_data['bpm']);
console.log(track + ' MIDI: ' + track_data['frequency']);
2018-10-23 11:36:17 -04:00
tracks[track]['point_counter'] = (track_data['point_counter'] + 1) % track_data['content'].length;
tracks[track]['bpm'] = track_data['content'][tracks[track]['point_counter']]['speed'];
tracks[track]['frequency'] = track_data['content'][tracks[track]['point_counter']]['elevation'];
}
}
2018-10-22 09:50:12 -04:00
}
window.addEventListener('load', mySetup);
2018-10-21 18:23:31 -04:00
</script>
</body>
</html>