@onjmin/dtm 0.1.30 → 0.1.32

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 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
- 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_IMAGE_KEY, type VoiceModel, type VoiceRegistry, analyzeMidiTracks, applyHarmonicFilter, applyMonophonic, buildChordPlacements, buildNameToKeyMapping, collectPitchTokens, createAudioContext, createDtmStudio, createKlattVoice, createKoeVoice, createLyricsConductor, createPianoRoll, createSequencer, createSingingVoices, createSynth, createVoiceRegistry, decomposeToMonophonic, drawGrid, drawHeader, drawKeyboard, drawNotes, drawSelectedNotes, drawSelectionRect, 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 };
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
- 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_IMAGE_KEY, type VoiceModel, type VoiceRegistry, analyzeMidiTracks, applyHarmonicFilter, applyMonophonic, buildChordPlacements, buildNameToKeyMapping, collectPitchTokens, createAudioContext, createDtmStudio, createKlattVoice, createKoeVoice, createLyricsConductor, createPianoRoll, createSequencer, createSingingVoices, createSynth, createVoiceRegistry, decomposeToMonophonic, drawGrid, drawHeader, drawKeyboard, drawNotes, drawSelectedNotes, drawSelectionRect, 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 };
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
- const tokens = m[2].trim().split(/\s+/);
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 colon = modelToken.indexOf(":");
2191
- const model = (colon === -1 ? modelToken : modelToken.slice(0, colon)).toLowerCase();
2192
- if (colon !== -1) {
2193
- const v = Number.parseInt(modelToken.slice(colon + 1), 10);
2194
- if (Number.isFinite(v)) volume = clamp(v, 0, MAX_VOCAL_VOLUME);
2195
- }
2196
- const metaTokens = [modelToken];
2197
- while (tokens.length > 0) {
2198
- const v = /^v(\d+)$/.exec(tokens[0]);
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(tokens.shift());
2202
+ metaTokens.push(modelMatch[0]);
2203
+ rest = rest.substring(modelMatch[0].length).trim();
2214
2204
  }
