Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[project-s]再生周りの機能を追加 #1184

Merged
merged 12 commits into from
Mar 1, 2023
Merged
124 changes: 103 additions & 21 deletions src/components/Sing/ToolBar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,37 @@
<img :src="selectedStyleIconPath" class="singer-avatar" />
</div>
<div class="sing-player">
<button type="button" class="sing-button-temp">戻る</button>
<button type="button" class="sing-button-temp">再生</button>
<div class="sing-player-position">00:00</div>
<q-btn
flat
round
class="sing-transport-button"
icon="skip_previous"
@click="seek(0)"
></q-btn>
<q-btn
v-if="!nowPlaying"
round
class="sing-playback-button"
icon="play_arrow"
@click="play"
></q-btn>
<q-btn
v-else
round
class="sing-playback-button"
icon="stop"
@click="stop"
></q-btn>
<q-btn flat round class="sing-transport-button" icon="loop"></q-btn>
<div class="sing-playback-position">{{ playbackPositionStr }}</div>
<q-input
type="number"
:model-value="tempoInputBuffer"
dense
hide-bottom-space
class="sing-tempo"
@update:model-value="setTempoInputBuffer"
@change="setTempo()"
@change="setTempo"
>
<template v-slot:prepend>
<div />
Expand All @@ -31,7 +51,7 @@
hide-bottom-space
class="sing-time-signature"
@update:model-value="setBeatsInputBuffer"
@change="setTimeSignature()"
@change="setTimeSignature"
>
<template v-slot:prepend>
<div />
Expand All @@ -45,15 +65,15 @@
hide-bottom-space
class="sing-time-signature"
@update:model-value="setBeatTypeInputBuffer"
@change="setTimeSignature()"
@change="setTimeSignature"
>
<template v-slot:prepend>
<div />
</template>
</q-input>
</div>
<div class="sing-setting">
<input type="range" min="0" max="100" class="sing-volume" />
<q-slider v-model.number="volume" class="sing-volume" />
<select class="sing-snap">
<option>1/16</option>
</select>
Expand Down Expand Up @@ -103,24 +123,43 @@ export default defineComponent({
const beatsInputBuffer = ref(0);
const beatTypeInputBuffer = ref(0);

const setTempoInputBuffer = (tempoStr: string) => {
const setTempoInputBuffer = (tempoStr: string | number | null) => {
const tempo = Number(tempoStr);
if (Number.isNaN(tempo) || tempo <= 0) return;
if (!Number.isFinite(tempo) || tempo <= 0) return;
tempoInputBuffer.value = tempo;
};
const setBeatsInputBuffer = (beatsStr: string) => {
const setBeatsInputBuffer = (beatsStr: string | number | null) => {
const beats = Number(beatsStr);
if (!Number.isInteger(beats) || beats <= 0) return;
beatsInputBuffer.value = beats;
};
const setBeatTypeInputBuffer = (beatTypeStr: string) => {
const setBeatTypeInputBuffer = (beatTypeStr: string | number | null) => {
const beatType = Number(beatTypeStr);
if (!Number.isInteger(beatType) || beatType <= 0) return;
beatTypeInputBuffer.value = beatType;
};

const playPos = ref(0);

const playbackPositionStr = computed(() => {
let playTime = 0;
if (store.state.score) {
playTime = store.getters.POSITION_TO_TIME(playPos.value);
}

const intPlayTime = Math.floor(playTime);
const min = Math.floor(intPlayTime / 60);
const minStr = String(min).padStart(2, "0");
const secStr = String(intPlayTime - min * 60).padStart(2, "0");
const match = String(playTime).match(/\.(\d+)$/);
const milliSecStr = (match?.[1] ?? "0").padEnd(3, "0").substring(0, 3);

return `${minStr}:${secStr}.${milliSecStr}`;
});

const tempos = computed(() => store.state.score?.tempos);
const timeSignatures = computed(() => store.state.score?.timeSignatures);
const nowPlaying = computed(() => store.state.nowPlaying);

watch(
tempos,
Expand All @@ -133,17 +172,26 @@ export default defineComponent({
timeSignatures,
() => {
beatsInputBuffer.value = timeSignatures.value?.[0].beats ?? 0;
},
{ deep: true }
);
watch(
timeSignatures,
() => {
beatTypeInputBuffer.value = timeSignatures.value?.[0].beatType ?? 0;
},
{ deep: true }
);

const timeout = 1 / 60;
let timeoutId: number | undefined = undefined;
watch(nowPlaying, (newState) => {
if (newState) {
const updateView = () => {
playPos.value = store.getters.GET_PLAYBACK_POSITION();
timeoutId = window.setTimeout(updateView, timeout);
};
updateView();
} else if (timeoutId !== undefined) {
window.clearTimeout(timeoutId);
timeoutId = undefined;
}
});

const setTempo = async () => {
const tempo = tempoInputBuffer.value;
if (tempo === 0) return;
Expand All @@ -168,6 +216,28 @@ export default defineComponent({
});
};

const play = () => {
store.dispatch("SING_PLAY_AUDIO");
};

const stop = () => {
store.dispatch("SING_STOP_AUDIO");
};

const seek = async (position: number) => {
await store.dispatch("SET_PLAYBACK_POSITION", { position });
playPos.value = position;
};

const volume = computed({
get() {
return store.state.volume * 100;
},
set(value: number) {
store.dispatch("SET_VOLUME", { volume: value / 100 });
},
});

return {
isShowSinger,
toggleShowSinger,
Expand All @@ -180,6 +250,12 @@ export default defineComponent({
setBeatTypeInputBuffer,
setTempo,
setTimeSignature,
playbackPositionStr,
nowPlaying,
play,
stop,
seek,
volume,
};
},
});
Expand Down Expand Up @@ -228,12 +304,17 @@ export default defineComponent({
display: flex;
}

.sing-button-temp {
.sing-transport-button {
margin: 0 1px;
}

.sing-playback-button {
margin: 0 4px;
}

.sing-tempo {
margin: 0 4px;
margin-left: 16px;
margin-right: 4px;
width: 64px;
}

Expand All @@ -242,9 +323,10 @@ export default defineComponent({
width: 36px;
}

.sing-player-position {
.sing-playback-position {
font-size: 18px;
margin: 0 4px;
min-width: 82px;
}

.sing-setting {
Expand All @@ -254,7 +336,7 @@ export default defineComponent({
}

.sing-volume {
margin-right: 4px;
margin-right: 10px;
width: 72px;
}
</style>
5 changes: 5 additions & 0 deletions src/helpers/singHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,8 @@ export const midiKeys = [...Array(128)]
};
})
.reverse();

export function round(value: number, digits: number) {
const powerOf10 = 10 ** digits;
return Math.round(value * powerOf10) / powerOf10;
}
Loading