mercury-engine 1.0.1 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +151 -28
- package/dist/mercury.js +192 -98
- package/dist/mercury.min.es5.js +2 -2
- package/dist/mercury.min.js +1 -1
- package/examples/basic/index.html +36 -8
- package/examples/midi/index.html +68 -0
- package/package.json +1 -1
package/dist/mercury.js
CHANGED
|
@@ -15195,7 +15195,7 @@ const LFO = function(_params){
|
|
|
15195
15195
|
if (this._waveMap[w]){
|
|
15196
15196
|
w = this._waveMap[w];
|
|
15197
15197
|
} else {
|
|
15198
|
-
|
|
15198
|
+
Util.log(`'${w} is not a valid waveshape`);
|
|
15199
15199
|
// default wave if wave does not exist
|
|
15200
15200
|
w = 'sine';
|
|
15201
15201
|
}
|
|
@@ -15244,7 +15244,7 @@ const Filter = function(_params){
|
|
|
15244
15244
|
if (this._types[_params[0]]){
|
|
15245
15245
|
this._fx.set({ type: this._types[_params[0]] });
|
|
15246
15246
|
} else {
|
|
15247
|
-
|
|
15247
|
+
Util.log(`'${_params[0]}' is not a valid filter type`);
|
|
15248
15248
|
this._fx.set({ type: 'lowpass' });
|
|
15249
15249
|
}
|
|
15250
15250
|
this._fx.set({ rolloff: -24 });
|
|
@@ -15318,7 +15318,7 @@ const TriggerFilter = function(_params){
|
|
|
15318
15318
|
if (this._types[_params[0][0]]){
|
|
15319
15319
|
this._fx.set({ type: this._types[_params[0][0]] });
|
|
15320
15320
|
} else {
|
|
15321
|
-
|
|
15321
|
+
Util.log(`'${_params[0][0]}' is not a valid filter type. Defaulting to lowpass`);
|
|
15322
15322
|
this._fx.set({ type: 'lowpass' });
|
|
15323
15323
|
}
|
|
15324
15324
|
|
|
@@ -15758,7 +15758,7 @@ class Instrument extends Sequencer {
|
|
|
15758
15758
|
let tmpF = fxMap[f[0]](f.slice(1));
|
|
15759
15759
|
this._fx.push(tmpF);
|
|
15760
15760
|
} else {
|
|
15761
|
-
log(`Effect ${f[0]} does not exist`);
|
|
15761
|
+
Util.log(`Effect ${f[0]} does not exist`);
|
|
15762
15762
|
}
|
|
15763
15763
|
});
|
|
15764
15764
|
// if any fx working
|
|
@@ -15789,6 +15789,7 @@ module.exports = Instrument;
|
|
|
15789
15789
|
},{"./Effects.js":56,"./Sequencer.js":65,"./Util.js":66,"tone":44}],58:[function(require,module,exports){
|
|
15790
15790
|
const Tone = require('tone');
|
|
15791
15791
|
const Instrument = require('./Instrument.js');
|
|
15792
|
+
const Util = require('./Util.js');
|
|
15792
15793
|
|
|
15793
15794
|
class MonoInput extends Instrument {
|
|
15794
15795
|
constructor(engine, d, canvas){
|
|
@@ -15799,7 +15800,7 @@ class MonoInput extends Instrument {
|
|
|
15799
15800
|
} else if (d.match(/in(\d+)/g)){
|
|
15800
15801
|
this._device = Number(d.match(/in(\d+)/)[1]);
|
|
15801
15802
|
} else {
|
|
15802
|
-
|
|
15803
|
+
Util.log(`${d} is not a valid microphone input. defaults to in0`);
|
|
15803
15804
|
this._device = 0;
|
|
15804
15805
|
}
|
|
15805
15806
|
|
|
@@ -15812,9 +15813,9 @@ class MonoInput extends Instrument {
|
|
|
15812
15813
|
createSource(){
|
|
15813
15814
|
this.mic = new Tone.UserMedia().connect(this.channelStrip());
|
|
15814
15815
|
this.mic.open(this._device).then(() => {
|
|
15815
|
-
|
|
15816
|
+
Util.log(`Opened microphone: ${window.devices[this._device]}`);
|
|
15816
15817
|
}).catch((e) => {
|
|
15817
|
-
|
|
15818
|
+
Util.log(`Unable to use microphone`);
|
|
15818
15819
|
});
|
|
15819
15820
|
this.mic.channelInterpretation = 'discrete';
|
|
15820
15821
|
|
|
@@ -15837,11 +15838,11 @@ class MonoInput extends Instrument {
|
|
|
15837
15838
|
}
|
|
15838
15839
|
}
|
|
15839
15840
|
module.exports = MonoInput;
|
|
15840
|
-
},{"./Instrument.js":57,"tone":44}],59:[function(require,module,exports){
|
|
15841
|
+
},{"./Instrument.js":57,"./Util.js":66,"tone":44}],59:[function(require,module,exports){
|
|
15841
15842
|
const Tone = require('tone');
|
|
15842
15843
|
const Util = require('./Util.js');
|
|
15843
15844
|
const Sequencer = require('./Sequencer.js');
|
|
15844
|
-
const WebMidi = require("webmidi");
|
|
15845
|
+
const { WebMidi } = require("webmidi");
|
|
15845
15846
|
|
|
15846
15847
|
class MonoMidi extends Sequencer {
|
|
15847
15848
|
constructor(engine, d='default', canvas){
|
|
@@ -15852,7 +15853,7 @@ class MonoMidi extends Sequencer {
|
|
|
15852
15853
|
if (d === 'default'){
|
|
15853
15854
|
this._device = WebMidi.outputs[0];
|
|
15854
15855
|
} else if (!this._device){
|
|
15855
|
-
|
|
15856
|
+
Util.log(`${d} is not a valid MIDI Device name, set to default`);
|
|
15856
15857
|
this._device = WebMidi.outputs[0];
|
|
15857
15858
|
}
|
|
15858
15859
|
|
|
@@ -15919,8 +15920,8 @@ class MonoMidi extends Sequencer {
|
|
|
15919
15920
|
n[x] = Util.toMidi(i[x], o);
|
|
15920
15921
|
}
|
|
15921
15922
|
|
|
15922
|
-
// play the note(s)!
|
|
15923
|
-
this._device.playNote(n, ch, { duration: d,
|
|
15923
|
+
// play the note(s)! updated for webmidi 3.x
|
|
15924
|
+
this._device.playNote(n, ch, { duration: d, attack: g, time: sync });
|
|
15924
15925
|
|
|
15925
15926
|
// }
|
|
15926
15927
|
}
|
|
@@ -15959,7 +15960,7 @@ class MonoMidi extends Sequencer {
|
|
|
15959
15960
|
this._cc = [];
|
|
15960
15961
|
cc.forEach((c) => {
|
|
15961
15962
|
if (isNaN(c[0])){
|
|
15962
|
-
|
|
15963
|
+
Util.log(`'${c[0]}' is not a valid CC number`);
|
|
15963
15964
|
} else {
|
|
15964
15965
|
let cc = [];
|
|
15965
15966
|
cc[0] = c[0];
|
|
@@ -16084,7 +16085,7 @@ class MonoSample extends Instrument {
|
|
|
16084
16085
|
// error if soundfile does not exist
|
|
16085
16086
|
else if (!this._bufs.has(s)){
|
|
16086
16087
|
// set default (or an ampty soundfile?)
|
|
16087
|
-
|
|
16088
|
+
Util.log(`sample ${s} not found`);
|
|
16088
16089
|
return 'kick_909';
|
|
16089
16090
|
}
|
|
16090
16091
|
return s;
|
|
@@ -16191,7 +16192,7 @@ class MonoSynth extends Instrument {
|
|
|
16191
16192
|
if (this._waveMap[w]){
|
|
16192
16193
|
w = this._waveMap[w];
|
|
16193
16194
|
} else {
|
|
16194
|
-
|
|
16195
|
+
Util.log(`${w} is not a valid waveshape`);
|
|
16195
16196
|
// default wave if wave does not exist
|
|
16196
16197
|
w = 'sine';
|
|
16197
16198
|
}
|
|
@@ -16387,7 +16388,7 @@ class PolyInstrument extends Instrument {
|
|
|
16387
16388
|
}
|
|
16388
16389
|
|
|
16389
16390
|
voices(v){
|
|
16390
|
-
|
|
16391
|
+
Util.log(`Changing voice amount is not yet supported. You can use voice-stealing with steal(on)`);
|
|
16391
16392
|
// TODO change voice amount
|
|
16392
16393
|
// set the voiceamount for the polyphonic synth
|
|
16393
16394
|
// this.numVoices = Math.max(1, isNaN(Number(v))? 6 : Number(v));
|
|
@@ -16402,7 +16403,7 @@ class PolyInstrument extends Instrument {
|
|
|
16402
16403
|
} else if (s === 'off' || s == 0){
|
|
16403
16404
|
this._steal = false;
|
|
16404
16405
|
} else {
|
|
16405
|
-
|
|
16406
|
+
Util.log(`${s} is not a valid argument for steal()`);
|
|
16406
16407
|
}
|
|
16407
16408
|
}
|
|
16408
16409
|
|
|
@@ -16543,7 +16544,7 @@ class PolySample extends PolyInstrument {
|
|
|
16543
16544
|
// error if soundfile does not exist
|
|
16544
16545
|
else if (!this._bufs.has(s)){
|
|
16545
16546
|
// set default (or an ampty soundfile?)
|
|
16546
|
-
|
|
16547
|
+
Util.log(`sample ${s} not found`);
|
|
16547
16548
|
return 'kick_909';
|
|
16548
16549
|
}
|
|
16549
16550
|
return s;
|
|
@@ -16960,7 +16961,7 @@ function getOSC(a){
|
|
|
16960
16961
|
return a;
|
|
16961
16962
|
} else if (osc.match(/^\/[^`'"\s]+/g)){
|
|
16962
16963
|
if (!window.oscMessages[osc]){
|
|
16963
|
-
|
|
16964
|
+
log(`No message received on address ${osc}`);
|
|
16964
16965
|
return [0];
|
|
16965
16966
|
}
|
|
16966
16967
|
return window.oscMessages[osc];
|
|
@@ -16993,7 +16994,7 @@ function evalExpr(a){
|
|
|
16993
16994
|
try {
|
|
16994
16995
|
result = eval(expr);
|
|
16995
16996
|
} catch (e){
|
|
16996
|
-
|
|
16997
|
+
log(`Unable to evaluate expression: ${expr}`);
|
|
16997
16998
|
}
|
|
16998
16999
|
return result;
|
|
16999
17000
|
}
|
|
@@ -17018,8 +17019,7 @@ function formatRatio(d, bpm){
|
|
|
17018
17019
|
} else if (!isNaN(Number(d))){
|
|
17019
17020
|
return Number(d) * 4.0 * 60 / bpm;
|
|
17020
17021
|
} else {
|
|
17021
|
-
|
|
17022
|
-
console.log(`${d} is not a valid time value`);
|
|
17022
|
+
log(`${d} is not a valid time value`);
|
|
17023
17023
|
return 60 / bpm;
|
|
17024
17024
|
}
|
|
17025
17025
|
}
|
|
@@ -17031,7 +17031,7 @@ function divToS(d, bpm){
|
|
|
17031
17031
|
} else if (!isNaN(Number(d))){
|
|
17032
17032
|
return Number(d) / 1000;
|
|
17033
17033
|
} else {
|
|
17034
|
-
|
|
17034
|
+
log(`${d} is not a valid time value`);
|
|
17035
17035
|
return 0.1;
|
|
17036
17036
|
}
|
|
17037
17037
|
}
|
|
@@ -17041,7 +17041,7 @@ function noteToFreq(i, o){
|
|
|
17041
17041
|
if (isNaN(i)){
|
|
17042
17042
|
let _i = noteToMidi(i);
|
|
17043
17043
|
if (!_i){
|
|
17044
|
-
|
|
17044
|
+
log(`${i} is not a valid number or name`);
|
|
17045
17045
|
i = 0;
|
|
17046
17046
|
} else {
|
|
17047
17047
|
i = _i - 48;
|
|
@@ -17072,7 +17072,7 @@ function assureWave(w){
|
|
|
17072
17072
|
if (waveMap[w]){
|
|
17073
17073
|
w = waveMap[w];
|
|
17074
17074
|
} else {
|
|
17075
|
-
|
|
17075
|
+
log(`${w} is not a valid waveshape`);
|
|
17076
17076
|
// default wave if wave does not exist
|
|
17077
17077
|
w = 'sine';
|
|
17078
17078
|
}
|
|
@@ -17084,7 +17084,7 @@ function toMidi(n=0, o=0){
|
|
|
17084
17084
|
if (isNaN(n)){
|
|
17085
17085
|
let _n = noteToMidi(n);
|
|
17086
17086
|
if (!_n){
|
|
17087
|
-
|
|
17087
|
+
log(`${n} is not a valid number or name`);
|
|
17088
17088
|
n = 0;
|
|
17089
17089
|
} else {
|
|
17090
17090
|
n = _n - 36;
|
|
@@ -17093,7 +17093,18 @@ function toMidi(n=0, o=0){
|
|
|
17093
17093
|
return toScale(n + o * 12 + 36);
|
|
17094
17094
|
}
|
|
17095
17095
|
|
|
17096
|
-
|
|
17096
|
+
// the log message is used to log to the console but also
|
|
17097
|
+
// sends a custom event that can be listened for to print the
|
|
17098
|
+
// content at some other place in the window, for example using a div
|
|
17099
|
+
function log(msg){
|
|
17100
|
+
console.log(msg);
|
|
17101
|
+
if (window){
|
|
17102
|
+
let print = new CustomEvent('mercuryLog', { detail: msg });
|
|
17103
|
+
window.dispatchEvent(print);
|
|
17104
|
+
}
|
|
17105
|
+
}
|
|
17106
|
+
|
|
17107
|
+
module.exports = { clip, assureNum, lookup, randLookup, isRandom, getParam, toArray, msToS, formatRatio, divToS, toMidi, mtof, noteToMidi, noteToFreq, assureWave, log }
|
|
17097
17108
|
},{"total-serialism":47}],67:[function(require,module,exports){
|
|
17098
17109
|
module.exports={
|
|
17099
17110
|
"uptempo" : 10,
|
|
@@ -17120,7 +17131,7 @@ module.exports={
|
|
|
17120
17131
|
const Tone = require('tone');
|
|
17121
17132
|
const Mercury = require('mercury-lang');
|
|
17122
17133
|
const TL = require('total-serialism').Translate;
|
|
17123
|
-
|
|
17134
|
+
const { normalize, multiply } = require('total-serialism').Utility;
|
|
17124
17135
|
|
|
17125
17136
|
const MonoSample = require('./core/MonoSample.js');
|
|
17126
17137
|
const MonoMidi = require('./core/MonoMidi.js');
|
|
@@ -17129,11 +17140,12 @@ const MonoInput = require('./core/MonoInput.js');
|
|
|
17129
17140
|
const PolySynth = require('./core/PolySynth.js');
|
|
17130
17141
|
const PolySample = require('./core/PolySample.js');
|
|
17131
17142
|
const Tempos = require('./data/genre-tempos.json');
|
|
17143
|
+
const Util = require('./core/Util.js');
|
|
17132
17144
|
|
|
17133
17145
|
class MercuryInterpreter {
|
|
17134
|
-
constructor(){
|
|
17146
|
+
constructor({ hydra, p5canvas } = {}){
|
|
17135
17147
|
// cross-fade time
|
|
17136
|
-
this.crossFade
|
|
17148
|
+
this.crossFade;
|
|
17137
17149
|
|
|
17138
17150
|
// arrays with the current and previous instruments for crossfade
|
|
17139
17151
|
this._sounds = [];
|
|
@@ -17146,6 +17158,10 @@ class MercuryInterpreter {
|
|
|
17146
17158
|
this.parse;
|
|
17147
17159
|
this.tree;
|
|
17148
17160
|
this.errors;
|
|
17161
|
+
|
|
17162
|
+
// Hydra and P5 canvas
|
|
17163
|
+
this.canvas = hydra;
|
|
17164
|
+
this.p5canvas = p5canvas;
|
|
17149
17165
|
}
|
|
17150
17166
|
|
|
17151
17167
|
getSounds(){
|
|
@@ -17169,32 +17185,51 @@ class MercuryInterpreter {
|
|
|
17169
17185
|
startSounds(s, f=0){
|
|
17170
17186
|
// fade in new sounds
|
|
17171
17187
|
s.map((_s) => {
|
|
17172
|
-
_s.fadeIn(f);
|
|
17188
|
+
if (_s){ _s.fadeIn(f); }
|
|
17173
17189
|
});
|
|
17174
17190
|
}
|
|
17175
17191
|
|
|
17176
17192
|
removeSounds(s, f=0) {
|
|
17177
17193
|
// fade out and delete after fade
|
|
17178
17194
|
s.map((_s) => {
|
|
17179
|
-
_s.fadeOut(f);
|
|
17195
|
+
if (_s){ _s.fadeOut(f); }
|
|
17180
17196
|
});
|
|
17181
17197
|
// empty array to trigger garbage collection
|
|
17182
17198
|
s.length = 0;
|
|
17183
17199
|
}
|
|
17184
17200
|
|
|
17185
|
-
|
|
17201
|
+
makeLoops(s){
|
|
17202
|
+
// make the loops for all the instruments
|
|
17203
|
+
s.map((_s) => {
|
|
17204
|
+
if (_s){ _s.makeLoop(); }
|
|
17205
|
+
});
|
|
17206
|
+
}
|
|
17207
|
+
|
|
17208
|
+
setCrossFade(f){
|
|
17209
|
+
// set the crossFade in milliseconds
|
|
17210
|
+
this.crossFade = Number(f) / 1000;
|
|
17211
|
+
Util.log(`Crossfade set to: ${f}ms`);
|
|
17212
|
+
}
|
|
17213
|
+
|
|
17214
|
+
getCode(){
|
|
17215
|
+
// return the last evaluated code
|
|
17216
|
+
return this._code;
|
|
17217
|
+
}
|
|
17218
|
+
|
|
17219
|
+
code(file=''){
|
|
17186
17220
|
// parse and evaluate the inputted code
|
|
17187
|
-
// as an asyncronous function with promise
|
|
17188
17221
|
let c = (!file)? this._code : file;
|
|
17189
|
-
|
|
17190
|
-
|
|
17222
|
+
|
|
17191
17223
|
let t = Tone.Transport.seconds;
|
|
17224
|
+
|
|
17192
17225
|
// is this necessary?
|
|
17226
|
+
// as an asyncronous function with promise
|
|
17193
17227
|
// let parser = new Promise((resolve) => {
|
|
17194
17228
|
// return resolve(Mercury(c));
|
|
17195
17229
|
// });
|
|
17196
17230
|
// this.parse = await parser;
|
|
17197
17231
|
this.parse = Mercury(c);
|
|
17232
|
+
|
|
17198
17233
|
console.log(`Evaluated code in: ${((Tone.Transport.seconds-t) * 1000).toFixed(3)}ms`);
|
|
17199
17234
|
|
|
17200
17235
|
this.tree = this.parse.parseTree;
|
|
@@ -17204,31 +17239,21 @@ class MercuryInterpreter {
|
|
|
17204
17239
|
// l.innerHTML = '';
|
|
17205
17240
|
// handle .print and .errors
|
|
17206
17241
|
this.errors.forEach((e) => {
|
|
17207
|
-
|
|
17208
|
-
// log(e);
|
|
17242
|
+
Util.log(e);
|
|
17209
17243
|
});
|
|
17210
17244
|
if (this.errors.length > 0){
|
|
17211
17245
|
// return if the code contains any syntax errors
|
|
17212
|
-
|
|
17213
|
-
|
|
17246
|
+
Util.log(`Could not run because of syntax error`);
|
|
17247
|
+
Util.log(`Please see Help for more information`);
|
|
17214
17248
|
return;
|
|
17215
17249
|
}
|
|
17250
|
+
// if no errors the last evaluated code is stored
|
|
17251
|
+
this._code = c;
|
|
17216
17252
|
|
|
17217
17253
|
this.tree.print.forEach((p) => {
|
|
17218
|
-
|
|
17254
|
+
Util.log(p);
|
|
17219
17255
|
});
|
|
17220
17256
|
|
|
17221
|
-
// hide canvas and noLoop
|
|
17222
|
-
// p5canvas.hide();
|
|
17223
|
-
|
|
17224
|
-
// handle .display to p5
|
|
17225
|
-
// tree.display.forEach((p) => {
|
|
17226
|
-
// // restart canvas if view is used
|
|
17227
|
-
// let n = Util.mul(Util.normalize(p), 255);
|
|
17228
|
-
// p5canvas.sketch.fillCanvas(n);
|
|
17229
|
-
// p5canvas.display();
|
|
17230
|
-
// });
|
|
17231
|
-
|
|
17232
17257
|
// set timer to check evaluation time
|
|
17233
17258
|
t = Tone.Transport.seconds;
|
|
17234
17259
|
|
|
@@ -17236,21 +17261,19 @@ class MercuryInterpreter {
|
|
|
17236
17261
|
const globalMap = {
|
|
17237
17262
|
'crossFade' : (args) => {
|
|
17238
17263
|
// set crossFade time in ms
|
|
17239
|
-
this.
|
|
17240
|
-
// log(`crossfade time is ${args[0]}ms`);
|
|
17241
|
-
console.log(`Crossfade: ${args[0]}ms`);
|
|
17264
|
+
this.setCrossFade(args[0]);
|
|
17242
17265
|
},
|
|
17243
17266
|
'tempo' : (args) => {
|
|
17244
17267
|
let t = args[0];
|
|
17245
17268
|
if (isNaN(t)){
|
|
17246
17269
|
t = Tempos[args[0].toLowerCase()];
|
|
17247
17270
|
if (t === undefined){
|
|
17248
|
-
|
|
17271
|
+
Util.log(`tempo ${args[0]} is not a valid genre or number`);
|
|
17249
17272
|
return;
|
|
17250
17273
|
}
|
|
17251
17274
|
args[0] = t;
|
|
17252
17275
|
}
|
|
17253
|
-
this.
|
|
17276
|
+
this.setBPM(...args);
|
|
17254
17277
|
// engine.setBPM(...args);
|
|
17255
17278
|
// log(`set bpm to ${bpm}`);
|
|
17256
17279
|
},
|
|
@@ -17275,16 +17298,15 @@ class MercuryInterpreter {
|
|
|
17275
17298
|
if (s.indexOf(scl) > -1){
|
|
17276
17299
|
TL.setScale(scl);
|
|
17277
17300
|
} else {
|
|
17278
|
-
|
|
17301
|
+
Util.log(`${scl} is not a valid scale`);
|
|
17279
17302
|
}
|
|
17280
17303
|
if (rt){
|
|
17281
17304
|
TL.setRoot(rt);
|
|
17282
17305
|
}
|
|
17283
|
-
|
|
17284
|
-
let
|
|
17285
|
-
let tmpR = TL.getScale().root;
|
|
17306
|
+
// let tmpS = TL.getScale().scale;
|
|
17307
|
+
// let tmpR = TL.getScale().root;
|
|
17286
17308
|
// document.getElementById('scale').innerHTML = `scale = ${tmpR} ${tmpS}`;
|
|
17287
|
-
// log(`set scale to ${tmpR} ${tmpS}`);
|
|
17309
|
+
// Util.log(`set scale to ${tmpR} ${tmpS}`);
|
|
17288
17310
|
},
|
|
17289
17311
|
'amp' : (args) => {
|
|
17290
17312
|
this.setVolume(...args);
|
|
@@ -17303,38 +17325,42 @@ class MercuryInterpreter {
|
|
|
17303
17325
|
// Handling all the different instrument types here
|
|
17304
17326
|
const objectMap = {
|
|
17305
17327
|
'sample' : (obj) => {
|
|
17306
|
-
let inst = new MonoSample(this, obj.type, canvas);
|
|
17328
|
+
let inst = new MonoSample(this, obj.type, this.canvas);
|
|
17307
17329
|
objectMap.applyFunctions(obj.functions, inst, obj.type);
|
|
17308
17330
|
return inst;
|
|
17309
17331
|
},
|
|
17310
17332
|
'loop' : (obj) => {
|
|
17311
|
-
let inst = new MonoSample(this, obj.type, canvas);
|
|
17333
|
+
let inst = new MonoSample(this, obj.type, this.canvas);
|
|
17312
17334
|
objectMap.applyFunctions(obj.functions, inst, obj.type);
|
|
17313
17335
|
return inst;
|
|
17314
17336
|
},
|
|
17315
17337
|
'synth' : (obj) => {
|
|
17316
17338
|
console.log(obj);
|
|
17317
|
-
let inst = new MonoSynth(this, obj.type, canvas);
|
|
17339
|
+
let inst = new MonoSynth(this, obj.type, this.canvas);
|
|
17318
17340
|
objectMap.applyFunctions(obj.functions, inst, obj.type);
|
|
17319
17341
|
return inst;
|
|
17320
17342
|
},
|
|
17321
17343
|
'polySynth' : (obj) => {
|
|
17322
|
-
let inst = new PolySynth(this, obj.type, canvas);
|
|
17344
|
+
let inst = new PolySynth(this, obj.type, this.canvas);
|
|
17323
17345
|
objectMap.applyFunctions(obj.functions, inst, obj.type);
|
|
17324
17346
|
return inst;
|
|
17325
17347
|
},
|
|
17326
17348
|
'polySample' : (obj) => {
|
|
17327
|
-
let inst = new PolySample(this, obj.type, canvas);
|
|
17349
|
+
let inst = new PolySample(this, obj.type, this.canvas);
|
|
17328
17350
|
objectMap.applyFunctions(obj.functions, inst, obj.type);
|
|
17329
17351
|
return inst;
|
|
17330
17352
|
},
|
|
17331
17353
|
'midi' : (obj) => {
|
|
17332
|
-
|
|
17354
|
+
if (!this.midi.enabled){
|
|
17355
|
+
Util.log(`WebMIDI is not started. Please load the package and check your browser compatibility`);
|
|
17356
|
+
return null;
|
|
17357
|
+
}
|
|
17358
|
+
let inst = new MonoMidi(this, obj.type, this.canvas);
|
|
17333
17359
|
objectMap.applyFunctions(obj.functions, inst, obj.type);
|
|
17334
17360
|
return inst;
|
|
17335
17361
|
},
|
|
17336
17362
|
'input' : (obj) => {
|
|
17337
|
-
let inst = new MonoInput(this, obj.type, canvas);
|
|
17363
|
+
let inst = new MonoInput(this, obj.type, this.canvas);
|
|
17338
17364
|
objectMap.applyFunctions(obj.functions, inst, obj.type);
|
|
17339
17365
|
return inst;
|
|
17340
17366
|
},
|
|
@@ -17369,18 +17395,15 @@ class MercuryInterpreter {
|
|
|
17369
17395
|
if (objectMap[type]){
|
|
17370
17396
|
this.sounds.push(objectMap[type](this.tree.objects[o]));
|
|
17371
17397
|
} else {
|
|
17372
|
-
log(`Instrument named '${type}' is not supported`);
|
|
17398
|
+
Util.log(`Instrument named '${type}' is not supported`);
|
|
17373
17399
|
}
|
|
17374
17400
|
}
|
|
17375
17401
|
|
|
17376
17402
|
// start new loops;
|
|
17377
|
-
this.sounds
|
|
17378
|
-
s.makeLoop();
|
|
17379
|
-
});
|
|
17380
|
-
|
|
17381
|
-
console.log(`Instruments added in: ${((Tone.Transport.seconds - t) * 1000).toFixed(3)}ms`);
|
|
17382
|
-
|
|
17403
|
+
this.makeLoops(this.sounds);
|
|
17383
17404
|
this.transferCounts(this._sounds, this.sounds);
|
|
17405
|
+
|
|
17406
|
+
console.log(`Instruments added in: ${((Tone.Transport.seconds - t) * 1000).toFixed(3)}ms`);
|
|
17384
17407
|
|
|
17385
17408
|
// when all loops started fade in the new sounds and fade out old
|
|
17386
17409
|
if (!this.sounds.length){
|
|
@@ -17390,22 +17413,39 @@ class MercuryInterpreter {
|
|
|
17390
17413
|
this.removeSounds(this._sounds, this.crossFade);
|
|
17391
17414
|
|
|
17392
17415
|
this.resume();
|
|
17416
|
+
|
|
17417
|
+
// if p5js canvas is included in the html page
|
|
17418
|
+
if (this.p5canvas){
|
|
17419
|
+
// hide canvas and noLoop
|
|
17420
|
+
this.p5canvas.hide();
|
|
17421
|
+
|
|
17422
|
+
// handle .display to p5
|
|
17423
|
+
tree.display.forEach((p) => {
|
|
17424
|
+
// restart canvas if view is used
|
|
17425
|
+
let n = multiply(normalize(p), 255);
|
|
17426
|
+
this.p5canvas.sketch.fillCanvas(n);
|
|
17427
|
+
this.p5canvas.display();
|
|
17428
|
+
});
|
|
17429
|
+
}
|
|
17393
17430
|
}
|
|
17394
17431
|
}
|
|
17395
17432
|
module.exports = { MercuryInterpreter }
|
|
17396
|
-
},{"./core/MonoInput.js":58,"./core/MonoMidi.js":59,"./core/MonoSample.js":60,"./core/MonoSynth.js":61,"./core/PolySample.js":63,"./core/PolySynth.js":64,"./data/genre-tempos.json":67,"mercury-lang":27,"tone":44,"total-serialism":47}],69:[function(require,module,exports){
|
|
17433
|
+
},{"./core/MonoInput.js":58,"./core/MonoMidi.js":59,"./core/MonoSample.js":60,"./core/MonoSynth.js":61,"./core/PolySample.js":63,"./core/PolySynth.js":64,"./core/Util.js":66,"./data/genre-tempos.json":67,"mercury-lang":27,"tone":44,"total-serialism":47}],69:[function(require,module,exports){
|
|
17397
17434
|
|
|
17398
17435
|
console.log(`
|
|
17399
17436
|
Mercury Engine by Timo Hoogland (c) 2023
|
|
17400
17437
|
more info:
|
|
17401
17438
|
https://www.timohoogland.com
|
|
17402
17439
|
https://mercury.timohoogland.com
|
|
17403
|
-
https://github.com/tmhglnd/mercury
|
|
17440
|
+
https://github.com/tmhglnd/mercury-playground
|
|
17441
|
+
https://github.com/tmhglnd/mercury-engine
|
|
17404
17442
|
|
|
17405
17443
|
`);
|
|
17406
17444
|
|
|
17407
17445
|
const Tone = require('tone');
|
|
17446
|
+
const Util = require('./core/Util.js');
|
|
17408
17447
|
const { MercuryInterpreter } = require('./interpreter');
|
|
17448
|
+
const { WebMidi } = require("webmidi");
|
|
17409
17449
|
|
|
17410
17450
|
// load extra AudioWorkletProcessors from file
|
|
17411
17451
|
// transformed to inline with browserify brfs
|
|
@@ -17413,15 +17453,15 @@ const { MercuryInterpreter } = require('./interpreter');
|
|
|
17413
17453
|
const fxExtensions = "\n// A white noise generator at -6dBFS to test AudioWorkletProcessor\n//\nclass NoiseProcessor extends AudioWorkletProcessor {\n\tprocess(inputs, outputs, parameters){\n\t\tconst output = outputs[0];\n\n\t\toutput.forEach((channel) => {\n\t\t\tfor (let i=0; i<channel.length; i++) {\n\t\t\t\tchannel[i] = Math.random() - 0.5;\n\t\t\t}\n\t\t});\n\t\treturn true;\n\t}\n}\nregisterProcessor('noise-processor', NoiseProcessor);\n\n// A Downsampling Chiptune effect. Downsamples the signal by a specified amount\n// Resulting in a lower samplerate, making it sound more like 8bit/chiptune\n// Programmed with a custom AudioWorkletProcessor, see effects/Processors.js\n//\nclass DownSampleProcessor extends AudioWorkletProcessor {\n\tstatic get parameterDescriptors() {\n\t\treturn [{\n\t\t\tname: 'down',\n\t\t\tdefaultValue: 8,\n\t\t\tminValue: 1,\n\t\t\tmaxValue: 2048\n\t\t}];\n\t}\n\n\tconstructor(){\n\t\tsuper();\n\t\t// the frame counter\n\t\tthis.count = 0;\n\t\t// sample and hold variable array\n\t\tthis.sah = [];\n\t}\n\n\tprocess(inputs, outputs, parameters){\n\t\tconst input = inputs[0];\n\t\tconst output = outputs[0];\n\n\t\t// if there is anything to process\n\t\tif (input.length > 0){\n\t\t\t// for the length of the sample array (generally 128)\n\t\t\tfor (let i=0; i<input[0].length; i++){\n\t\t\t\tconst d = (parameters.down.length > 1) ? parameters.down[i] : parameters.down[0];\n\t\t\t\t// for every channel\n\t\t\t\tfor (let channel=0; channel<input.length; ++channel){\n\t\t\t\t\t// if counter equals 0, sample and hold\n\t\t\t\t\tif (this.count % d === 0){\n\t\t\t\t\t\tthis.sah[channel] = input[channel][i];\n\t\t\t\t\t}\n\t\t\t\t\t// output the currently held sample\n\t\t\t\t\toutput[channel][i] = this.sah[channel];\n\t\t\t\t}\n\t\t\t\t// increment sample counter\n\t\t\t\tthis.count++;\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n}\nregisterProcessor('downsampler-processor', DownSampleProcessor);\n\n// A distortion algorithm using the tanh (hyperbolic-tangent) as a \n// waveshaping technique. Some mapping to apply a more equal loudness \n// distortion is applied on the overdrive parameter\n//\nclass TanhDistortionProcessor extends AudioWorkletProcessor {\n\tconstructor(){\n\t\tsuper();\n\t}\n\n\tprocess(inputs, outputs, parameters){\n\t\tconst input = inputs[0];\n\t\tconst output = outputs[0];\n\n\t\tif (input.length > 0){\n\t\t\tfor (let channel=0; channel<input.length; ++channel){\n\t\t\t\tfor (let i=0; i<input[channel].length; i++){\n\t\t\t\t\t// simple waveshaping with tanh\n\t\t\t\t\toutput[channel][i] = Math.tanh(input[channel][i]);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n}\nregisterProcessor('tanh-distortion-processor', TanhDistortionProcessor);\n\n// A distortion/compression effect of an incoming signal\n// Based on an algorithm by Peter McCulloch\n// \nclass SquashProcessor extends AudioWorkletProcessor {\n\tstatic get parameterDescriptors(){\n\t\treturn [{\n\t\t\tname: 'amount',\n\t\t\tdefaultValue: 4,\n\t\t\tminValue: 1,\n\t\t\tmaxValue: 1024\n\t\t}];\n\t}\n\n\tconstructor(){\n\t\tsuper();\n\t}\n\n\tprocess(inputs, outputs, parameters){\n\t\tconst input = inputs[0];\n\t\tconst output = outputs[0];\n\t\t\n\t\tif (input.length > 0){\n\t\t\tfor (let channel=0; channel<input.length; ++channel){\n\t\t\t\tfor (let i=0; i<input[channel].length; i++){\n\t\t\t\t\t// (s * a) / ((s * a)^2 * 0.28 + 1) / √a\n\t\t\t\t\t// drive amount, minimum of 1\n\t\t\t\t\tconst a = (parameters.amount.length > 1)? parameters.amount[i] : parameters.amount[0];\n\t\t\t\t\t// set the waveshaper effect\n\t\t\t\t\tconst s = input[channel][i];\n\t\t\t\t\tconst p = (s * a) / ((s * a) * (s * a) * 0.28 + 1.0);\n\t\t\t\t\toutput[channel][i] = p;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n}\nregisterProcessor('squash-processor', SquashProcessor);";
|
|
17414
17454
|
Tone.getContext().addAudioWorkletModule(URL.createObjectURL(new Blob([ fxExtensions ], { type: 'text/javascript' })));
|
|
17415
17455
|
|
|
17416
|
-
// const minifyInline = require('minify-inline-json');
|
|
17417
|
-
|
|
17418
17456
|
// Mercury main class controls Tone and loads samples
|
|
17419
17457
|
// also has the interpreter evaluating the code and adding the instruments
|
|
17420
17458
|
//
|
|
17421
17459
|
class Mercury extends MercuryInterpreter {
|
|
17422
|
-
constructor(
|
|
17423
|
-
// initalize the constructor of inheriting class
|
|
17424
|
-
|
|
17460
|
+
constructor({ onload, onmidi, hydra, p5canvas } = {}){
|
|
17461
|
+
// initalize the constructor of inheriting class with
|
|
17462
|
+
// optionally a hydra and p5 canvas
|
|
17463
|
+
super({ hydra, p5canvas });
|
|
17464
|
+
|
|
17425
17465
|
// store sample files in buffers
|
|
17426
17466
|
this.samples = JSON.parse("{\n \"noise_a\": \"noise/noise_a.wav\",\n \"drone_cymbal\": \"ambient/cymbal/drone_cymbal.wav\",\n \"drone_cymbal_01\": \"ambient/cymbal/drone_cymbal_01.wav\",\n \"clap_808\": \"drums/clap/clap_808.wav\",\n \"clap_808_short\": \"drums/clap/clap_808_short.wav\",\n \"clap_909\": \"drums/clap/clap_909.wav\",\n \"clap_min\": \"drums/clap/clap_min.wav\",\n \"hat_808\": \"drums/hat/hat_808.wav\",\n \"hat_808_open\": \"drums/hat/hat_808_open.wav\",\n \"hat_808_semi\": \"drums/hat/hat_808_semi.wav\",\n \"hat_909\": \"drums/hat/hat_909.wav\",\n \"hat_909_open\": \"drums/hat/hat_909_open.wav\",\n \"hat_909_open_short\": \"drums/hat/hat_909_open_short.wav\",\n \"hat_909_short\": \"drums/hat/hat_909_short.wav\",\n \"hat_click\": \"drums/hat/hat_click.wav\",\n \"hat_dub\": \"drums/hat/hat_dub.wav\",\n \"hat_min\": \"drums/hat/hat_min.wav\",\n \"hat_min_open\": \"drums/hat/hat_min_open.wav\",\n \"kick_808\": \"drums/kick/kick_808.wav\",\n \"kick_808_dist\": \"drums/kick/kick_808_dist.wav\",\n \"kick_909\": \"drums/kick/kick_909.wav\",\n \"kick_909_dist\": \"drums/kick/kick_909_dist.wav\",\n \"kick_909_dist_long\": \"drums/kick/kick_909_dist_long.wav\",\n \"kick_909_long\": \"drums/kick/kick_909_long.wav\",\n \"kick_deep\": \"drums/kick/kick_deep.wav\",\n \"kick_dub\": \"drums/kick/kick_dub.wav\",\n \"kick_house\": \"drums/kick/kick_house.wav\",\n \"kick_min\": \"drums/kick/kick_min.wav\",\n \"kick_sub\": \"drums/kick/kick_sub.wav\",\n \"kick_ua\": \"drums/kick/kick_ua.wav\",\n \"kick_vintage\": \"drums/kick/kick_vintage.wav\",\n \"block\": \"drums/perc/block.wav\",\n \"block_lo\": \"drums/perc/block_lo.wav\",\n \"bongo\": \"drums/perc/bongo.wav\",\n \"bongo_lo\": \"drums/perc/bongo_lo.wav\",\n \"clave_808\": \"drums/perc/clave_808.wav\",\n \"cowbell_808\": \"drums/perc/cowbell_808.wav\",\n \"cymbal_808\": \"drums/perc/cymbal_808.wav\",\n \"maracas_808\": \"drums/perc/maracas_808.wav\",\n \"snare_808\": \"drums/snare/snare_808.wav\",\n \"snare_909\": \"drums/snare/snare_909.wav\",\n \"snare_909_short\": \"drums/snare/snare_909_short.wav\",\n \"snare_ac\": \"drums/snare/snare_ac.wav\",\n \"snare_dnb\": \"drums/snare/snare_dnb.wav\",\n \"snare_dub\": \"drums/snare/snare_dub.wav\",\n \"snare_fat\": \"drums/snare/snare_fat.wav\",\n \"snare_hvy\": \"drums/snare/snare_hvy.wav\",\n \"snare_min\": \"drums/snare/snare_min.wav\",\n \"snare_rock\": \"drums/snare/snare_rock.wav\",\n \"snare_step\": \"drums/snare/snare_step.wav\",\n \"tabla_01\": \"drums/tabla/tabla_01.wav\",\n \"tabla_02\": \"drums/tabla/tabla_02.wav\",\n \"tabla_03\": \"drums/tabla/tabla_03.wav\",\n \"tabla_hi\": \"drums/tabla/tabla_hi.wav\",\n \"tabla_hi_long\": \"drums/tabla/tabla_hi_long.wav\",\n \"tabla_hi_short\": \"drums/tabla/tabla_hi_short.wav\",\n \"tabla_lo\": \"drums/tabla/tabla_lo.wav\",\n \"tabla_lo_long\": \"drums/tabla/tabla_lo_long.wav\",\n \"tabla_lo_short\": \"drums/tabla/tabla_lo_short.wav\",\n \"tabla_mid\": \"drums/tabla/tabla_mid.wav\",\n \"tabla_mid_long\": \"drums/tabla/tabla_mid_long.wav\",\n \"tabla_mid_short\": \"drums/tabla/tabla_mid_short.wav\",\n \"tom_808\": \"drums/tom/tom_808.wav\",\n \"tom_hi\": \"drums/tom/tom_hi.wav\",\n \"tom_lo\": \"drums/tom/tom_lo.wav\",\n \"tom_mid\": \"drums/tom/tom_mid.wav\",\n \"tongue\": \"foley/body/tongue.wav\",\n \"tongue_lo\": \"foley/body/tongue_lo.wav\",\n \"shatter\": \"foley/glass/shatter.wav\",\n \"metal\": \"foley/metal/metal.wav\",\n \"metal_lo\": \"foley/metal/metal_lo.wav\",\n \"wobble\": \"foley/plastic/wobble.wav\",\n \"wobble_02\": \"foley/plastic/wobble_02.wav\",\n \"door\": \"foley/wood/door.wav\",\n \"scrape\": \"foley/wood/scrape.wav\",\n \"scrape_01\": \"foley/wood/scrape_01.wav\",\n \"wood_hit\": \"foley/wood/wood_hit.wav\",\n \"wood_metal\": \"foley/wood/wood_metal.wav\",\n \"wood_plate\": \"foley/wood/wood_plate.wav\",\n \"bell\": \"idiophone/bell/bell.wav\",\n \"chimes\": \"idiophone/chimes/chimes.wav\",\n \"chimes_chord\": \"idiophone/chimes/chimes_chord.wav\",\n \"chimes_chord_01\": \"idiophone/chimes/chimes_chord_01.wav\",\n \"chimes_chord_02\": \"idiophone/chimes/chimes_chord_02.wav\",\n \"chimes_hi\": \"idiophone/chimes/chimes_hi.wav\",\n \"gong_hi\": \"idiophone/gong/gong_hi.wav\",\n \"gong_lo\": \"idiophone/gong/gong_lo.wav\",\n \"kalimba_a\": \"idiophone/kalimba/kalimba_a.wav\",\n \"kalimba_ab\": \"idiophone/kalimba/kalimba_ab.wav\",\n \"kalimba_cis\": \"idiophone/kalimba/kalimba_cis.wav\",\n \"kalimba_e\": \"idiophone/kalimba/kalimba_e.wav\",\n \"kalimba_g\": \"idiophone/kalimba/kalimba_g.wav\",\n \"bamboo_a\": \"idiophone/marimba-bamboo/bamboo_a.wav\",\n \"bamboo_c\": \"idiophone/marimba-bamboo/bamboo_c.wav\",\n \"bamboo_f\": \"idiophone/marimba-bamboo/bamboo_f.wav\",\n \"bamboo_g\": \"idiophone/marimba-bamboo/bamboo_g.wav\",\n \"bowl_hi\": \"idiophone/singing-bowl/bowl_hi.wav\",\n \"bowl_lo\": \"idiophone/singing-bowl/bowl_lo.wav\",\n \"bowl_mid\": \"idiophone/singing-bowl/bowl_mid.wav\",\n \"rhodes_8bit\": \"keys/pad/rhodes_8bit.wav\",\n \"piano_a\": \"keys/piano/piano_a.wav\",\n \"piano_b\": \"keys/piano/piano_b.wav\",\n \"piano_c\": \"keys/piano/piano_c.wav\",\n \"piano_d\": \"keys/piano/piano_d.wav\",\n \"piano_e\": \"keys/piano/piano_e.wav\",\n \"piano_f\": \"keys/piano/piano_f.wav\",\n \"piano_g\": \"keys/piano/piano_g.wav\",\n \"amen\": \"loops/breaks/amen.wav\",\n \"amen_alt\": \"loops/breaks/amen_alt.wav\",\n \"amen_break\": \"loops/breaks/amen_break.wav\",\n \"amen_fill\": \"loops/breaks/amen_fill.wav\",\n \"house\": \"loops/breaks/house.wav\",\n \"chimes_l\": \"loops/chimes/chimes_l.wav\",\n \"noise_c\": \"loops/noise/noise_c.wav\",\n \"noise_e\": \"loops/noise/noise_e.wav\",\n \"noise_e_01\": \"loops/noise/noise_e_01.wav\",\n \"noise_mw\": \"loops/noise/noise_mw.wav\",\n \"noise_p\": \"loops/noise/noise_p.wav\",\n \"noise_r\": \"loops/noise/noise_r.wav\",\n \"choir_01\": \"vocal/choir/choir_01.wav\",\n \"choir_02\": \"vocal/choir/choir_02.wav\",\n \"choir_03\": \"vocal/choir/choir_03.wav\",\n \"choir_o\": \"vocal/choir/choir_o.wav\",\n \"wiper\": \"loops/foley/car/wiper.wav\",\n \"wiper_out\": \"loops/foley/car/wiper_out.wav\",\n \"wood_l\": \"loops/foley/wood/wood_l.wav\",\n \"wood_l_01\": \"loops/foley/wood/wood_l_01.wav\",\n \"violin_a\": \"string/bowed/violin/violin_a.wav\",\n \"violin_b\": \"string/bowed/violin/violin_b.wav\",\n \"violin_c\": \"string/bowed/violin/violin_c.wav\",\n \"violin_d\": \"string/bowed/violin/violin_d.wav\",\n \"violin_e\": \"string/bowed/violin/violin_e.wav\",\n \"violin_f\": \"string/bowed/violin/violin_f.wav\",\n \"violin_g\": \"string/bowed/violin/violin_g.wav\",\n \"harp_down\": \"string/plucked/harp/harp_down.wav\",\n \"harp_up\": \"string/plucked/harp/harp_up.wav\",\n \"pluck_a\": \"string/plucked/violin/pluck_a.wav\",\n \"pluck_b\": \"string/plucked/violin/pluck_b.wav\",\n \"pluck_c\": \"string/plucked/violin/pluck_c.wav\",\n \"pluck_d\": \"string/plucked/violin/pluck_d.wav\",\n \"pluck_e\": \"string/plucked/violin/pluck_e.wav\",\n \"pluck_f\": \"string/plucked/violin/pluck_f.wav\",\n \"pluck_g\": \"string/plucked/violin/pluck_g.wav\"\n}\n");
|
|
17427
17467
|
|
|
@@ -17429,23 +17469,68 @@ class Mercury extends MercuryInterpreter {
|
|
|
17429
17469
|
// add the buffers via function
|
|
17430
17470
|
// this.addBuffers(['http://localhost:8080/mercury-engine/src/data/samples.json'])
|
|
17431
17471
|
|
|
17472
|
+
// setting parameters
|
|
17473
|
+
this.bpm;
|
|
17474
|
+
this.volume;
|
|
17475
|
+
this.lowPass;
|
|
17476
|
+
this.highPass;
|
|
17477
|
+
|
|
17432
17478
|
// effects on main output for Tone
|
|
17433
17479
|
this.gain = new Tone.Gain(1);
|
|
17434
|
-
this.
|
|
17435
|
-
this.
|
|
17436
|
-
Tone.Destination.chain(this.
|
|
17480
|
+
this.lowPassF = new Tone.Filter(18000, 'lowpass');
|
|
17481
|
+
this.highPassF = new Tone.Filter(5, 'highpass');
|
|
17482
|
+
Tone.Destination.chain(this.lowPassF, this.highPassF, this.gain);
|
|
17437
17483
|
|
|
17438
17484
|
// a recorder for the sound
|
|
17439
17485
|
this.recorder = new Tone.Recorder({ mimeType: 'audio/webm' });
|
|
17440
17486
|
this.gain.connect(this.recorder);
|
|
17441
17487
|
|
|
17488
|
+
// default settings
|
|
17489
|
+
this.setBPM(100);
|
|
17490
|
+
this.setVolume(1);
|
|
17491
|
+
this.setHighPass(18000);
|
|
17492
|
+
this.setLowPass(5);
|
|
17493
|
+
this.setCrossFade(250);
|
|
17494
|
+
|
|
17495
|
+
// load the buffers from the github
|
|
17442
17496
|
this.buffers = new Tone.ToneAudioBuffers({
|
|
17443
17497
|
urls: this.samples,
|
|
17444
17498
|
baseUrl: "https://raw.githubusercontent.com/tmhglnd/mercury-playground/main/public/assets/samples/",
|
|
17445
17499
|
onload: () => {
|
|
17446
17500
|
console.log('Samples loaded', this.buffers);
|
|
17447
17501
|
// executes a callback from the class constructor
|
|
17448
|
-
if
|
|
17502
|
+
// if a callback is provided
|
|
17503
|
+
if (onload){ onload(); }
|
|
17504
|
+
}
|
|
17505
|
+
});
|
|
17506
|
+
|
|
17507
|
+
// the midi status, inputs and outputs
|
|
17508
|
+
this.midi = { enabled: false, inputs: [], outputs: [] };
|
|
17509
|
+
|
|
17510
|
+
// WebMIDI Setup if supported by the browser
|
|
17511
|
+
// Else `midi` not supported in the Mercury code
|
|
17512
|
+
WebMidi.enable((error) => {
|
|
17513
|
+
if (error) {
|
|
17514
|
+
console.error(`WebMIDI not enabled: ${error}`);
|
|
17515
|
+
} else {
|
|
17516
|
+
this.midi.enabled = true;
|
|
17517
|
+
|
|
17518
|
+
console.log(`WebMIDI enabled`);
|
|
17519
|
+
if (WebMidi.inputs.length < 1){
|
|
17520
|
+
console.log(`No MIDI device detected`);
|
|
17521
|
+
} else {
|
|
17522
|
+
this.midi.inputs = WebMidi.inputs;
|
|
17523
|
+
this.midi.outputs = WebMidi.outputs;
|
|
17524
|
+
|
|
17525
|
+
WebMidi.inputs.forEach((device, index) => {
|
|
17526
|
+
console.log(`in ${index}: ${device.name}`);
|
|
17527
|
+
});
|
|
17528
|
+
WebMidi.outputs.forEach((device, index) => {
|
|
17529
|
+
console.log(`out ${index}: ${device.name}`);
|
|
17530
|
+
});
|
|
17531
|
+
}
|
|
17532
|
+
// execute a callback when midi is loaded if provided
|
|
17533
|
+
if (onmidi) { onmidi(); }
|
|
17449
17534
|
}
|
|
17450
17535
|
});
|
|
17451
17536
|
}
|
|
@@ -17480,7 +17565,8 @@ class Mercury extends MercuryInterpreter {
|
|
|
17480
17565
|
}
|
|
17481
17566
|
|
|
17482
17567
|
// set the bpm and optionally ramp in milliseconds
|
|
17483
|
-
|
|
17568
|
+
setBPM(bpm, ramp=0) {
|
|
17569
|
+
this.bpm = bpm;
|
|
17484
17570
|
if (ramp > 0){
|
|
17485
17571
|
Tone.Transport.bpm.rampTo(bpm, ramp / 1000);
|
|
17486
17572
|
} else {
|
|
@@ -17496,12 +17582,12 @@ class Mercury extends MercuryInterpreter {
|
|
|
17496
17582
|
// generate a random bpm between 75 and 150
|
|
17497
17583
|
randomBPM(){
|
|
17498
17584
|
let bpm = Math.floor(Math.random() * 75) + 75.0;
|
|
17499
|
-
this.
|
|
17585
|
+
this.setBPM(bpm);
|
|
17500
17586
|
}
|
|
17501
17587
|
|
|
17502
17588
|
// add files to the buffer from a single File Link
|
|
17503
17589
|
// an array or file paths, or a json of { name:file, ... }
|
|
17504
|
-
async
|
|
17590
|
+
async addBuffers(uploads){
|
|
17505
17591
|
// for every file from uploads
|
|
17506
17592
|
uploads.forEach((f) => {
|
|
17507
17593
|
let n = f;
|
|
@@ -17542,7 +17628,7 @@ class Mercury extends MercuryInterpreter {
|
|
|
17542
17628
|
|
|
17543
17629
|
// add to ToneAudioBuffers
|
|
17544
17630
|
this.buffers.add(n, url, () => {
|
|
17545
|
-
|
|
17631
|
+
Util.log(`sound added as: ${n}`);
|
|
17546
17632
|
URL.revokeObjectURL(url);
|
|
17547
17633
|
|
|
17548
17634
|
// also add soundfiles to menu for easy selection
|
|
@@ -17551,7 +17637,7 @@ class Mercury extends MercuryInterpreter {
|
|
|
17551
17637
|
// o.value = o.innerHTML = n;
|
|
17552
17638
|
// m.appendChild(o);
|
|
17553
17639
|
}, (e) => {
|
|
17554
|
-
|
|
17640
|
+
Util.log(`error adding sound from: ${n}`);
|
|
17555
17641
|
});
|
|
17556
17642
|
}
|
|
17557
17643
|
|
|
@@ -17589,24 +17675,27 @@ class Mercury extends MercuryInterpreter {
|
|
|
17589
17675
|
|
|
17590
17676
|
// set lowpass frequency cutoff and ramptime
|
|
17591
17677
|
setLowPass(f, t=0){
|
|
17678
|
+
this.lowPass = f;
|
|
17592
17679
|
if (t > 0){
|
|
17593
|
-
this.
|
|
17680
|
+
this.lowPassF.frequency.rampTo(f, t/1000, Tone.now());
|
|
17594
17681
|
} else {
|
|
17595
|
-
this.
|
|
17682
|
+
this.lowPassF.frequency.setValueAtTime(f, Tone.now());
|
|
17596
17683
|
}
|
|
17597
17684
|
}
|
|
17598
17685
|
|
|
17599
17686
|
// set highpass frequency cutoff and ramptime
|
|
17600
17687
|
setHighPass(f, t=0){
|
|
17688
|
+
this.highPass = f;
|
|
17601
17689
|
if (t > 0){
|
|
17602
|
-
this.
|
|
17690
|
+
this.highPassF.frequency.rampTo(f, t/1000, Tone.now());
|
|
17603
17691
|
} else {
|
|
17604
|
-
this.
|
|
17692
|
+
this.highPassF.frequency.setValueAtTime(f, Tone.now());
|
|
17605
17693
|
}
|
|
17606
17694
|
}
|
|
17607
17695
|
|
|
17608
17696
|
// set volume in floatingpoint and ramptime
|
|
17609
17697
|
setVolume(v, t=0){
|
|
17698
|
+
this.volume = v;
|
|
17610
17699
|
if (t > 0){
|
|
17611
17700
|
this.gain.gain.rampTo(v, t/1000, Tone.now());
|
|
17612
17701
|
} else {
|
|
@@ -17614,6 +17703,11 @@ class Mercury extends MercuryInterpreter {
|
|
|
17614
17703
|
}
|
|
17615
17704
|
}
|
|
17616
17705
|
|
|
17706
|
+
// get the volume as float between 0-1
|
|
17707
|
+
getVolume(){
|
|
17708
|
+
return this.gain.gain.value;
|
|
17709
|
+
}
|
|
17710
|
+
|
|
17617
17711
|
// a recording function
|
|
17618
17712
|
// default starts recording, a false/0 stops recording
|
|
17619
17713
|
// optionally add a filename to the downloading file
|
|
@@ -17633,7 +17727,7 @@ class Mercury extends MercuryInterpreter {
|
|
|
17633
17727
|
anchor.click();
|
|
17634
17728
|
}
|
|
17635
17729
|
} catch(e) {
|
|
17636
|
-
|
|
17730
|
+
Util.log(`Error starting/stopping recording ${e}`);
|
|
17637
17731
|
}
|
|
17638
17732
|
}
|
|
17639
17733
|
|
|
@@ -17643,5 +17737,5 @@ class Mercury extends MercuryInterpreter {
|
|
|
17643
17737
|
}
|
|
17644
17738
|
}
|
|
17645
17739
|
module.exports = { Mercury };
|
|
17646
|
-
},{"./interpreter":68,"tone":44}]},{},[69])(69)
|
|
17740
|
+
},{"./core/Util.js":66,"./interpreter":68,"tone":44,"webmidi":55}]},{},[69])(69)
|
|
17647
17741
|
});
|