Skip to content

Commit

Permalink
CubicHermite補間とCatmullRom補間を実装、ポイントを描画する処理を実装
Browse files Browse the repository at this point in the history
  • Loading branch information
sigprogramming committed Nov 20, 2024
1 parent fc0784e commit 867e266
Show file tree
Hide file tree
Showing 8 changed files with 361 additions and 47 deletions.
6 changes: 3 additions & 3 deletions src/components/Sing/ScoreSequencer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ import {
useCommandOrControlKey,
useShiftKey,
} from "@/composables/useModifierKey";
import { applyGaussianFilter, linearInterpolation } from "@/sing/utility";
import { applyGaussianFilter, Interpolate } from "@/sing/utility";
import { useLyricInput } from "@/composables/useLyricInput";
import { useCursorState, CursorState } from "@/composables/useCursorState";
import { ExhaustiveError } from "@/type/utility";
Expand Down Expand Up @@ -667,7 +667,7 @@ const previewDrawPitch = () => {
} else if (cursorFrame < prevCursorPos.frame) {
for (let i = cursorFrame; i <= prevCursorPos.frame; i++) {
tempPitchEdit.data[i - tempPitchEdit.startFrame] = Math.exp(
linearInterpolation(
Interpolate.linear(
cursorFrame,
Math.log(cursorFrequency),
prevCursorPos.frame,
Expand All @@ -679,7 +679,7 @@ const previewDrawPitch = () => {
} else {
for (let i = prevCursorPos.frame; i <= cursorFrame; i++) {
tempPitchEdit.data[i - tempPitchEdit.startFrame] = Math.exp(
linearInterpolation(
Interpolate.linear(
prevCursorPos.frame,
Math.log(prevCursorPos.frequency),
cursorFrame,
Expand Down
122 changes: 121 additions & 1 deletion src/components/Sing/SequencerPitch.vue
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
VALUE_INDICATING_NO_DATA,
convertToFramePhonemes,
frequencyToNoteNumber,
noteNumberToFrequency,
secondToTick,
} from "@/sing/domain";
import {
Expand All @@ -21,17 +22,32 @@ import {
noteNumberToBaseY,
tickToBaseX,
} from "@/sing/viewHelper";
import { Color, LineStrip } from "@/sing/graphics/lineStrip";
import { LineStrip } from "@/sing/graphics/lineStrip";
import {
onMountedOrActivated,
onUnmountedOrDeactivated,
} from "@/composables/onMountOrActivate";
import { ExhaustiveError } from "@/type/utility";
import { createLogger } from "@/domain/frontend/log";
import { Interpolate } from "@/sing/utility";
import { Color } from "@/sing/graphics/color";
import { Points } from "@/sing/graphics/points";
import { getLast } from "@/sing/utility";
import { getOrThrow } from "@/helpers/mapHelper";
import { EditorFrameAudioQuery } from "@/store/type";
type KnotsData = {
xArray: number[];
yArray: number[];
};
type PitchKnots = {
readonly color: Color;
readonly radius: number;
knotsData?: KnotsData;
points?: Points;
};
type PitchLine = {
color: Ref<Color>;
readonly width: number;
Expand Down Expand Up @@ -103,6 +119,16 @@ const pitchEditLine: PitchLine = {
pitchDataMap: new Map(),
lineStripMap: new Map(),
};
const interpOriginalPitchLine: PitchLine = {
color: new Color(171, 199, 201, 255),
width: 1.5,
pitchDataMap: new Map(),
lineStripMap: new Map(),
};
const interpOriginalPitchKnots: PitchKnots = {
color: new Color(149, 188, 207, 255),
radius: 2,
};
const canvasContainer = ref<HTMLElement | null>(null);
let resizeObserver: ResizeObserver | undefined;
Expand Down Expand Up @@ -221,6 +247,47 @@ const updateLineStrips = (pitchLine: PitchLine) => {
}
};
const updatePoints = (pitchKnots: PitchKnots) => {
if (stage == undefined) {
throw new Error("stage is undefined.");
}
const tpqn = store.state.tpqn;
const zoomX = store.state.sequencerZoomX;
const zoomY = store.state.sequencerZoomY;
const offsetX = props.offsetX;
const offsetY = props.offsetY;
if (pitchKnots.knotsData == undefined) {
return;
}
// pointsがあれば再利用し、なければpointsを作成する
const numKnots = pitchKnots.knotsData.xArray.length;
if (pitchKnots.points != undefined) {
pitchKnots.points.numOfPoints = numKnots;
} else {
pitchKnots.points = new Points(
numKnots,
pitchKnots.color,
pitchKnots.radius,
8,
);
stage.addChild(pitchKnots.points.displayObject);
}
// ポイントを計算してlineStripに設定&更新
for (let i = 0; i < numKnots; i++) {
const ticks = pitchKnots.knotsData.xArray[i];
const baseX = tickToBaseX(ticks, tpqn);
const x = baseX * zoomX - offsetX;
const noteNumber = pitchKnots.knotsData.yArray[i];
const baseY = noteNumberToBaseY(noteNumber);
const y = baseY * zoomY - offsetY;
pitchKnots.points.setPoint(i, x, y);
}
pitchKnots.points.update();
};
const render = () => {
if (renderer == undefined) {
throw new Error("renderer is undefined.");
Expand All @@ -245,6 +312,8 @@ const render = () => {
// ピッチラインのLineStripを更新する
updateLineStrips(originalPitchLine);
updateLineStrips(pitchEditLine);
updateLineStrips(interpOriginalPitchLine);
updatePoints(interpOriginalPitchKnots);
renderer.render(stage);
};
Expand Down Expand Up @@ -382,6 +451,39 @@ const generatePitchEditData = () => {
return toPitchData(tempData, frameRate);
};
const generateInterpOriginalPitchData = (
points: { x: number; y: number }[],
) => {
const frameRate = editFrameRate.value;
const xArray: number[] = [];
for (let i = 0; i < 400; i++) {
xArray.push(i);
}
const tempData = Interpolate.catmullRom(points, xArray).map((value) =>
noteNumberToFrequency(value),
);
return toPitchData(tempData, frameRate);
};
const setKnotsDataToPitchKnots = (points: { x: number; y: number }[]) => {
const frameRate = editFrameRate.value;
const ticksArray: number[] = [];
for (let i = 0; i < points.length; i++) {
const ticks = secondToTick(
points[i].x / frameRate,
tempos.value,
tpqn.value,
);
ticksArray.push(ticks);
}
interpOriginalPitchKnots.knotsData = {
xArray: ticksArray,
yArray: points.map((value) => value.y),
};
};
const asyncLock = new AsyncLock({ maxPending: 1 });
watch(
Expand All @@ -392,6 +494,22 @@ watch(
async () => {
const originalPitchData = generateOriginalPitchData();
await setPitchDataToPitchLine(originalPitchData, originalPitchLine);
const points = [
{ x: 100, y: 60 },
{ x: 160, y: 62 },
{ x: 165, y: 62 },
{ x: 180, y: 65 },
{ x: 220, y: 63 },
{ x: 290, y: 69 },
];
const interpOriginalPitchData = generateInterpOriginalPitchData(points);
await setPitchDataToPitchLine(
interpOriginalPitchData,
interpOriginalPitchLine,
);
setKnotsDataToPitchKnots(points);
renderInNextFrame = true;
},
(err) => {
Expand Down Expand Up @@ -519,6 +637,8 @@ onUnmountedOrDeactivated(() => {
originalPitchLine.lineStripMap.clear();
pitchEditLine.lineStripMap.forEach((value) => value.destroy());
pitchEditLine.lineStripMap.clear();
interpOriginalPitchLine.lineStripMap.forEach((value) => value.destroy());
interpOriginalPitchLine.lineStripMap.clear();
renderer?.destroy(true);
resizeObserver?.disconnect();
});
Expand Down
29 changes: 29 additions & 0 deletions src/sing/graphics/color.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/**
* 色を表します。各値は0以上255以下です。
*/
export class Color {
readonly r: number;
readonly g: number;
readonly b: number;
readonly a: number;

constructor(r: number, g: number, b: number, a: number) {
this.r = r;
this.g = g;
this.b = b;
this.a = a;
}

equals(color: Color) {
return (
this.r === color.r &&
this.g === color.g &&
this.b === color.b &&
this.a === color.a
);
}

toRgbaArray() {
return [this.r, this.g, this.b, this.a];
}
}
33 changes: 2 additions & 31 deletions src/sing/graphics/lineStrip.ts
Original file line number Diff line number Diff line change
@@ -1,36 +1,7 @@
import * as PIXI from "pixi.js";
import lineStripVertexShaderSource from "@/sing/graphics/shaders/lineStripVertexShader.glsl?raw";
import fragmentShaderSource from "@/sing/graphics/shaders/fragmentShader.glsl?raw";

/**
* 色を表します。各値は0以上255以下です。
*/
export class Color {
readonly r: number;
readonly g: number;
readonly b: number;
readonly a: number;

constructor(r: number, g: number, b: number, a: number) {
this.r = r;
this.g = g;
this.b = b;
this.a = a;
}

equals(color: Color) {
return (
this.r === color.r &&
this.g === color.g &&
this.b === color.b &&
this.a === color.a
);
}

toRgbaArray() {
return [this.r, this.g, this.b, this.a];
}
}
import { Color } from "@/sing/graphics/color";

/**
* 複数のポイントから折れ線を引きます。
Expand Down Expand Up @@ -134,7 +105,7 @@ export class LineStrip {
}

/**
* 折れ線を更新します。(設定されたポイントを適用します)
* LineStripを更新します。(設定されたポイントを適用します)
*/
update() {
this.pointsBuffer.update(this.points);
Expand Down
Loading

0 comments on commit 867e266

Please sign in to comment.