From 1f2b0ba41942ab858d8375a65c9e9f5e32003112 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johan=20Hillerstr=C3=B6m?= Date: Fri, 13 Nov 2015 23:43:18 +0100 Subject: [PATCH 1/2] Add safeguards when setting cur_pat --- xm.js | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/xm.js b/xm.js index ff31034..1552f82 100644 --- a/xm.js +++ b/xm.js @@ -107,13 +107,37 @@ function periodForNote(ch, note) { return 1920 - (note + ch.samp.note)*16 - ch.samp.fine / 8.0; } +function setCurrentPattern() { + var nextPat = player.xm.songpats[player.cur_songpos]; + + // check for out of range pattern index + while (nextPat >= player.xm.patterns.length) { + if (player.cur_songpos + 1 < player.xm.songpats.length) { + // first try skipping the position + player.cur_songpos++; + } else if ((player.cur_songpos === player.xm.song_looppos && player.cur_songpos !== 0) + || player.xm.song_looppos >= player.xm.songpats.length) { + // if we allready tried song_looppos or if song_looppos + // is out of range, go to the first position + player.cur_songpos = 0; + } else { + // try going to song_looppos + player.cur_songpos = player.xm.song_looppos; + } + + nextPat = player.xm.songpats[player.cur_songpos]; + } + + player.cur_pat = nextPat; +} + function nextRow() { if (player.cur_pat == -1 || player.cur_row >= player.xm.patterns[player.cur_pat].length) { player.cur_row = 0; player.cur_songpos++; if (player.cur_songpos >= player.xm.songpats.length) player.cur_songpos = player.xm.song_looppos; - player.cur_pat = player.xm.songpats[player.cur_songpos]; + setCurrentPattern(); } var p = player.xm.patterns[player.cur_pat]; var r = p[player.cur_row]; From fc6be2b2466be046864666484f42faa68c66e948 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johan=20Hillerstr=C3=B6m?= Date: Sat, 14 Nov 2015 12:35:28 +0100 Subject: [PATCH 2/2] Add tests for non-existing song positions --- test/all.js | 104 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) diff --git a/test/all.js b/test/all.js index c0a6053..aed5085 100644 --- a/test/all.js +++ b/test/all.js @@ -20,6 +20,110 @@ exports['test XM startup'] = function(assert) { assert.equal(XMPlayer.cur_row, 1, 'advance to row 1'); }; +exports['test non-existing song position'] = function(assert) { + testdata.resetXMData(); + // 2 existing patterns, 1 non-existing + XMPlayer.xm.songpats = [0, 1, 2] + // 1 channel, 1 row, 2 blank patterns + XMPlayer.xm.patterns = [ + [[[-1, -1, -1, 0, 0]]], + [[[-1, -1, -1, 0, 0]]] + ]; + XMPlayer.xm.tempo = 1; + XMPlayer.nextTick(); + assert.equal(XMPlayer.cur_songpos, 0, 'advance to initial song position'); + assert.equal(XMPlayer.cur_pat, 0, 'advance to pattern 0'); + assert.equal(XMPlayer.cur_row, 1, 'advance to row 1'); + XMPlayer.nextTick(); + assert.equal(XMPlayer.cur_songpos, 1, 'advance to song position 1'); + assert.equal(XMPlayer.cur_pat, 1, 'advance to pattern 1'); + XMPlayer.nextTick(); + assert.equal(XMPlayer.cur_songpos, 0, 'return to song position 0'); + assert.equal(XMPlayer.cur_pat, 0, 'return to pattern 0'); +}; + +exports['test non-existing first song position'] = function(assert) { + testdata.resetXMData(); + // 2 existing patterns, 1 non-existing + XMPlayer.xm.songpats = [2, 0, 1] + // 1 channel, 1 row, 2 blank patterns + XMPlayer.xm.patterns = [ + [[[-1, -1, -1, 0, 0]]], + [[[-1, -1, -1, 0, 0]]] + ]; + XMPlayer.xm.tempo = 1; + XMPlayer.nextTick(); + assert.equal(XMPlayer.cur_songpos, 1, 'advance to song position 1'); + assert.equal(XMPlayer.cur_pat, 0, 'advance to pattern 0'); + XMPlayer.nextTick(); + assert.equal(XMPlayer.cur_songpos, 2, 'advance to song position 2'); + assert.equal(XMPlayer.cur_pat, 1, 'advance to pattern 1'); +}; + +exports['test multiple non-existing song positions'] = function(assert) { + testdata.resetXMData(); + // 2 existing patterns, 2 non-existing + XMPlayer.xm.songpats = [2, 0, 3, 1] + // 1 channel, 1 row, 2 blank patterns + XMPlayer.xm.patterns = [ + [[[-1, -1, -1, 0, 0]]], + [[[-1, -1, -1, 0, 0]]] + ]; + XMPlayer.xm.tempo = 1; + XMPlayer.nextTick(); + assert.equal(XMPlayer.cur_songpos, 1, 'advance to song position 1'); + assert.equal(XMPlayer.cur_pat, 0, 'advance to pattern 0'); + XMPlayer.nextTick(); + assert.equal(XMPlayer.cur_songpos, 3, 'advance to song position 3'); + assert.equal(XMPlayer.cur_pat, 1, 'advance to pattern 1'); +}; + +exports['test non-existing song position with loop'] = function(assert) { + testdata.resetXMData(); + // 2 existing patterns, 1 non-existing + XMPlayer.xm.songpats = [0, 1, 2] + // 1 channel, 1 row, 2 blank patterns + XMPlayer.xm.patterns = [ + [[[-1, -1, -1, 0, 0]]], + [[[-1, -1, -1, 0, 0]]] + ]; + XMPlayer.xm.song_looppos = 1; + XMPlayer.xm.tempo = 1; + XMPlayer.nextTick(); + assert.equal(XMPlayer.cur_songpos, 0, 'advance to initial song position'); + assert.equal(XMPlayer.cur_pat, 0, 'advance to pattern 0'); + assert.equal(XMPlayer.cur_row, 1, 'advance to row 1'); + XMPlayer.nextTick(); + assert.equal(XMPlayer.cur_songpos, 1, 'advance to song position 1'); + assert.equal(XMPlayer.cur_pat, 1, 'advance to pattern 1'); + XMPlayer.nextTick(); + assert.equal(XMPlayer.cur_songpos, 1, 'replay song position 1'); + assert.equal(XMPlayer.cur_pat, 1, 'replay pattern 1'); +}; + +exports['test non-existing song position with invalid loop'] = function(assert) { + testdata.resetXMData(); + // 2 existing patterns, 1 non-existing + XMPlayer.xm.songpats = [0, 1, 2] + // 1 channel, 1 row, 2 blank patterns + XMPlayer.xm.patterns = [ + [[[-1, -1, -1, 0, 0]]], + [[[-1, -1, -1, 0, 0]]] + ]; + XMPlayer.xm.song_looppos = 4; + XMPlayer.xm.tempo = 1; + XMPlayer.nextTick(); + assert.equal(XMPlayer.cur_songpos, 0, 'advance to initial song position'); + assert.equal(XMPlayer.cur_pat, 0, 'advance to pattern 0'); + assert.equal(XMPlayer.cur_row, 1, 'advance to row 1'); + XMPlayer.nextTick(); + assert.equal(XMPlayer.cur_songpos, 1, 'advance to song position 1'); + assert.equal(XMPlayer.cur_pat, 1, 'advance to pattern 1'); + XMPlayer.nextTick(); + assert.equal(XMPlayer.cur_songpos, 0, 'return to song position 0'); + assert.equal(XMPlayer.cur_pat, 0, 'return to pattern 0'); +}; + exports['test instruments'] = require('./instrument.js'); exports['test effects'] = require('./effects.js');