2215
- const lyricLines = [tokens.join(" ")];
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 {
@@ -8165,7 +8265,7 @@ var mountDAW = (target, options = {}) => {
8165
8265
  redrawAll();
8166
8266
  };
8167
8267
  const togglePlay = () => {
8168
- if (playbackState === "playing") pause();
8268
+ if (playbackState === "playing") stop();
8169
8269
  else play();
8170
8270
  };
8171
8271
  const updateTransport = () => {
@@ -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 metaLine = formatMmlMeta({
8438
- instrument: currentInstrument || void 0,
8439
- drum: currentDrumPattern !== "none" ? currentDrumPattern : void 0,
8440
- volume: masterVolume,
8441
- drumVolume,
8442
- mode
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 = [metaLine, ...decomposedFull, MML_END_MARKER].filter((s) => s.length > 0).join(";\n");
8460
- const minified2 = [metaLine, ...decomposedMini, MML_END_MARKER].filter((s) => s.length > 0).join(";");
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 = [metaLine, ...trackLines, ...lyricLines, MML_END_MARKER].filter((s) => s.length > 0).join(";\n");
8613
+ const full = [metaLineFull, ...trackLines, ...lyricLines, MML_END_MARKER].filter((s) => s.length > 0).join(";\n");
8501
8614
  const minified = [
8502
- metaLine,
8615
+ metaLineMini,
8503
8616
  ...trackLinesMini,
8504
8617
  ...lyricLines,
8505
8618
  MML_END_MARKER
@@ -8678,6 +8791,14 @@ var mountDAW = (target, options = {}) => {
8678
8791
  stop();
8679
8792
  clearAll();
8680
8793
  for (const t of trackStates) t.core.setLoadMode(true);
8794
+ for (const t of trackStates) {
8795
+ t.lyrics = "";
8796
+ t.lyricModel = "";
8797
+ t.vocalVolume = DEFAULT_VOCAL_VOLUME;
8798
+ t.vocalGate = 100;
8799
+ t.vocalPan = 64;
8800
+ t.vocalOctave = 0;
8801
+ }
8681
8802
  const { placements, bpm: parsedBpm } = isAdvanced ? extractMidiPlacementsByTrack(
8682
8803
  midi,
8683
8804
  selectedIndices,
@@ -8705,6 +8826,7 @@ var mountDAW = (target, options = {}) => {
8705
8826
  setDrawOffset(currentOffsetX, currentOffsetY);
8706
8827
  }
8707
8828
  redrawAll();
8829
+ updateTrackPanel();
8708
8830
  updateUndoRedo();
8709
8831
  };
8710
8832
  const exportMIDI2 = () => exportMIDI({
@@ -9003,13 +9125,13 @@ var mountDAW = (target, options = {}) => {
9003
9125
  );
9004
9126
  if (showMidi) wireMidi();
9005
9127
  document.addEventListener("keydown", onKeyDown);
9006
- for (const ta of refs.root.querySelectorAll("textarea, input")) {
9007
- ta.addEventListener("keydown", (e) => {
9008
- const ke = e;
9009
- if ((ke.ctrlKey || ke.metaKey) && ["KeyZ", "KeyY", "KeyV", "KeyC", "KeyX"].includes(ke.code))
9010
- e.stopPropagation();
9011
- });
9012
- }
9128
+ refs.root.addEventListener("keydown", (e) => {
9129
+ const t = e.target;
9130
+ if (t.tagName !== "TEXTAREA" && t.tagName !== "INPUT") return;
9131
+ const ke = e;
9132
+ if ((ke.ctrlKey || ke.metaKey) && ["KeyZ", "KeyY", "KeyV", "KeyC", "KeyX"].includes(ke.code))
9133
+ e.stopPropagation();
9134
+ });
9013
9135
  };
9014
9136
  let pendingMidi = null;
9015
9137
  let detectedTracks = [];
@@ -10285,6 +10407,7 @@ var createDtmStudio = async (options = {}) => {
10285
10407
  PREWARM_NOTES,
10286
10408
  TRACKS_ADVANCED,
10287
10409
  TRACKS_SIMPLE,
10410
+ VOICE_IMAGES,
10288
10411
  VOICE_IMAGE_KEY,
10289
10412
  analyzeMidiTracks,
10290
10413
  applyHarmonicFilter,
@@ -10302,6 +10425,7 @@ var createDtmStudio = async (options = {}) => {
10302
10425
  createSingingVoices,
10303
10426
  createSynth,
10304
10427
  createVoiceRegistry,
10428
+ decodeMml,
10305
10429
  decomposeToMonophonic,
10306
10430
  drawGrid,
10307
10431
  drawHeader,
@@ -10309,6 +10433,7 @@ var createDtmStudio = async (options = {}) => {
10309
10433
  drawNotes,
10310
10434
  drawSelectedNotes,
10311
10435
  drawSelectionRect,
10436
+ encodeMml,
10312
10437
  exportMIDI,
10313
10438
  extractMidiPlacements,
10314
10439
  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
- const tokens = m[2].trim().split(/\s+/);
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 colon = modelToken.indexOf(":");
2083
- const model = (colon === -1 ? modelToken : modelToken.slice(0, colon)).toLowerCase();
2084
- if (colon !== -1) {
2085
- const v = Number.parseInt(modelToken.slice(colon + 1), 10);
2086
- if (Number.isFinite(v)) volume = clamp(v, 0, MAX_VOCAL_VOLUME);
2087
- }
2088
- const metaTokens = [modelToken];
2089
- while (tokens.length > 0) {
2090
- const v = /^v(\d+)$/.exec(tokens[0]);
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(tokens.shift());
2091
+ metaTokens.push(modelMatch[0]);
2092
+ rest = rest.substring(modelMatch[0].length).trim();
2106
2093
  }
2107
- const lyricLines = [tokens.join(" ")];
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 {
@@ -8057,7 +8154,7 @@ var mountDAW = (target, options = {}) => {
8057
8154
  redrawAll();
8058
8155
  };
8059
8156
  const togglePlay = () => {
8060
- if (playbackState === "playing") pause();
8157
+ if (playbackState === "playing") stop();
8061
8158
  else play();
8062
8159
  };
8063
8160
  const updateTransport = () => {
@@ -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 metaLine = formatMmlMeta({
8330
- instrument: currentInstrument || void 0,
8331
- drum: currentDrumPattern !== "none" ? currentDrumPattern : void 0,
8332
- volume: masterVolume,
8333
- drumVolume,
8334
- mode
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 = [metaLine, ...decomposedFull, MML_END_MARKER].filter((s) => s.length > 0).join(";\n");
8352
- const minified2 = [metaLine, ...decomposedMini, MML_END_MARKER].filter((s) => s.length > 0).join(";");
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 = [metaLine, ...trackLines, ...lyricLines, MML_END_MARKER].filter((s) => s.length > 0).join(";\n");
8502
+ const full = [metaLineFull, ...trackLines, ...lyricLines, MML_END_MARKER].filter((s) => s.length > 0).join(";\n");
8393
8503
  const minified = [
8394
- metaLine,
8504
+ metaLineMini,
8395
8505
  ...trackLinesMini,
8396
8506
  ...lyricLines,
8397
8507
  MML_END_MARKER
@@ -8570,6 +8680,14 @@ var mountDAW = (target, options = {}) => {
8570
8680
  stop();
8571
8681
  clearAll();
8572
8682
  for (const t of trackStates) t.core.setLoadMode(true);
8683
+ for (const t of trackStates) {
8684
+ t.lyrics = "";
8685
+ t.lyricModel = "";
8686
+ t.vocalVolume = DEFAULT_VOCAL_VOLUME;
8687
+ t.vocalGate = 100;
8688
+ t.vocalPan = 64;
8689
+ t.vocalOctave = 0;
8690
+ }
8573
8691
  const { placements, bpm: parsedBpm } = isAdvanced ? extractMidiPlacementsByTrack(
8574
8692
  midi,
8575
8693
  selectedIndices,
@@ -8597,6 +8715,7 @@ var mountDAW = (target, options = {}) => {
8597
8715
  setDrawOffset(currentOffsetX, currentOffsetY);
8598
8716
  }
8599
8717
  redrawAll();
8718
+ updateTrackPanel();
8600
8719
  updateUndoRedo();
8601
8720
  };
8602
8721
  const exportMIDI2 = () => exportMIDI({
@@ -8895,13 +9014,13 @@ var mountDAW = (target, options = {}) => {
8895
9014
  );
8896
9015
  if (showMidi) wireMidi();
8897
9016
  document.addEventListener("keydown", onKeyDown);
8898
- for (const ta of refs.root.querySelectorAll("textarea, input")) {
8899
- ta.addEventListener("keydown", (e) => {
8900
- const ke = e;
8901
- if ((ke.ctrlKey || ke.metaKey) && ["KeyZ", "KeyY", "KeyV", "KeyC", "KeyX"].includes(ke.code))
8902
- e.stopPropagation();
8903
- });
8904
- }
9017
+ refs.root.addEventListener("keydown", (e) => {
9018
+ const t = e.target;
9019
+ if (t.tagName !== "TEXTAREA" && t.tagName !== "INPUT") return;
9020
+ const ke = e;
9021
+ if ((ke.ctrlKey || ke.metaKey) && ["KeyZ", "KeyY", "KeyV", "KeyC", "KeyX"].includes(ke.code))
9022
+ e.stopPropagation();
9023
+ });
8905
9024
  };
8906
9025
  let pendingMidi = null;
8907
9026
  let detectedTracks = [];
@@ -10175,6 +10294,7 @@ export {
10175
10294
  PREWARM_NOTES,
10176
10295
  TRACKS_ADVANCED,
10177
10296
  TRACKS_SIMPLE,
10297
+ VOICE_IMAGES,
10178
10298
  VOICE_IMAGE_KEY,
10179
10299
  analyzeMidiTracks,
10180
10300
  applyHarmonicFilter,
@@ -10192,6 +10312,7 @@ export {
10192
10312
  createSingingVoices,
10193
10313
  createSynth,
10194
10314
  createVoiceRegistry,
10315
+ decodeMml,
10195
10316
  decomposeToMonophonic,
10196
10317
  drawGrid,
10197
10318
  drawHeader,
@@ -10199,6 +10320,7 @@ export {
10199
10320
  drawNotes,
10200
10321
  drawSelectedNotes,
10201
10322
  drawSelectionRect,
10323
+ encodeMml,
10202
10324
  exportMIDI,
10203
10325
  extractMidiPlacements,
10204
10326
  extractMidiPlacementsByTrack,
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "author": "onjmin",
3
3
  "license": "MIT",
4
4
  "name": "@onjmin/dtm",
5
- "version": "0.1.30",
5
+ "version": "0.1.32",
6
6
  "description": "MMLを中間言語に用いた、モバイルファーストなDAW / ピアノロール打ち込みコンポーネント",
7
7
  "homepage": "https://onjmin.github.io/dtm",
8
8
  "repository": {