@onjmin/dtm 1.0.5 → 1.0.7

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
@@ -1996,6 +1996,16 @@ declare const drawGrid: (noteLengthSteps?: number) => void;
1996
1996
  * 指定されたノートの配列を描画します。
1997
1997
  */
1998
1998
  declare const drawNotes: (notes: Note[], color?: number[]) => void;
1999
+ /**
2000
+ * ノートの上に歌詞(かな)を重ねて描画します。
2001
+ *
2002
+ * 音節の割り当ては発音側(StreamVoiceTrack の組み立て)と同じ規則で、
2003
+ * startStep 昇順に並べたノートの i 番目へ syllables[i] を対応させます。
2004
+ * 音節が足りないぶんのノートには何も描きません。
2005
+ *
2006
+ * 文字はノート矩形でクリップするため、隣のノートへはみ出しません。
2007
+ */
2008
+ declare const drawNoteLyrics: (notes: Note[], syllables: string[]) => void;
1999
2009
  /**
2000
2010
  * 選択範囲の四角形を描画します。
2001
2011
  */
@@ -2473,4 +2483,4 @@ declare const encodeWavPCM16: (channels: Float32Array[], sampleRate: number) =>
2473
2483
  /** Float32Array のチャンクを1本へ連結する。 */
2474
2484
  declare const concatFloat32: (chunks: Float32Array[]) => Float32Array;
2475
2485
 
2476
- export { type AddNoteOptions, type AnyDrumPattern, type ApplyChordOptions, type ChordPatternType, type ChordPlacement, type ChordPlayerInstance, type ConsumedSyllable, type CoreEventHandlers, type CustomVocalDef, 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 DrumPatternDef, type DtmStudio, type DtmStudioEngines, type DtmStudioOptions, type ExportMidiOptions, type FadeScheduleParams, GM_INSTRUMENT_NAMES, 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 LyricSyncData, type LyricTrack, type LyricsConductor, MAX_VOCAL_VOLUME, MMLCore, type MMLDisplayToken, type MMLNotePlacement, MML_END_MARKER, type MidiExtraction, type MidiNotePlacement, MidiSearchClient, type MidiSearchConfig, type MidiTrackAnalysis, type MmlMeta, type MmlPlayback, type MmlPlayerInstance, type MmlPlayerOptions, type ModeSwitchInstance, type ModeSwitchOptions, type MountChordPlayerOptions, type MountEditorOptions, type MountPlayerOptions, type Note, type NoteData, type NoteRemove, type OctaveUnisonMode, PITCH_MAP, PREWARM_NOTES, type ParseMMLOptions, type ParseMidiFn, type ParsedMML, type PianoRollInstance, type PianoRollOptions, type PicotuneSearchParams, type PicotuneSong, type PitchToken, type PlayChordsOptions, type PlayDrumEvent, type PlayMmlOptions, type PlayNoteEvent, type PlayNoteOptions, type PlayPlacementsOptions, 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, VIBRATO_MIN_SEC, VOICE_IMAGES, VOICE_IMAGE_KEY, type VoiceExpression, type VoiceModel, type VoiceRegistry, analyzeMidiTracks, applyHarmonicFilter, applyMonophonic, buildChordPlacements, buildDrumPatternJson, buildNameToKeyMapping, collectPitchTokens, concatFloat32, createAudioContext, createDtmStudio, createKlattVoice, createKoeVoice, createLyricsConductor, createPianoRoll, createSequencer, createSingingVoices, createSynth, createVoiceRegistry, decodeMml, decomposeToMonophonic, drawGrid, drawHeader, drawKeyboard, drawNotes, drawSelectedNotes, drawSelectionRect, encodeMml, encodeWavPCM16, exportMIDI, extractDrumPatternFromNotes, extractMidiDrumPattern, extractMidiPlacements, extractMidiPlacementsByTrack, formatMmlMeta, freqFromPitch, generateRandomPattern, getDrawOffset, getDrumPatternKeys, getGridCanvas, getGridContext, getGridPosition, getHeaderCanvas, getMidiBPM, getRenderConfig, getXY, icon, init, injectStyles, isChordHeavyTrack, isPlausibleMidiTranscription, isValidHttpUrl, koeUrl, mountChordPlayer, mountDAW, mountMmlPlayer, normalizeDrumPatterns, normalizeLyrics, onClick, panToStereo, parseCustomVocals, parseLyrics, parseMML, parseMmlMeta, playChords, playMML, playNote, playPlacements, playSingingMML, resolveDrumPattern, resolveLoopPoint, setBackgroundActive, setDrawOffset, shiftNotes, showLoadingOverlay, stripCustomVocals, stripLyrics, stripMmlMeta, transposeNotes, vocalVolumeToGain };
2486
+ export { type AddNoteOptions, type AnyDrumPattern, type ApplyChordOptions, type ChordPatternType, type ChordPlacement, type ChordPlayerInstance, type ConsumedSyllable, type CoreEventHandlers, type CustomVocalDef, 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 DrumPatternDef, type DtmStudio, type DtmStudioEngines, type DtmStudioOptions, type ExportMidiOptions, type FadeScheduleParams, GM_INSTRUMENT_NAMES, 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 LyricSyncData, type LyricTrack, type LyricsConductor, MAX_VOCAL_VOLUME, MMLCore, type MMLDisplayToken, type MMLNotePlacement, MML_END_MARKER, type MidiExtraction, type MidiNotePlacement, MidiSearchClient, type MidiSearchConfig, type MidiTrackAnalysis, type MmlMeta, type MmlPlayback, type MmlPlayerInstance, type MmlPlayerOptions, type ModeSwitchInstance, type ModeSwitchOptions, type MountChordPlayerOptions, type MountEditorOptions, type MountPlayerOptions, type Note, type NoteData, type NoteRemove, type OctaveUnisonMode, PITCH_MAP, PREWARM_NOTES, type ParseMMLOptions, type ParseMidiFn, type ParsedMML, type PianoRollInstance, type PianoRollOptions, type PicotuneSearchParams, type PicotuneSong, type PitchToken, type PlayChordsOptions, type PlayDrumEvent, type PlayMmlOptions, type PlayNoteEvent, type PlayNoteOptions, type PlayPlacementsOptions, 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, VIBRATO_MIN_SEC, VOICE_IMAGES, VOICE_IMAGE_KEY, type VoiceExpression, type VoiceModel, type VoiceRegistry, analyzeMidiTracks, applyHarmonicFilter, applyMonophonic, buildChordPlacements, buildDrumPatternJson, buildNameToKeyMapping, collectPitchTokens, concatFloat32, createAudioContext, createDtmStudio, createKlattVoice, createKoeVoice, createLyricsConductor, createPianoRoll, createSequencer, createSingingVoices, createSynth, createVoiceRegistry, decodeMml, decomposeToMonophonic, drawGrid, drawHeader, drawKeyboard, drawNoteLyrics, drawNotes, drawSelectedNotes, drawSelectionRect, encodeMml, encodeWavPCM16, exportMIDI, extractDrumPatternFromNotes, extractMidiDrumPattern, extractMidiPlacements, extractMidiPlacementsByTrack, formatMmlMeta, freqFromPitch, generateRandomPattern, getDrawOffset, getDrumPatternKeys, getGridCanvas, getGridContext, getGridPosition, getHeaderCanvas, getMidiBPM, getRenderConfig, getXY, icon, init, injectStyles, isChordHeavyTrack, isPlausibleMidiTranscription, isValidHttpUrl, koeUrl, mountChordPlayer, mountDAW, mountMmlPlayer, normalizeDrumPatterns, normalizeLyrics, onClick, panToStereo, parseCustomVocals, parseLyrics, parseMML, parseMmlMeta, playChords, playMML, playNote, playPlacements, playSingingMML, resolveDrumPattern, resolveLoopPoint, setBackgroundActive, setDrawOffset, shiftNotes, showLoadingOverlay, stripCustomVocals, stripLyrics, stripMmlMeta, transposeNotes, vocalVolumeToGain };
package/dist/index.d.ts CHANGED
@@ -1996,6 +1996,16 @@ declare const drawGrid: (noteLengthSteps?: number) => void;
1996
1996
  * 指定されたノートの配列を描画します。
