utkucoban commited on
Commit
4c51fc1
·
verified ·
1 Parent(s): 0006fb5

Upload 4 files

Browse files
Files changed (3) hide show
  1. app.js +9 -3
  2. index.html +1 -0
  3. worker.js +26 -98
app.js CHANGED
@@ -123,6 +123,7 @@ const midiBpmModeGroup = document.querySelector("#midiBpmModeGroup");
123
  const midiBpmModeButtons = midiBpmModeGroup ? midiBpmModeGroup.querySelectorAll(".toggle-btn") : [];
124
 
125
  let midiSeedActive = false;
 
126
  let midiBpmMode = "lock";
127
  let midiTokens = [];
128
  let midiStartBar = 0;
@@ -581,8 +582,6 @@ const pianoSamples = {
581
  C8: "C8.mp3",
582
  };
583
 
584
- const abcNotePattern = /^(?:\^\^|__|\^|_|=)?[A-Ga-g][,']*$/;
585
-
586
  // Status Handler
587
  function setStatus(message, state = "idle") {
588
  if (appStatusEl) appStatusEl.textContent = message;
@@ -781,7 +780,8 @@ async function start() {
781
  midiSeedActive: midiSeedActive,
782
  midiTokens: midiSeedActive ? midiTokens : [],
783
  midiStartBar: midiStartBar,
784
- midiBpmMode: midiBpmMode
 
785
  });
786
  });
787
 
@@ -1487,9 +1487,15 @@ toggleButtons.forEach(btn => {
1487
  if (value === "midi") {
1488
  midiSeedActive = true;
1489
  midiSeedControls.style.display = "block";
 
 
 
 
 
1490
  } else {
1491
  midiSeedActive = false;
1492
  midiSeedControls.style.display = "none";
 
1493
  }
1494
  });
1495
  });
 
123
  const midiBpmModeButtons = midiBpmModeGroup ? midiBpmModeGroup.querySelectorAll(".toggle-btn") : [];
124
 
125
  let midiSeedActive = false;
126
+ let bachSeedActive = false;
127
  let midiBpmMode = "lock";
128
  let midiTokens = [];
129
  let midiStartBar = 0;
 
582
  C8: "C8.mp3",
583
  };
584
 
 
 
585
  // Status Handler
586
  function setStatus(message, state = "idle") {
587
  if (appStatusEl) appStatusEl.textContent = message;
 
780
  midiSeedActive: midiSeedActive,
781
  midiTokens: midiSeedActive ? midiTokens : [],
782
  midiStartBar: midiStartBar,
783
+ midiBpmMode: midiBpmMode,
784
+ bachSeedActive: bachSeedActive
785
  });
786
  });
787
 
 
1487
  if (value === "midi") {
1488
  midiSeedActive = true;
1489
  midiSeedControls.style.display = "block";
1490
+ bachSeedActive = false;
1491
+ } else if (value === "bach") {
1492
+ midiSeedActive = false;
1493
+ midiSeedControls.style.display = "none";
1494
+ bachSeedActive = true;
1495
  } else {
1496
  midiSeedActive = false;
1497
  midiSeedControls.style.display = "none";
1498
+ bachSeedActive = false;
1499
  }
1500
  });
1501
  });
index.html CHANGED
@@ -121,6 +121,7 @@
121
  <div class="toggle-group" id="seedSourceGroup">
122
  <button type="button" class="toggle-btn active" data-value="default">Start from Blank</button>
123
  <button type="button" class="toggle-btn" data-value="midi">Start from MIDI</button>
 
124
  </div>
125
  </div>
126
  </div>
 
121
  <div class="toggle-group" id="seedSourceGroup">
122
  <button type="button" class="toggle-btn active" data-value="default">Start from Blank</button>
123
  <button type="button" class="toggle-btn" data-value="midi">Start from MIDI</button>
124
+ <button type="button" class="toggle-btn" data-value="bach">Bach Seed Test</button>
125
  </div>
126
  </div>
127
  </div>
worker.js CHANGED
@@ -10,7 +10,6 @@ let session = null;
10
  let stoi = null;
11
  let itos = null;
12
  let vocabSize = 0;
13
- let activeTokenizer = "abc";
14
 
15
  let h = null;
16
  let c = null;
@@ -29,6 +28,7 @@ let midiBpmMode = "lock";
29
 
30
  // Seeding settings
31
  let midiSeedActive = false;
 
32
  let midiTokens = [];
33
  let midiStartBar = 0;
34
  let isWarmingUp = false;
@@ -37,8 +37,7 @@ let isWarmingUp = false;
37
  let tempQueue = [];
38
  let parser = null;
39
 
