Skip to content

Commit

Permalink
ソング:再生位置の表示形式を変更できるようにする (VOICEVOX#2306)
Browse files Browse the repository at this point in the history
Co-authored-by: Hiroshiba <[email protected]>
  • Loading branch information
sigprogramming and Hiroshiba authored Oct 28, 2024
1 parent 31f04d3 commit 17b5920
Show file tree
Hide file tree
Showing 10 changed files with 208 additions and 172 deletions.
138 changes: 138 additions & 0 deletions src/components/Sing/PlayheadPositionDisplay.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
<template>
<div>
<div v-if="displayFormat === 'MINUTES_SECONDS'" class="playhead-position">
<div>{{ minAndSecStr }}</div>
<div class="millisec">.{{ milliSecStr }}</div>
</div>
<div v-if="displayFormat === 'MEASURES_BEATS'" class="playhead-position">
<div>{{ measuresStr }}.</div>
<div>{{ beatsIntegerPartStr }}</div>
<div class="beats-fractional-part">.{{ beatsFractionalPartStr }}</div>
</div>
<ContextMenu ref="contextMenu" :menudata="contextMenuData" />
</div>
</template>

<script setup lang="ts">
import { ref, computed } from "vue";
import { useStore } from "@/store";
import ContextMenu, {
ContextMenuItemData,
} from "@/components/Menu/ContextMenu.vue";
import {
getTimeSignaturePositions,
MeasuresBeats,
ticksToMeasuresBeats,
} from "@/sing/domain";
import { useRootMiscSetting } from "@/composables/useRootMiscSetting";
const store = useStore();
const playheadTicks = computed(() => store.getters.PLAYHEAD_POSITION);
const [displayFormat, setDisplayFormat] = useRootMiscSetting(
store,
"playheadPositionDisplayFormat",
);
const timeSignatures = computed(() => {
const tpqn = store.state.tpqn;
const timeSignatures = store.state.timeSignatures;
const tsPositions = getTimeSignaturePositions(timeSignatures, tpqn);
return timeSignatures.map((value, index) => ({
...value,
position: tsPositions[index],
}));
});
const measuresBeats = computed((): MeasuresBeats => {
const tpqn = store.state.tpqn;
return ticksToMeasuresBeats(playheadTicks.value, timeSignatures.value, tpqn);
});
const measuresStr = computed(() => {
return measuresBeats.value.measures >= 0
? String(measuresBeats.value.measures).padStart(3, "0")
: String(measuresBeats.value.measures);
});
const beatsIntegerPartStr = computed(() => {
const integerPart = Math.floor(measuresBeats.value.beats);
return String(integerPart).padStart(2, "0");
});
const beatsFractionalPartStr = computed(() => {
const integerPart = Math.floor(measuresBeats.value.beats);
const fractionalPart = Math.floor(
(measuresBeats.value.beats - integerPart) * 100,
);
return String(fractionalPart).padStart(2, "0");
});
const minAndSecStr = computed(() => {
const ticks = playheadTicks.value;
const time = store.getters.TICK_TO_SECOND(ticks);
const intTime = Math.trunc(time);
const min = Math.trunc(intTime / 60);
const minStr = String(min).padStart(2, "0");
const secStr = String(intTime - min * 60).padStart(2, "0");
return `${minStr}:${secStr}`;
});
const milliSecStr = computed(() => {
const ticks = playheadTicks.value;
const time = store.getters.TICK_TO_SECOND(ticks);
const intTime = Math.trunc(time);
const milliSec = Math.trunc((time - intTime) * 1000);
const milliSecStr = String(milliSec).padStart(3, "0");
return milliSecStr;
});
const contextMenu = ref<InstanceType<typeof ContextMenu>>();
const contextMenuData = computed<ContextMenuItemData[]>(() => {
return [
{
type: "button",
label: "分:秒",
disabled: displayFormat.value === "MINUTES_SECONDS",
onClick: async () => {
contextMenu.value?.hide();
setDisplayFormat("MINUTES_SECONDS");
},
disableWhenUiLocked: false,
},
{
type: "button",
label: "小節.拍",
disabled: displayFormat.value === "MEASURES_BEATS",
onClick: async () => {
contextMenu.value?.hide();
setDisplayFormat("MEASURES_BEATS");
},
disableWhenUiLocked: false,
},
];
});
</script>

<style scoped lang="scss">
@use "@/styles/v2/variables" as vars;
@use "@/styles/colors" as colors;
.playhead-position {
align-items: center;
display: flex;
font-weight: 700;
font-size: 28px;
color: var(--scheme-color-on-surface);
}
.millisec {
font-size: 16px;
margin: 10px 0 0 2px;
}
.beats-fractional-part {
font-size: 16px;
margin: 10px 0 0 2px;
}
</style>
20 changes: 5 additions & 15 deletions src/components/Sing/ScoreSequencer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,7 @@ const scrollX = ref(0);
const scrollY = ref(0);
// 再生ヘッドの位置
const playheadTicks = ref(0);
const playheadTicks = computed(() => store.getters.PLAYHEAD_POSITION);
const playheadX = computed(() => {
const baseX = tickToBaseX(playheadTicks.value, tpqn.value);
return Math.floor(baseX * zoomX.value);
Expand Down Expand Up @@ -1316,10 +1316,8 @@ const onScroll = (event: Event) => {
}
};
const playheadPositionChangeListener = (position: number) => {
playheadTicks.value = position;
// オートスクロール
// オートスクロール
watch(playheadTicks, (newPlayheadPosition) => {
const sequencerBodyElement = sequencerBody.value;
if (!sequencerBodyElement) {
if (import.meta.env.DEV) {
Expand All @@ -1335,7 +1333,7 @@ const playheadPositionChangeListener = (position: number) => {
const scrollTop = sequencerBodyElement.scrollTop;
const scrollWidth = sequencerBodyElement.scrollWidth;
const clientWidth = sequencerBodyElement.clientWidth;
const playheadX = tickToBaseX(position, tpqn.value) * zoomX.value;
const playheadX = tickToBaseX(newPlayheadPosition, tpqn.value) * zoomX.value;
const tolerance = 3;
if (playheadX < scrollLeft) {
sequencerBodyElement.scrollTo(playheadX, scrollTop);
Expand All @@ -1345,7 +1343,7 @@ const playheadPositionChangeListener = (position: number) => {
) {
sequencerBodyElement.scrollTo(playheadX, scrollTop);
}
};
});
// スクロールバーの幅を取得する
onMounted(() => {
Expand Down Expand Up @@ -1392,21 +1390,13 @@ onActivated(() => {
// リスナー登録
onActivated(() => {
void store.actions.ADD_PLAYHEAD_POSITION_CHANGE_LISTENER({
listener: playheadPositionChangeListener,
});
document.addEventListener("keydown", handleKeydown);
window.addEventListener("mousemove", onMouseMove);
window.addEventListener("mouseup", onMouseUp);
});
// リスナー解除
onDeactivated(() => {
void store.actions.REMOVE_PLAYHEAD_POSITION_CHANGE_LISTENER({
listener: playheadPositionChangeListener,
});
document.removeEventListener("keydown", handleKeydown);
window.removeEventListener("mousemove", onMouseMove);
window.removeEventListener("mouseup", onMouseUp);
Expand Down
19 changes: 2 additions & 17 deletions src/components/Sing/SequencerRuler/Container.vue
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
</template>

<script setup lang="ts">
import { computed, onMounted, onUnmounted, ref } from "vue";
import { computed } from "vue";
import Presentation from "./Presentation.vue";
import { useStore } from "@/store";
Expand All @@ -36,27 +36,12 @@ const tpqn = computed(() => store.state.tpqn);
const timeSignatures = computed(() => store.state.timeSignatures);
const sequencerZoomX = computed(() => store.state.sequencerZoomX);
const playheadTicks = ref(0);
const playheadTicks = computed(() => store.getters.PLAYHEAD_POSITION);
const updatePlayheadTicks = (ticks: number) => {
void store.actions.SET_PLAYHEAD_POSITION({ position: ticks });
};
const playheadPositionChangeListener = (position: number) => {
playheadTicks.value = position;
};
onMounted(() => {
void store.actions.ADD_PLAYHEAD_POSITION_CHANGE_LISTENER({
listener: playheadPositionChangeListener,
});
});
onUnmounted(() => {
void store.actions.REMOVE_PLAYHEAD_POSITION_CHANGE_LISTENER({
listener: playheadPositionChangeListener,
});
});
const deselectAllNotes = () => {
void store.actions.DESELECT_ALL_NOTES();
};
Expand Down
62 changes: 3 additions & 59 deletions src/components/Sing/ToolBar/ToolBar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -113,12 +113,7 @@
icon="stop"
@click="stop"
/>
<div class="sing-playhead-position">
<div>{{ playheadPositionMinSecStr }}</div>
<div class="sing-playhead-position-millisec">
.{{ playHeadPositionMilliSecStr }}
</div>
</div>
<PlayheadPositionDisplay class="sing-playhead-position" />
</div>
<!-- settings for edit controls -->
<div class="sing-controls">
Expand Down Expand Up @@ -164,7 +159,8 @@
</template>

<script setup lang="ts">
import { computed, watch, ref, onMounted, onUnmounted } from "vue";
import { computed, watch, ref } from "vue";
import PlayheadPositionDisplay from "../PlayheadPositionDisplay.vue";
import EditTargetSwicher from "./EditTargetSwicher.vue";
import { useStore } from "@/store";
Expand Down Expand Up @@ -383,30 +379,6 @@ const setVolumeRangeAdjustment = () => {
});
};
const playheadTicks = ref(0);
/// 再生時間の分と秒
const playheadPositionMinSecStr = computed(() => {
const ticks = playheadTicks.value;
const time = store.getters.TICK_TO_SECOND(ticks);
const intTime = Math.trunc(time);
const min = Math.trunc(intTime / 60);
const minStr = String(min).padStart(2, "0");
const secStr = String(intTime - min * 60).padStart(2, "0");
return `${minStr}:${secStr}`;
});
const playHeadPositionMilliSecStr = computed(() => {
const ticks = playheadTicks.value;
const time = store.getters.TICK_TO_SECOND(ticks);
const intTime = Math.trunc(time);
const milliSec = Math.trunc((time - intTime) * 1000);
const milliSecStr = String(milliSec).padStart(3, "0");
return milliSecStr;
});
const nowPlaying = computed(() => store.state.nowPlaying);
const play = () => {
Expand Down Expand Up @@ -463,22 +435,6 @@ const snapTypeSelectModel = computed({
});
},
});
const playheadPositionChangeListener = (position: number) => {
playheadTicks.value = position;
};
onMounted(() => {
void store.actions.ADD_PLAYHEAD_POSITION_CHANGE_LISTENER({
listener: playheadPositionChangeListener,
});
});
onUnmounted(() => {
void store.actions.REMOVE_PLAYHEAD_POSITION_CHANGE_LISTENER({
listener: playheadPositionChangeListener,
});
});
</script>

<style scoped lang="scss">
Expand Down Expand Up @@ -714,19 +670,7 @@ onUnmounted(() => {
}
.sing-playhead-position {
align-items: center;
display: flex;
font-size: 28px;
font-weight: 700;
margin-left: 16px;
color: var(--scheme-color-on-surface);
}
.sing-playhead-position-millisec {
font-size: 16px;
font-weight: 700;
margin: 10px 0 0 2px;
color: var(--scheme-color-on-surface);
}
.sing-controls {
Expand Down
Loading

0 comments on commit 17b5920

Please sign in to comment.