-
Notifications
You must be signed in to change notification settings - Fork 6
/
createMuse.js
109 lines (76 loc) · 2.4 KB
/
createMuse.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
import { getLetters } from "./letters.js";
import { parse, tokenize } from "./parser.js";
import { compile as compileTemp } from "./compile.js";
const sleep = m => new Promise(r => setTimeout(r, m));
const AudioContext = window.AudioContext || window.webkitAudioContext;
const audioCtx = new AudioContext();
const museTag = (strs, ...vals) => {
let result = "";
let refs = {};
strs.forEach((str, i) => {
if (i >= vals.length) result = result + str;
else {
const val = vals[i];
if (typeof val === "function") {
let tempName = `$f${i}`;
refs[tempName] = val;
result = result + str + tempName;
} else if (Array.isArray(val)) {
let tempName = `$a${i}`;
refs[tempName] = val;
result = result + str + tempName;
} else if (typeof val === "string" || typeof val === "number") {
result = result + str + val;
} else {
console.error("Unexpected interpolated value:", val);
}
}
})
// console.log(result);
const toks = tokenize(result);
// console.log(toks);
const [ ast, remainder ] = parse(toks);
// console.log(ast);
const compiled = compileTemp(ast, refs);
// console.log(compiled);
return compiled;
}
async function playHelper(that, args) {
const arr = museTag(...args);
that.playing = true;
for (let i = 0; i < arr.length; i++) {
if (that.playing === false) continue;
let [ symbol, beats ] = arr[i];
if (window.IS_MUSE_EDITOR) dispatch("ADD_PLAYED", { symbol });
if (symbol === ";") await sleep(1000/that.bpm*60*beats);
else if (symbol in that.samples) that.samples[symbol](60*1000/that.bpm*beats, audioCtx);
}
that.playing = false;
}
export class Muse {
constructor(ops = {}) {
this.bpm = ops.bpm ?? 110;
this.volume = ops.volume ?? 100; // TODO
const type = ops.type ?? "sine";
const synthOptions = { type, volume: this.volume };
const samples = ops.samples ?? {};
this.samples = { ...samples, ...getLetters(synthOptions) };
this.playing = false;
}
play() {
playHelper(this, arguments)
return this; // arr?
}
stop() {
this.playing = false;
}
}
const createMuse = (samples = {}) => (ops = {}) => {
ops.samples = samples;
const newMuse = new Muse(ops);
if (window.IS_MUSE_EDITOR) dispatch("ADD_ACTIVE_MUSE", { newMuse })
return newMuse;
}
const length = x => x.reduce((acc, cur) => acc + (cur[0] == ";" ? cur[1] : 0), 0)
const compile = (...args) => museTag(...args);
export { createMuse, compile, length };