Skip to content

Commit

Permalink
[refactor] NoteIdブランド型定義 (VOICEVOX#1969)
Browse files Browse the repository at this point in the history
NoteIdブランド型定義
  • Loading branch information
Hiroshiba authored May 4, 2024
1 parent f560c6f commit 0fb559d
Show file tree
Hide file tree
Showing 8 changed files with 50 additions and 41 deletions.
19 changes: 10 additions & 9 deletions src/components/Sing/ScoreSequencer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,7 @@ import { v4 as uuidv4 } from "uuid";
import ContextMenu, {
ContextMenuItemData,
} from "@/components/Menu/ContextMenu.vue";
import { NoteId } from "@/type/preload";
import { useStore } from "@/store";
import { Note, SequencerEditTarget } from "@/store/type";
import {
Expand Down Expand Up @@ -433,11 +434,11 @@ let previewStartEditTarget: SequencerEditTarget = "NOTE";
let executePreviewProcess = false;
// ノート編集のプレビュー
const previewNotes = ref<Note[]>([]);
const copiedNotesForPreview = new Map<string, Note>();
const copiedNotesForPreview = new Map<NoteId, Note>();
let dragStartTicks = 0;
let dragStartNoteNumber = 0;
let dragStartGuideLineTicks = 0;
let draggingNoteId = ""; // FIXME: 無効状態はstring以外の型にする
let draggingNoteId = NoteId(""); // FIXME: 無効状態はstring以外の型にする
let edited = false; // プレビュー終了時にstore.stateの更新を行うかどうかを表す変数
// ピッチ編集のプレビュー
const previewPitchEdit = ref<
Expand Down Expand Up @@ -470,7 +471,7 @@ const previewAdd = () => {
Math.round(dragTicks / snapTicks.value) * snapTicks.value;
const noteEndPos = draggingNote.position + noteDuration;
const editedNotes = new Map<string, Note>();
const editedNotes = new Map<NoteId, Note>();
for (const note of previewNotes.value) {
const copiedNote = copiedNotesForPreview.get(note.id);
if (!copiedNote) {
Expand Down Expand Up @@ -507,7 +508,7 @@ const previewMove = () => {
const movingTicks = newNotePos - notePos;
const movingSemitones = cursorNoteNumber - dragStartNoteNumber;
const editedNotes = new Map<string, Note>();
const editedNotes = new Map<NoteId, Note>();
for (const note of previewNotes.value) {
const copiedNote = copiedNotesForPreview.get(note.id);
if (!copiedNote) {
Expand Down Expand Up @@ -557,7 +558,7 @@ const previewResizeRight = () => {
Math.round((noteEndPos + dragTicks) / snapTicks.value) * snapTicks.value;
const movingTicks = newNoteEndPos - noteEndPos;
const editedNotes = new Map<string, Note>();
const editedNotes = new Map<NoteId, Note>();
for (const note of previewNotes.value) {
const copiedNote = copiedNotesForPreview.get(note.id);
if (!copiedNote) {
Expand Down Expand Up @@ -597,7 +598,7 @@ const previewResizeLeft = () => {
Math.round((notePos + dragTicks) / snapTicks.value) * snapTicks.value;
const movingTicks = newNotePos - notePos;
const editedNotes = new Map<string, Note>();
const editedNotes = new Map<NoteId, Note>();
for (const note of previewNotes.value) {
const copiedNote = copiedNotesForPreview.get(note.id);
if (!copiedNote) {
Expand Down Expand Up @@ -813,7 +814,7 @@ const startPreview = (event: MouseEvent, mode: PreviewMode, note?: Note) => {
return;
}
note = {
id: uuidv4(),
id: NoteId(uuidv4()),
position: guideLineTicks,
duration: snapTicks.value,
noteNumber: cursorNoteNumber,
Expand All @@ -835,7 +836,7 @@ const startPreview = (event: MouseEvent, mode: PreviewMode, note?: Note) => {
maxIndex = Math.max(maxIndex, i);
}
}
const noteIdsToSelect: string[] = [];
const noteIdsToSelect: NoteId[] = [];
for (let i = minIndex; i <= maxIndex; i++) {
const noteId = notes.value[i].id;
if (!state.selectedNoteIds.has(noteId)) {
Expand Down Expand Up @@ -1126,7 +1127,7 @@ const rectSelect = (additive: boolean) => {
(scrollY.value + top + height) / zoomY.value,
);
const noteIdsToSelect: string[] = [];
const noteIdsToSelect: NoteId[] = [];
for (const note of notes.value) {
if (
note.position + note.duration >= startTicks &&
Expand Down
3 changes: 2 additions & 1 deletion src/domain/project/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { z } from "zod";
import {
audioKeySchema,
engineIdSchema,
noteIdSchema,
presetKeySchema,
speakerIdSchema,
styleIdSchema,
Expand Down Expand Up @@ -70,7 +71,7 @@ export const timeSignatureSchema = z.object({
});

export const noteSchema = z.object({
id: z.string(),
id: noteIdSchema,
position: z.number(),
duration: z.number(),
noteNumber: z.number(),
Expand Down
11 changes: 6 additions & 5 deletions src/sing/storeHelper.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { NoteId } from "@/type/preload";
import { Note } from "@/store/type";

export const DEFAULT_TPQN = 480;
Expand Down Expand Up @@ -48,10 +49,10 @@ export class FrequentlyUpdatedState<T> {
type NoteInfo = {
startTicks: number;
endTicks: number;
overlappingNoteIds: Set<string>;
overlappingNoteIds: Set<NoteId>;
};

export type OverlappingNoteInfos = Map<string, NoteInfo>;
export type OverlappingNoteInfos = Map<NoteId, NoteInfo>;

export function addNotesToOverlappingNoteInfos(
overlappingNoteInfos: OverlappingNoteInfos,
Expand All @@ -66,7 +67,7 @@ export function addNotesToOverlappingNoteInfos(
}
// TODO: 計算量がO(n^2)になっているので、区間木などを使用してO(nlogn)にする
for (const note of notes) {
const overlappingNoteIds = new Set<string>();
const overlappingNoteIds = new Set<NoteId>();
for (const [noteId, noteInfo] of overlappingNoteInfos) {
if (noteId === note.id) {
continue;
Expand Down Expand Up @@ -130,8 +131,8 @@ export function updateNotesOfOverlappingNoteInfos(

export function getOverlappingNoteIds(
currentNoteInfos: OverlappingNoteInfos,
): Set<string> {
const overlappingNoteIds = new Set<string>();
): Set<NoteId> {
const overlappingNoteIds = new Set<NoteId>();
for (const [noteId, noteInfo] of currentNoteInfos) {
if (noteInfo.overlappingNoteIds.size !== 0) {
overlappingNoteIds.add(noteId);
Expand Down
6 changes: 3 additions & 3 deletions src/sing/viewHelper.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { z } from "zod";
import { StyleInfo, isMac } from "@/type/preload";
import { StyleInfo, isMac, NoteId } from "@/type/preload";
import { calculateHash } from "@/sing/utility";

const BASE_X_PER_QUARTER_NOTE = 120;
Expand Down Expand Up @@ -163,9 +163,9 @@ export class DoubleClickDetector<T extends AreaInfo> {
export class NoteAreaInfo implements AreaInfo {
readonly type: "note";
readonly id: string;
readonly noteId: string;
readonly noteId: NoteId;

constructor(noteId: string) {
constructor(noteId: NoteId) {
this.type = "note";
this.id = `NOTE-${noteId}`;
this.noteId = noteId;
Expand Down
22 changes: 11 additions & 11 deletions src/store/singing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ import {
SequencerEditTarget,
} from "./type";
import { sanitizeFileName } from "./utility";
import { EngineId, NoteId, StyleId } from "@/type/preload";
import { Midi } from "@/sing/midi";
import { EngineId, StyleId } from "@/type/preload";
import { FrameAudioQuery, Note as NoteForRequestToEngine } from "@/openapi";
import { ResultError, getValueOrThrow } from "@/type/result";
import {
Expand Down Expand Up @@ -437,7 +437,7 @@ export const singingStore = createPartialStore<SingingStoreTypes>({

UPDATE_NOTES: {
mutation(state, { notes }: { notes: Note[] }) {
const notesMap = new Map<string, Note>();
const notesMap = new Map<NoteId, Note>();
for (const note of notes) {
notesMap.set(note.id, note);
}
Expand All @@ -453,7 +453,7 @@ export const singingStore = createPartialStore<SingingStoreTypes>({
},

REMOVE_NOTES: {
mutation(state, { noteIds }: { noteIds: string[] }) {
mutation(state, { noteIds }: { noteIds: NoteId[] }) {
const noteIdsSet = new Set(noteIds);
const selectedTrack = state.tracks[selectedTrackIndex];
const notes = selectedTrack.notes.filter((value) => {
Expand All @@ -479,12 +479,12 @@ export const singingStore = createPartialStore<SingingStoreTypes>({
},

SELECT_NOTES: {
mutation(state, { noteIds }: { noteIds: string[] }) {
mutation(state, { noteIds }: { noteIds: NoteId[] }) {
for (const noteId of noteIds) {
state.selectedNoteIds.add(noteId);
}
},
async action({ getters, commit }, { noteIds }: { noteIds: string[] }) {
async action({ getters, commit }, { noteIds }: { noteIds: NoteId[] }) {
const existingNoteIds = getters.NOTE_IDS;
const isValidNoteIds = noteIds.every((value) => {
return existingNoteIds.has(value);
Expand Down Expand Up @@ -518,14 +518,14 @@ export const singingStore = createPartialStore<SingingStoreTypes>({
},

SET_EDITING_LYRIC_NOTE_ID: {
mutation(state, { noteId }: { noteId?: string }) {
mutation(state, { noteId }: { noteId?: NoteId }) {
if (noteId != undefined && !state.selectedNoteIds.has(noteId)) {
state.selectedNoteIds.clear();
state.selectedNoteIds.add(noteId);
}
state.editingLyricNoteId = noteId;
},
async action({ getters, commit }, { noteId }: { noteId?: string }) {
async action({ getters, commit }, { noteId }: { noteId?: NoteId }) {
if (noteId != undefined && !getters.NOTE_IDS.has(noteId)) {
throw new Error("The note id is invalid.");
}
Expand Down Expand Up @@ -1612,7 +1612,7 @@ export const singingStore = createPartialStore<SingingStoreTypes>({

let notes = midiNotes.map((value): Note => {
return {
id: uuidv4(),
id: NoteId(uuidv4()),
position: convertPosition(value.ticks, midiTpqn, tpqn),
duration: convertDuration(
value.ticks,
Expand Down Expand Up @@ -1919,7 +1919,7 @@ export const singingStore = createPartialStore<SingingStoreTypes>({
}

const note: Note = {
id: uuidv4(),
id: NoteId(uuidv4()),
position,
duration,
noteNumber,
Expand Down Expand Up @@ -2104,7 +2104,7 @@ export const singingStore = createPartialStore<SingingStoreTypes>({
} else {
// それ以外の場合はノートを追加
notes.push({
id: uuidv4(),
id: NoteId(uuidv4()),
position,
duration,
noteNumber,
Expand Down Expand Up @@ -2514,7 +2514,7 @@ export const singingStore = createPartialStore<SingingStoreTypes>({
const quantizedPastePos =
Math.round(pasteOriginPos / snapTicks) * snapTicks;
return {
id: uuidv4(),
id: NoteId(uuidv4()),
position: quantizedPastePos,
duration: Number(note.duration),
noteNumber: Number(note.noteNumber),
Expand Down
23 changes: 12 additions & 11 deletions src/store/type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ import {
PresetKey,
RootMiscSettingType,
EditorType,
NoteId,
} from "@/type/preload";
import { IEngineConnectorFactory } from "@/infrastructures/EngineConnector";
import {
Expand Down Expand Up @@ -816,10 +817,10 @@ export type SingingStoreState = {
sequencerZoomY: number;
sequencerSnapType: number;
sequencerEditTarget: SequencerEditTarget;
selectedNoteIds: Set<string>;
overlappingNoteIds: Set<string>;
selectedNoteIds: Set<NoteId>;
overlappingNoteIds: Set<NoteId>;
overlappingNoteInfos: OverlappingNoteInfos;
editingLyricNoteId?: string;
editingLyricNoteId?: NoteId;
nowPlaying: boolean;
volume: number;
startRenderingRequested: boolean;
Expand Down Expand Up @@ -876,7 +877,7 @@ export type SingingStoreTypes = {
};

NOTE_IDS: {
getter: Set<string>;
getter: Set<NoteId>;
};

ADD_NOTES: {
Expand All @@ -888,12 +889,12 @@ export type SingingStoreTypes = {
};

REMOVE_NOTES: {
mutation: { noteIds: string[] };
mutation: { noteIds: NoteId[] };
};

SELECT_NOTES: {
mutation: { noteIds: string[] };
action(payload: { noteIds: string[] }): void;
mutation: { noteIds: NoteId[] };
action(payload: { noteIds: NoteId[] }): void;
};

SELECT_ALL_NOTES: {
Expand All @@ -907,8 +908,8 @@ export type SingingStoreTypes = {
};

SET_EDITING_LYRIC_NOTE_ID: {
mutation: { noteId?: string };
action(payload: { noteId?: string }): void;
mutation: { noteId?: NoteId };
action(payload: { noteId?: NoteId }): void;
};

SET_PITCH_EDIT_DATA: {
Expand Down Expand Up @@ -1161,8 +1162,8 @@ export type SingingCommandStoreTypes = {
};

COMMAND_REMOVE_NOTES: {
mutation: { noteIds: string[] };
action(payload: { noteIds: string[] }): void;
mutation: { noteIds: NoteId[] };
action(payload: { noteIds: NoteId[] }): void;
};

COMMAND_REMOVE_SELECTED_NOTES: {
Expand Down
4 changes: 4 additions & 0 deletions src/type/preload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ export type VoiceId = z.infer<typeof voiceIdSchema>;
export const VoiceId = (voice: Voice): VoiceId =>
voiceIdSchema.parse(`${voice.engineId}:${voice.speakerId}:${voice.styleId}`);

export const noteIdSchema = z.string().brand<"NoteId">();
export type NoteId = z.infer<typeof noteIdSchema>;
export const NoteId = (id: string): NoteId => noteIdSchema.parse(id);

// 共通のアクション名
export const actionPostfixSelectNthCharacter = "番目のキャラクターを選択";

Expand Down
3 changes: 2 additions & 1 deletion tests/unit/lib/selectPriorPhrase.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { v4 as uuidv4 } from "uuid";
import { Phrase, PhraseState } from "@/store/type";
import { DEFAULT_TPQN } from "@/sing/storeHelper";
import { selectPriorPhrase } from "@/sing/domain";
import { NoteId } from "@/type/preload";

const createPhrase = (
start: number,
Expand All @@ -12,7 +13,7 @@ const createPhrase = (
return {
notes: [
{
id: uuidv4(),
id: NoteId(uuidv4()),
position: start * DEFAULT_TPQN,
duration: (end - start) * DEFAULT_TPQN,
noteNumber: 60,
Expand Down

0 comments on commit 0fb559d

Please sign in to comment.