From 4287ea5336dc5aa2055023a0398bbe98d6ee8697 Mon Sep 17 00:00:00 2001
From: bye <bye@byecorps.com>
Date: Fri, 16 Aug 2024 09:59:43 +0100
Subject: [PATCH] Unfinished load thing

---
 README.md                        |   5 +
 src/js/main.js                   |  61 ++---
 src/js/sb-player-small.js        | 364 +++++++++++++++++++++++++++++
 src/music/DEMOSONGDONOTCOMMIT.js | 387 +++++++++++++++++++++++++++++++
 4 files changed, 777 insertions(+), 40 deletions(-)
 create mode 100644 src/js/sb-player-small.js
 create mode 100644 src/music/DEMOSONGDONOTCOMMIT.js

diff --git a/README.md b/README.md
index f97feeb..7773cf3 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,6 @@
 # js13k2024
+
+## External code
+
+This entry uses [player-small.js](https://sb.bitsnbites.eu/player-small.js) from SoundBox. `player-small.js` is licensed
+under [the zlib/libpng License](https://opensource.org/license/Zlib).
diff --git a/src/js/main.js b/src/js/main.js
index 3c69ab5..aaf1ad5 100644
--- a/src/js/main.js
+++ b/src/js/main.js
@@ -4,15 +4,22 @@ import Engine from "../../hampsterengine/src/engine.js";
 import {Room} from "../../hampsterengine/src/things.js";
 
 import {Logo, MainMenuButton} from "./objects.js";
+import SoundBox from "./sb-player-small";
+import {mus_DEMOSONG} from "../music/DEMOSONGDONOTCOMMIT";
 
 // Rooms
 import {rm_DEBUG_button} from "./rooms/debug_button";
 import {rm_DEBUG_mouse} from "./rooms/debug_mouse";
+import assetStore from "../../hampsterengine/src/assetStore";
+
+// Music
 
 const canvas = new Canvas('canvas');
 const engine = new Engine(canvas);
 const assets = engine.assetStore;
 
+assets.addSoundBoxAudio('mus_DEMO', mus_DEMOSONG, new SoundBox());
+
 canvas.width = 640;
 canvas.height = 480;
 canvas.pixelRatio = 2;
@@ -51,45 +58,6 @@ engine.registerRoom(rm_MainMenu, 'mainMenu');
 engine.registerRoom(rm_DEBUG_button, 'debug_button');
 engine.registerRoom(rm_DEBUG_mouse, 'debug_mouse');
 
-// const rm_DEBUG_music = new Room();
-// rm_DEBUG_music.audio = document.createElement("audio");
-// rm_DEBUG_music.start = _=> {
-//     canvas.pixelRatio =1;
-//     canvas.ctx.setTransform(1, 0, 0, 1, 0, 0);
-//
-//     const player = new Soundbox();
-//     const audio = rm_DEBUG_music.audio;
-//     player.init(song);
-//
-//     let done = false;
-//     setInterval(_=>{
-//         if (done) return;
-//
-//         done = player.generate() >= 1;
-//
-//         if (done) {
-//             const wave = player.createWave();
-//             audio.src = URL.createObjectURL(new Blob([wave], {type: "audio/wav"}));
-//             audio.play();
-//         }
-//     })
-// }
-//
-// rm_DEBUG_music.drawGui = _ => {
-//     const audio = rm_DEBUG_music.audio;
-//
-//     // get the time in seconds
-//     const date = new Date(0);
-//     date.setSeconds(audio.currentTime);
-//     const timeString = date.toISOString().substring(11, 19);
-//
-//     canvas.setFillColor('black');
-//     canvas.drawText(audio.paused ? 'Paused' : 'Playing', 10, canvas.height - 10, {});
-//     canvas.drawText(`${timeString}`, 10, canvas.height - 30, {});
-// }
-//
-// engine.registerRoom(rm_DEBUG_music, 'debug_music');
-
 function main() {
     requestAnimationFrame(main);
     canvas.fill(engine.room.bgColor ?? 'white');
@@ -115,4 +83,17 @@ if (document.location.hash) {
 } else {
     engine.room = engine.getRoomIndex('mainMenu');
 }
-main();
+
+// Ensure assets are loaded.
+
+function load() {
+    if (engine.loading) {
+        engine.loadLoop();
+        setTimeout(main, 1000/60);
+    } else {
+        engine.room = engine.getRoomIndex('mainMenu');
+        main();
+    }
+}
+
+load();
diff --git a/src/js/sb-player-small.js b/src/js/sb-player-small.js
new file mode 100644
index 0000000..a03cff8
--- /dev/null
+++ b/src/js/sb-player-small.js
@@ -0,0 +1,364 @@
+/* -*- mode: javascript; tab-width: 4; indent-tabs-mode: nil; -*-
+*
+* Copyright (c) 2011-2013 Marcus Geelnard
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+*
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+*
+* 1. The origin of this software must not be misrepresented; you must not
+*    claim that you wrote the original software. If you use this software
+*    in a product, an acknowledgment in the product documentation would be
+*    appreciated but is not required.
+*
+* 2. Altered source versions must be plainly marked as such, and must not be
+*    misrepresented as being the original software.
+*
+* 3. This notice may not be removed or altered from any source
+*    distribution.
+*
+* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+*
+* This source code has been modified to work with `import` syntax.
+*
+*/
+
+"use strict";
+
+// Some general notes and recommendations:
+//  * This code uses modern ECMAScript features, such as ** instead of
+//    Math.pow(). You may have to modify the code to make it work on older
+//    browsers.
+//  * If you're not using all the functionality (e.g. not all oscillator types,
+//    or certain effects), you can reduce the size of the player routine even
+//    further by deleting the code.
+
+
+const SoundBox = function () {
+
+    //--------------------------------------------------------------------------
+    // Private methods
+    //--------------------------------------------------------------------------
+
+    // Oscillators
+    var osc_sin = function (value) {
+        return Math.sin(value * 6.283184);
+    };
+
+    var osc_saw = function (value) {
+        return 2 * (value % 1) - 1;
+    };
+
+    var osc_square = function (value) {
+        return (value % 1) < 0.5 ? 1 : -1;
+    };
+
+    var osc_tri = function (value) {
+        var v2 = (value % 1) * 4;
+        if (v2 < 2) return v2 - 1;
+        return 3 - v2;
+    };
+
+    var getnotefreq = function (n) {
+        // 174.61.. / 44100 = 0.003959503758 (F3)
+        return 0.003959503758 * (2 ** ((n - 128) / 12));
+    };
+
+    var createNote = function (instr, n, rowLen) {
+        var osc1 = mOscillators[instr.i[0]],
+            o1vol = instr.i[1],
+            o1xenv = instr.i[3] / 32,
+            osc2 = mOscillators[instr.i[4]],
+            o2vol = instr.i[5],
+            o2xenv = instr.i[8] / 32,
+            noiseVol = instr.i[9],
+            attack = instr.i[10] * instr.i[10] * 4,
+            sustain = instr.i[11] * instr.i[11] * 4,
+            release = instr.i[12] * instr.i[12] * 4,
+            releaseInv = 1 / release,
+            expDecay = -instr.i[13] / 16,
+            arp = instr.i[14],
+            arpInterval = rowLen * (2 ** (2 - instr.i[15]));
+
+        var noteBuf = new Int32Array(attack + sustain + release);
+
+        // Re-trig oscillators
+        var c1 = 0, c2 = 0;
+
+        // Local variables.
+        var j, j2, e, t, rsample, o1t, o2t;
+
+        // Generate one note (attack + sustain + release)
+        for (j = 0, j2 = 0; j < attack + sustain + release; j++, j2++) {
+            if (j2 >= 0) {
+                // Switch arpeggio note.
+                arp = (arp >> 8) | ((arp & 255) << 4);
+                j2 -= arpInterval;
+
+                // Calculate note frequencies for the oscillators
+                o1t = getnotefreq(n + (arp & 15) + instr.i[2] - 128);
+                o2t = getnotefreq(n + (arp & 15) + instr.i[6] - 128) * (1 + 0.0008 * instr.i[7]);
+            }
+
+            // Envelope
+            e = 1;
+            if (j < attack) {
+                e = j / attack;
+            } else if (j >= attack + sustain) {
+                e = (j - attack - sustain) * releaseInv;
+                e = (1 - e) * (3 ** (expDecay * e));
+            }
+
+            // Oscillator 1
+            c1 += o1t * e ** o1xenv;
+            rsample = osc1(c1) * o1vol;
+
+            // Oscillator 2
+            c2 += o2t * e ** o2xenv;
+            rsample += osc2(c2) * o2vol;
+
+            // Noise oscillator
+            if (noiseVol) {
+                rsample += (2 * Math.random() - 1) * noiseVol;
+            }
+
+            // Add to (mono) channel buffer
+            noteBuf[j] = (80 * rsample * e) | 0;
+        }
+
+        return noteBuf;
+    };
+
+
+    //--------------------------------------------------------------------------
+    // Private members
+    //--------------------------------------------------------------------------
+
+    // Array of oscillator functions
+    var mOscillators = [
+        osc_sin,
+        osc_square,
+        osc_saw,
+        osc_tri
+    ];
+
+    // Private variables set up by init()
+    var mSong, mLastRow, mCurrentCol, mNumWords, mMixBuf;
+
+
+    //--------------------------------------------------------------------------
+    // Initialization
+    //--------------------------------------------------------------------------
+
+    this.init = function (song) {
+        // Define the song
+        mSong = song;
+
+        // Init iteration state variables
+        mLastRow = song.endPattern;
+        mCurrentCol = 0;
+
+        // Prepare song info
+        mNumWords = song.rowLen * song.patternLen * (mLastRow + 1) * 2;
+
+        // Create work buffer (initially cleared)
+        mMixBuf = new Int32Array(mNumWords);
+    };
+
+
+    //--------------------------------------------------------------------------
+    // Public methods
+    //--------------------------------------------------------------------------
+
+    // Generate audio data for a single track
+    this.generate = function () {
+        // Local variables
+        var i, j, b, p, row, col, n, cp,
+            k, t, lfor, e, x, rsample, rowStartSample, f, da;
+
+        // Put performance critical items in local variables
+        var chnBuf = new Int32Array(mNumWords),
+            instr = mSong.songData[mCurrentCol],
+            rowLen = mSong.rowLen,
+            patternLen = mSong.patternLen;
+
+        // Clear effect state
+        var low = 0, band = 0, high;
+        var lsample, filterActive = false;
+
+        // Clear note cache.
+        var noteCache = [];
+
+        // Patterns
+        for (p = 0; p <= mLastRow; ++p) {
+            cp = instr.p[p];
+
+            // Pattern rows
+            for (row = 0; row < patternLen; ++row) {
+                // Execute effect command.
+                var cmdNo = cp ? instr.c[cp - 1].f[row] : 0;
+                if (cmdNo) {
+                    instr.i[cmdNo - 1] = instr.c[cp - 1].f[row + patternLen] || 0;
+
+                    // Clear the note cache since the instrument has changed.
+                    if (cmdNo < 17) {
+                        noteCache = [];
+                    }
+                }
+
+                // Put performance critical instrument properties in local variables
+                var oscLFO = mOscillators[instr.i[16]],
+                    lfoAmt = instr.i[17] / 512,
+                    lfoFreq = (2 ** (instr.i[18] - 9)) / rowLen,
+                    fxLFO = instr.i[19],
+                    fxFilter = instr.i[20],
+                    fxFreq = instr.i[21] * 43.23529 * 3.141592 / 44100,
+                    q = 1 - instr.i[22] / 255,
+                    dist = instr.i[23] * 1e-5,
+                    drive = instr.i[24] / 32,
+                    panAmt = instr.i[25] / 512,
+                    panFreq = 6.283184 * (2 ** (instr.i[26] - 9)) / rowLen,
+                    dlyAmt = instr.i[27] / 255,
+                    dly = instr.i[28] * rowLen & ~1;  // Must be an even number
+
+                // Calculate start sample number for this row in the pattern
+                rowStartSample = (p * patternLen + row) * rowLen;
+
+                // Generate notes for this pattern row
+                for (col = 0; col < 4; ++col) {
+                    n = cp ? instr.c[cp - 1].n[row + col * patternLen] : 0;
+                    if (n) {
+                        if (!noteCache[n]) {
+                            noteCache[n] = createNote(instr, n, rowLen);
+                        }
+
+                        // Copy note from the note cache
+                        var noteBuf = noteCache[n];
+                        for (j = 0, i = rowStartSample * 2; j < noteBuf.length; j++, i += 2) {
+                            chnBuf[i] += noteBuf[j];
+                        }
+                    }
+                }
+
+                // Perform effects for this pattern row
+                for (j = 0; j < rowLen; j++) {
+                    // Dry mono-sample
+                    k = (rowStartSample + j) * 2;
+                    rsample = chnBuf[k];
+
+                    // We only do effects if we have some sound input
+                    if (rsample || filterActive) {
+                        // State variable filter
+                        f = fxFreq;
+                        if (fxLFO) {
+                            f *= oscLFO(lfoFreq * k) * lfoAmt + 0.5;
+                        }
+                        f = 1.5 * Math.sin(f);
+                        low += f * band;
+                        high = q * (rsample - band) - low;
+                        band += f * high;
+                        rsample = fxFilter == 3 ? band : fxFilter == 1 ? high : low;
+
+                        // Distortion
+                        if (dist) {
+                            rsample *= dist;
+                            rsample = rsample < 1 ? rsample > -1 ? osc_sin(rsample * .25) : -1 : 1;
+                            rsample /= dist;
+                        }
+
+                        // Drive
+                        rsample *= drive;
+
+                        // Is the filter active (i.e. still audiable)?
+                        filterActive = rsample * rsample > 1e-5;
+
+                        // Panning
+                        t = Math.sin(panFreq * k) * panAmt + 0.5;
+                        lsample = rsample * (1 - t);
+                        rsample *= t;
+                    } else {
+                        lsample = 0;
+                    }
+
+                    // Delay is always done, since it does not need sound input
+                    if (k >= dly) {
+                        // Left channel = left + right[-p] * t
+                        lsample += chnBuf[k - dly + 1] * dlyAmt;
+
+                        // Right channel = right + left[-p] * t
+                        rsample += chnBuf[k - dly] * dlyAmt;
+                    }
+
+                    // Store in stereo channel buffer (needed for the delay effect)
+                    chnBuf[k] = lsample | 0;
+                    chnBuf[k + 1] = rsample | 0;
+
+                    // ...and add to stereo mix buffer
+                    mMixBuf[k] += lsample | 0;
+                    mMixBuf[k + 1] += rsample | 0;
+                }
+            }
+        }
+
+        // Next iteration. Return progress (1.0 == done!).
+        mCurrentCol++;
+        return mCurrentCol / mSong.numChannels;
+    };
+
+    // Create a AudioBuffer from the generated audio data
+    this.createAudioBuffer = function (context) {
+        var buffer = context.createBuffer(2, mNumWords / 2, 44100);
+        for (var i = 0; i < 2; i++) {
+            var data = buffer.getChannelData(i);
+            for (var j = i; j < mNumWords; j += 2) {
+                data[j >> 1] = mMixBuf[j] / 65536;
+            }
+        }
+        return buffer;
+    };
+
+    // Create a WAVE formatted Uint8Array from the generated audio data
+    this.createWave = function () {
+        // Create WAVE header
+        var headerLen = 44;
+        var l1 = headerLen + mNumWords * 2 - 8;
+        var l2 = l1 - 36;
+        var wave = new Uint8Array(headerLen + mNumWords * 2);
+        wave.set(
+            [82, 73, 70, 70,
+                l1 & 255, (l1 >> 8) & 255, (l1 >> 16) & 255, (l1 >> 24) & 255,
+                87, 65, 86, 69, 102, 109, 116, 32, 16, 0, 0, 0, 1, 0, 2, 0,
+                68, 172, 0, 0, 16, 177, 2, 0, 4, 0, 16, 0, 100, 97, 116, 97,
+                l2 & 255, (l2 >> 8) & 255, (l2 >> 16) & 255, (l2 >> 24) & 255]
+        );
+
+        // Append actual wave data
+        for (var i = 0, idx = headerLen; i < mNumWords; ++i) {
+            // Note: We clamp here
+            var y = mMixBuf[i];
+            y = y < -32767 ? -32767 : (y > 32767 ? 32767 : y);
+            wave[idx++] = y & 255;
+            wave[idx++] = (y >> 8) & 255;
+        }
+
+        // Return the WAVE formatted typed array
+        return wave;
+    };
+
+    // Get n samples of wave data at time t [s]. Wave data in range [-2,2].
+    this.getData = function (t, n) {
+        var i = 2 * Math.floor(t * 44100);
+        var d = new Array(n);
+        for (var j = 0; j < 2 * n; j += 1) {
+            var k = i + j;
+            d[j] = t > 0 && k < mMixBuf.length ? mMixBuf[k] / 32768 : 0;
+        }
+        return d;
+    };
+};
+
+export default SoundBox
diff --git a/src/music/DEMOSONGDONOTCOMMIT.js b/src/music/DEMOSONGDONOTCOMMIT.js
new file mode 100644
index 0000000..36a4cd7
--- /dev/null
+++ b/src/music/DEMOSONGDONOTCOMMIT.js
@@ -0,0 +1,387 @@
+    // This music has been exported by SoundBox. You can use it with
+    // http://sb.bitsnbites.eu/player-small.js in your own product.
+
+    // See http://sb.bitsnbites.eu/demo.html for an example of how to
+    // use it in a demo.
+
+    // Song data
+    export var mus_DEMOSONG = {
+      songData: [
+        { // Instrument 0
+          i: [
+          2, // OSC1_WAVEFORM
+          100, // OSC1_VOL
+          128, // OSC1_SEMI
+          0, // OSC1_XENV
+          3, // OSC2_WAVEFORM
+          201, // OSC2_VOL
+          128, // OSC2_SEMI
+          0, // OSC2_DETUNE
+          0, // OSC2_XENV
+          0, // NOISE_VOL
+          0, // ENV_ATTACK
+          6, // ENV_SUSTAIN
+          29, // ENV_RELEASE
+          0, // ENV_EXP_DECAY
+          0, // ARP_CHORD
+          0, // ARP_SPEED
+          0, // LFO_WAVEFORM
+          194, // LFO_AMT
+          4, // LFO_FREQ
+          1, // LFO_FX_FREQ
+          3, // FX_FILTER
+          25, // FX_FREQ
+          191, // FX_RESONANCE
+          115, // FX_DIST
+          244, // FX_DRIVE
+          147, // FX_PAN_AMT
+          6, // FX_PAN_FREQ
+          84, // FX_DELAY_AMT
+          6 // FX_DELAY_TIME
+          ],
+          // Patterns
+          p: [5,1,2,1,1,1,1,3,4,1,2,1,2,1,2,,,7,8,7,8,7,8,7,8,6,9],
+          // Columns
+          c: [
+            {n: [123,123,135,128,123,123,135,130,126,125,126,128,123,123,135,128,123,123,135,130,126,125,126,128,123,123,135,128,123,123,135,130],
+             f: [22,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,48]},
+            {n: [123,123,135,128,123,123,135,130,126,125,126,128,123,123,135,128,123,123,135,130,126,125,126,128,123,,99,,,,99,,,,,,,,,,,,,,,,,,,,,,,,,,111],
+             f: [,,,,,,,,,,,,,,,,,,,,,,,,,,,11,13,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,31]},
+            {n: [111,,,,,,,,123,,,,,,,,111,,,,,,,,123],
+             f: []},
+            {n: [114,,,,,,,,126,,,,,,,,114,,,,,,,,114,126,111,123,114,126,118,130],
+             f: [13,,,,,,,,,,,,,,,,,,,,,,,,13,,13,,13,,13,11,29,,,,,,,,,,,,,,,,,,,,,,,,32,,41,,29,,25,15]},
+            {n: [123,123,135,128,123,123,135,130,126,125,126,128,123,123,135,128,123,123,135,130,126,125,126,128,123,,99,,,,99,,,,,,,,,,,,,,,,,,,,,,,,,,111],
+             f: [13,11,22,18,,,,,,,,,,,,,,,,,,,,,,,,,,,,18,29,,25,113,,,,,,,,,,,,,,,,,,,,,,,,,,,,194]},
+            {n: [111,,,,,,,,123,,,,,,,,111,,,,,,,,99],
+             f: []},
+            {n: [111,123,,123,111,,123,111,111,123,,123,111,,123,111,111,123,,123,111,,123,111,111,123,,123,111,,123,111],
+             f: []},
+            {n: [114,126,,126,114,,126,114,114,126,,126,114,,126,114,114,126,,126,114,,126,114,116,128,,128,116,,114,121],
+             f: []},
+            {n: [],
+             f: []}
+          ]
+        },
+        { // Instrument 1
+          i: [
+          0, // OSC1_WAVEFORM
+          255, // OSC1_VOL
+          117, // OSC1_SEMI
+          64, // OSC1_XENV
+          0, // OSC2_WAVEFORM
+          255, // OSC2_VOL
+          110, // OSC2_SEMI
+          0, // OSC2_DETUNE
+          64, // OSC2_XENV
+          0, // NOISE_VOL
+          4, // ENV_ATTACK
+          6, // ENV_SUSTAIN
+          35, // ENV_RELEASE
+          0, // ENV_EXP_DECAY
+          0, // ARP_CHORD
+          0, // ARP_SPEED
+          0, // LFO_WAVEFORM
+          0, // LFO_AMT
+          0, // LFO_FREQ
+          0, // LFO_FX_FREQ
+          2, // FX_FILTER
+          14, // FX_FREQ
+          1, // FX_RESONANCE
+          1, // FX_DIST
+          39, // FX_DRIVE
+          76, // FX_PAN_AMT
+          5, // FX_PAN_FREQ
+          0, // FX_DELAY_AMT
+          0 // FX_DELAY_TIME
+          ],
+          // Patterns
+          p: [,1,1,1,1,1,1,2,,,,1,1,1,1,1,1,,,1,1,1,1,1,1],
+          // Columns
+          c: [
+            {n: [147,,,,,,147,,,,147,,,,,,147,,,,,,147,,,,147,,,,147],
+             f: []},
+            {n: [147],
+             f: []}
+          ]
+        },
+        { // Instrument 2
+          i: [
+          0, // OSC1_WAVEFORM
+          0, // OSC1_VOL
+          140, // OSC1_SEMI
+          0, // OSC1_XENV
+          0, // OSC2_WAVEFORM
+          0, // OSC2_VOL
+          140, // OSC2_SEMI
+          0, // OSC2_DETUNE
+          0, // OSC2_XENV
+          60, // NOISE_VOL
+          4, // ENV_ATTACK
+          10, // ENV_SUSTAIN
+          68, // ENV_RELEASE
+          0, // ENV_EXP_DECAY
+          0, // ARP_CHORD
+          0, // ARP_SPEED
+          0, // LFO_WAVEFORM
+          187, // LFO_AMT
+          5, // LFO_FREQ
+          0, // LFO_FX_FREQ
+          1, // FX_FILTER
+          239, // FX_FREQ
+          135, // FX_RESONANCE
+          0, // FX_DIST
+          32, // FX_DRIVE
+          108, // FX_PAN_AMT
+          5, // FX_PAN_FREQ
+          16, // FX_DELAY_AMT
+          4 // FX_DELAY_TIME
+          ],
+          // Patterns
+          p: [,1,1,2,3,2,3,4,,,,2,3,2,3,2,3,,,5,5,5,5,5,5,4],
+          // Columns
+          c: [
+            {n: [,,,,147,,,,,,,,148,,,,,,,,147,,,,,,,,147],
+             f: [13,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,35]},
+            {n: [,,,,147,,,147,,,,,148,,,,,,,,147,,,147,,,147,,,,147],
+             f: [13,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,35]},
+            {n: [,,,,147,,,147,,,,,148,,,,,,,,147,,,147,,,147,,,147,147,147],
+             f: [13,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,35]},
+            {n: [147],
+             f: [13,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,68]},
+            {n: [147,,,147,,,147,,147,,,147,,147,,147,147,,,147,,,147,,147,,,147,,147,,147],
+             f: [13,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,35]}
+          ]
+        },
+        { // Instrument 3
+          i: [
+          2, // OSC1_WAVEFORM
+          192, // OSC1_VOL
+          128, // OSC1_SEMI
+          0, // OSC1_XENV
+          2, // OSC2_WAVEFORM
+          192, // OSC2_VOL
+          140, // OSC2_SEMI
+          18, // OSC2_DETUNE
+          0, // OSC2_XENV
+          0, // NOISE_VOL
+          107, // ENV_ATTACK
+          115, // ENV_SUSTAIN
+          138, // ENV_RELEASE
+          0, // ENV_EXP_DECAY
+          0, // ARP_CHORD
+          0, // ARP_SPEED
+          0, // LFO_WAVEFORM
+          136, // LFO_AMT
+          5, // LFO_FREQ
+          1, // LFO_FX_FREQ
+          2, // FX_FILTER
+          8, // FX_FREQ
+          92, // FX_RESONANCE
+          21, // FX_DIST
+          56, // FX_DRIVE
+          148, // FX_PAN_AMT
+          5, // FX_PAN_FREQ
+          85, // FX_DELAY_AMT
+          8 // FX_DELAY_TIME
+          ],
+          // Patterns
+          p: [3,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2],
+          // Columns
+          c: [
+            {n: [111],
+             f: []},
+            {n: [114],
+             f: []},
+            {n: [111],
+             f: [25,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,25,5,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,56]}
+          ]
+        },
+        { // Instrument 4
+          i: [
+          3, // OSC1_WAVEFORM
+          0, // OSC1_VOL
+          127, // OSC1_SEMI
+          0, // OSC1_XENV
+          3, // OSC2_WAVEFORM
+          68, // OSC2_VOL
+          127, // OSC2_SEMI
+          0, // OSC2_DETUNE
+          64, // OSC2_XENV
+          218, // NOISE_VOL
+          4, // ENV_ATTACK
+          4, // ENV_SUSTAIN
+          40, // ENV_RELEASE
+          0, // ENV_EXP_DECAY
+          0, // ARP_CHORD
+          0, // ARP_SPEED
+          1, // LFO_WAVEFORM
+          55, // LFO_AMT
+          4, // LFO_FREQ
+          1, // LFO_FX_FREQ
+          2, // FX_FILTER
+          67, // FX_FREQ
+          115, // FX_RESONANCE
+          124, // FX_DIST
+          190, // FX_DRIVE
+          67, // FX_PAN_AMT
+          6, // FX_PAN_FREQ
+          39, // FX_DELAY_AMT
+          1 // FX_DELAY_TIME
+          ],
+          // Patterns
+          p: [,,,1,2,1,2,3,,,,1,2,1,2,1,2,,,1,4,1,4,1,4,3],
+          // Columns
+          c: [
+            {n: [,,,,147,,,,,,,,147,,,,,,,,147,,,,,,,,147],
+             f: []},
+            {n: [,,,,147,,,,,,,,147,,,,,,,,147,,,,,,,,147,,147,147],
+             f: []},
+            {n: [147],
+             f: []},
+            {n: [,,,,147,,,,,,,,147,,,,,,,,147,,,,,,,,147,,,147],
+             f: []}
+          ]
+        },
+        { // Instrument 5
+          i: [
+          0, // OSC1_WAVEFORM
+          91, // OSC1_VOL
+          128, // OSC1_SEMI
+          0, // OSC1_XENV
+          0, // OSC2_WAVEFORM
+          95, // OSC2_VOL
+          128, // OSC2_SEMI
+          12, // OSC2_DETUNE
+          0, // OSC2_XENV
+          0, // NOISE_VOL
+          12, // ENV_ATTACK
+          0, // ENV_SUSTAIN
+          67, // ENV_RELEASE
+          0, // ENV_EXP_DECAY
+          0, // ARP_CHORD
+          0, // ARP_SPEED
+          0, // LFO_WAVEFORM
+          0, // LFO_AMT
+          0, // LFO_FREQ
+          0, // LFO_FX_FREQ
+          2, // FX_FILTER
+          255, // FX_FREQ
+          15, // FX_RESONANCE
+          0, // FX_DIST
+          32, // FX_DRIVE
+          83, // FX_PAN_AMT
+          3, // FX_PAN_FREQ
+          134, // FX_DELAY_AMT
+          4 // FX_DELAY_TIME
+          ],
+          // Patterns
+          p: [,,,1,2,3,2,1,2,,,1,2,3,2,1,2,,,,,4,5,4,5],
+          // Columns
+          c: [
+            {n: [159,,147,,154,,147,,157,,147,,154,,150,,159,,147,,154,,147,,162,,147,,154,,150,,123],
+             f: [5,13,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,67]},
+            {n: [159,,147,,154,,147,,157,,147,,154,,150,,159,,147,,154,,147,,162,,147,,157,,162,,126],
+             f: []},
+            {n: [159,,147,,154,,147,,157,,147,,154,,150,,159,,147,,154,,147,,162,,147,,154,,150,,123],
+             f: [5,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,3]},
+            {n: [159,,162,,164,,,,159,,162,164,,,162,,159,,162,,164,,,,159,,162,164,,,162],
+             f: [13,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,25]},
+            {n: [157,,162,,164,,,,157,,162,164,,,162,,157,,162,,164,,,,157,,162,164,,,162],
+             f: [,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,13,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,67]}
+          ]
+        },
+        { // Instrument 6
+          i: [
+          3, // OSC1_WAVEFORM
+          146, // OSC1_VOL
+          140, // OSC1_SEMI
+          0, // OSC1_XENV
+          1, // OSC2_WAVEFORM
+          224, // OSC2_VOL
+          128, // OSC2_SEMI
+          3, // OSC2_DETUNE
+          0, // OSC2_XENV
+          0, // NOISE_VOL
+          92, // ENV_ATTACK
+          0, // ENV_SUSTAIN
+          95, // ENV_RELEASE
+          0, // ENV_EXP_DECAY
+          0, // ARP_CHORD
+          0, // ARP_SPEED
+          3, // LFO_WAVEFORM
+          179, // LFO_AMT
+          5, // LFO_FREQ
+          1, // LFO_FX_FREQ
+          3, // FX_FILTER
+          37, // FX_FREQ
+          135, // FX_RESONANCE
+          63, // FX_DIST
+          67, // FX_DRIVE
+          150, // FX_PAN_AMT
+          3, // FX_PAN_FREQ
+          157, // FX_DELAY_AMT
+          6 // FX_DELAY_TIME
+          ],
+          // Patterns
+          p: [,,,,,,,,,1,2,3,,1,2,1,2,3,,4,5,,,,,3],
+          // Columns
+          c: [
+            {n: [123,,,,,,,,,,,,,,,,130],
+             f: [11,25,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,92,67]},
+            {n: [133,,,,,,,,,,,,,,,138,126,,,,,,,,,,,,125],
+             f: [11,,,,,,,,,,,,,,,,,,,,,,,,,,,,11,,,,95,,,,,,,,,,,,,,,,,,,,,,,,,,,,29]},
+            {n: [123],
+             f: [25,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,25,52,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,67]},
+            {n: [123,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,138,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,116],
+             f: [11,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,95]},
+            {n: [133,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,126,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,118],
+             f: []}
+          ]
+        },
+        { // Instrument 7
+          i: [
+          0, // OSC1_WAVEFORM
+          255, // OSC1_VOL
+          106, // OSC1_SEMI
+          64, // OSC1_XENV
+          0, // OSC2_WAVEFORM
+          255, // OSC2_VOL
+          106, // OSC2_SEMI
+          0, // OSC2_DETUNE
+          64, // OSC2_XENV
+          0, // NOISE_VOL
+          5, // ENV_ATTACK
+          7, // ENV_SUSTAIN
+          164, // ENV_RELEASE
+          0, // ENV_EXP_DECAY
+          0, // ARP_CHORD
+          0, // ARP_SPEED
+          0, // LFO_WAVEFORM
+          0, // LFO_AMT
+          0, // LFO_FREQ
+          0, // LFO_FX_FREQ
+          2, // FX_FILTER
+          255, // FX_FREQ
+          0, // FX_RESONANCE
+          2, // FX_DIST
+          16, // FX_DRIVE
+          83, // FX_PAN_AMT
+          5, // FX_PAN_FREQ
+          53, // FX_DELAY_AMT
+          1 // FX_DELAY_TIME
+          ],
+          // Patterns
+          p: [,,,,,,,1,,,,,,,,,,1,,,,,,,,1],
+          // Columns
+          c: [
+            {n: [147],
+             f: []}
+          ]
+        },
+      ],
+      rowLen: 5513,   // In sample lengths
+      patternLen: 32,  // Rows per pattern
+      endPattern: 26,  // End pattern
+      numChannels: 8  // Number of channels
+    };
-- 
GitLab