@onjmin/dtm 1.0.4 → 1.0.6

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.js CHANGED
@@ -2810,7 +2810,7 @@ var KOE_VOICEBANKS = {
2810
2810
  mgroid: "MGRoid_\u539F\u97F3\u8A2D\u5B9A\u6E08\u307F.koe",
2811
2811
  motroid: "MOTRoid\u5B8C\u5168\u7248V2.koe",
2812
2812
  nynroid: "NYNRoidver1.4.koe",
2813
- uc: "\u84C4\u97F3\u30AD\u30EA\u30B3 \uFF08beta1.0\uFF09.koe"
2813
+ uc: "\u84C4\u97F3\u30AD\u30EA\u30B3 \uFF08beta1.1\uFF09.koe"
2814
2814
  };
2815
2815
  var KOE_VOICEBANK_LABELS = {
2816
2816
  tsukuyomi: "\u3064\u304F\u3088\u307F\u3061\u3083\u3093",
@@ -4024,6 +4024,7 @@ var reverbAmountToGain = (amount) => Math.max(0, Math.min(100, amount)) / 100;
4024
4024
  var STEPS_PER_BEAT = 48;
4025
4025
  var PLAN_TIME = 0.5;
4026
4026
  var TICK_INTERVAL_MS = 20;
4027
+ var STEP_EPSILON = 1e-4;
4027
4028
  var resolveLoopPoint = (point, _bpm, stepsPerBar, sps) => {
4028
4029
  if ("step" in point) {
4029
4030
  return point.step;
@@ -4055,6 +4056,8 @@ var createSequencer = (options) => {
4055
4056
  let loopDurationSec = 0;
4056
4057
  let loopStartIndex = 0;
4057
4058
  let loopBase = 0;
4059
+ let drumCursor = 0;
4060
+ let lastDrumStep = Number.NEGATIVE_INFINITY;
4058
4061
  let lastPlayStep = 0;
4059
4062
  const secondsPerStep = () => 60 / options.getBpm() / STEPS_PER_BEAT;
4060
4063
  const getWrappedPlayStep = (time, sps) => {
@@ -4164,24 +4167,32 @@ var createSequencer = (options) => {
4164
4167
  }
4165
4168
  const { stepsPerBar } = options;
4166
4169
  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
- });
4170
+ if (isLooping && loopDurationSec > 0 && currentStep + STEP_EPSILON < lastDrumStep) {
4171
+ drumCursor = loopStartStep - STEP_EPSILON;
4172
+ }
4173
+ lastDrumStep = currentStep;
4174
+ let drumScanTo = currentStep + PLAN_TIME / sps;
4175
+ if (isLooping && loopDurationSec > 0) {
4176
+ drumScanTo = Math.min(drumScanTo, loopEndStep - STEP_EPSILON);
4177
+ }
4178
+ if (drumScanTo > drumCursor) {
4179
+ const firstBar = Math.floor(Math.max(0, drumCursor) / stepsPerBar);
4180
+ const lastBar = Math.floor(Math.max(0, drumScanTo) / stepsPerBar);
4181
+ for (let bar = firstBar; bar <= lastBar; bar++) {
4182
+ const pattern = options.getDrumPattern(bar + 1);
4183
+ if (!pattern || pattern.length === 0) continue;
4184
+ for (const drum of pattern) {
4185
+ const absStep = bar * stepsPerBar + drum.step;
4186
+ if (absStep <= drumCursor || absStep > drumScanTo) continue;
4187
+ options.onPlayDrum({
4188
+ pitch: drum.pitch,
4189
+ velocity: drum.velocity ?? 1,
4190
+ when: Math.max(0, (absStep - currentStep) * sps),
4191
+ duration: 0.1
4192
+ });
4193
+ }
4184
4194
  }
4195
+ drumCursor = drumScanTo;
4185
4196
  }
4186
4197
  if (time >= 0) {
4187
4198
  const currentStep2 = getWrappedPlayStep(time, sps);
@@ -4252,6 +4263,8 @@ var createSequencer = (options) => {
4252
4263
  nowIndex++;
4253
4264
  }
4254
4265
  loopBase = 0;
4266
+ drumCursor = fromStepValue - STEP_EPSILON;
4267
+ lastDrumStep = Number.NEGATIVE_INFINITY;
4255
4268
  lastPlayStep = fromStepValue - 1e-4;
4256
4269
  lastRealTime = -1;
4257
4270
  lastAudioTime = -1;
@@ -8891,14 +8904,20 @@ var mountMmlPlayer = (target, mml, options = {}) => {
8891
8904
  }
8892
8905
  const seqTracks = trackIndices.map((index) => {
8893
8906
  let id = 0;
8894
- const notes = placements.filter((p) => p.trackIndex === index).map((p) => ({
8907
+ const trackPlacements = placements.filter((p) => p.trackIndex === index);
8908
+ const headerVelocity = trackPlacements[0]?.velocity ?? DEFAULT_VELOCITY;
8909
+ const notes = trackPlacements.map((p) => ({
8895
8910
  id: id++,
8896
8911
  startStep: p.startStep,
8897
8912
  durationSteps: p.durationSteps,
8898
8913
  pitch: p.pitch,
8899
- velocity: p.velocity
8914
+ velocity: DEFAULT_VELOCITY
8900
8915
  }));
8901
- return { id: String(index), volume: trackVolume, notes };
8916
+ return {
8917
+ id: String(index),
8918
+ volume: trackVolume * headerVelocity / DEFAULT_VELOCITY,
8919
+ notes
8920
+ };
8902
8921
  });
8903
8922
  const colorOf = (index) => colors[index % colors.length] ?? DEFAULT_TRACK_COLORS[0];
8904
8923
  let audioCtx = null;
@@ -12226,6 +12245,7 @@ var shiftNotes = (cores, shiftSteps) => {
12226
12245
  if (newStart < 0) core.deleteNoteById(note.id);
12227
12246
  else core.moveNote(note.id, newStart, note.pitch);
12228
12247
  }
12248
+ core.saveHistory();
12229
12249
  }
12230
12250
  };
12231
12251
  var transposeNotes = (cores, semitones) => {
@@ -12238,6 +12258,7 @@ var transposeNotes = (cores, semitones) => {
12238
12258
  core.moveNote(note.id, note.startStep, newPitch);
12239
12259
  }
12240
12260
  }
12261
+ core.saveHistory();
12241
12262
  }
12242
12263
  };
12243
12264
 
@@ -12846,7 +12867,8 @@ var LinkedList = class {
12846
12867
  * Undo可能かチェック(カーソル移動なし)
12847
12868
  */
12848
12869
  canUndo() {
12849
- return this.#cursor.prev?.value !== null;
12870
+ const { prev } = this.#cursor;
12871
+ return prev !== null && prev.value !== null;
12850
12872
  }
12851
12873
  /**
12852
12874
  * Redo可能かチェック(カーソル移動なし)
@@ -13064,7 +13086,7 @@ var drawGrid = (noteLengthSteps = 1) => {
13064
13086
  for (let y = startY; y < endY; y += keyHeight) {
13065
13087
  const pitchIndex = keyCount - 1 - y / keyHeight;
13066
13088
  const totalPitch = pitchIndex + pitchRangeStart;
13067
- const pitchMod12 = pitchIndex % 12;
13089
+ const pitchMod12 = totalPitch % 12;
13068
13090
  const isBlackKey = blackKeyPitches.has(pitchMod12);
13069
13091
  const isC = pitchMod12 === 0;
13070
13092
  const octave = Math.floor(totalPitch / 12) - 1;
@@ -18653,6 +18675,10 @@ var createPianoRoll = (options, handlers) => {
18653
18675
  selectionStart = null;
18654
18676
  }
18655
18677
  if (dragState) {
18678
+ if (hasDragged) {
18679
+ if (dragState.mode === "move") core.moveNoteEnd(dragState.noteId);
18680
+ else core.resizeNoteEnd(dragState.noteId);
18681
+ }
18656
18682
  dragState = null;
18657
18683
  if (hasDragged) {
18658
18684
  suppressClick = true;
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;
@@ -8758,14 +8771,20 @@ var mountMmlPlayer = (target, mml, options = {}) => {
8758
8771
  }
8759
8772
  const seqTracks = trackIndices.map((index) => {
8760
8773
  let id = 0;
8761
- const notes = placements.filter((p) => p.trackIndex === index).map((p) => ({
8774
+ const trackPlacements = placements.filter((p) => p.trackIndex === index);
8775
+ const headerVelocity = trackPlacements[0]?.velocity ?? DEFAULT_VELOCITY;
8776
+ const notes = trackPlacements.map((p) => ({
8762
8777
  id: id++,
8763
8778
  startStep: p.startStep,
8764
8779
  durationSteps: p.durationSteps,
8765
8780
  pitch: p.pitch,
8766
- velocity: p.velocity
8781
+ velocity: DEFAULT_VELOCITY
8767
8782
  }));
8768
- return { id: String(index), volume: trackVolume, notes };
8783
+ return {
8784
+ id: String(index),
8785
+ volume: trackVolume * headerVelocity / DEFAULT_VELOCITY,
8786
+ notes
8787
+ };
8769
8788
  });
8770
8789
  const colorOf = (index) => colors[index % colors.length] ?? DEFAULT_TRACK_COLORS[0];
8771
8790
  let audioCtx = null;
@@ -12093,6 +12112,7 @@ var shiftNotes = (cores, shiftSteps) => {
12093
12112
  if (newStart < 0) core.deleteNoteById(note.id);
12094
12113
  else core.moveNote(note.id, newStart, note.pitch);
12095
12114
  }
12115
+ core.saveHistory();
12096
12116
  }
12097
12117
  };
12098
12118
  var transposeNotes = (cores, semitones) => {
@@ -12105,6 +12125,7 @@ var transposeNotes = (cores, semitones) => {
12105
12125
  core.moveNote(note.id, note.startStep, newPitch);
12106
12126
  }
12107
12127
  }
12128
+ core.saveHistory();
12108
12129
  }
12109
12130
  };
12110
12131
 
@@ -12713,7 +12734,8 @@ var LinkedList = class {
12713
12734
  * Undo可能かチェック(カーソル移動なし)
12714
12735
  */
12715
12736
  canUndo() {
12716
- return this.#cursor.prev?.value !== null;
12737
+ const { prev } = this.#cursor;
12738
+ return prev !== null && prev.value !== null;
12717
12739
  }
12718
12740
  /**
12719
12741
  * Redo可能かチェック(カーソル移動なし)
@@ -12931,7 +12953,7 @@ var drawGrid = (noteLengthSteps = 1) => {
12931
12953
  for (let y = startY; y < endY; y += keyHeight) {
12932
12954
  const pitchIndex = keyCount - 1 - y / keyHeight;
12933
12955
  const totalPitch = pitchIndex + pitchRangeStart;
12934
- const pitchMod12 = pitchIndex % 12;
12956
+ const pitchMod12 = totalPitch % 12;
12935
12957
  const isBlackKey = blackKeyPitches.has(pitchMod12);
12936
12958
  const isC = pitchMod12 === 0;
12937
12959
  const octave = Math.floor(totalPitch / 12) - 1;
@@ -18520,6 +18542,10 @@ var createPianoRoll = (options, handlers) => {
18520
18542
  selectionStart = null;
18521
18543
  }
18522
18544
  if (dragState) {
18545
+ if (hasDragged) {
18546
+ if (dragState.mode === "move") core.moveNoteEnd(dragState.noteId);
18547
+ else core.resizeNoteEnd(dragState.noteId);
18548
+ }
18523
18549
  dragState = null;
18524
18550
  if (hasDragged) {
18525
18551
  suppressClick = true;
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.4",
5
+ "version": "1.0.6",
6
6
  "description": "MMLを中間言語に用いた、モバイルファーストなDAW / ピアノロール打ち込みコンポーネント",
7
7
  "homepage": "https://onjmin.github.io/dtm",
8
8
  "repository": {