@onjmin/dtm 0.1.30 → 0.1.31
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/dist/index.d.mts +6 -2
- package/dist/index.d.ts +6 -2
- package/dist/index.js +156 -40
- package/dist/index.mjs +153 -40
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -1118,7 +1118,7 @@ declare const parseMmlMeta: (mml: string) => MmlMeta;
|
|
|
1118
1118
|
/** MMLからトップレベル宣言を取り除く(ノート解析が誤解釈しないように) */
|
|
1119
1119
|
declare const stripMmlMeta: (mml: string) => string;
|
|
1120
1120
|
/** メタ情報を `#inst=… #drum=… #volume=… #mode=…` のMML宣言文字列へ直列化する(空なら空文字) */
|
|
1121
|
-
declare const formatMmlMeta: (meta: MmlMeta) => string;
|
|
1121
|
+
declare const formatMmlMeta: (meta: MmlMeta, space?: string) => string;
|
|
1122
1122
|
type MMLNotePlacement = {
|
|
1123
1123
|
/** 0:melody 1:submelody 2:bass 3:chord */
|
|
1124
1124
|
trackIndex: number;
|
|
@@ -1226,6 +1226,8 @@ type MmlPlayerInstance = {
|
|
|
1226
1226
|
isPlaying: () => boolean;
|
|
1227
1227
|
destroy: () => void;
|
|
1228
1228
|
};
|
|
1229
|
+
declare const encodeMml: (mml: string) => Promise<string>;
|
|
1230
|
+
declare const decodeMml: (payload: string) => Promise<string>;
|
|
1229
1231
|
/**
|
|
1230
1232
|
* MML文字列を再生専用ビューとして target にマウントする。
|
|
1231
1233
|
*/
|
|
@@ -1612,4 +1614,6 @@ declare const DAW_CSS = "\n@font-face {\n font-family: 'k8x12';\n src: url('ht
|
|
|
1612
1614
|
*/
|
|
1613
1615
|
declare const injectStyles: (doc?: Document) => void;
|
|
1614
1616
|
|
|
1615
|
-
|
|
1617
|
+
declare const VOICE_IMAGES: Record<string, string>;
|
|
1618
|
+
|
|
1619
|
+
export { type AddNoteOptions, type ApplyChordOptions, type ChordPatternType, type ChordPlacement, type ConsumedSyllable, type CoreEventHandlers, DAW_CSS, DEFAULT_BPM, DEFAULT_GATE, DEFAULT_PAN, DEFAULT_PLAYBACK_VELOCITY, DEFAULT_STEPS_PER_BAR, DEFAULT_VELOCITY, DEFAULT_VOCAL_VOLUME, DRUM_FONT, DRUM_KEYS, DRUM_PATTERNS, type DawInstance, type DawMode, type DawOptions, type DawViewState, type DrumPattern, type DtmStudio, type DtmStudioEngines, type DtmStudioOptions, type ExportMidiOptions, INSTRUMENT_PRESETS, type InstrumentPreset, KOE_BASE_URL, KOE_VOICEBANKS, KOE_VOICEBANK_LABELS, KOE_VOICEBANK_TERMS, type KoeVoiceOptions, LinkedList, type LoopConfig, type LoopPoint, type LyricSyllable, type LyricTrack, type LyricsConductor, MAX_VOCAL_VOLUME, MMLCore, type MMLDisplayToken, type MMLNotePlacement, MML_END_MARKER, type MidiExtraction, type MidiNotePlacement, type MidiTrackAnalysis, type MmlMeta, type MmlPlayback, type MmlPlayerInstance, type MmlPlayerOptions, type ModeSwitchInstance, type ModeSwitchOptions, type MountEditorOptions, type MountPlayerOptions, type Note, PITCH_MAP, PREWARM_NOTES, type ParseMMLOptions, type ParseMidiFn, type ParsedMML, type PianoRollInstance, type PianoRollOptions, type PitchToken, type PlayDrumEvent, type PlayMmlOptions, type PlayNoteEvent, type PlaySingingMmlOptions, type PlaybackCue, type PlaybackState, type PresetSelectInstance, type PresetSelectOptions, type PreviewSoundCallback, type RenderConfig, type Sequencer, type SequencerOptions, type SequencerTrack, type SingingVoices, type SingingVoicesOptions, type StreamPlaybackOptions, type StreamVoiceNote, type StreamVoiceTrack, type Synth, TRACKS_ADVANCED, TRACKS_SIMPLE, type ToolMode, type TrackConfig, VOICE_IMAGES, VOICE_IMAGE_KEY, type VoiceModel, type VoiceRegistry, analyzeMidiTracks, applyHarmonicFilter, applyMonophonic, buildChordPlacements, buildNameToKeyMapping, collectPitchTokens, createAudioContext, createDtmStudio, createKlattVoice, createKoeVoice, createLyricsConductor, createPianoRoll, createSequencer, createSingingVoices, createSynth, createVoiceRegistry, decodeMml, decomposeToMonophonic, drawGrid, drawHeader, drawKeyboard, drawNotes, drawSelectedNotes, drawSelectionRect, encodeMml, exportMIDI, extractMidiPlacements, extractMidiPlacementsByTrack, fetchSoundFontList, formatMmlMeta, freqFromPitch, generateRandomPattern, getDrawOffset, getGridCanvas, getGridContext, getGridPosition, getHeaderCanvas, getMidiBPM, getRenderConfig, getXY, icon, init, injectStyles, isChordHeavyTrack, koeUrl, mountDAW, mountMmlPlayer, normalizeLyrics, onClick, panToStereo, parseLyrics, parseMML, parseMmlMeta, playMML, playSingingMML, setDrawOffset, shiftNotes, stripLyrics, stripMmlMeta, vocalVolumeToGain };
|
package/dist/index.d.ts
CHANGED
|
@@ -1118,7 +1118,7 @@ declare const parseMmlMeta: (mml: string) => MmlMeta;
|
|
|
1118
1118
|
/** MMLからトップレベル宣言を取り除く(ノート解析が誤解釈しないように) */
|
|
1119
1119
|
declare const stripMmlMeta: (mml: string) => string;
|
|
1120
1120
|
/** メタ情報を `#inst=… #drum=… #volume=… #mode=…` のMML宣言文字列へ直列化する(空なら空文字) */
|
|
1121
|
-
declare const formatMmlMeta: (meta: MmlMeta) => string;
|
|
1121
|
+
declare const formatMmlMeta: (meta: MmlMeta, space?: string) => string;
|
|
1122
1122
|
type MMLNotePlacement = {
|
|
1123
1123
|
/** 0:melody 1:submelody 2:bass 3:chord */
|
|
1124
1124
|
trackIndex: number;
|
|
@@ -1226,6 +1226,8 @@ type MmlPlayerInstance = {
|
|
|
1226
1226
|
isPlaying: () => boolean;
|
|
1227
1227
|
destroy: () => void;
|
|
1228
1228
|
};
|
|
1229
|
+
declare const encodeMml: (mml: string) => Promise<string>;
|
|
1230
|
+
declare const decodeMml: (payload: string) => Promise<string>;
|
|
1229
1231
|
/**
|
|
1230
1232
|
* MML文字列を再生専用ビューとして target にマウントする。
|
|
1231
1233
|
*/
|
|
@@ -1612,4 +1614,6 @@ declare const DAW_CSS = "\n@font-face {\n font-family: 'k8x12';\n src: url('ht
|
|
|
1612
1614
|
*/
|
|
1613
1615
|
declare const injectStyles: (doc?: Document) => void;
|
|
1614
1616
|
|
|
1615
|
-
|
|
1617
|
+
declare const VOICE_IMAGES: Record<string, string>;
|
|
1618
|
+
|
|
1619
|
+
export { type AddNoteOptions, type ApplyChordOptions, type ChordPatternType, type ChordPlacement, type ConsumedSyllable, type CoreEventHandlers, DAW_CSS, DEFAULT_BPM, DEFAULT_GATE, DEFAULT_PAN, DEFAULT_PLAYBACK_VELOCITY, DEFAULT_STEPS_PER_BAR, DEFAULT_VELOCITY, DEFAULT_VOCAL_VOLUME, DRUM_FONT, DRUM_KEYS, DRUM_PATTERNS, type DawInstance, type DawMode, type DawOptions, type DawViewState, type DrumPattern, type DtmStudio, type DtmStudioEngines, type DtmStudioOptions, type ExportMidiOptions, INSTRUMENT_PRESETS, type InstrumentPreset, KOE_BASE_URL, KOE_VOICEBANKS, KOE_VOICEBANK_LABELS, KOE_VOICEBANK_TERMS, type KoeVoiceOptions, LinkedList, type LoopConfig, type LoopPoint, type LyricSyllable, type LyricTrack, type LyricsConductor, MAX_VOCAL_VOLUME, MMLCore, type MMLDisplayToken, type MMLNotePlacement, MML_END_MARKER, type MidiExtraction, type MidiNotePlacement, type MidiTrackAnalysis, type MmlMeta, type MmlPlayback, type MmlPlayerInstance, type MmlPlayerOptions, type ModeSwitchInstance, type ModeSwitchOptions, type MountEditorOptions, type MountPlayerOptions, type Note, PITCH_MAP, PREWARM_NOTES, type ParseMMLOptions, type ParseMidiFn, type ParsedMML, type PianoRollInstance, type PianoRollOptions, type PitchToken, type PlayDrumEvent, type PlayMmlOptions, type PlayNoteEvent, type PlaySingingMmlOptions, type PlaybackCue, type PlaybackState, type PresetSelectInstance, type PresetSelectOptions, type PreviewSoundCallback, type RenderConfig, type Sequencer, type SequencerOptions, type SequencerTrack, type SingingVoices, type SingingVoicesOptions, type StreamPlaybackOptions, type StreamVoiceNote, type StreamVoiceTrack, type Synth, TRACKS_ADVANCED, TRACKS_SIMPLE, type ToolMode, type TrackConfig, VOICE_IMAGES, VOICE_IMAGE_KEY, type VoiceModel, type VoiceRegistry, analyzeMidiTracks, applyHarmonicFilter, applyMonophonic, buildChordPlacements, buildNameToKeyMapping, collectPitchTokens, createAudioContext, createDtmStudio, createKlattVoice, createKoeVoice, createLyricsConductor, createPianoRoll, createSequencer, createSingingVoices, createSynth, createVoiceRegistry, decodeMml, decomposeToMonophonic, drawGrid, drawHeader, drawKeyboard, drawNotes, drawSelectedNotes, drawSelectionRect, encodeMml, exportMIDI, extractMidiPlacements, extractMidiPlacementsByTrack, fetchSoundFontList, formatMmlMeta, freqFromPitch, generateRandomPattern, getDrawOffset, getGridCanvas, getGridContext, getGridPosition, getHeaderCanvas, getMidiBPM, getRenderConfig, getXY, icon, init, injectStyles, isChordHeavyTrack, koeUrl, mountDAW, mountMmlPlayer, normalizeLyrics, onClick, panToStereo, parseLyrics, parseMML, parseMmlMeta, playMML, playSingingMML, setDrawOffset, shiftNotes, stripLyrics, stripMmlMeta, vocalVolumeToGain };
|
package/dist/index.js
CHANGED
|
@@ -44,6 +44,7 @@ __export(index_exports, {
|
|
|
44
44
|
PREWARM_NOTES: () => PREWARM_NOTES,
|
|
45
45
|
TRACKS_ADVANCED: () => TRACKS_ADVANCED,
|
|
46
46
|
TRACKS_SIMPLE: () => TRACKS_SIMPLE,
|
|
47
|
+
VOICE_IMAGES: () => VOICE_IMAGES,
|
|
47
48
|
VOICE_IMAGE_KEY: () => VOICE_IMAGE_KEY,
|
|
48
49
|
analyzeMidiTracks: () => analyzeMidiTracks,
|
|
49
50
|
applyHarmonicFilter: () => applyHarmonicFilter,
|
|
@@ -61,6 +62,7 @@ __export(index_exports, {
|
|
|
61
62
|
createSingingVoices: () => createSingingVoices,
|
|
62
63
|
createSynth: () => createSynth,
|
|
63
64
|
createVoiceRegistry: () => createVoiceRegistry,
|
|
65
|
+
decodeMml: () => decodeMml,
|
|
64
66
|
decomposeToMonophonic: () => decomposeToMonophonic,
|
|
65
67
|
drawGrid: () => drawGrid,
|
|
66
68
|
drawHeader: () => drawHeader,
|
|
@@ -68,6 +70,7 @@ __export(index_exports, {
|
|
|
68
70
|
drawNotes: () => drawNotes,
|
|
69
71
|
drawSelectedNotes: () => drawSelectedNotes,
|
|
70
72
|
drawSelectionRect: () => drawSelectionRect,
|
|
73
|
+
encodeMml: () => encodeMml,
|
|
71
74
|
exportMIDI: () => exportMIDI,
|
|
72
75
|
extractMidiPlacements: () => extractMidiPlacements,
|
|
73
76
|
extractMidiPlacementsByTrack: () => extractMidiPlacementsByTrack,
|
|
@@ -2163,7 +2166,7 @@ var normalizeLyricLines = (lines) => {
|
|
|
2163
2166
|
}
|
|
2164
2167
|
return { syllables, lineBreaks };
|
|
2165
2168
|
};
|
|
2166
|
-
var LYRIC_LINE = /^@@(\d+)\s
|
|
2169
|
+
var LYRIC_LINE = /^@@(\d+)\s*(.*)$/;
|
|
2167
2170
|
var isLyricContinuation = (seg) => !/^[@#]/.test(seg);
|
|
2168
2171
|
var splitSegments = (mml) => mml.split(/[;\n\r]+/).map((s) => s.trim()).filter((s) => s.length > 0);
|
|
2169
2172
|
var clamp = (value, lo, hi) => Math.min(hi, Math.max(lo, value));
|
|
@@ -2181,38 +2184,56 @@ var parseLyrics = (mml) => {
|
|
|
2181
2184
|
const m = segments[i].match(LYRIC_LINE);
|
|
2182
2185
|
if (!m) continue;
|
|
2183
2186
|
const trackId = Number.parseInt(m[1], 10);
|
|
2184
|
-
|
|
2185
|
-
const modelToken = tokens.shift() ?? "";
|
|
2187
|
+
let rest = m[2].trim();
|
|
2186
2188
|
let volume = DEFAULT_VOCAL_VOLUME;
|
|
2187
2189
|
let gate = 100;
|
|
2188
2190
|
let pan = 64;
|
|
2189
2191
|
let octave = 0;
|
|
2190
|
-
const
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
const q2 = /^q(\d+)$/.exec(tokens[0]);
|
|
2200
|
-
const p = /^p(\d+)$/.exec(tokens[0]);
|
|
2201
|
-
const o = /^o(-?\d+)$/.exec(tokens[0]);
|
|
2202
|
-
if (v) {
|
|
2203
|
-
volume = clamp(Number.parseInt(v[1], 10), 0, MAX_VOCAL_VOLUME);
|
|
2204
|
-
} else if (q2) {
|
|
2205
|
-
gate = clamp(Number.parseInt(q2[1], 10), 0, 100);
|
|
2206
|
-
} else if (p) {
|
|
2207
|
-
pan = clamp(Number.parseInt(p[1], 10), 0, 127);
|
|
2208
|
-
} else if (o) {
|
|
2209
|
-
octave = clamp(Number.parseInt(o[1], 10), -2, 2);
|
|
2210
|
-
} else {
|
|
2211
|
-
break;
|
|
2192
|
+
const modelMatch = rest.match(
|
|
2193
|
+
/^([a-z_]+?)(?=(?:[vqpo]-?\d)|[^a-z_]|$)(?::(\d+))?/i
|
|
2194
|
+
);
|
|
2195
|
+
let model = "";
|
|
2196
|
+
const metaTokens = [];
|
|
2197
|
+
if (modelMatch) {
|
|
2198
|
+
model = modelMatch[1].toLowerCase();
|
|
2199
|
+
if (modelMatch[2]) {
|
|
2200
|
+
volume = clamp(Number.parseInt(modelMatch[2], 10), 0, MAX_VOCAL_VOLUME);
|
|
2212
2201
|
}
|
|
2213
|
-
metaTokens.push(
|
|
2202
|
+
metaTokens.push(modelMatch[0]);
|
|
2203
|
+
rest = rest.substring(modelMatch[0].length).trim();
|
|
2214
2204
|
}
|
|
2215
|
-
|
|
2205
|
+
while (true) {
|
|
2206
|
+
const vMatch = rest.match(/^v(\d+)/i);
|
|
2207
|
+
if (vMatch) {
|
|
2208
|
+
volume = clamp(Number.parseInt(vMatch[1], 10), 0, MAX_VOCAL_VOLUME);
|
|
2209
|
+
metaTokens.push(vMatch[0]);
|
|
2210
|
+
rest = rest.substring(vMatch[0].length).trim();
|
|
2211
|
+
continue;
|
|
2212
|
+
}
|
|
2213
|
+
const qMatch = rest.match(/^q(\d+)/i);
|
|
2214
|
+
if (qMatch) {
|
|
2215
|
+
gate = clamp(Number.parseInt(qMatch[1], 10), 0, 100);
|
|
2216
|
+
metaTokens.push(qMatch[0]);
|
|
2217
|
+
rest = rest.substring(qMatch[0].length).trim();
|
|
2218
|
+
continue;
|
|
2219
|
+
}
|
|
2220
|
+
const pMatch = rest.match(/^p(\d+)/i);
|
|
2221
|
+
if (pMatch) {
|
|
2222
|
+
pan = clamp(Number.parseInt(pMatch[1], 10), 0, 127);
|
|
2223
|
+
metaTokens.push(pMatch[0]);
|
|
2224
|
+
rest = rest.substring(pMatch[0].length).trim();
|
|
2225
|
+
continue;
|
|
2226
|
+
}
|
|
2227
|
+
const oMatch = rest.match(/^o(-?\d+)/i);
|
|
2228
|
+
if (oMatch) {
|
|
2229
|
+
octave = clamp(Number.parseInt(oMatch[1], 10), -2, 2);
|
|
2230
|
+
metaTokens.push(oMatch[0]);
|
|
2231
|
+
rest = rest.substring(oMatch[0].length).trim();
|
|
2232
|
+
continue;
|
|
2233
|
+
}
|
|
2234
|
+
break;
|
|
2235
|
+
}
|
|
2236
|
+
const lyricLines = [rest];
|
|
2216
2237
|
while (i + 1 < segments.length && isLyricContinuation(segments[i + 1])) {
|
|
2217
2238
|
lyricLines.push(segments[++i]);
|
|
2218
2239
|
}
|
|
@@ -4276,7 +4297,7 @@ var parseMmlMeta = (mml) => {
|
|
|
4276
4297
|
return meta;
|
|
4277
4298
|
};
|
|
4278
4299
|
var stripMmlMeta = (mml) => mml.replace(META_DIRECTIVE, "");
|
|
4279
|
-
var formatMmlMeta = (meta) => {
|
|
4300
|
+
var formatMmlMeta = (meta, space = "") => {
|
|
4280
4301
|
const parts = [];
|
|
4281
4302
|
if (meta.instrument) parts.push(`#inst=${meta.instrument}`);
|
|
4282
4303
|
if (meta.drum) parts.push(`#drum=${meta.drum}`);
|
|
@@ -4284,7 +4305,7 @@ var formatMmlMeta = (meta) => {
|
|
|
4284
4305
|
if (meta.drumVolume !== void 0)
|
|
4285
4306
|
parts.push(`#drumvolume=${meta.drumVolume}`);
|
|
4286
4307
|
if (meta.mode) parts.push(`#mode=${meta.mode}`);
|
|
4287
|
-
return parts.join(
|
|
4308
|
+
return parts.join(space);
|
|
4288
4309
|
};
|
|
4289
4310
|
var parseMML = (mml, options = {}) => {
|
|
4290
4311
|
const stepsPerBar = options.stepsPerBar ?? DEFAULT_STEPS_PER_BAR;
|
|
@@ -6236,6 +6257,9 @@ var customEncode = (str) => {
|
|
|
6236
6257
|
const bytes = [];
|
|
6237
6258
|
for (let i = 0; i < str.length; i++) {
|
|
6238
6259
|
const code = str.charCodeAt(i);
|
|
6260
|
+
if (code === 32) {
|
|
6261
|
+
continue;
|
|
6262
|
+
}
|
|
6239
6263
|
if (code <= 127) {
|
|
6240
6264
|
bytes.push(code);
|
|
6241
6265
|
} else if (code === PROLONGED_MARK) {
|
|
@@ -6267,6 +6291,82 @@ var encodeMml = async (mml) => {
|
|
|
6267
6291
|
}
|
|
6268
6292
|
return `u.${encodeURIComponent(mml)}`;
|
|
6269
6293
|
};
|
|
6294
|
+
var fromBase64Url = (s) => {
|
|
6295
|
+
let normalized = s.replace(/-/g, "+").replace(/_/g, "/");
|
|
6296
|
+
while (normalized.length % 4 !== 0) {
|
|
6297
|
+
normalized += "=";
|
|
6298
|
+
}
|
|
6299
|
+
const bin = atob(normalized);
|
|
6300
|
+
const bytes = new Uint8Array(bin.length);
|
|
6301
|
+
for (let i = 0; i < bin.length; i++) {
|
|
6302
|
+
bytes[i] = bin.charCodeAt(i);
|
|
6303
|
+
}
|
|
6304
|
+
return bytes;
|
|
6305
|
+
};
|
|
6306
|
+
var customDecode = (bytes) => {
|
|
6307
|
+
let str = "";
|
|
6308
|
+
let i = 0;
|
|
6309
|
+
while (i < bytes.length) {
|
|
6310
|
+
const byte = bytes[i];
|
|
6311
|
+
if (byte <= 127) {
|
|
6312
|
+
str += String.fromCharCode(byte);
|
|
6313
|
+
i++;
|
|
6314
|
+
} else if (byte === VALUE_PROLONGED) {
|
|
6315
|
+
str += String.fromCharCode(PROLONGED_MARK);
|
|
6316
|
+
i++;
|
|
6317
|
+
} else if (byte >= 128 && byte <= 222) {
|
|
6318
|
+
str += String.fromCharCode(HIRAGANA_START + (byte - 128));
|
|
6319
|
+
i++;
|
|
6320
|
+
} else if (byte === SHIFT_KATAKANA) {
|
|
6321
|
+
if (i + 1 < bytes.length) {
|
|
6322
|
+
const nextByte = bytes[i + 1];
|
|
6323
|
+
if (nextByte >= 128 && nextByte <= 222) {
|
|
6324
|
+
str += String.fromCharCode(HIRAGANA_START + 96 + (nextByte - 128));
|
|
6325
|
+
}
|
|
6326
|
+
i += 2;
|
|
6327
|
+
} else {
|
|
6328
|
+
i++;
|
|
6329
|
+
}
|
|
6330
|
+
} else {
|
|
6331
|
+
i++;
|
|
6332
|
+
}
|
|
6333
|
+
}
|
|
6334
|
+
return str;
|
|
6335
|
+
};
|
|
6336
|
+
var gunzipCustom = async (bytes) => {
|
|
6337
|
+
const ds = new DecompressionStream("gzip");
|
|
6338
|
+
const writer = ds.writable.getWriter();
|
|
6339
|
+
writer.write(bytes);
|
|
6340
|
+
writer.close();
|
|
6341
|
+
const buf = await new Response(ds.readable).arrayBuffer();
|
|
6342
|
+
return customDecode(new Uint8Array(buf));
|
|
6343
|
+
};
|
|
6344
|
+
var gunzip = async (bytes) => {
|
|
6345
|
+
const ds = new DecompressionStream("gzip");
|
|
6346
|
+
const writer = ds.writable.getWriter();
|
|
6347
|
+
writer.write(bytes);
|
|
6348
|
+
writer.close();
|
|
6349
|
+
const buf = await new Response(ds.readable).arrayBuffer();
|
|
6350
|
+
return new TextDecoder().decode(buf);
|
|
6351
|
+
};
|
|
6352
|
+
var decodeMml = async (payload) => {
|
|
6353
|
+
if (!payload) return "";
|
|
6354
|
+
try {
|
|
6355
|
+
if (payload.startsWith("z.")) {
|
|
6356
|
+
return await gunzipCustom(fromBase64Url(payload.slice(2)));
|
|
6357
|
+
}
|
|
6358
|
+
if (payload.startsWith("g.")) {
|
|
6359
|
+
return await gunzip(fromBase64Url(payload.slice(2)));
|
|
6360
|
+
}
|
|
6361
|
+
if (payload.startsWith("u.")) {
|
|
6362
|
+
return decodeURIComponent(payload.slice(2));
|
|
6363
|
+
}
|
|
6364
|
+
return decodeURIComponent(payload);
|
|
6365
|
+
} catch (e) {
|
|
6366
|
+
console.error("[dtm] failed to decode MML payload", e);
|
|
6367
|
+
return "";
|
|
6368
|
+
}
|
|
6369
|
+
};
|
|
6270
6370
|
var mountMmlPlayer = (target, mml, options = {}) => {
|
|
6271
6371
|
injectStyles(target.ownerDocument ?? document);
|
|
6272
6372
|
const {
|
|
@@ -8434,13 +8534,26 @@ var mountDAW = (target, options = {}) => {
|
|
|
8434
8534
|
const barLimitBars = Number(refs.barLimitSelect.value);
|
|
8435
8535
|
const limitSteps = barLimitBars > 0 ? barLimitBars * renderConfig.stepsPerBar : Infinity;
|
|
8436
8536
|
const clipNotes = (notes) => limitSteps === Infinity ? notes : notes.filter((n) => n.startStep < limitSteps);
|
|
8437
|
-
const
|
|
8438
|
-
|
|
8439
|
-
|
|
8440
|
-
|
|
8441
|
-
|
|
8442
|
-
|
|
8443
|
-
|
|
8537
|
+
const metaLineFull = formatMmlMeta(
|
|
8538
|
+
{
|
|
8539
|
+
instrument: currentInstrument || void 0,
|
|
8540
|
+
drum: currentDrumPattern !== "none" ? currentDrumPattern : void 0,
|
|
8541
|
+
volume: masterVolume,
|
|
8542
|
+
drumVolume,
|
|
8543
|
+
mode
|
|
8544
|
+
},
|
|
8545
|
+
" "
|
|
8546
|
+
);
|
|
8547
|
+
const metaLineMini = formatMmlMeta(
|
|
8548
|
+
{
|
|
8549
|
+
instrument: currentInstrument || void 0,
|
|
8550
|
+
drum: currentDrumPattern !== "none" ? currentDrumPattern : void 0,
|
|
8551
|
+
volume: masterVolume,
|
|
8552
|
+
drumVolume,
|
|
8553
|
+
mode
|
|
8554
|
+
},
|
|
8555
|
+
""
|
|
8556
|
+
);
|
|
8444
8557
|
if (refs.decomposeChordToggle.checked) {
|
|
8445
8558
|
const ignoreHeavy = refs.ignoreChordHeavyToggle.checked;
|
|
8446
8559
|
const targetStates = ignoreHeavy ? trackStates.filter((t) => !isChordHeavyTrack(t.core.getNotes())) : trackStates;
|
|
@@ -8456,8 +8569,8 @@ var mountDAW = (target, options = {}) => {
|
|
|
8456
8569
|
const decomposedMini = monoTracks.map(
|
|
8457
8570
|
(notes, i) => `@${i}${refCore.getMMLFromNotes(notes, bpm, 100).trim().replace(/\s+/g, "")}`
|
|
8458
8571
|
);
|
|
8459
|
-
const full2 = [
|
|
8460
|
-
const minified2 = [
|
|
8572
|
+
const full2 = [metaLineFull, ...decomposedFull, MML_END_MARKER].filter((s) => s.length > 0).join(";\n");
|
|
8573
|
+
const minified2 = [metaLineMini, ...decomposedMini, MML_END_MARKER].filter((s) => s.length > 0).join(";");
|
|
8461
8574
|
return {
|
|
8462
8575
|
full: full2,
|
|
8463
8576
|
minified: minified2,
|
|
@@ -8497,9 +8610,9 @@ var mountDAW = (target, options = {}) => {
|
|
|
8497
8610
|
const head = params ? `${x.model} ${params}` : x.model;
|
|
8498
8611
|
return `@@${x.i} ${head} ${x.text}`;
|
|
8499
8612
|
});
|
|
8500
|
-
const full = [
|
|
8613
|
+
const full = [metaLineFull, ...trackLines, ...lyricLines, MML_END_MARKER].filter((s) => s.length > 0).join(";\n");
|
|
8501
8614
|
const minified = [
|
|
8502
|
-
|
|
8615
|
+
metaLineMini,
|
|
8503
8616
|
...trackLinesMini,
|
|
8504
8617
|
...lyricLines,
|
|
8505
8618
|
MML_END_MARKER
|
|
@@ -10285,6 +10398,7 @@ var createDtmStudio = async (options = {}) => {
|
|
|
10285
10398
|
PREWARM_NOTES,
|
|
10286
10399
|
TRACKS_ADVANCED,
|
|
10287
10400
|
TRACKS_SIMPLE,
|
|
10401
|
+
VOICE_IMAGES,
|
|
10288
10402
|
VOICE_IMAGE_KEY,
|
|
10289
10403
|
analyzeMidiTracks,
|
|
10290
10404
|
applyHarmonicFilter,
|
|
@@ -10302,6 +10416,7 @@ var createDtmStudio = async (options = {}) => {
|
|
|
10302
10416
|
createSingingVoices,
|
|
10303
10417
|
createSynth,
|
|
10304
10418
|
createVoiceRegistry,
|
|
10419
|
+
decodeMml,
|
|
10305
10420
|
decomposeToMonophonic,
|
|
10306
10421
|
drawGrid,
|
|
10307
10422
|
drawHeader,
|
|
@@ -10309,6 +10424,7 @@ var createDtmStudio = async (options = {}) => {
|
|
|
10309
10424
|
drawNotes,
|
|
10310
10425
|
drawSelectedNotes,
|
|
10311
10426
|
drawSelectionRect,
|
|
10427
|
+
encodeMml,
|
|
10312
10428
|
exportMIDI,
|
|
10313
10429
|
extractMidiPlacements,
|
|
10314
10430
|
extractMidiPlacementsByTrack,
|
package/dist/index.mjs
CHANGED
|
@@ -2055,7 +2055,7 @@ var normalizeLyricLines = (lines) => {
|
|
|
2055
2055
|
}
|
|
2056
2056
|
return { syllables, lineBreaks };
|
|
2057
2057
|
};
|
|
2058
|
-
var LYRIC_LINE = /^@@(\d+)\s
|
|
2058
|
+
var LYRIC_LINE = /^@@(\d+)\s*(.*)$/;
|
|
2059
2059
|
var isLyricContinuation = (seg) => !/^[@#]/.test(seg);
|
|
2060
2060
|
var splitSegments = (mml) => mml.split(/[;\n\r]+/).map((s) => s.trim()).filter((s) => s.length > 0);
|
|
2061
2061
|
var clamp = (value, lo, hi) => Math.min(hi, Math.max(lo, value));
|
|
@@ -2073,38 +2073,56 @@ var parseLyrics = (mml) => {
|
|
|
2073
2073
|
const m = segments[i].match(LYRIC_LINE);
|
|
2074
2074
|
if (!m) continue;
|
|
2075
2075
|
const trackId = Number.parseInt(m[1], 10);
|
|
2076
|
-
|
|
2077
|
-
const modelToken = tokens.shift() ?? "";
|
|
2076
|
+
let rest = m[2].trim();
|
|
2078
2077
|
let volume = DEFAULT_VOCAL_VOLUME;
|
|
2079
2078
|
let gate = 100;
|
|
2080
2079
|
let pan = 64;
|
|
2081
2080
|
let octave = 0;
|
|
2082
|
-
const
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
const q2 = /^q(\d+)$/.exec(tokens[0]);
|
|
2092
|
-
const p = /^p(\d+)$/.exec(tokens[0]);
|
|
2093
|
-
const o = /^o(-?\d+)$/.exec(tokens[0]);
|
|
2094
|
-
if (v) {
|
|
2095
|
-
volume = clamp(Number.parseInt(v[1], 10), 0, MAX_VOCAL_VOLUME);
|
|
2096
|
-
} else if (q2) {
|
|
2097
|
-
gate = clamp(Number.parseInt(q2[1], 10), 0, 100);
|
|
2098
|
-
} else if (p) {
|
|
2099
|
-
pan = clamp(Number.parseInt(p[1], 10), 0, 127);
|
|
2100
|
-
} else if (o) {
|
|
2101
|
-
octave = clamp(Number.parseInt(o[1], 10), -2, 2);
|
|
2102
|
-
} else {
|
|
2103
|
-
break;
|
|
2081
|
+
const modelMatch = rest.match(
|
|
2082
|
+
/^([a-z_]+?)(?=(?:[vqpo]-?\d)|[^a-z_]|$)(?::(\d+))?/i
|
|
2083
|
+
);
|
|
2084
|
+
let model = "";
|
|
2085
|
+
const metaTokens = [];
|
|
2086
|
+
if (modelMatch) {
|
|
2087
|
+
model = modelMatch[1].toLowerCase();
|
|
2088
|
+
if (modelMatch[2]) {
|
|
2089
|
+
volume = clamp(Number.parseInt(modelMatch[2], 10), 0, MAX_VOCAL_VOLUME);
|
|
2104
2090
|
}
|
|
2105
|
-
metaTokens.push(
|
|
2091
|
+
metaTokens.push(modelMatch[0]);
|
|
2092
|
+
rest = rest.substring(modelMatch[0].length).trim();
|
|
2106
2093
|
}
|
|
2107
|
-
|
|
2094
|
+
while (true) {
|
|
2095
|
+
const vMatch = rest.match(/^v(\d+)/i);
|
|
2096
|
+
if (vMatch) {
|
|
2097
|
+
volume = clamp(Number.parseInt(vMatch[1], 10), 0, MAX_VOCAL_VOLUME);
|
|
2098
|
+
metaTokens.push(vMatch[0]);
|
|
2099
|
+
rest = rest.substring(vMatch[0].length).trim();
|
|
2100
|
+
continue;
|
|
2101
|
+
}
|
|
2102
|
+
const qMatch = rest.match(/^q(\d+)/i);
|
|
2103
|
+
if (qMatch) {
|
|
2104
|
+
gate = clamp(Number.parseInt(qMatch[1], 10), 0, 100);
|
|
2105
|
+
metaTokens.push(qMatch[0]);
|
|
2106
|
+
rest = rest.substring(qMatch[0].length).trim();
|
|
2107
|
+
continue;
|
|
2108
|
+
}
|
|
2109
|
+
const pMatch = rest.match(/^p(\d+)/i);
|
|
2110
|
+
if (pMatch) {
|
|
2111
|
+
pan = clamp(Number.parseInt(pMatch[1], 10), 0, 127);
|
|
2112
|
+
metaTokens.push(pMatch[0]);
|
|
2113
|
+
rest = rest.substring(pMatch[0].length).trim();
|
|
2114
|
+
continue;
|
|
2115
|
+
}
|
|
2116
|
+
const oMatch = rest.match(/^o(-?\d+)/i);
|
|
2117
|
+
if (oMatch) {
|
|
2118
|
+
octave = clamp(Number.parseInt(oMatch[1], 10), -2, 2);
|
|
2119
|
+
metaTokens.push(oMatch[0]);
|
|
2120
|
+
rest = rest.substring(oMatch[0].length).trim();
|
|
2121
|
+
continue;
|
|
2122
|
+
}
|
|
2123
|
+
break;
|
|
2124
|
+
}
|
|
2125
|
+
const lyricLines = [rest];
|
|
2108
2126
|
while (i + 1 < segments.length && isLyricContinuation(segments[i + 1])) {
|
|
2109
2127
|
lyricLines.push(segments[++i]);
|
|
2110
2128
|
}
|
|
@@ -4168,7 +4186,7 @@ var parseMmlMeta = (mml) => {
|
|
|
4168
4186
|
return meta;
|
|
4169
4187
|
};
|
|
4170
4188
|
var stripMmlMeta = (mml) => mml.replace(META_DIRECTIVE, "");
|
|
4171
|
-
var formatMmlMeta = (meta) => {
|
|
4189
|
+
var formatMmlMeta = (meta, space = "") => {
|
|
4172
4190
|
const parts = [];
|
|
4173
4191
|
if (meta.instrument) parts.push(`#inst=${meta.instrument}`);
|
|
4174
4192
|
if (meta.drum) parts.push(`#drum=${meta.drum}`);
|
|
@@ -4176,7 +4194,7 @@ var formatMmlMeta = (meta) => {
|
|
|
4176
4194
|
if (meta.drumVolume !== void 0)
|
|
4177
4195
|
parts.push(`#drumvolume=${meta.drumVolume}`);
|
|
4178
4196
|
if (meta.mode) parts.push(`#mode=${meta.mode}`);
|
|
4179
|
-
return parts.join(
|
|
4197
|
+
return parts.join(space);
|
|
4180
4198
|
};
|
|
4181
4199
|
var parseMML = (mml, options = {}) => {
|
|
4182
4200
|
const stepsPerBar = options.stepsPerBar ?? DEFAULT_STEPS_PER_BAR;
|
|
@@ -6128,6 +6146,9 @@ var customEncode = (str) => {
|
|
|
6128
6146
|
const bytes = [];
|
|
6129
6147
|
for (let i = 0; i < str.length; i++) {
|
|
6130
6148
|
const code = str.charCodeAt(i);
|
|
6149
|
+
if (code === 32) {
|
|
6150
|
+
continue;
|
|
6151
|
+
}
|
|
6131
6152
|
if (code <= 127) {
|
|
6132
6153
|
bytes.push(code);
|
|
6133
6154
|
} else if (code === PROLONGED_MARK) {
|
|
@@ -6159,6 +6180,82 @@ var encodeMml = async (mml) => {
|
|
|
6159
6180
|
}
|
|
6160
6181
|
return `u.${encodeURIComponent(mml)}`;
|
|
6161
6182
|
};
|
|
6183
|
+
var fromBase64Url = (s) => {
|
|
6184
|
+
let normalized = s.replace(/-/g, "+").replace(/_/g, "/");
|
|
6185
|
+
while (normalized.length % 4 !== 0) {
|
|
6186
|
+
normalized += "=";
|
|
6187
|
+
}
|
|
6188
|
+
const bin = atob(normalized);
|
|
6189
|
+
const bytes = new Uint8Array(bin.length);
|
|
6190
|
+
for (let i = 0; i < bin.length; i++) {
|
|
6191
|
+
bytes[i] = bin.charCodeAt(i);
|
|
6192
|
+
}
|
|
6193
|
+
return bytes;
|
|
6194
|
+
};
|
|
6195
|
+
var customDecode = (bytes) => {
|
|
6196
|
+
let str = "";
|
|
6197
|
+
let i = 0;
|
|
6198
|
+
while (i < bytes.length) {
|
|
6199
|
+
const byte = bytes[i];
|
|
6200
|
+
if (byte <= 127) {
|
|
6201
|
+
str += String.fromCharCode(byte);
|
|
6202
|
+
i++;
|
|
6203
|
+
} else if (byte === VALUE_PROLONGED) {
|
|
6204
|
+
str += String.fromCharCode(PROLONGED_MARK);
|
|
6205
|
+
i++;
|
|
6206
|
+
} else if (byte >= 128 && byte <= 222) {
|
|
6207
|
+
str += String.fromCharCode(HIRAGANA_START + (byte - 128));
|
|
6208
|
+
i++;
|
|
6209
|
+
} else if (byte === SHIFT_KATAKANA) {
|
|
6210
|
+
if (i + 1 < bytes.length) {
|
|
6211
|
+
const nextByte = bytes[i + 1];
|
|
6212
|
+
if (nextByte >= 128 && nextByte <= 222) {
|
|
6213
|
+
str += String.fromCharCode(HIRAGANA_START + 96 + (nextByte - 128));
|
|
6214
|
+
}
|
|
6215
|
+
i += 2;
|
|
6216
|
+
} else {
|
|
6217
|
+
i++;
|
|
6218
|
+
}
|
|
6219
|
+
} else {
|
|
6220
|
+
i++;
|
|
6221
|
+
}
|
|
6222
|
+
}
|
|
6223
|
+
return str;
|
|
6224
|
+
};
|
|
6225
|
+
var gunzipCustom = async (bytes) => {
|
|
6226
|
+
const ds = new DecompressionStream("gzip");
|
|
6227
|
+
const writer = ds.writable.getWriter();
|
|
6228
|
+
writer.write(bytes);
|
|
6229
|
+
writer.close();
|
|
6230
|
+
const buf = await new Response(ds.readable).arrayBuffer();
|
|
6231
|
+
return customDecode(new Uint8Array(buf));
|
|
6232
|
+
};
|
|
6233
|
+
var gunzip = async (bytes) => {
|
|
6234
|
+
const ds = new DecompressionStream("gzip");
|
|
6235
|
+
const writer = ds.writable.getWriter();
|
|
6236
|
+
writer.write(bytes);
|
|
6237
|
+
writer.close();
|
|
6238
|
+
const buf = await new Response(ds.readable).arrayBuffer();
|
|
6239
|
+
return new TextDecoder().decode(buf);
|
|
6240
|
+
};
|
|
6241
|
+
var decodeMml = async (payload) => {
|
|
6242
|
+
if (!payload) return "";
|
|
6243
|
+
try {
|
|
6244
|
+
if (payload.startsWith("z.")) {
|
|
6245
|
+
return await gunzipCustom(fromBase64Url(payload.slice(2)));
|
|
6246
|
+
}
|
|
6247
|
+
if (payload.startsWith("g.")) {
|
|
6248
|
+
return await gunzip(fromBase64Url(payload.slice(2)));
|
|
6249
|
+
}
|
|
6250
|
+
if (payload.startsWith("u.")) {
|
|
6251
|
+
return decodeURIComponent(payload.slice(2));
|
|
6252
|
+
}
|
|
6253
|
+
return decodeURIComponent(payload);
|
|
6254
|
+
} catch (e) {
|
|
6255
|
+
console.error("[dtm] failed to decode MML payload", e);
|
|
6256
|
+
return "";
|
|
6257
|
+
}
|
|
6258
|
+
};
|
|
6162
6259
|
var mountMmlPlayer = (target, mml, options = {}) => {
|
|
6163
6260
|
injectStyles(target.ownerDocument ?? document);
|
|
6164
6261
|
const {
|
|
@@ -8326,13 +8423,26 @@ var mountDAW = (target, options = {}) => {
|
|
|
8326
8423
|
const barLimitBars = Number(refs.barLimitSelect.value);
|
|
8327
8424
|
const limitSteps = barLimitBars > 0 ? barLimitBars * renderConfig.stepsPerBar : Infinity;
|
|
8328
8425
|
const clipNotes = (notes) => limitSteps === Infinity ? notes : notes.filter((n) => n.startStep < limitSteps);
|
|
8329
|
-
const
|
|
8330
|
-
|
|
8331
|
-
|
|
8332
|
-
|
|
8333
|
-
|
|
8334
|
-
|
|
8335
|
-
|
|
8426
|
+
const metaLineFull = formatMmlMeta(
|
|
8427
|
+
{
|
|
8428
|
+
instrument: currentInstrument || void 0,
|
|
8429
|
+
drum: currentDrumPattern !== "none" ? currentDrumPattern : void 0,
|
|
8430
|
+
volume: masterVolume,
|
|
8431
|
+
drumVolume,
|
|
8432
|
+
mode
|
|
8433
|
+
},
|
|
8434
|
+
" "
|
|
8435
|
+
);
|
|
8436
|
+
const metaLineMini = formatMmlMeta(
|
|
8437
|
+
{
|
|
8438
|
+
instrument: currentInstrument || void 0,
|
|
8439
|
+
drum: currentDrumPattern !== "none" ? currentDrumPattern : void 0,
|
|
8440
|
+
volume: masterVolume,
|
|
8441
|
+
drumVolume,
|
|
8442
|
+
mode
|
|
8443
|
+
},
|
|
8444
|
+
""
|
|
8445
|
+
);
|
|
8336
8446
|
if (refs.decomposeChordToggle.checked) {
|
|
8337
8447
|
const ignoreHeavy = refs.ignoreChordHeavyToggle.checked;
|
|
8338
8448
|
const targetStates = ignoreHeavy ? trackStates.filter((t) => !isChordHeavyTrack(t.core.getNotes())) : trackStates;
|
|
@@ -8348,8 +8458,8 @@ var mountDAW = (target, options = {}) => {
|
|
|
8348
8458
|
const decomposedMini = monoTracks.map(
|
|
8349
8459
|
(notes, i) => `@${i}${refCore.getMMLFromNotes(notes, bpm, 100).trim().replace(/\s+/g, "")}`
|
|
8350
8460
|
);
|
|
8351
|
-
const full2 = [
|
|
8352
|
-
const minified2 = [
|
|
8461
|
+
const full2 = [metaLineFull, ...decomposedFull, MML_END_MARKER].filter((s) => s.length > 0).join(";\n");
|
|
8462
|
+
const minified2 = [metaLineMini, ...decomposedMini, MML_END_MARKER].filter((s) => s.length > 0).join(";");
|
|
8353
8463
|
return {
|
|
8354
8464
|
full: full2,
|
|
8355
8465
|
minified: minified2,
|
|
@@ -8389,9 +8499,9 @@ var mountDAW = (target, options = {}) => {
|
|
|
8389
8499
|
const head = params ? `${x.model} ${params}` : x.model;
|
|
8390
8500
|
return `@@${x.i} ${head} ${x.text}`;
|
|
8391
8501
|
});
|
|
8392
|
-
const full = [
|
|
8502
|
+
const full = [metaLineFull, ...trackLines, ...lyricLines, MML_END_MARKER].filter((s) => s.length > 0).join(";\n");
|
|
8393
8503
|
const minified = [
|
|
8394
|
-
|
|
8504
|
+
metaLineMini,
|
|
8395
8505
|
...trackLinesMini,
|
|
8396
8506
|
...lyricLines,
|
|
8397
8507
|
MML_END_MARKER
|
|
@@ -10175,6 +10285,7 @@ export {
|
|
|
10175
10285
|
PREWARM_NOTES,
|
|
10176
10286
|
TRACKS_ADVANCED,
|
|
10177
10287
|
TRACKS_SIMPLE,
|
|
10288
|
+
VOICE_IMAGES,
|
|
10178
10289
|
VOICE_IMAGE_KEY,
|
|
10179
10290
|
analyzeMidiTracks,
|
|
10180
10291
|
applyHarmonicFilter,
|
|
@@ -10192,6 +10303,7 @@ export {
|
|
|
10192
10303
|
createSingingVoices,
|
|
10193
10304
|
createSynth,
|
|
10194
10305
|
createVoiceRegistry,
|
|
10306
|
+
decodeMml,
|
|
10195
10307
|
decomposeToMonophonic,
|
|
10196
10308
|
drawGrid,
|
|
10197
10309
|
drawHeader,
|
|
@@ -10199,6 +10311,7 @@ export {
|
|
|
10199
10311
|
drawNotes,
|
|
10200
10312
|
drawSelectedNotes,
|
|
10201
10313
|
drawSelectionRect,
|
|
10314
|
+
encodeMml,
|
|
10202
10315
|
exportMIDI,
|
|
10203
10316
|
extractMidiPlacements,
|
|
10204
10317
|
extractMidiPlacementsByTrack,
|
package/package.json
CHANGED