40
- // MIDI to Pitch Name helpers
41
- const abcNotePattern = /^(?:\^\^|__|\^|_|=)?[A-Ga-g][,']*$/;
42
 
43
  function tokenId(token) {
44
  return stoi?.[token] ?? null;
@@ -119,21 +118,7 @@ function sampleFromLogits(logits) {
119
  }
120
 
121
  // Duration converters
122
- function durationToSecondsFromAbc(duration) {
123
- let eighths = 1;
124
- if (duration) {
125
- if (duration === "/") eighths = 0.5;
126
- else if (duration.startsWith("/")) eighths = 1 / Number(duration.slice(1));
127
- else if (duration.includes("/")) {
128
- const [a, b] = duration.split("/").map(Number);
129
- eighths = a / b;
130
- } else {
131
- eighths = Number(duration);
132
- }
133
- }
134
- const quarterSeconds = 60 / currentBpm;
135
- return Math.max(0.08, eighths * quarterSeconds * 0.5);
136
- }
137
 
138
  function durationToSecondsFromEventSteps(steps, grid) {
139
  const quarterSeconds = 60 / currentBpm;
@@ -145,17 +130,7 @@ function midiToTonePitch(midi) {
145
  return `${names[((midi % 12) + 12) % 12]}${Math.floor(midi / 12) - 1}`;
146
  }
147
 
148
- function abcToTonePitch(token) {
149
- const match = token.match(/^(\^\^|__|\^|_|=)?([A-Ga-g])([,']*)$/);
150
- if (!match) return null;
151
- const accidental = match[1] || "";
152
- const step = match[2];
153
- const marks = match[3] || "";
154
- let octave = step === step.toLowerCase() ? 5 : 4;
155
- for (const mark of marks) octave += mark === "'" ? 1 : -1;
156
- const accidentalText = accidental === "^^" ? "##" : accidental === "__" ? "bb" : accidental === "^" ? "#" : accidental === "_" ? "b" : "";
157
- return `${step.toUpperCase()}${accidentalText}${octave}`;
158
- }
159
 
160
  function pushEvent(event) {
161
  if (isWarmingUp) return; // Discard prompt history events
@@ -178,68 +153,7 @@ function getTokensUpToBar(tokens, targetBar) {
178
  return sliced;
179
  }
180
 
181
- // ABC Parser
182
- function makeAbcParser() {
183
- return {
184
- pending: null,
185
- chord: null,
186
- reset() {
187
- this.pending = null;
188
- this.chord = null;
189
- },
190
- feed(token) {
191
- if (token === "Q:") {
192
- this.pending = { type: "tempoHeader" };
193
- return;
194
- }
195
- if (this.pending?.type === "tempoHeader") {
196
- const bpm = Number(String(token).split("=").pop());
197
- if (Number.isFinite(bpm) && bpm >= 40 && bpm <= 220) {
198
- if (!midiSeedActive || isWarmingUp || midiBpmMode === "model") {
199
- currentBpm = bpm;
200
- self.postMessage({ action: "tempo", bpm: bpm });
201
- }
202
- }
203
- this.pending = null;
204
- return;
205
- }
206
- if (token === "[") {
207
- this.chord = [];
208
- this.pending = null;
209
- return;
210
- }
211
- if (this.chord) {
212
- if (token === "]") {
213
- this.pending = { type: "chord", notes: this.chord.map(abcToTonePitch).filter(Boolean) };
214
- this.chord = null;
215
- return;
216
- }
217
- if (abcNotePattern.test(token)) this.chord.push(token);
218
- return;
219
- }
220
- if (token === "z") {
221
- this.pending = { type: "rest" };
222
- return;
223
- }
224
- if (abcNotePattern.test(token)) {
225
- this.pending = { type: "note", note: abcToTonePitch(token) };
226
- return;
227
- }
228
- if (token.startsWith("DUR:") && this.pending) {
229
- this.emitPending(token.slice(4));
230
- return;
231
- }
232
- if (this.pending && (token === "|" || token === "<NL>" || token === "<EOP>")) this.emitPending(null);
233
- },
234
- emitPending(durationToken) {
235
- const duration = durationToSecondsFromAbc(durationToken);
236
- if (this.pending.type === "rest") pushEvent({ type: "rest", duration });
237
- if (this.pending.type === "note" && this.pending.note) pushEvent({ type: "note", notes: [this.pending.note], duration, advance: duration });
238
- if (this.pending.type === "chord" && this.pending.notes.length) pushEvent({ type: "note", notes: this.pending.notes.slice(0, 8), duration, advance: duration });
239
- this.pending = null;
240
- },
241
- };
242
- }
243
 
244
  // Event Parser
245
  function makeEventParser() {
@@ -346,18 +260,32 @@ function makeEventParser() {
346
  }
347
 
348
  function makeParser() {
349
- return activeTokenizer === "giantmidi_event" ? makeEventParser() : makeAbcParser();
350
  }
351
 
352
  async function warmPrompt() {
353
  h = zeroState();
354
  c = zeroState();
355
 
356
- const allTokensStr = midiSeedActive && midiTokens.length > 0
357
- ? getTokensUpToBar(midiTokens, midiStartBar)
358
- : (activeTokenizer === "giantmidi_event"
359
- ? ["BOS", "BPM_120", "GRID_64", "BAR", "POS_0"]
360
- : ["X:", "1", "<NL>", "T:", "piece", "<NL>", "M:", "4/4", "<NL>", "L:", "1/8", "<NL>", "Q:", "1/4=120", "<NL>", "K:", "C", "<NL>"]);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
361
 
362
  isWarmingUp = true;
363
 
@@ -406,7 +334,6 @@ self.onmessage = async function (e) {
406
  stoi = data.vocab.stoi;
407
  itos = Object.fromEntries(Object.entries(data.vocab.itos).map(([key, value]) => [Number(key), value]));
408
  vocabSize = data.vocab.vocab_size;
409
- activeTokenizer = data.vocab.tokenizer || "abc";
410
 
411
  session = await ort.InferenceSession.create(data.modelBuffer, {
412
  executionProviders: ["wasm"],
@@ -430,6 +357,7 @@ self.onmessage = async function (e) {
430
  midiTokens = data.midiTokens;
431
  midiStartBar = data.midiStartBar;
432
  midiBpmMode = data.midiBpmMode || "lock";
 
433
 
434
  parser = makeParser();
435
  parser.reset();
 
10
  let stoi = null;
11
  let itos = null;
12
  let vocabSize = 0;
 
13
 
14
  let h = null;
15
  let c = null;
 
28
 
29
  // Seeding settings
30
  let midiSeedActive = false;
31
+ let bachSeedActive = false;
32
  let midiTokens = [];
33
  let midiStartBar = 0;
34
  let isWarmingUp = false;
 
37
  let tempQueue = [];
38
  let parser = null;
39
 
40
+
 
41
 
42
  function tokenId(token) {
43
  return stoi?.[token] ?? null;
 
118
  }
119
 
120
  // Duration converters
121
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
122
 
123
  function durationToSecondsFromEventSteps(steps, grid) {
124
  const quarterSeconds = 60 / currentBpm;
 
130
  return `${names[((midi % 12) + 12) % 12]}${Math.floor(midi / 12) - 1}`;
131
  }
132
 
133
+
 
 
 
 
 
 
 
 
 
 
134
 
135
  function pushEvent(event) {
136
  if (isWarmingUp) return; // Discard prompt history events
 
153
  return sliced;
154
  }
155
 
156
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
157
 
158
  // Event Parser
159
  function makeEventParser() {
 
260
  }
261
 
262
  function makeParser() {
263
+ return makeEventParser();
264
  }
265
 
266
  async function warmPrompt() {
267
  h = zeroState();
268
  c = zeroState();
269
 
270
+ let allTokensStr;
271
+ if (midiSeedActive && midiTokens.length > 0) {
272
+ allTokensStr = getTokensUpToBar(midiTokens, midiStartBar);
273
+ } else if (bachSeedActive) {
274
+ allTokensStr = [
275
+ "BOS", "BPM_100", "GRID_64",
276
+ "BAR",
277
+ "POS_0", "NOTE_81", "DUR_4", "VEL_6",
278
+ "POS_4", "NOTE_79", "DUR_4", "VEL_6",
279
+ "POS_8", "NOTE_77", "DUR_4", "VEL_6",
280
+ "POS_12", "NOTE_76", "DUR_4", "VEL_6",
281
+ "POS_16", "NOTE_74", "DUR_4", "VEL_6",
282
+ "POS_20", "NOTE_73", "DUR_4", "VEL_6",
283
+ "POS_24", "NOTE_74", "DUR_16", "VEL_6",
284
+ "BAR"
285
+ ];
286
+ } else {
287
+ allTokensStr = ["BOS", "BPM_120", "GRID_64", "BAR", "POS_0"];
288
+ }
289
 
290
  isWarmingUp = true;
291
 
 
334
  stoi = data.vocab.stoi;
335
  itos = Object.fromEntries(Object.entries(data.vocab.itos).map(([key, value]) => [Number(key), value]));
336
  vocabSize = data.vocab.vocab_size;
 
337
 
338
  session = await ort.InferenceSession.create(data.modelBuffer, {
339
  executionProviders: ["wasm"],
 
357
  midiTokens = data.midiTokens;
358
  midiStartBar = data.midiStartBar;
359
  midiBpmMode = data.midiBpmMode || "lock";
360
+ bachSeedActive = data.bachSeedActive || false;
361
 
362
  parser = makeParser();
363
  parser.reset();