diff --git a/index.html b/index.html index c0d7a18..ef7e8e1 100644 --- a/index.html +++ b/index.html @@ -2,12 +2,17 @@ js xm + @@ -16,17 +21,22 @@ canvas.centered {
-
+
+

+ + +

+
+
 code: github.com/a1k0n/jsxm
 todo:
- - file picker, upload more xms to a host we can access cross-origin
- - render instrument list in ft2 font
  - missing XM effects:
    - E3x, E4x, E5x, E6x, E7x, E9x, EDx, EEx
    - 7xy - tremolo
    - Gxx, Hxy, Kxx, Lxx, Pxy, Txy
+ - render pattern with the wider fonts for fewer channels
 
diff --git a/xm.js b/xm.js index 490f098..13b8a7b 100644 --- a/xm.js +++ b/xm.js @@ -794,7 +794,7 @@ function UnrollSampleLoop(samp) { samp.type = 1; } -function loadXM(arrayBuf) { +function LoadXM(arrayBuf) { var dv = new DataView(arrayBuf); var xm = {}; @@ -1026,6 +1026,10 @@ function loadXM(arrayBuf) { DrawBigText(xm.songname, 0, 1, ctx); var instrlist = document.getElementById("instruments"); + // clear instrument list if not already clear + while (instrlist.childNodes.length) { + instrlist.removeChild(instrlist.childNodes[0]); + } var instrcols = ((xm.instruments.length + 7) / 8) | 0; for (var i = 0; i < instrcols; i++) { var canvas = document.createElement('canvas'); @@ -1074,10 +1078,12 @@ var playing = false; var jsNode, gainNode; var paused_events = []; function InitAudio() { - audioContext = window.AudioContext || window.webkitAudioContext; - audioctx = new audioContext(); - gainNode = audioctx.createGain(); - gainNode.gain.value = 0.1; // master volume + if (audioctx == undefined) { + audioContext = window.AudioContext || window.webkitAudioContext; + audioctx = new audioContext(); + gainNode = audioctx.createGain(); + gainNode.gain.value = 0.1; // master volume + } jsNode = audioctx.createScriptProcessor(16384, 0, 2); jsNode.onaudioprocess = audio_cb; gainNode.connect(audioctx.destination); @@ -1113,19 +1119,25 @@ function PauseXM() { playing = false; } -function main() { - InitAudio(); - var xmReq = new XMLHttpRequest(); - var uri = location.search.substr(1); - if (uri == "") { - uri = "kamel.xm"; +function StopXM() { + if (playing) { + jsNode.disconnect(gainNode); + playing = false; + audio_events = []; + paused_events = []; } + cur_songpos = -1, cur_pat = -1, cur_row = 64, cur_ticksamp = 0; + InitAudio(); +} + +function DownloadXM(uri) { + var xmReq = new XMLHttpRequest(); xmReq.open("GET", uri, true); xmReq.responseType = "arraybuffer"; xmReq.onload = function (xmEvent) { var arrayBuffer = xmReq.response; if (arrayBuffer) { - xm = loadXM(arrayBuffer); + xm = LoadXM(arrayBuffer); } else { console.log("unable to load", uri); } @@ -1133,6 +1145,7 @@ function main() { var gfxpattern = document.getElementById("gfxpattern"); gfxpattern.width = _pattern_cellwidth * xm.nchan + _pattern_border; var playbutton = document.getElementById('playpause'); + playbutton.innerHTML='Play'; playbutton.onclick = function() { if (playing) { PauseXM(); @@ -1148,6 +1161,11 @@ function main() { for (var i = 0; i < xm.nchan; i++) { scopes.push(new Float32Array(_scope_width)); } + + // reset display + shown_row = undefined; + pat_canvas_patnum = undefined; + audio_events.push({ t: 0, row: 0, pat: xm.songpats[0], vu: new Float32Array(xm.nchan), @@ -1158,3 +1176,37 @@ function main() { xmReq.send(null); } +function InitFilelist() { + var el = document.getElementById('filelist'); + xmuris.forEach(function(entry) { + var a = document.createElement('a'); + a.text = entry[0]; + a.href = '#'+entry[1]; + a.onclick = function() { + el.style.display = "none"; + StopXM(); + DownloadXM(baseuri + entry[1]); + } + el.appendChild(a); + el.appendChild(document.createElement('br')); + }); + var loadbutton = document.getElementById('loadbutton'); + loadbutton.onclick = function() { + if (el.style.display == "none") { + el.style.display = "block"; + } else { + el.style.display = "none"; + } + } +} + +function main() { + InitAudio(); + InitFilelist(); + var uri = location.hash.substr(1); + if (uri == "") { + uri = "kamel.xm"; + } + DownloadXM(baseuri + uri); +} +