├── .gitignore
├── .babelrc
├── watch.sh
├── audio
├── concert-crowd.mp3
└── concert-crowd.ogg
├── README.md
├── src
├── audio-distortion-node.js
├── get-set-controls.js
├── tracker-table.js
├── tracker-table-svg.js
├── simple-tracker.js
├── app.js
└── default-track.js
├── package.json
├── main.css
└── index.html
/.gitignore:
--------------------------------------------------------------------------------
1 | nbproject
2 | dist
3 | node_modules
4 |
--------------------------------------------------------------------------------
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 |
3 | "presets": ["es2015"]
4 |
5 | }
6 |
--------------------------------------------------------------------------------
/watch.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | watchify src/app.js -t --debug -o 'bundle.js'
3 |
--------------------------------------------------------------------------------
/audio/concert-crowd.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diversen/drum-machine-javascript/HEAD/audio/concert-crowd.mp3
--------------------------------------------------------------------------------
/audio/concert-crowd.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diversen/drum-machine-javascript/HEAD/audio/concert-crowd.ogg
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # drum-machine-javascript
2 |
3 | A simple drum-machine written in javascript
4 |
5 | It uses these great drum-samples:
6 |
7 | https://github.com/oramics/sampled/
8 |
9 | You can try it out here: https://diversen.github.io/drum-machine-javascript/
10 |
11 | ## Install
12 |
13 | git clone https://github.com/diversen/drum-machine-javascript
14 |
15 | Just clone this repo, and start a server inside it - og place it on a server.
16 |
17 | ## Dev install
18 |
19 | Install deps:
20 |
21 | npm install
22 |
23 | ## Watch and build:
24 |
25 | You will need watchify `sudo npm install -g watchify`
26 |
27 | watchify src/main.js -t --debug -o 'bundle.js'
28 |
29 | Or (short form of above)
30 |
31 | npm run watch
32 |
33 | ## Licence
34 |
35 | MIT © [Dennis Iversen](https://github.com/diversen)
36 |
37 |
--------------------------------------------------------------------------------
/src/audio-distortion-node.js:
--------------------------------------------------------------------------------
1 | function audioDistortionNode(ctx) {
2 |
3 | this.ctx = ctx;
4 | this.distortion;
5 | this.amount = 400;
6 |
7 | this.getDistortionNode = function (amount) {
8 |
9 | if (amount) {
10 | this.amount = amount;
11 | }
12 |
13 | this.distortion = this.ctx.createWaveShaper();
14 | this.distortion.oversample = '4x';
15 | this.distortion.curve = this.makeDistortionCurve(this.amount);
16 | return this.distortion;
17 | }
18 |
19 | this.makeDistortionCurve = function (amount) {
20 | var k = typeof amount === 'number' ? amount : 50,
21 | n_samples = 44100,
22 | curve = new Float32Array(n_samples),
23 | deg = Math.PI / 180,
24 | i = 0,
25 | x;
26 | for (; i < n_samples; ++i) {
27 | x = i * 2 / n_samples - 1;
28 | curve[i] = (3 + k) * x * 20 * deg / (Math.PI + k * Math.abs(x));
29 | }
30 | return curve;
31 |
32 | };
33 | }
34 |
35 | module.exports = audioDistortionNode;
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "drum-machine",
3 | "version": "3.0.2",
4 | "description": "A simple drum machine / sequencer written in javascript",
5 | "main": "src/main.js",
6 | "scripts": {
7 | "test": "test.js",
8 | "watch": "watchify src/main.js -t --debug -o 'bundle.js'"
9 | },
10 | "repository": {
11 | "type": "git",
12 | "url": "git+https://github.com/diversen/drum-machine-javascript.git"
13 | },
14 | "keywords": [
15 | "drum-machine",
16 | "sequencer"
17 | ],
18 | "author": "dennis iversen",
19 | "license": "MIT",
20 | "bugs": {
21 | "url": "https://github.com/diversen/drum-machine-javascript/issues"
22 | },
23 | "homepage": "https://github.com/diversen/drum-machine-javascript#readme",
24 | "dependencies": {
25 | "adsr-gain-node": "^3.1.0",
26 | "file-saver": "^1.3.8",
27 | "get-html-rows-cells": "^2.0.0",
28 | "get-set-form-values": "^4.0.0",
29 | "has-class": "^1.0.6",
30 | "load-sample-set": "^4.0.2",
31 | "select-element": "^2.1.0",
32 | "set-value": "^2.0.1",
33 | "tiny-sample-loader": "^2.0.0",
34 | "toggle-class": "0.0.0",
35 | "waaclock": "^0.5.3"
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/get-set-controls.js:
--------------------------------------------------------------------------------
1 | const getSetFormValues = require('get-set-form-values');
2 |
3 | function getSetControls() {
4 |
5 | this.getTrackerControls = function() {
6 |
7 | let formValues = new getSetFormValues();
8 | let form = document.getElementById("trackerControls");
9 | let values = formValues.get(form);
10 | let ret = {};
11 | for (let key in values) {
12 |
13 | if (key === 'delayEnabled') {
14 | ret[key] = 'delay';
15 | continue;
16 | }
17 | if (key === 'gainEnabled') {
18 | ret[key] = 'gain';
19 | continue;
20 | }
21 |
22 | if (key === 'sampleSet') {
23 | ret[key] = values[key];
24 | continue;
25 | }
26 | ret[key] = parseFloat(values[key]);
27 | }
28 | return ret;
29 | }
30 |
31 | this.setTrackerControls = function (values) {
32 | if (!values) {
33 | values = this.getTrackerControls();
34 | }
35 | this.options = values;
36 | };
37 |
38 | }
39 |
40 | module.exports = getSetControls;
41 |
--------------------------------------------------------------------------------
/main.css:
--------------------------------------------------------------------------------
1 | @import url(https://fonts.googleapis.com/css?family=Merriweather:400,700);
2 |
3 | .merriweather {
4 | font-family: 'Merriweather';
5 | }
6 |
7 | /*
8 | #controls {
9 | font-family: 'Merriweather';
10 | font-size: 10px;
11 | }*/
12 | a {
13 | color: hotpink;
14 | }
15 |
16 | #tracker-container {
17 | background-color: ghostwhite;
18 | width: 100%;
19 | padding: 20px;
20 | background-color: #F4A360;
21 | display: flex;
22 | flex-wrap:wrap;
23 | }
24 |
25 | #tracker-controls {
26 | margin-left: 20px;
27 | padding:20px;
28 | background-color: tomato;
29 | }
30 |
31 |
32 | #tracker-parent {
33 | padding:20px;
34 | flex-basis: auto;
35 | background-color: gainsboro;
36 | /*overflow-x: visible;*/
37 | }
38 |
39 |
40 | .tracker-cell, .tracker-first-cell, .tracker-cell-header {
41 | height: 20px;
42 | min-width: 20px;
43 | border: black;
44 | border-color: black;
45 | background: #fff;
46 | border-style: solid;
47 | border-width: 1px;
48 | font-size: 75%;
49 | padding:2px;
50 | /*background-color: pink;*/
51 | }
52 |
53 | .tracker-enabled {
54 | background: orange;
55 | }
56 |
57 | .tracker-current {
58 | background: blueviolet;
59 | }
60 |
61 | #app-message {
62 | position: fixed;
63 | top: 10px;
64 | left: 10px;
65 | background-color: peru;
66 | margin: 10px;
67 | padding: 10px;
68 | display: none;
69 | }
70 |
--------------------------------------------------------------------------------
/src/tracker-table.js:
--------------------------------------------------------------------------------
1 | function trackerTable() {
2 |
3 | this.str = '';
4 | this.getTable = function () {
5 | return '
';
6 | };
7 |
8 | this.setHeader = function (numRows, data) {
9 | this.str += ``;
12 |
13 | };
14 |
15 | this.setRows = function (numRows, numCols, data) {
16 |
17 | this.setHeader(numCols, data);
18 | for (let rowID = 0; rowID < numRows; rowID++) {
19 | this.str += ``;
20 | this.str += this.getCells(rowID, numCols, data);
21 | this.str += `
`;
22 | }
23 | };
24 |
25 | this.getFirstCell = function (rowID, data) {
26 | var str = '';
27 |
28 | str += ``;
29 | if (data.title) {
30 | str += data.title[rowID];
31 | }
32 |
33 | str += ` | `;
34 | return str;
35 | };
36 |
37 | this.getCells = function (rowID, numRows, data) {
38 | var str = '';
39 |
40 | str += this.getFirstCell(rowID, data);
41 |
42 | let cssClass = 'tracker-cell'
43 |
44 | if (rowID == 'header') {
45 | cssClass = 'tracker-cell-header'
46 | }
47 |
48 | for (let c = 0; c < numRows; c++) {
49 | str += ``;
50 | if (data.header) {
51 | str += c + 1;
52 | }
53 | str += ` | `;
54 | }
55 | return str;
56 | };
57 | }
58 |
59 | module.exports = trackerTable;
60 |
--------------------------------------------------------------------------------
/src/tracker-table-svg.js:
--------------------------------------------------------------------------------
1 | function trackerTableSvg() {
2 |
3 | this.str = '';
4 | this.options = {
5 | cellFirst: 120,
6 | cellWidth: 16,
7 | cellSpace: 4
8 | }
9 |
10 | this.options.cellWithSpace = this.options.cellSpace + this.options.cellWidth
11 | this.options.cellFirstWithSpace = this.options.cellFirst + this.options.cellSpace
12 |
13 | /**
14 | * @param int number of cells
15 | * @param int number of rows
16 | * @param object data
17 | */
18 | this.setRows = function (numRows, numRows, data) {
19 |
20 | this.numRows = numRows;
21 | this.numRows = numRows;
22 |
23 | this.setHeader(numRows, data);
24 | for (let rowID = 0; rowID < numRows; rowID++) {
25 | this.str += this.getCells(rowID, numRows, data);
26 | }
27 | };
28 |
29 | this.setHeader = function (numRows, data) {
30 | this.str += this.getCells('header', numRows, { header: true });
31 | };
32 |
33 | this.getTable = function () {
34 |
35 |
36 | let boxX = (this.options.cellFirst + this.options.cellSpace) +
37 | (this.numRows * this.options.cellWithSpace)
38 | let boxY = (this.numRows + 1) * (this.options.cellWithSpace)
39 |
40 | let html = `
41 | `
51 | return html
52 | };
53 |
54 | this.getFirstCell = function (rowID, data) {
55 |
56 | let str = '';
57 | str += `
58 | `;
65 |
66 | if (data.title) {
67 | let text = data.title[rowID];
68 | str += `
69 | ${text}
73 | `;
74 | }
75 |
76 | this.currentX = this.options.cellFirstWithSpace
77 | return str;
78 | };
79 |
80 | this.currentX = 0
81 | this.getCurrentX = function (x) {
82 | return x + this.currentX
83 | }
84 |
85 | this.y = 0;
86 | this.getCells = function (rowID, numRows, data) {
87 | var str = '';
88 | var x = 0;
89 |
90 | // Get first cell. E.g. instrument
91 | str += this.getFirstCell(rowID, data);
92 | for (let c = 0; c < numRows; c++) {
93 |
94 | str += `
95 |
103 | `;
104 |
105 | if (data.header) {
106 | // column header. A number
107 | let text = c + 1;
108 | str += `
109 | ${text}
116 | `;
117 | }
118 |
119 | x += this.options.cellWithSpace
120 | }
121 |
122 | this.y += this.options.cellWithSpace
123 | return str;
124 | };
125 | }
126 |
127 | module.exports = trackerTableSvg;
128 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | javascript drum machine
6 |
8 |
9 |
11 |
12 |
13 |
14 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
71 |
72 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
--------------------------------------------------------------------------------
/src/simple-tracker.js:
--------------------------------------------------------------------------------
1 | const WAAClock = require('waaclock');
2 | const trackerTable = require('./tracker-table');
3 | const hasClass = require('has-class');
4 |
5 | /**
6 | * Construct object
7 | * @param {audioContext} ctx
8 | * @param {function} scheduleAudioBeat funtion when an audio is played
9 | */
10 | function tracker(ctx, scheduleAudioBeat) {
11 |
12 | this.measureLength = 16;
13 | this.scheduleAudioBeat = scheduleAudioBeat;
14 | this.scheduleForward = 0.1;
15 | this.current = 0;
16 | this.eventMap = {};
17 | this.clock = new WAAClock(ctx);
18 | this.clock.start();
19 | this.running = false;
20 |
21 | /**
22 | * Draw a tracker table by numRows and numCols
23 | */
24 | this.drawTracker = function(numRows, numCols, data) {
25 |
26 | let htmlTable = new trackerTable();
27 |
28 | htmlTable.setRows(numRows, numCols, data);
29 | let str = htmlTable.getTable();
30 |
31 | let t = document.getElementById('tracker-parent');
32 | t.innerHTML = '';
33 | t.insertAdjacentHTML('afterbegin', str);
34 | }
35 |
36 | /**
37 | * Push current beat one forward
38 | */
39 | this.next = function () {
40 | this.current++;
41 | if (this.current >= this.measureLength) {
42 | this.current = 0;
43 | }
44 | };
45 |
46 | /**
47 | * Calculate milli seconds per beat
48 | */
49 | this.milliPerBeat = function (beats) {
50 | if (!beats) {
51 | beats = 60;
52 | }
53 | return 1000 * 60 / beats;
54 | };
55 |
56 | /**
57 | * Get a tracker row from a cell-id
58 | */
59 | this.getTrackerRowValues = function (colId) {
60 | let values = [];
61 | let selector = `[data-col-id="${colId}"]`;
62 |
63 | let elems = document.querySelectorAll(selector);
64 | elems.forEach((el) => {
65 | let val = Object.assign({}, el.dataset);
66 | val.enabled = el.classList.contains('tracker-enabled');
67 | values.push(val);
68 | });
69 | return values;
70 | };
71 |
72 | /**
73 | * Schedule a beat column
74 | */
75 | this.schedule = function () {
76 | let beatColumn = this.getTrackerRowValues(this.current);
77 | let now = ctx.currentTime;
78 |
79 | let selector = `[data-col-id="${this.current}"]`;
80 |
81 | let event = this.clock.callbackAtTime(() => {
82 | let elems = document.querySelectorAll(selector);
83 | elems.forEach( (e) => {
84 | e.classList.add('tracker-current')
85 | })
86 | }, now + this.scheduleForward);
87 |
88 | this.clock.callbackAtTime(() => {
89 | let elems = document.querySelectorAll(selector);
90 | elems.forEach( (e) => {
91 | e.classList.remove('tracker-current')
92 | })
93 | }, now + this.scheduleForward + this.milliPerBeat(this.bpm) / 1000);
94 |
95 | beatColumn.forEach((beat) => {
96 | this.scheduleBeat(beat, now);
97 | });
98 | };
99 |
100 | this.scheduleBeat = function (beat, now) {
101 |
102 | let triggerTime = now + this.scheduleForward;
103 | this.scheduleMap[beat.colId] = triggerTime;
104 | if (beat.enabled) {
105 | this.eventMap[this.getEventKey(beat)] = this.clock.callbackAtTime(() => {
106 | this.scheduleAudioBeat(beat, triggerTime);
107 | }, now);
108 | }
109 | };
110 |
111 | this.scheduleMap = {};
112 |
113 | this.scheduleAudioBeatNow = function (beat) {
114 |
115 | if (beat.enabled) {
116 | let beatEvent = this.eventMap[this.getEventKey(beat)];
117 | if (beatEvent) {
118 | beatEvent.clear();
119 | delete this.eventMap[this.getEventKey(beat)];
120 | }
121 | return;
122 | }
123 |
124 | let triggerTime = this.scheduleMap[0] + beat.colId * this.milliPerBeat(this.bpm) / 1000;
125 | let now = ctx.currentTime;
126 | this.eventMap[this.getEventKey(beat)] = this.clock.callbackAtTime(() => {
127 | this.scheduleAudioBeat(beat, triggerTime);
128 | }, now);
129 | };
130 |
131 | this.interval;
132 | this.runSchedule = function (bpm) {
133 | this.running = true;
134 | this.bpm = bpm;
135 | let interval = this.milliPerBeat(bpm);
136 |
137 | setTimeout(() => {
138 | this.schedule();
139 | this.next();
140 | }, 0);
141 |
142 | this.interval = setInterval(() => {
143 | this.schedule();
144 | this.next();
145 |
146 | }, interval);
147 | };
148 |
149 | this.stop = function () {
150 | this.running = false;
151 | clearInterval(this.interval);
152 | };
153 |
154 | this.getEventKey = function getEventKey(beat) {
155 | return beat.rowId + beat.colId;
156 | };
157 |
158 | /**
159 | * Get tracker values
160 | */
161 | this.getTrackerValues = function () {
162 | let values = [];
163 | let elems = document.querySelectorAll('.tracker-cell');
164 | elems.forEach(function (e) {
165 | let val = Object.assign({}, e.dataset);
166 | val.enabled = hasClass(e, "tracker-enabled");
167 | values.push(val);
168 | });
169 | return values;
170 | };
171 |
172 | /**
173 | * Load tracker values in JSON format
174 | */
175 | this.loadTrackerValues = function (json) {
176 |
177 | let elems = document.querySelectorAll('.tracker-enabled');
178 | elems.forEach(function(e) {
179 | e.classList.remove('tracker-enabled');
180 | });
181 |
182 | json.forEach(function (data) {
183 | if (data.enabled === true) {
184 | let selector = `.tracker-cell[data-row-id="${data.rowId}"][data-col-id="${data.colId}"]`;
185 | let elem = document.querySelector(selector);
186 | if (elem) {
187 | elem.classList.add("tracker-enabled");
188 | }
189 | }
190 | });
191 | };
192 |
193 | /**
194 | * Listen on tracker-cell
195 | * Schedule if cell is clicked and toggle css class
196 | */
197 | this.setupEvents = function () {
198 |
199 | let elems = document.querySelectorAll('.tracker-cell');
200 |
201 | elems.forEach(function (e) {
202 | e.addEventListener('click', function(e) {
203 | let val = Object.assign({}, e.target.dataset);
204 | val.enabled = hasClass(e.target, "tracker-enabled");
205 | let currentBeat = e.target.dataset.colId;
206 | if (val.colId > currentBeat) {
207 | this.scheduleAudioBeatNow(val);
208 | }
209 | e.target.classList.toggle('tracker-enabled');
210 | })
211 | })
212 | }
213 | }
214 |
215 | module.exports = tracker;
--------------------------------------------------------------------------------
/src/app.js:
--------------------------------------------------------------------------------
1 | const loadSampleSet = require('load-sample-set');
2 | const selectElement = require('select-element');
3 | const getSetFormValues = require('get-set-form-values');
4 | const adsrGainNode = require('adsr-gain-node');
5 | const simpleTracker = require('./simple-tracker');
6 | const FileSaver = require('file-saver');
7 |
8 | const getSetControls = require('./get-set-controls');
9 | const getSetAudioOptions = new getSetControls();
10 |
11 | const ctx = new AudioContext();
12 | const defaultTrack = require('./default-track');
13 |
14 | var buffers;
15 | var currentSampleData;
16 | var storage;
17 |
18 | function initializeSampleSet(ctx, dataUrl, track) {
19 |
20 | var sampleSetPromise = loadSampleSet(ctx, dataUrl);
21 | sampleSetPromise.then(function (data) {
22 |
23 | buffers = data.buffers;
24 | sampleData = data.data;
25 |
26 | if (!track) {
27 | track = storage.getTrack();
28 | }
29 |
30 | if (!track.settings.measureLength) {
31 | track.settings.measureLength = 16;
32 | }
33 |
34 | currentSampleData = sampleData;
35 | setupTrackerHtml(sampleData, track.settings.measureLength);
36 | schedule.loadTrackerValues(track.beat);
37 | schedule.setupEvents();
38 | });
39 |
40 | }
41 |
42 | window.onload = function () {
43 |
44 | let formValues = new getSetFormValues();
45 | let form = document.getElementById("trackerControls");
46 |
47 | formValues.set(form, defaultTrack.settings);
48 | getSetAudioOptions.setTrackerControls(defaultTrack.settings);
49 |
50 | initializeSampleSet(ctx, defaultTrack.settings.sampleSet, defaultTrack);
51 | setupBaseEvents();
52 |
53 | storage = new tracksLocalStorage();
54 | storage.setupStorage();
55 | };
56 |
57 | var instrumentData = {};
58 | function setupTrackerHtml(data, measureLength) {
59 | instrumentData = data;
60 | instrumentData.title = instrumentData.filename;
61 | schedule.drawTracker(data.filename.length, measureLength, instrumentData);
62 | return;
63 | }
64 |
65 | function disconnectNode(node, options) {
66 | let totalLength =
67 | options.attackTime + options.sustainTime + options.releaseTime;
68 | setTimeout(() => {
69 | node.disconnect();
70 | }, totalLength * 1000);
71 | }
72 |
73 | function scheduleAudioBeat(beat, triggerTime) {
74 |
75 | let instrumentName = instrumentData.filename[beat.rowId];
76 | let instrument = buffers[instrumentName].get();
77 | let options = getSetAudioOptions.getTrackerControls();
78 |
79 |
80 | function play(source) {
81 |
82 | source.detune.value = options.detune;
83 |
84 | // Gain
85 | let node = routeGain(source)
86 | node = routeDelay(node);
87 | // node = routeCompressor(node);
88 | node.connect(ctx.destination);
89 | source.start(triggerTime);
90 |
91 | }
92 |
93 |
94 | function routeGain (source) {
95 | let gain = new adsrGainNode(ctx);
96 | gain.mode = 'linearRampToValueAtTime';
97 | let options = getSetAudioOptions.getTrackerControls();
98 |
99 | let gainNode;
100 |
101 | // Not enabled - default gain
102 | if (!options.gainEnabled) {
103 | gainNode = gain.getGainNode(triggerTime);
104 | source.connect(gainNode);
105 | return gainNode;
106 | }
107 |
108 | gain.setOptions(options);
109 | gainNode = gain.getGainNode(triggerTime);
110 | source.connect(gainNode);
111 | return gainNode;
112 |
113 |
114 | }
115 |
116 | // Note delay always uses above gain - even if not enabled
117 | function routeDelay(node) {
118 | if (!options.delayEnabled) {
119 | return node;
120 | }
121 |
122 | // create delay node
123 | let delay = ctx.createDelay();
124 | delay.delayTime.value = options.delay;
125 |
126 | // create adsr gain node
127 | let gain = new adsrGainNode(ctx);
128 | gain.mode = 'linearRampToValueAtTime';
129 | gain.setOptions(options);
130 | let feedbackGain = gain.getGainNode(triggerTime);
131 |
132 | // create filter
133 | let filter = ctx.createBiquadFilter();
134 | filter.frequency.value = options.filter;
135 |
136 | // delay -> feedbackGain
137 | delay.connect(feedbackGain);
138 | disconnectNode(delay, options);
139 |
140 | // feedback -> filter
141 | feedbackGain.connect(filter);
142 |
143 | // filter ->delay
144 | filter.connect(delay);
145 |
146 | node.connect(delay);
147 |
148 | return delay;
149 | }
150 | play(instrument);
151 | }
152 |
153 | var schedule = new simpleTracker(ctx, scheduleAudioBeat);
154 |
155 | function setupBaseEvents() {
156 |
157 | // var initializedCtx;
158 | document.getElementById('play').addEventListener('click', function (e) {
159 |
160 | ctx.resume().then(() => {
161 | console.log('Playback resumed successfully');
162 | });
163 |
164 | let storage = new tracksLocalStorage();
165 | let track = storage.getTrack();
166 |
167 | schedule.measureLength = track.settings.measureLength;
168 | schedule.stop();
169 |
170 | schedule.runSchedule(getSetAudioOptions.options.bpm);
171 | });
172 |
173 | document.getElementById('pause').addEventListener('click', function (e) {
174 | schedule.stop();
175 | });
176 |
177 | document.getElementById('stop').addEventListener('click', function (e) {
178 | schedule.stop();
179 | schedule = new simpleTracker(ctx, scheduleAudioBeat);
180 | });
181 |
182 | document.getElementById('bpm').addEventListener('change', function (e) {
183 | getSetAudioOptions.setTrackerControls();
184 | if (schedule.running) {
185 | schedule.stop();
186 | schedule.runSchedule(getSetAudioOptions.options.bpm);
187 | }
188 | });
189 |
190 | document.getElementById('measureLength').addEventListener('input', (e) => {
191 |
192 | $('#measureLength').bind('keypress keydown keyup', (e) => {
193 | if (e.keyCode == 13) {
194 |
195 | e.preventDefault();
196 |
197 | let value = document.getElementById('measureLength').value;
198 | let length = parseInt(value);
199 |
200 | if (length < 1) return;
201 | schedule.measureLength = length;
202 |
203 | let track = schedule.getTrackerValues();
204 | setupTrackerHtml(currentSampleData, length);
205 | schedule.measureLength = length;
206 | schedule.loadTrackerValues(track)
207 | schedule.setupEvents();
208 | }
209 | });
210 | });
211 |
212 | $('.base').on('change', function () {
213 | getSetAudioOptions.setTrackerControls();
214 | });
215 | }
216 |
217 | $('#sampleSet').on('change', function () {
218 | initializeSampleSet(ctx, this.value);
219 | });
220 |
221 | function tracksLocalStorage() {
222 |
223 | this.setLocalStorage = function (update) {
224 | var storage = {};
225 | storage['Select'] = 'Select';
226 |
227 |
228 | for (var i = 0, len = localStorage.length; i < len; ++i) {
229 | let item = localStorage.key(i);
230 | storage[item] = item;
231 | }
232 |
233 | // Create select element
234 | var s = new selectElement(
235 | 'load-storage', // id to append the select list to
236 | 'beat-list', // id of the select list
237 | storage //
238 | );
239 |
240 | if (update) {
241 | s.update('beat-list', storage);
242 | } else {
243 | s.create();
244 | }
245 | };
246 |
247 | this.getFilename = function () {
248 | let filename = $('#filename').val();
249 | if (!filename) {
250 | filename = 'untitled';
251 | }
252 | return filename;
253 | }
254 |
255 | /**
256 | * Get complete song
257 | */
258 | this.getTrack = function () {
259 | let formData = getSetAudioOptions.getTrackerControls();
260 |
261 | let beat = schedule.getTrackerValues();
262 | let song = { "beat": beat, "settings": formData };
263 |
264 | return song;
265 | }
266 |
267 | this.alert = function (message) {
268 | let appMessage = document.getElementById('app-message');
269 |
270 | appMessage.innerHTML = message
271 | appMessage.style.display = 'block'
272 | setTimeout(function () {
273 | appMessage.style.display = 'none'
274 | }, 2000)
275 | }
276 |
277 | this.setupStorage = function () {
278 |
279 | this.setLocalStorage();
280 | document.getElementById('save').addEventListener('click', (e) => {
281 | e.preventDefault();
282 |
283 | let song = this.getTrack();
284 | let json = JSON.stringify(song);
285 |
286 | let filename = this.getFilename();
287 |
288 | localStorage.setItem(filename, json);
289 | this.setLocalStorage('update');
290 |
291 | $("#beat-list").val(filename);
292 |
293 | this.alert(`The track has been saved to local storage as ${filename}`)
294 |
295 | });
296 |
297 | // saveAsJson
298 | document.getElementById('saveAsJson').addEventListener('click', (e) => {
299 | e.preventDefault();
300 |
301 | let song = this.getTrack();
302 | let json = JSON.stringify(song);
303 |
304 | let filename = this.getFilename();
305 |
306 | var blob = new Blob([json], {type: "application/json"});
307 | FileSaver.saveAs(blob, filename + ".json");
308 |
309 |
310 | });
311 |
312 | $('#filename').bind('keypress keydown keyup', (e) => {
313 | if (e.keyCode == 13) {
314 | e.preventDefault();
315 | }
316 | });
317 |
318 | document.getElementById('beat-list').addEventListener('change', (e) => {
319 | let item = $('#beat-list').val();
320 | if (item === 'Select') {
321 | document.getElementById('filename').value = '';
322 | return;
323 | }
324 |
325 | document.getElementById('filename').value = item;
326 | let track = JSON.parse(localStorage.getItem(item));
327 |
328 | let formValues = new getSetFormValues();
329 | let form = document.getElementById("trackerControls");
330 |
331 | formValues.set(form, track.settings);
332 | getSetAudioOptions.setTrackerControls(track.settings);
333 | schedule.stop();
334 | schedule.measureLength = track.settings.measureLength;
335 |
336 | initializeSampleSet(ctx, track.settings.sampleSet, track);
337 |
338 | });
339 |
340 | document.getElementById('delete').addEventListener('click', (e) => {
341 |
342 | e.preventDefault();
343 |
344 | let elem = document.getElementById('beat-list');
345 | let toDelete = elem.options[elem.selectedIndex].text;
346 |
347 | localStorage.removeItem(toDelete);
348 | document.getElementById('filename').value = '';
349 | this.setLocalStorage('update');
350 |
351 | this.alert(`Track has been deleted`)
352 |
353 | });
354 | };
355 | }
356 |
--------------------------------------------------------------------------------
/src/default-track.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | beat: [
3 | { rowId: "0", colId: "0", enabled: false },
4 | { rowId: "0", colId: "1", enabled: false },
5 | { rowId: "0", colId: "2", enabled: false },
6 | { rowId: "0", colId: "3", enabled: false },
7 | { rowId: "0", colId: "4", enabled: false },
8 | { rowId: "0", colId: "5", enabled: false },
9 | { rowId: "0", colId: "6", enabled: false },
10 | { rowId: "0", colId: "7", enabled: false },
11 | { rowId: "0", colId: "8", enabled: false },
12 | { rowId: "0", colId: "9", enabled: false },
13 | { rowId: "0", colId: "10", enabled: false },
14 | { rowId: "0", colId: "11", enabled: false },
15 | { rowId: "0", colId: "12", enabled: false },
16 | { rowId: "0", colId: "13", enabled: false },
17 | { rowId: "0", colId: "14", enabled: false },
18 | { rowId: "0", colId: "15", enabled: false },
19 | { rowId: "0", colId: "16", enabled: false },
20 | { rowId: "0", colId: "17", enabled: false },
21 | { rowId: "0", colId: "18", enabled: false },
22 | { rowId: "0", colId: "19", enabled: false },
23 | { rowId: "0", colId: "20", enabled: false },
24 | { rowId: "0", colId: "21", enabled: false },
25 | { rowId: "0", colId: "22", enabled: false },
26 | { rowId: "0", colId: "23", enabled: false },
27 | { rowId: "0", colId: "24", enabled: false },
28 | { rowId: "0", colId: "25", enabled: false },
29 | { rowId: "0", colId: "26", enabled: false },
30 | { rowId: "0", colId: "27", enabled: false },
31 | { rowId: "0", colId: "28", enabled: false },
32 | { rowId: "0", colId: "29", enabled: false },
33 | { rowId: "0", colId: "30", enabled: false },
34 | { rowId: "0", colId: "31", enabled: false },
35 | { rowId: "1", colId: "0", enabled: false },
36 | { rowId: "1", colId: "1", enabled: false },
37 | { rowId: "1", colId: "2", enabled: false },
38 | { rowId: "1", colId: "3", enabled: false },
39 | { rowId: "1", colId: "4", enabled: false },
40 | { rowId: "1", colId: "5", enabled: false },
41 | { rowId: "1", colId: "6", enabled: false },
42 | { rowId: "1", colId: "7", enabled: false },
43 | { rowId: "1", colId: "8", enabled: false },
44 | { rowId: "1", colId: "9", enabled: false },
45 | { rowId: "1", colId: "10", enabled: false },
46 | { rowId: "1", colId: "11", enabled: false },
47 | { rowId: "1", colId: "12", enabled: false },
48 | { rowId: "1", colId: "13", enabled: false },
49 | { rowId: "1", colId: "14", enabled: false },
50 | { rowId: "1", colId: "15", enabled: false },
51 | { rowId: "1", colId: "16", enabled: false },
52 | { rowId: "1", colId: "17", enabled: false },
53 | { rowId: "1", colId: "18", enabled: false },
54 | { rowId: "1", colId: "19", enabled: false },
55 | { rowId: "1", colId: "20", enabled: false },
56 | { rowId: "1", colId: "21", enabled: false },
57 | { rowId: "1", colId: "22", enabled: false },
58 | { rowId: "1", colId: "23", enabled: false },
59 | { rowId: "1", colId: "24", enabled: false },
60 | { rowId: "1", colId: "25", enabled: false },
61 | { rowId: "1", colId: "26", enabled: false },
62 | { rowId: "1", colId: "27", enabled: false },
63 | { rowId: "1", colId: "28", enabled: false },
64 | { rowId: "1", colId: "29", enabled: false },
65 | { rowId: "1", colId: "30", enabled: false },
66 | { rowId: "1", colId: "31", enabled: false },
67 | { rowId: "2", colId: "0", enabled: false },
68 | { rowId: "2", colId: "1", enabled: false },
69 | { rowId: "2", colId: "2", enabled: false },
70 | { rowId: "2", colId: "3", enabled: false },
71 | { rowId: "2", colId: "4", enabled: true },
72 | { rowId: "2", colId: "5", enabled: false },
73 | { rowId: "2", colId: "6", enabled: false },
74 | { rowId: "2", colId: "7", enabled: false },
75 | { rowId: "2", colId: "8", enabled: false },
76 | { rowId: "2", colId: "9", enabled: false },
77 | { rowId: "2", colId: "10", enabled: false },
78 | { rowId: "2", colId: "11", enabled: false },
79 | { rowId: "2", colId: "12", enabled: false },
80 | { rowId: "2", colId: "13", enabled: false },
81 | { rowId: "2", colId: "14", enabled: false },
82 | { rowId: "2", colId: "15", enabled: false },
83 | { rowId: "2", colId: "16", enabled: false },
84 | { rowId: "2", colId: "17", enabled: false },
85 | { rowId: "2", colId: "18", enabled: false },
86 | { rowId: "2", colId: "19", enabled: false },
87 | { rowId: "2", colId: "20", enabled: false },
88 | { rowId: "2", colId: "21", enabled: false },
89 | { rowId: "2", colId: "22", enabled: false },
90 | { rowId: "2", colId: "23", enabled: true },
91 | { rowId: "2", colId: "24", enabled: false },
92 | { rowId: "2", colId: "25", enabled: false },
93 | { rowId: "2", colId: "26", enabled: false },
94 | { rowId: "2", colId: "27", enabled: false },
95 | { rowId: "2", colId: "28", enabled: false },
96 | { rowId: "2", colId: "29", enabled: false },
97 | { rowId: "2", colId: "30", enabled: false },
98 | { rowId: "2", colId: "31", enabled: false },
99 | { rowId: "3", colId: "0", enabled: false },
100 | { rowId: "3", colId: "1", enabled: true },
101 | { rowId: "3", colId: "2", enabled: false },
102 | { rowId: "3", colId: "3", enabled: false },
103 | { rowId: "3", colId: "4", enabled: false },
104 | { rowId: "3", colId: "5", enabled: false },
105 | { rowId: "3", colId: "6", enabled: true },
106 | { rowId: "3", colId: "7", enabled: false },
107 | { rowId: "3", colId: "8", enabled: false },
108 | { rowId: "3", colId: "9", enabled: false },
109 | { rowId: "3", colId: "10", enabled: false },
110 | { rowId: "3", colId: "11", enabled: false },
111 | { rowId: "3", colId: "12", enabled: false },
112 | { rowId: "3", colId: "13", enabled: false },
113 | { rowId: "3", colId: "14", enabled: false },
114 | { rowId: "3", colId: "15", enabled: false },
115 | { rowId: "3", colId: "16", enabled: false },
116 | { rowId: "3", colId: "17", enabled: true },
117 | { rowId: "3", colId: "18", enabled: false },
118 | { rowId: "3", colId: "19", enabled: false },
119 | { rowId: "3", colId: "20", enabled: false },
120 | { rowId: "3", colId: "21", enabled: false },
121 | { rowId: "3", colId: "22", enabled: false },
122 | { rowId: "3", colId: "23", enabled: false },
123 | { rowId: "3", colId: "24", enabled: false },
124 | { rowId: "3", colId: "25", enabled: false },
125 | { rowId: "3", colId: "26", enabled: false },
126 | { rowId: "3", colId: "27", enabled: false },
127 | { rowId: "3", colId: "28", enabled: false },
128 | { rowId: "3", colId: "29", enabled: false },
129 | { rowId: "3", colId: "30", enabled: false },
130 | { rowId: "3", colId: "31", enabled: false },
131 | { rowId: "4", colId: "0", enabled: true },
132 | { rowId: "4", colId: "1", enabled: false },
133 | { rowId: "4", colId: "2", enabled: true },
134 | { rowId: "4", colId: "3", enabled: false },
135 | { rowId: "4", colId: "4", enabled: false },
136 | { rowId: "4", colId: "5", enabled: false },
137 | { rowId: "4", colId: "6", enabled: false },
138 | { rowId: "4", colId: "7", enabled: false },
139 | { rowId: "4", colId: "8", enabled: false },
140 | { rowId: "4", colId: "9", enabled: false },
141 | { rowId: "4", colId: "10", enabled: false },
142 | { rowId: "4", colId: "11", enabled: false },
143 | { rowId: "4", colId: "12", enabled: true },
144 | { rowId: "4", colId: "13", enabled: false },
145 | { rowId: "4", colId: "14", enabled: true },
146 | { rowId: "4", colId: "15", enabled: false },
147 | { rowId: "4", colId: "16", enabled: false },
148 | { rowId: "4", colId: "17", enabled: false },
149 | { rowId: "4", colId: "18", enabled: false },
150 | { rowId: "4", colId: "19", enabled: false },
151 | { rowId: "4", colId: "20", enabled: false },
152 | { rowId: "4", colId: "21", enabled: true },
153 | { rowId: "4", colId: "22", enabled: false },
154 | { rowId: "4", colId: "23", enabled: false },
155 | { rowId: "4", colId: "24", enabled: false },
156 | { rowId: "4", colId: "25", enabled: true },
157 | { rowId: "4", colId: "26", enabled: false },
158 | { rowId: "4", colId: "27", enabled: false },
159 | { rowId: "4", colId: "28", enabled: false },
160 | { rowId: "4", colId: "29", enabled: false },
161 | { rowId: "4", colId: "30", enabled: false },
162 | { rowId: "4", colId: "31", enabled: false },
163 | { rowId: "5", colId: "0", enabled: false },
164 | { rowId: "5", colId: "1", enabled: false },
165 | { rowId: "5", colId: "2", enabled: false },
166 | { rowId: "5", colId: "3", enabled: false },
167 | { rowId: "5", colId: "4", enabled: true },
168 | { rowId: "5", colId: "5", enabled: false },
169 | { rowId: "5", colId: "6", enabled: false },
170 | { rowId: "5", colId: "7", enabled: true },
171 | { rowId: "5", colId: "8", enabled: false },
172 | { rowId: "5", colId: "9", enabled: false },
173 | { rowId: "5", colId: "10", enabled: false },
174 | { rowId: "5", colId: "11", enabled: true },
175 | { rowId: "5", colId: "12", enabled: false },
176 | { rowId: "5", colId: "13", enabled: false },
177 | { rowId: "5", colId: "14", enabled: false },
178 | { rowId: "5", colId: "15", enabled: true },
179 | { rowId: "5", colId: "16", enabled: false },
180 | { rowId: "5", colId: "17", enabled: false },
181 | { rowId: "5", colId: "18", enabled: false },
182 | { rowId: "5", colId: "19", enabled: true },
183 | { rowId: "5", colId: "20", enabled: false },
184 | { rowId: "5", colId: "21", enabled: false },
185 | { rowId: "5", colId: "22", enabled: false },
186 | { rowId: "5", colId: "23", enabled: false },
187 | { rowId: "5", colId: "24", enabled: false },
188 | { rowId: "5", colId: "25", enabled: false },
189 | { rowId: "5", colId: "26", enabled: false },
190 | { rowId: "5", colId: "27", enabled: false },
191 | { rowId: "5", colId: "28", enabled: false },
192 | { rowId: "5", colId: "29", enabled: false },
193 | { rowId: "5", colId: "30", enabled: false },
194 | { rowId: "5", colId: "31", enabled: false },
195 | { rowId: "6", colId: "0", enabled: false },
196 | { rowId: "6", colId: "1", enabled: false },
197 | { rowId: "6", colId: "2", enabled: false },
198 | { rowId: "6", colId: "3", enabled: false },
199 | { rowId: "6", colId: "4", enabled: false },
200 | { rowId: "6", colId: "5", enabled: false },
201 | { rowId: "6", colId: "6", enabled: false },
202 | { rowId: "6", colId: "7", enabled: false },
203 | { rowId: "6", colId: "8", enabled: false },
204 | { rowId: "6", colId: "9", enabled: false },
205 | { rowId: "6", colId: "10", enabled: false },
206 | { rowId: "6", colId: "11", enabled: false },
207 | { rowId: "6", colId: "12", enabled: false },
208 | { rowId: "6", colId: "13", enabled: false },
209 | { rowId: "6", colId: "14", enabled: false },
210 | { rowId: "6", colId: "15", enabled: false },
211 | { rowId: "6", colId: "16", enabled: false },
212 | { rowId: "6", colId: "17", enabled: false },
213 | { rowId: "6", colId: "18", enabled: false },
214 | { rowId: "6", colId: "19", enabled: false },
215 | { rowId: "6", colId: "20", enabled: false },
216 | { rowId: "6", colId: "21", enabled: false },
217 | { rowId: "6", colId: "22", enabled: false },
218 | { rowId: "6", colId: "23", enabled: false },
219 | { rowId: "6", colId: "24", enabled: false },
220 | { rowId: "6", colId: "25", enabled: false },
221 | { rowId: "6", colId: "26", enabled: false },
222 | { rowId: "6", colId: "27", enabled: true },
223 | { rowId: "6", colId: "28", enabled: false },
224 | { rowId: "6", colId: "29", enabled: false },
225 | { rowId: "6", colId: "30", enabled: false },
226 | { rowId: "6", colId: "31", enabled: true },
227 | { rowId: "7", colId: "0", enabled: false },
228 | { rowId: "7", colId: "1", enabled: false },
229 | { rowId: "7", colId: "2", enabled: false },
230 | { rowId: "7", colId: "3", enabled: false },
231 | { rowId: "7", colId: "4", enabled: false },
232 | { rowId: "7", colId: "5", enabled: false },
233 | { rowId: "7", colId: "6", enabled: false },
234 | { rowId: "7", colId: "7", enabled: false },
235 | { rowId: "7", colId: "8", enabled: false },
236 | { rowId: "7", colId: "9", enabled: true },
237 | { rowId: "7", colId: "10", enabled: false },
238 | { rowId: "7", colId: "11", enabled: false },
239 | { rowId: "7", colId: "12", enabled: false },
240 | { rowId: "7", colId: "13", enabled: false },
241 | { rowId: "7", colId: "14", enabled: false },
242 | { rowId: "7", colId: "15", enabled: false },
243 | { rowId: "7", colId: "16", enabled: false },
244 | { rowId: "7", colId: "17", enabled: false },
245 | { rowId: "7", colId: "18", enabled: false },
246 | { rowId: "7", colId: "19", enabled: false },
247 | { rowId: "7", colId: "20", enabled: false },
248 | { rowId: "7", colId: "21", enabled: false },
249 | { rowId: "7", colId: "22", enabled: false },
250 | { rowId: "7", colId: "23", enabled: false },
251 | { rowId: "7", colId: "24", enabled: false },
252 | { rowId: "7", colId: "25", enabled: false },
253 | { rowId: "7", colId: "26", enabled: false },
254 | { rowId: "7", colId: "27", enabled: false },
255 | { rowId: "7", colId: "28", enabled: false },
256 | { rowId: "7", colId: "29", enabled: false },
257 | { rowId: "7", colId: "30", enabled: false },
258 | { rowId: "7", colId: "31", enabled: false },
259 | { rowId: "8", colId: "0", enabled: false },
260 | { rowId: "8", colId: "1", enabled: false },
261 | { rowId: "8", colId: "2", enabled: false },
262 | { rowId: "8", colId: "3", enabled: false },
263 | { rowId: "8", colId: "4", enabled: false },
264 | { rowId: "8", colId: "5", enabled: false },
265 | { rowId: "8", colId: "6", enabled: false },
266 | { rowId: "8", colId: "7", enabled: false },
267 | { rowId: "8", colId: "8", enabled: false },
268 | { rowId: "8", colId: "9", enabled: false },
269 | { rowId: "8", colId: "10", enabled: false },
270 | { rowId: "8", colId: "11", enabled: false },
271 | { rowId: "8", colId: "12", enabled: false },
272 | { rowId: "8", colId: "13", enabled: false },
273 | { rowId: "8", colId: "14", enabled: false },
274 | { rowId: "8", colId: "15", enabled: false },
275 | { rowId: "8", colId: "16", enabled: false },
276 | { rowId: "8", colId: "17", enabled: false },
277 | { rowId: "8", colId: "18", enabled: false },
278 | { rowId: "8", colId: "19", enabled: false },
279 | { rowId: "8", colId: "20", enabled: false },
280 | { rowId: "8", colId: "21", enabled: false },
281 | { rowId: "8", colId: "22", enabled: false },
282 | { rowId: "8", colId: "23", enabled: false },
283 | { rowId: "8", colId: "24", enabled: false },
284 | { rowId: "8", colId: "25", enabled: false },
285 | { rowId: "8", colId: "26", enabled: false },
286 | { rowId: "8", colId: "27", enabled: false },
287 | { rowId: "8", colId: "28", enabled: false },
288 | { rowId: "8", colId: "29", enabled: true },
289 | { rowId: "8", colId: "30", enabled: false },
290 | { rowId: "8", colId: "31", enabled: false },
291 | { rowId: "9", colId: "0", enabled: false },
292 | { rowId: "9", colId: "1", enabled: false },
293 | { rowId: "9", colId: "2", enabled: false },
294 | { rowId: "9", colId: "3", enabled: false },
295 | { rowId: "9", colId: "4", enabled: false },
296 | { rowId: "9", colId: "5", enabled: false },
297 | { rowId: "9", colId: "6", enabled: false },
298 | { rowId: "9", colId: "7", enabled: false },
299 | { rowId: "9", colId: "8", enabled: false },
300 | { rowId: "9", colId: "9", enabled: false },
301 | { rowId: "9", colId: "10", enabled: false },
302 | { rowId: "9", colId: "11", enabled: false },
303 | { rowId: "9", colId: "12", enabled: false },
304 | { rowId: "9", colId: "13", enabled: false },
305 | { rowId: "9", colId: "14", enabled: false },
306 | { rowId: "9", colId: "15", enabled: false },
307 | { rowId: "9", colId: "16", enabled: false },
308 | { rowId: "9", colId: "17", enabled: false },
309 | { rowId: "9", colId: "18", enabled: false },
310 | { rowId: "9", colId: "19", enabled: false },
311 | { rowId: "9", colId: "20", enabled: false },
312 | { rowId: "9", colId: "21", enabled: false },
313 | { rowId: "9", colId: "22", enabled: false },
314 | { rowId: "9", colId: "23", enabled: false },
315 | { rowId: "9", colId: "24", enabled: false },
316 | { rowId: "9", colId: "25", enabled: false },
317 | { rowId: "9", colId: "26", enabled: false },
318 | { rowId: "9", colId: "27", enabled: false },
319 | { rowId: "9", colId: "28", enabled: false },
320 | { rowId: "9", colId: "29", enabled: false },
321 | { rowId: "9", colId: "30", enabled: false },
322 | { rowId: "9", colId: "31", enabled: false },
323 | { rowId: "10", colId: "0", enabled: false },
324 | { rowId: "10", colId: "1", enabled: false },
325 | { rowId: "10", colId: "2", enabled: false },
326 | { rowId: "10", colId: "3", enabled: false },
327 | { rowId: "10", colId: "4", enabled: false },
328 | { rowId: "10", colId: "5", enabled: false },
329 | { rowId: "10", colId: "6", enabled: false },
330 | { rowId: "10", colId: "7", enabled: false },
331 | { rowId: "10", colId: "8", enabled: false },
332 | { rowId: "10", colId: "9", enabled: false },
333 | { rowId: "10", colId: "10", enabled: false },
334 | { rowId: "10", colId: "11", enabled: false },
335 | { rowId: "10", colId: "12", enabled: false },
336 | { rowId: "10", colId: "13", enabled: false },
337 | { rowId: "10", colId: "14", enabled: false },
338 | { rowId: "10", colId: "15", enabled: false },
339 | { rowId: "10", colId: "16", enabled: false },
340 | { rowId: "10", colId: "17", enabled: false },
341 | { rowId: "10", colId: "18", enabled: false },
342 | { rowId: "10", colId: "19", enabled: false },
343 | { rowId: "10", colId: "20", enabled: false },
344 | { rowId: "10", colId: "21", enabled: false },
345 | { rowId: "10", colId: "22", enabled: false },
346 | { rowId: "10", colId: "23", enabled: false },
347 | { rowId: "10", colId: "24", enabled: false },
348 | { rowId: "10", colId: "25", enabled: false },
349 | { rowId: "10", colId: "26", enabled: false },
350 | { rowId: "10", colId: "27", enabled: false },
351 | { rowId: "10", colId: "28", enabled: false },
352 | { rowId: "10", colId: "29", enabled: false },
353 | { rowId: "10", colId: "30", enabled: false },
354 | { rowId: "10", colId: "31", enabled: false },
355 | { rowId: "11", colId: "0", enabled: false },
356 | { rowId: "11", colId: "1", enabled: false },
357 | { rowId: "11", colId: "2", enabled: false },
358 | { rowId: "11", colId: "3", enabled: false },
359 | { rowId: "11", colId: "4", enabled: false },
360 | { rowId: "11", colId: "5", enabled: false },
361 | { rowId: "11", colId: "6", enabled: false },
362 | { rowId: "11", colId: "7", enabled: false },
363 | { rowId: "11", colId: "8", enabled: false },
364 | { rowId: "11", colId: "9", enabled: false },
365 | { rowId: "11", colId: "10", enabled: false },
366 | { rowId: "11", colId: "11", enabled: false },
367 | { rowId: "11", colId: "12", enabled: false },
368 | { rowId: "11", colId: "13", enabled: false },
369 | { rowId: "11", colId: "14", enabled: false },
370 | { rowId: "11", colId: "15", enabled: false },
371 | { rowId: "11", colId: "16", enabled: false },
372 | { rowId: "11", colId: "17", enabled: false },
373 | { rowId: "11", colId: "18", enabled: false },
374 | { rowId: "11", colId: "19", enabled: false },
375 | { rowId: "11", colId: "20", enabled: false },
376 | { rowId: "11", colId: "21", enabled: false },
377 | { rowId: "11", colId: "22", enabled: false },
378 | { rowId: "11", colId: "23", enabled: false },
379 | { rowId: "11", colId: "24", enabled: false },
380 | { rowId: "11", colId: "25", enabled: false },
381 | { rowId: "11", colId: "26", enabled: false },
382 | { rowId: "11", colId: "27", enabled: false },
383 | { rowId: "11", colId: "28", enabled: false },
384 | { rowId: "11", colId: "29", enabled: false },
385 | { rowId: "11", colId: "30", enabled: false },
386 | { rowId: "11", colId: "31", enabled: false },
387 | { rowId: "12", colId: "0", enabled: false },
388 | { rowId: "12", colId: "1", enabled: false },
389 | { rowId: "12", colId: "2", enabled: false },
390 | { rowId: "12", colId: "3", enabled: false },
391 | { rowId: "12", colId: "4", enabled: false },
392 | { rowId: "12", colId: "5", enabled: false },
393 | { rowId: "12", colId: "6", enabled: false },
394 | { rowId: "12", colId: "7", enabled: false },
395 | { rowId: "12", colId: "8", enabled: false },
396 | { rowId: "12", colId: "9", enabled: false },
397 | { rowId: "12", colId: "10", enabled: false },
398 | { rowId: "12", colId: "11", enabled: false },
399 | { rowId: "12", colId: "12", enabled: false },
400 | { rowId: "12", colId: "13", enabled: false },
401 | { rowId: "12", colId: "14", enabled: false },
402 | { rowId: "12", colId: "15", enabled: false },
403 | { rowId: "12", colId: "16", enabled: false },
404 | { rowId: "12", colId: "17", enabled: false },
405 | { rowId: "12", colId: "18", enabled: false },
406 | { rowId: "12", colId: "19", enabled: false },
407 | { rowId: "12", colId: "20", enabled: false },
408 | { rowId: "12", colId: "21", enabled: false },
409 | { rowId: "12", colId: "22", enabled: false },
410 | { rowId: "12", colId: "23", enabled: true },
411 | { rowId: "12", colId: "24", enabled: false },
412 | { rowId: "12", colId: "25", enabled: true },
413 | { rowId: "12", colId: "26", enabled: false },
414 | { rowId: "12", colId: "27", enabled: false },
415 | { rowId: "12", colId: "28", enabled: false },
416 | { rowId: "12", colId: "29", enabled: false },
417 | { rowId: "12", colId: "30", enabled: false },
418 | { rowId: "12", colId: "31", enabled: false },
419 | { rowId: "13", colId: "0", enabled: false },
420 | { rowId: "13", colId: "1", enabled: false },
421 | { rowId: "13", colId: "2", enabled: false },
422 | { rowId: "13", colId: "3", enabled: false },
423 | { rowId: "13", colId: "4", enabled: false },
424 | { rowId: "13", colId: "5", enabled: false },
425 | { rowId: "13", colId: "6", enabled: false },
426 | { rowId: "13", colId: "7", enabled: false },
427 | { rowId: "13", colId: "8", enabled: false },
428 | { rowId: "13", colId: "9", enabled: false },
429 | { rowId: "13", colId: "10", enabled: false },
430 | { rowId: "13", colId: "11", enabled: false },
431 | { rowId: "13", colId: "12", enabled: false },
432 | { rowId: "13", colId: "13", enabled: false },
433 | { rowId: "13", colId: "14", enabled: false },
434 | { rowId: "13", colId: "15", enabled: false },
435 | { rowId: "13", colId: "16", enabled: false },
436 | { rowId: "13", colId: "17", enabled: false },
437 | { rowId: "13", colId: "18", enabled: false },
438 | { rowId: "13", colId: "19", enabled: false },
439 | { rowId: "13", colId: "20", enabled: false },
440 | { rowId: "13", colId: "21", enabled: false },
441 | { rowId: "13", colId: "22", enabled: false },
442 | { rowId: "13", colId: "23", enabled: false },
443 | { rowId: "13", colId: "24", enabled: true },
444 | { rowId: "13", colId: "25", enabled: false },
445 | { rowId: "13", colId: "26", enabled: false },
446 | { rowId: "13", colId: "27", enabled: false },
447 | { rowId: "13", colId: "28", enabled: true },
448 | { rowId: "13", colId: "29", enabled: false },
449 | { rowId: "13", colId: "30", enabled: false },
450 | { rowId: "13", colId: "31", enabled: false },
451 | { rowId: "14", colId: "0", enabled: false },
452 | { rowId: "14", colId: "1", enabled: false },
453 | { rowId: "14", colId: "2", enabled: false },
454 | { rowId: "14", colId: "3", enabled: false },
455 | { rowId: "14", colId: "4", enabled: false },
456 | { rowId: "14", colId: "5", enabled: false },
457 | { rowId: "14", colId: "6", enabled: false },
458 | { rowId: "14", colId: "7", enabled: false },
459 | { rowId: "14", colId: "8", enabled: false },
460 | { rowId: "14", colId: "9", enabled: false },
461 | { rowId: "14", colId: "10", enabled: false },
462 | { rowId: "14", colId: "11", enabled: false },
463 | { rowId: "14", colId: "12", enabled: false },
464 | { rowId: "14", colId: "13", enabled: false },
465 | { rowId: "14", colId: "14", enabled: false },
466 | { rowId: "14", colId: "15", enabled: false },
467 | { rowId: "14", colId: "16", enabled: false },
468 | { rowId: "14", colId: "17", enabled: false },
469 | { rowId: "14", colId: "18", enabled: false },
470 | { rowId: "14", colId: "19", enabled: false },
471 | { rowId: "14", colId: "20", enabled: false },
472 | { rowId: "14", colId: "21", enabled: false },
473 | { rowId: "14", colId: "22", enabled: false },
474 | { rowId: "14", colId: "23", enabled: false },
475 | { rowId: "14", colId: "24", enabled: false },
476 | { rowId: "14", colId: "25", enabled: false },
477 | { rowId: "14", colId: "26", enabled: true },
478 | { rowId: "14", colId: "27", enabled: false },
479 | { rowId: "14", colId: "28", enabled: false },
480 | { rowId: "14", colId: "29", enabled: false },
481 | { rowId: "14", colId: "30", enabled: false },
482 | { rowId: "14", colId: "31", enabled: false }
483 | ],
484 | settings: {
485 | sampleSet:
486 | "https://raw.githubusercontent.com/oramics/sampled/master/DRUMS/pearl-master-studio/sampled.instrument.json",
487 | measureLength: 32,
488 | bpm: 460,
489 | detune: 0,
490 | gainEnabled: "gain",
491 | attackAmp: 0,
492 | sustainAmp: 0.4,
493 | decayAmp: 0.7,
494 | releaseAmp: 1,
495 | attackTime: 0,
496 | decayTime: 0,
497 | sustainTime: 2,
498 | releaseTime: 2,
499 | adsrInterval: 0.1,
500 | delay: 0.01,
501 | filter: 1000
502 | }
503 | };
504 |
--------------------------------------------------------------------------------