1997
1997
  */
1998
1998
  declare const drawNotes: (notes: Note[], color?: number[]) => void;
1999
+ /**
2000
+ * ノートの上に歌詞(かな)を重ねて描画します。
2001
+ *
2002
+ * 音節の割り当ては発音側(StreamVoiceTrack の組み立て)と同じ規則で、
2003
+ * startStep 昇順に並べたノートの i 番目へ syllables[i] を対応させます。
2004
+ * 音節が足りないぶんのノートには何も描きません。
2005
+ *
2006
+ * 文字はノート矩形でクリップするため、隣のノートへはみ出しません。
2007
+ */
2008
+ declare const drawNoteLyrics: (notes: Note[], syllables: string[]) => void;
1999
2009
  /**
2000
2010
  * 選択範囲の四角形を描画します。
2001
2011
  */
@@ -2473,4 +2483,4 @@ declare const encodeWavPCM16: (channels: Float32Array[], sampleRate: number) =>
2473
2483
  /** Float32Array のチャンクを1本へ連結する。 */
2474
2484
  declare const concatFloat32: (chunks: Float32Array[]) => Float32Array;
2475
2485
 
2476
- export { type AddNoteOptions, type AnyDrumPattern, type ApplyChordOptions, type ChordPatternType, type ChordPlacement, type ChordPlayerInstance, type ConsumedSyllable, type CoreEventHandlers, type CustomVocalDef, 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 DrumPatternDef, type DtmStudio, type DtmStudioEngines, type DtmStudioOptions, type ExportMidiOptions, type FadeScheduleParams, GM_INSTRUMENT_NAMES, 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 LyricSyncData, type LyricTrack, type LyricsConductor, MAX_VOCAL_VOLUME, MMLCore, type MMLDisplayToken, type MMLNotePlacement, MML_END_MARKER, type MidiExtraction, type MidiNotePlacement, MidiSearchClient, type MidiSearchConfig, type MidiTrackAnalysis, type MmlMeta, type MmlPlayback, type MmlPlayerInstance, type MmlPlayerOptions, type ModeSwitchInstance, type ModeSwitchOptions, type MountChordPlayerOptions, type MountEditorOptions, type MountPlayerOptions, type Note, type NoteData, type NoteRemove, type OctaveUnisonMode, PITCH_MAP, PREWARM_NOTES, type ParseMMLOptions, type ParseMidiFn, type ParsedMML, type PianoRollInstance, type PianoRollOptions, type PicotuneSearchParams, type PicotuneSong, type PitchToken, type PlayChordsOptions, type PlayDrumEvent, type PlayMmlOptions, type PlayNoteEvent, type PlayNoteOptions, type PlayPlacementsOptions, 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, VIBRATO_MIN_SEC, VOICE_IMAGES, VOICE_IMAGE_KEY, type VoiceExpression, type VoiceModel, type VoiceRegistry, analyzeMidiTracks, applyHarmonicFilter, applyMonophonic, buildChordPlacements, buildDrumPatternJson, buildNameToKeyMapping, collectPitchTokens, concatFloat32, createAudioContext, createDtmStudio, createKlattVoice, createKoeVoice, createLyricsConductor, createPianoRoll, createSequencer, createSingingVoices, createSynth, createVoiceRegistry, decodeMml, decomposeToMonophonic, drawGrid, drawHeader, drawKeyboard, drawNotes, drawSelectedNotes, drawSelectionRect, encodeMml, encodeWavPCM16, exportMIDI, extractDrumPatternFromNotes, extractMidiDrumPattern, extractMidiPlacements, extractMidiPlacementsByTrack, formatMmlMeta, freqFromPitch, generateRandomPattern, getDrawOffset, getDrumPatternKeys, getGridCanvas, getGridContext, getGridPosition, getHeaderCanvas, getMidiBPM, getRenderConfig, getXY, icon, init, injectStyles, isChordHeavyTrack, isPlausibleMidiTranscription, isValidHttpUrl, koeUrl, mountChordPlayer, mountDAW, mountMmlPlayer, normalizeDrumPatterns, normalizeLyrics, onClick, panToStereo, parseCustomVocals, parseLyrics, parseMML, parseMmlMeta, playChords, playMML, playNote, playPlacements, playSingingMML, resolveDrumPattern, resolveLoopPoint, setBackgroundActive, setDrawOffset, shiftNotes, showLoadingOverlay, stripCustomVocals, stripLyrics, stripMmlMeta, transposeNotes, vocalVolumeToGain };
2486
+ export { type AddNoteOptions, type AnyDrumPattern, type ApplyChordOptions, type ChordPatternType, type ChordPlacement, type ChordPlayerInstance, type ConsumedSyllable, type CoreEventHandlers, type CustomVocalDef, 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 DrumPatternDef, type DtmStudio, type DtmStudioEngines, type DtmStudioOptions, type ExportMidiOptions, type FadeScheduleParams, GM_INSTRUMENT_NAMES, 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 LyricSyncData, type LyricTrack, type LyricsConductor, MAX_VOCAL_VOLUME, MMLCore, type MMLDisplayToken, type MMLNotePlacement, MML_END_MARKER, type MidiExtraction, type MidiNotePlacement, MidiSearchClient, type MidiSearchConfig, type MidiTrackAnalysis, type MmlMeta, type MmlPlayback, type MmlPlayerInstance, type MmlPlayerOptions, type ModeSwitchInstance, type ModeSwitchOptions, type MountChordPlayerOptions, type MountEditorOptions, type MountPlayerOptions, type Note, type NoteData, type NoteRemove, type OctaveUnisonMode, PITCH_MAP, PREWARM_NOTES, type ParseMMLOptions, type ParseMidiFn, type ParsedMML, type PianoRollInstance, type PianoRollOptions, type PicotuneSearchParams, type PicotuneSong, type PitchToken, type PlayChordsOptions, type PlayDrumEvent, type PlayMmlOptions, type PlayNoteEvent, type PlayNoteOptions, type PlayPlacementsOptions, 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, VIBRATO_MIN_SEC, VOICE_IMAGES, VOICE_IMAGE_KEY, type VoiceExpression, type VoiceModel, type VoiceRegistry, analyzeMidiTracks, applyHarmonicFilter, applyMonophonic, buildChordPlacements, buildDrumPatternJson, buildNameToKeyMapping, collectPitchTokens, concatFloat32, createAudioContext, createDtmStudio, createKlattVoice, createKoeVoice, createLyricsConductor, createPianoRoll, createSequencer, createSingingVoices, createSynth, createVoiceRegistry, decodeMml, decomposeToMonophonic, drawGrid, drawHeader, drawKeyboard, drawNoteLyrics, drawNotes, drawSelectedNotes, drawSelectionRect, encodeMml, encodeWavPCM16, exportMIDI, extractDrumPatternFromNotes, extractMidiDrumPattern, extractMidiPlacements, extractMidiPlacementsByTrack, formatMmlMeta, freqFromPitch, generateRandomPattern, getDrawOffset, getDrumPatternKeys, getGridCanvas, getGridContext, getGridPosition, getHeaderCanvas, getMidiBPM, getRenderConfig, getXY, icon, init, injectStyles, isChordHeavyTrack, isPlausibleMidiTranscription, isValidHttpUrl, koeUrl, mountChordPlayer, mountDAW, mountMmlPlayer, normalizeDrumPatterns, normalizeLyrics, onClick, panToStereo, parseCustomVocals, parseLyrics, parseMML, parseMmlMeta, playChords, playMML, playNote, playPlacements, playSingingMML, resolveDrumPattern, resolveLoopPoint, setBackgroundActive, setDrawOffset, shiftNotes, showLoadingOverlay, stripCustomVocals, stripLyrics, stripMmlMeta, transposeNotes, vocalVolumeToGain };
package/dist/index.js CHANGED
@@ -72,6 +72,7 @@ __export(index_exports, {
72
72
  drawGrid: () => drawGrid,
73
73
  drawHeader: () => drawHeader,
74
74
  drawKeyboard: () => drawKeyboard,
75
+ drawNoteLyrics: () => drawNoteLyrics,
75
76
  drawNotes: () => drawNotes,
76
77
  drawSelectedNotes: () => drawSelectedNotes,
77
78
  drawSelectionRect: () => drawSelectionRect,
@@ -2810,7 +2811,7 @@ var KOE_VOICEBANKS = {
2810
2811
  mgroid: "MGRoid_\u539F\u97F3\u8A2D\u5B9A\u6E08\u307F.koe",
2811
2812
  motroid: "MOTRoid\u5B8C\u5168\u7248V2.koe",
2812
2813
  nynroid: "NYNRoidver1.4.koe",
2813
- uc: "\u84C4\u97F3\u30AD\u30EA\u30B3 \uFF08beta1.0\uFF09.koe"
2814
+ uc: "\u84C4\u97F3\u30AD\u30EA\u30B3 \uFF08beta1.1\uFF09.koe"
2814
2815
  };
2815
2816
  var KOE_VOICEBANK_LABELS = {
2816
2817
  tsukuyomi: "\u3064\u304F\u3088\u307F\u3061\u3083\u3093",
@@ -4024,6 +4025,7 @@ var reverbAmountToGain = (amount) => Math.max(0, Math.min(100, amount)) / 100;
4024
4025
  var STEPS_PER_BEAT = 48;
4025
4026
  var PLAN_TIME = 0.5;
4026
4027
  var TICK_INTERVAL_MS = 20;
4028
+ var STEP_EPSILON = 1e-4;
4027
4029
  var resolveLoopPoint = (point, _bpm, stepsPerBar, sps) => {
4028
4030
  if ("step" in point) {
4029
4031
  return point.step;
@@ -4055,6 +4057,8 @@ var createSequencer = (options) => {
4055
4057
  let loopDurationSec = 0;
4056
4058
  let loopStartIndex = 0;
4057
4059
  let loopBase = 0;
4060
+ let drumCursor = 0;
4061
+ let lastDrumStep = Number.NEGATIVE_INFINITY;
4058
4062
  let lastPlayStep = 0;
4059
4063
  const secondsPerStep = () => 60 / options.getBpm() / STEPS_PER_BEAT;
4060
4064
  const getWrappedPlayStep = (time, sps) => {
@@ -4164,24 +4168,32 @@ var createSequencer = (options) => {
4164
4168
  }
4165
4169
  const { stepsPerBar } = options;
4166
4170
  const currentStep = getWrappedPlayStep(time, sps);
4167
- const currentBar = Math.floor(currentStep / stepsPerBar) + 1;
4168
- const pattern = options.getDrumPattern(currentBar);
4169
- if (pattern && pattern.length > 0) {
4170
- const currentStepInBar = currentStep % stepsPerBar;
4171
- const nextStep = currentStepInBar + 4;
4172
- const crossedBar = currentStepInBar < 4;
4173
- for (const drum of pattern) {
4174
- const shouldPlay = crossedBar && drum.step === 0 || drum.step >= currentStepInBar && drum.step < nextStep;
4175
- if (!shouldPlay) continue;
4176
- const whenSeconds = (drum.step - currentStepInBar) * sps;
4177
- if (whenSeconds < -0.1 || whenSeconds > PLAN_TIME) continue;
4178
- options.onPlayDrum({
4179
- pitch: drum.pitch,
4180
- velocity: drum.velocity ?? 1,
4181
- when: Math.max(0, whenSeconds),
4182
- duration: 0.1
4183
- });
4171
+ if (isLooping && loopDurationSec > 0 && currentStep + STEP_EPSILON < lastDrumStep) {
4172
+ drumCursor = loopStartStep - STEP_EPSILON;
4173
+ }
4174
+ lastDrumStep = currentStep;
4175
+ let drumScanTo = currentStep + PLAN_TIME / sps;
4176
+ if (isLooping && loopDurationSec > 0) {
4177
+ drumScanTo = Math.min(drumScanTo, loopEndStep - STEP_EPSILON);
4178
+ }
4179
+ if (drumScanTo > drumCursor) {
4180
+ const firstBar = Math.floor(Math.max(0, drumCursor) / stepsPerBar);
4181
+ const lastBar = Math.floor(Math.max(0, drumScanTo) / stepsPerBar);
4182
+ for (let bar = firstBar; bar <= lastBar; bar++) {
4183
+ const pattern = options.getDrumPattern(bar + 1);
4184
+ if (!pattern || pattern.length === 0) continue;
4185
+ for (const drum of pattern) {
4186
+ const absStep = bar * stepsPerBar + drum.step;
4187
+ if (absStep <= drumCursor || absStep > drumScanTo) continue;
4188
+ options.onPlayDrum({
4189
+ pitch: drum.pitch,
4190
+ velocity: drum.velocity ?? 1,
4191
+ when: Math.max(0, (absStep - currentStep) * sps),
4192
+ duration: 0.1
4193
+ });
4194
+ }
4184
4195
  }
4196
+ drumCursor = drumScanTo;
4185
4197
  }
4186
4198
  if (time >= 0) {
4187
4199
  const currentStep2 = getWrappedPlayStep(time, sps);
@@ -4252,6 +4264,8 @@ var createSequencer = (options) => {
4252
4264
  nowIndex++;
4253
4265
  }
4254
4266
  loopBase = 0;
4267
+ drumCursor = fromStepValue - STEP_EPSILON;
4268
+ lastDrumStep = Number.NEGATIVE_INFINITY;
4255
4269
  lastPlayStep = fromStepValue - 1e-4;
4256
4270
  lastRealTime = -1;
4257
4271
  lastAudioTime = -1;
@@ -12232,6 +12246,7 @@ var shiftNotes = (cores, shiftSteps) => {
12232
12246
  if (newStart < 0) core.deleteNoteById(note.id);
12233
12247
  else core.moveNote(note.id, newStart, note.pitch);
12234
12248
  }
12249
+ core.saveHistory();
12235
12250
  }
12236
12251
  };
12237
12252
  var transposeNotes = (cores, semitones) => {
@@ -12244,6 +12259,7 @@ var transposeNotes = (cores, semitones) => {
12244
12259
  core.moveNote(note.id, note.startStep, newPitch);
12245
12260
  }
12246
12261
  }
12262
+ core.saveHistory();
12247
12263
  }
12248
12264
  };
12249
12265
 
@@ -12852,7 +12868,8 @@ var LinkedList = class {
12852
12868
  * Undo可能かチェック(カーソル移動なし)
12853
12869
  */
12854
12870
  canUndo() {
12855
- return this.#cursor.prev?.value !== null;
12871
+ const { prev } = this.#cursor;
12872
+ return prev !== null && prev.value !== null;
12856
12873
  }
12857
12874
  /**
12858
12875
  * Redo可能かチェック(カーソル移動なし)
@@ -13070,7 +13087,7 @@ var drawGrid = (noteLengthSteps = 1) => {
13070
13087
  for (let y = startY; y < endY; y += keyHeight) {
13071
13088
  const pitchIndex = keyCount - 1 - y / keyHeight;
13072
13089
  const totalPitch = pitchIndex + pitchRangeStart;
13073
- const pitchMod12 = pitchIndex % 12;
13090
+ const pitchMod12 = totalPitch % 12;
13074
13091
  const isBlackKey = blackKeyPitches.has(pitchMod12);
13075
13092
  const isC = pitchMod12 === 0;
13076
13093
  const octave = Math.floor(totalPitch / 12) - 1;
@@ -13124,6 +13141,43 @@ var drawNotes = (notes, color = [59, 130, 246, 1]) => {
13124
13141
  g_grid_ctx.fillRect(renderX + 1, renderY + 1, w - 2, h - 2);
13125
13142
  }
13126
13143
  };
13144
+ var drawNoteLyrics = (notes, syllables) => {
13145
+ if (syllables.length === 0) return;
13146
+ const { keyHeight, stepWidth, keyCount, pitchRangeStart } = g_config;
13147
+ if (keyHeight < 10) return;
13148
+ const fontSize = Math.min(12, Math.floor(keyHeight * 0.85));
13149
+ const sorted = [...notes].sort((a, b) => a.startStep - b.startStep);
13150
+ const count = Math.min(sorted.length, syllables.length);
13151
+ g_grid_ctx.save();
13152
+ g_grid_ctx.font = `${fontSize}px 'k8x12',sans-serif`;
13153
+ g_grid_ctx.textAlign = "left";
13154
+ g_grid_ctx.textBaseline = "middle";
13155
+ g_grid_ctx.lineWidth = 3;
13156
+ g_grid_ctx.lineJoin = "round";
13157
+ for (let i2 = 0; i2 < count; i2++) {
13158
+ const kana = syllables[i2];
13159
+ if (!kana) continue;
13160
+ const note = sorted[i2];
13161
+ const renderX = note.startStep * stepWidth - g_draw_offset_x;
13162
+ const renderY = (keyCount - 1 - (note.pitch - pitchRangeStart)) * keyHeight - g_draw_offset_y;
13163
+ const w = note.durationSteps * stepWidth;
13164
+ if (w < 6) continue;
13165
+ if (renderX + w < 0 || renderX > g_grid_canvas.width) continue;
13166
+ if (renderY + keyHeight < 0 || renderY > g_grid_canvas.height) continue;
13167
+ const textX = renderX + 2;
13168
+ const textY = renderY + keyHeight / 2;
13169
+ g_grid_ctx.save();
13170
+ g_grid_ctx.beginPath();
13171
+ g_grid_ctx.rect(renderX + 1, renderY + 1, w - 2, keyHeight - 2);
13172
+ g_grid_ctx.clip();
13173
+ g_grid_ctx.strokeStyle = "rgba(0,0,0,0.85)";
13174
+ g_grid_ctx.strokeText(kana, textX, textY);
13175
+ g_grid_ctx.fillStyle = "#fff1e8";
13176
+ g_grid_ctx.fillText(kana, textX, textY);
13177
+ g_grid_ctx.restore();
13178
+ }
13179
+ g_grid_ctx.restore();
13180
+ };
13127
13181
  var drawSelectionRect = (rect) => {
13128
13182
  if (!rect) return;
13129
13183
  g_grid_ctx.save();
@@ -14475,6 +14529,19 @@ var mountDAW = (target, options = {}) => {
14475
14529
  return map;
14476
14530
  };
14477
14531
  const getActive = () => trackStates.find((t) => t.config.id === activeTrackId) ?? trackStates[0];
14532
+ let lyricKanaCacheText = "";
14533
+ let lyricKanaCache = [];
14534
+ const getActiveLyricKana = () => {
14535
+ const t = getActive();
14536
+ if (!t?.lyricModel.trim()) return [];
14537
+ const text = t.lyrics.trim();
14538
+ if (!text) return [];
14539
+ if (text !== lyricKanaCacheText) {
14540
+ lyricKanaCacheText = text;
14541
+ lyricKanaCache = normalizeLyrics(text).map((sy) => sy.kana);
14542
+ }
14543
+ return lyricKanaCache;
14544
+ };
14478
14545
  let showModal;
14479
14546
  const getSongEndStepExact = () => {
14480
14547
  let maxEndStep = 0;
@@ -14539,12 +14606,16 @@ var mountDAW = (target, options = {}) => {
14539
14606
  };
14540
14607
  const redrawAll = () => {
14541
14608
  drawGrid(gridLineSteps);
14609
+ let lyricTargetNotes = null;
14542
14610
  for (const t of trackStates) {
14543
14611
  if (hiddenTracks.has(t.config.id)) continue;
14544
14612
  if (isSolo && t.config.id !== activeTrackId) continue;
14545
14613
  const [r, g, b] = t.config.color;
14546
- const a = t.config.id === activeTrackId ? 1 : 0.3;
14547
- drawNotes(t.core.getNotes(), [r, g, b, a]);
14614
+ const isActive = t.config.id === activeTrackId;
14615
+ const a = isActive ? 1 : 0.3;
14616
+ const notes = t.core.getNotes();
14617
+ drawNotes(notes, [r, g, b, a]);
14618
+ if (isActive) lyricTargetNotes = notes;
14548
14619
  }
14549
14620
  if (activeToolMode === "select" && selectionRect) {
14550
14621
  const ctx = getGridContext();
@@ -14575,6 +14646,8 @@ var mountDAW = (target, options = {}) => {
14575
14646
  1
14576
14647
  ]);
14577
14648
  }
14649
+ if (lyricTargetNotes)
14650
+ drawNoteLyrics(lyricTargetNotes, getActiveLyricKana());
14578
14651
  drawStartLine();
14579
14652
  if (playbackState === "playing") drawPlayhead();
14580
14653
  updateScrollbars();
@@ -16041,6 +16114,7 @@ var mountDAW = (target, options = {}) => {
16041
16114
  syncLyricVisibility();
16042
16115
  syncInstDisabled();
16043
16116
  syncVelocityDisabled();
16117
+ redrawAll();
16044
16118
  fireLyricsChange(active);
16045
16119
  reloadVoicesForModel(active.lyricModel);
16046
16120
  });
@@ -16082,6 +16156,7 @@ var mountDAW = (target, options = {}) => {
16082
16156
  label: existing?.label
16083
16157
  });
16084
16158
  active.lyricModel = key;
16159
+ redrawAll();
16085
16160
  fireLyricsChange(active);
16086
16161
  updateTrackPanel();
16087
16162
  reloadVoicesForModel(key);
@@ -16101,6 +16176,7 @@ var mountDAW = (target, options = {}) => {
16101
16176
  lyricInput.addEventListener("input", () => {
16102
16177
  active.lyrics = lyricInput.value;
16103
16178
  updateLyricCount();
16179
+ redrawAll();
16104
16180
  fireLyricsChange(active);
16105
16181
  });
16106
16182
  lyricVol.addEventListener("input", () => {
@@ -18252,6 +18328,7 @@ var mountDAW = (target, options = {}) => {
18252
18328
  t.vocalBreathiness = data.vocalBreathiness ?? 50;
18253
18329
  t.vocalTension = data.vocalTension ?? 50;
18254
18330
  t.vocalOctaveUnison = data.vocalOctaveUnison ?? "none";
18331
+ if (t.config.id === activeTrackId) redrawAll();
18255
18332
  },
18256
18333
  applyTrackInstrument: (trackIndex, instrumentName) => {
18257
18334
  const t = trackStates[trackIndex];
@@ -18659,6 +18736,10 @@ var createPianoRoll = (options, handlers) => {
18659
18736
  selectionStart = null;
18660
18737
  }
18661
18738
  if (dragState) {
18739
+ if (hasDragged) {
18740
+ if (dragState.mode === "move") core.moveNoteEnd(dragState.noteId);
18741
+ else core.resizeNoteEnd(dragState.noteId);
18742
+ }
18662
18743
  dragState = null;
18663
18744
  if (hasDragged) {
18664
18745
  suppressClick = true;
@@ -20437,6 +20518,7 @@ var createDtmStudio = async (options = {}) => {
20437
20518
  drawGrid,
20438
20519
  drawHeader,
20439
20520
  drawKeyboard,
20521
+ drawNoteLyrics,
20440
20522
  drawNotes,
20441
20523
  drawSelectedNotes,
20442
20524
  drawSelectionRect,
package/dist/index.mjs CHANGED
@@ -2677,7 +2677,7 @@ var KOE_VOICEBANKS = {
2677
2677
  mgroid: "MGRoid_\u539F\u97F3\u8A2D\u5B9A\u6E08\u307F.koe",
2678
2678
  motroid: "MOTRoid\u5B8C\u5168\u7248V2.koe",
2679
2679
  nynroid: "NYNRoidver1.4.koe",
2680
- uc: "\u84C4\u97F3\u30AD\u30EA\u30B3 \uFF08beta1.0\uFF09.koe"
2680
+ uc: "\u84C4\u97F3\u30AD\u30EA\u30B3 \uFF08beta1.1\uFF09.koe"
2681
2681
  };
2682
2682
  var KOE_VOICEBANK_LABELS = {
2683
2683
  tsukuyomi: "\u3064\u304F\u3088\u307F\u3061\u3083\u3093",
@@ -3891,6 +3891,7 @@ var reverbAmountToGain = (amount) => Math.max(0, Math.min(100, amount)) / 100;
3891
3891
  var STEPS_PER_BEAT = 48;
3892
3892
  var PLAN_TIME = 0.5;
3893
3893
  var TICK_INTERVAL_MS = 20;
3894
+ var STEP_EPSILON = 1e-4;
3894
3895
  var resolveLoopPoint = (point, _bpm, stepsPerBar, sps) => {
3895
3896
  if ("step" in point) {
3896
3897
  return point.step;
@@ -3922,6 +3923,8 @@ var createSequencer = (options) => {
3922
3923
  let loopDurationSec = 0;
3923
3924
  let loopStartIndex = 0;
3924
3925
  let loopBase = 0;
3926
+ let drumCursor = 0;
3927
+ let lastDrumStep = Number.NEGATIVE_INFINITY;
3925
3928
  let lastPlayStep = 0;
3926
3929
  const secondsPerStep = () => 60 / options.getBpm() / STEPS_PER_BEAT;
3927
3930
  const getWrappedPlayStep = (time, sps) => {
@@ -4031,24 +4034,32 @@ var createSequencer = (options) => {
4031
4034
  }
4032
4035
  const { stepsPerBar } = options;
4033
4036
  const currentStep = getWrappedPlayStep(time, sps);
4034
- const currentBar = Math.floor(currentStep / stepsPerBar) + 1;
4035
- const pattern = options.getDrumPattern(currentBar);
4036
- if (pattern && pattern.length > 0) {
4037
- const currentStepInBar = currentStep % stepsPerBar;
4038
- const nextStep = currentStepInBar + 4;
4039
- const crossedBar = currentStepInBar < 4;
4040
- for (const drum of pattern) {
4041
- const shouldPlay = crossedBar && drum.step === 0 || drum.step >= currentStepInBar && drum.step < nextStep;
4042
- if (!shouldPlay) continue;
4043
- const whenSeconds = (drum.step - currentStepInBar) * sps;
4044
- if (whenSeconds < -0.1 || whenSeconds > PLAN_TIME) continue;
4045
- options.onPlayDrum({
4046
- pitch: drum.pitch,
4047
- velocity: drum.velocity ?? 1,
4048
- when: Math.max(0, whenSeconds),
4049
- duration: 0.1
4050
- });
4037
+ if (isLooping && loopDurationSec > 0 && currentStep + STEP_EPSILON < lastDrumStep) {
4038
+ drumCursor = loopStartStep - STEP_EPSILON;
4039
+ }
4040
+ lastDrumStep = currentStep;
4041
+ let drumScanTo = currentStep + PLAN_TIME / sps;
4042
+ if (isLooping && loopDurationSec > 0) {
4043
+ drumScanTo = Math.min(drumScanTo, loopEndStep - STEP_EPSILON);
4044
+ }
4045
+ if (drumScanTo > drumCursor) {
4046
+ const firstBar = Math.floor(Math.max(0, drumCursor) / stepsPerBar);
4047
+ const lastBar = Math.floor(Math.max(0, drumScanTo) / stepsPerBar);
4048
+ for (let bar = firstBar; bar <= lastBar; bar++) {
4049
+ const pattern = options.getDrumPattern(bar + 1);
4050
+ if (!pattern || pattern.length === 0) continue;
4051
+ for (const drum of pattern) {
4052
+ const absStep = bar * stepsPerBar + drum.step;
4053
+ if (absStep <= drumCursor || absStep > drumScanTo) continue;
4054
+ options.onPlayDrum({
4055
+ pitch: drum.pitch,
4056
+ velocity: drum.velocity ?? 1,
4057
+ when: Math.max(0, (absStep - currentStep) * sps),
4058
+ duration: 0.1
4059
+ });
4060
+ }
4051
4061
  }
4062
+ drumCursor = drumScanTo;
4052
4063
  }
4053
4064
  if (time >= 0) {
4054
4065
  const currentStep2 = getWrappedPlayStep(time, sps);
@@ -4119,6 +4130,8 @@ var createSequencer = (options) => {
4119
4130
  nowIndex++;
4120
4131
  }
4121
4132
  loopBase = 0;
4133
+ drumCursor = fromStepValue - STEP_EPSILON;
4134
+ lastDrumStep = Number.NEGATIVE_INFINITY;
4122
4135
  lastPlayStep = fromStepValue - 1e-4;
4123
4136
  lastRealTime = -1;
4124
4137
  lastAudioTime = -1;
@@ -12099,6 +12112,7 @@ var shiftNotes = (cores, shiftSteps) => {
12099
12112
  if (newStart < 0) core.deleteNoteById(note.id);
12100
12113
  else core.moveNote(note.id, newStart, note.pitch);
12101
12114
  }
12115
+ core.saveHistory();
12102
12116
  }
12103
12117
  };
12104
12118
  var transposeNotes = (cores, semitones) => {
@@ -12111,6 +12125,7 @@ var transposeNotes = (cores, semitones) => {
12111
12125
  core.moveNote(note.id, note.startStep, newPitch);
12112
12126
  }
12113
12127
  }
12128
+ core.saveHistory();
12114
12129
  }
12115
12130
  };
12116
12131
 
@@ -12719,7 +12734,8 @@ var LinkedList = class {
12719
12734
  * Undo可能かチェック(カーソル移動なし)
12720
12735
  */
12721
12736
  canUndo() {
12722
- return this.#cursor.prev?.value !== null;
12737
+ const { prev } = this.#cursor;
12738
+ return prev !== null && prev.value !== null;
12723
12739
  }
12724
12740
  /**
12725
12741
  * Redo可能かチェック(カーソル移動なし)
@@ -12937,7 +12953,7 @@ var drawGrid = (noteLengthSteps = 1) => {
12937
12953
  for (let y = startY; y < endY; y += keyHeight) {
12938
12954
  const pitchIndex = keyCount - 1 - y / keyHeight;
12939
12955
  const totalPitch = pitchIndex + pitchRangeStart;
12940
- const pitchMod12 = pitchIndex % 12;
12956
+ const pitchMod12 = totalPitch % 12;
12941
12957
  const isBlackKey = blackKeyPitches.has(pitchMod12);
12942
12958
  const isC = pitchMod12 === 0;
12943
12959
  const octave = Math.floor(totalPitch / 12) - 1;
@@ -12991,6 +13007,43 @@ var drawNotes = (notes, color = [59, 130, 246, 1]) => {
12991
13007
  g_grid_ctx.fillRect(renderX + 1, renderY + 1, w - 2, h - 2);
12992
13008
  }
12993
13009
  };
13010
+ var drawNoteLyrics = (notes, syllables) => {
13011
+ if (syllables.length === 0) return;
13012
+ const { keyHeight, stepWidth, keyCount, pitchRangeStart } = g_config;
13013
+ if (keyHeight < 10) return;
13014
+ const fontSize = Math.min(12, Math.floor(keyHeight * 0.85));
13015
+ const sorted = [...notes].sort((a, b) => a.startStep - b.startStep);
13016
+ const count = Math.min(sorted.length, syllables.length);
13017
+ g_grid_ctx.save();
13018
+ g_grid_ctx.font = `${fontSize}px 'k8x12',sans-serif`;
13019
+ g_grid_ctx.textAlign = "left";
13020
+ g_grid_ctx.textBaseline = "middle";
13021
+ g_grid_ctx.lineWidth = 3;
13022
+ g_grid_ctx.lineJoin = "round";
13023
+ for (let i2 = 0; i2 < count; i2++) {
13024
+ const kana = syllables[i2];
13025
+ if (!kana) continue;
13026
+ const note = sorted[i2];
13027
+ const renderX = note.startStep * stepWidth - g_draw_offset_x;
13028
+ const renderY = (keyCount - 1 - (note.pitch - pitchRangeStart)) * keyHeight - g_draw_offset_y;
13029
+ const w = note.durationSteps * stepWidth;
13030
+ if (w < 6) continue;
13031
+ if (renderX + w < 0 || renderX > g_grid_canvas.width) continue;
13032
+ if (renderY + keyHeight < 0 || renderY > g_grid_canvas.height) continue;
13033
+ const textX = renderX + 2;
13034
+ const textY = renderY + keyHeight / 2;
13035
+ g_grid_ctx.save();
13036
+ g_grid_ctx.beginPath();
13037
+ g_grid_ctx.rect(renderX + 1, renderY + 1, w - 2, keyHeight - 2);
13038
+ g_grid_ctx.clip();
13039
+ g_grid_ctx.strokeStyle = "rgba(0,0,0,0.85)";
13040
+ g_grid_ctx.strokeText(kana, textX, textY);
13041
+ g_grid_ctx.fillStyle = "#fff1e8";
13042
+ g_grid_ctx.fillText(kana, textX, textY);
13043
+ g_grid_ctx.restore();
13044
+ }
13045
+ g_grid_ctx.restore();
13046
+ };
12994
13047
  var drawSelectionRect = (rect) => {
12995
13048
  if (!rect) return;
12996
13049
  g_grid_ctx.save();
@@ -14342,6 +14395,19 @@ var mountDAW = (target, options = {}) => {
14342
14395
  return map;
14343
14396
  };
14344
14397
  const getActive = () => trackStates.find((t) => t.config.id === activeTrackId) ?? trackStates[0];
14398
+ let lyricKanaCacheText = "";
14399
+ let lyricKanaCache = [];
14400
+ const getActiveLyricKana = () => {
14401
+ const t = getActive();
14402
+ if (!t?.lyricModel.trim()) return [];
14403
+ const text = t.lyrics.trim();
14404
+ if (!text) return [];
14405
+ if (text !== lyricKanaCacheText) {
14406
+ lyricKanaCacheText = text;
14407
+ lyricKanaCache = normalizeLyrics(text).map((sy) => sy.kana);
14408
+ }
14409
+ return lyricKanaCache;
14410
+ };
14345
14411
  let showModal;
14346
14412
  const getSongEndStepExact = () => {
14347
14413
  let maxEndStep = 0;
@@ -14406,12 +14472,16 @@ var mountDAW = (target, options = {}) => {
14406
14472
  };
14407
14473
  const redrawAll = () => {
14408
14474
  drawGrid(gridLineSteps);
14475
+ let lyricTargetNotes = null;
14409
14476
  for (const t of trackStates) {
14410
14477
  if (hiddenTracks.has(t.config.id)) continue;
14411
14478
  if (isSolo && t.config.id !== activeTrackId) continue;
14412
14479
  const [r, g, b] = t.config.color;
14413
- const a = t.config.id === activeTrackId ? 1 : 0.3;
14414
- drawNotes(t.core.getNotes(), [r, g, b, a]);
14480
+ const isActive = t.config.id === activeTrackId;
14481
+ const a = isActive ? 1 : 0.3;
14482
+ const notes = t.core.getNotes();
14483
+ drawNotes(notes, [r, g, b, a]);
14484
+ if (isActive) lyricTargetNotes = notes;
14415
14485
  }
14416
14486
  if (activeToolMode === "select" && selectionRect) {
14417
14487
  const ctx = getGridContext();
@@ -14442,6 +14512,8 @@ var mountDAW = (target, options = {}) => {
14442
14512
  1
14443
14513
  ]);
14444
14514
  }
14515
+ if (lyricTargetNotes)
14516
+ drawNoteLyrics(lyricTargetNotes, getActiveLyricKana());
14445
14517
  drawStartLine();
14446
14518
  if (playbackState === "playing") drawPlayhead();
14447
14519
  updateScrollbars();
@@ -15908,6 +15980,7 @@ var mountDAW = (target, options = {}) => {
15908
15980
  syncLyricVisibility();
15909
15981
  syncInstDisabled();
15910
15982
  syncVelocityDisabled();
15983
+ redrawAll();
15911
15984
  fireLyricsChange(active);
15912
15985
  reloadVoicesForModel(active.lyricModel);
15913
15986
  });
@@ -15949,6 +16022,7 @@ var mountDAW = (target, options = {}) => {
15949
16022
  label: existing?.label
15950
16023
  });
15951
16024
  active.lyricModel = key;
16025
+ redrawAll();
15952
16026
  fireLyricsChange(active);
15953
16027
  updateTrackPanel();
15954
16028
  reloadVoicesForModel(key);
@@ -15968,6 +16042,7 @@ var mountDAW = (target, options = {}) => {
15968
16042
  lyricInput.addEventListener("input", () => {
15969
16043
  active.lyrics = lyricInput.value;
15970
16044
  updateLyricCount();
16045
+ redrawAll();
15971
16046
  fireLyricsChange(active);
15972
16047
  });
15973
16048
  lyricVol.addEventListener("input", () => {
@@ -18119,6 +18194,7 @@ var mountDAW = (target, options = {}) => {
18119
18194
  t.vocalBreathiness = data.vocalBreathiness ?? 50;
18120
18195
  t.vocalTension = data.vocalTension ?? 50;
18121
18196
  t.vocalOctaveUnison = data.vocalOctaveUnison ?? "none";
18197
+ if (t.config.id === activeTrackId) redrawAll();
18122
18198
  },
18123
18199
  applyTrackInstrument: (trackIndex, instrumentName) => {
18124
18200
  const t = trackStates[trackIndex];
@@ -18526,6 +18602,10 @@ var createPianoRoll = (options, handlers) => {
18526
18602
  selectionStart = null;
18527
18603
  }
18528
18604
  if (dragState) {
18605
+ if (hasDragged) {
18606
+ if (dragState.mode === "move") core.moveNoteEnd(dragState.noteId);
18607
+ else core.resizeNoteEnd(dragState.noteId);
18608
+ }
18529
18609
  dragState = null;
18530
18610
  if (hasDragged) {
18531
18611
  suppressClick = true;
@@ -20302,6 +20382,7 @@ export {
20302
20382
  drawGrid,
20303
20383
  drawHeader,
20304
20384
  drawKeyboard,
20385
+ drawNoteLyrics,
20305
20386
  drawNotes,
20306
20387
  drawSelectedNotes,
20307
20388
  drawSelectionRect,
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "author": "onjmin",
3
3
  "license": "MIT",
4
4
  "name": "@onjmin/dtm",
5
- "version": "1.0.5",
5
+ "version": "1.0.7",
6
6
  "description": "MMLを中間言語に用いた、モバイルファーストなDAW / ピアノロール打ち込みコンポーネント",
7
7
  "homepage": "https://onjmin.github.io/dtm",
8
8
  "repository": {