From 51090baea2cd430638468fad40661ec21eb9b7c9 Mon Sep 17 00:00:00 2001 From: tiramisu_oTATo Date: Tue, 8 Aug 2023 22:32:35 +0900 Subject: [PATCH 01/22] =?UTF-8?q?`audioPlayer.ts`=E3=82=92=E6=96=B0?= =?UTF-8?q?=E8=A6=8F=E4=BD=9C=E6=88=90=E3=81=97`audio.ts`=E3=81=AE?= =?UTF-8?q?=E4=B8=80=E9=83=A8=E6=A9=9F=E8=83=BD=E3=82=92=E7=A7=BB=E8=BB=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/AudioDetail.vue | 12 +- src/components/DictionaryManageDialog.vue | 9 +- src/components/HeaderBar.vue | 6 +- src/store/audio.ts | 238 ++++++---------------- src/store/audioPlayer.ts | 166 +++++++++++++++ src/store/index.ts | 5 + src/store/type.ts | 90 ++++---- tests/unit/store/Vuex.spec.ts | 9 +- 8 files changed, 312 insertions(+), 223 deletions(-) create mode 100644 src/store/audioPlayer.ts diff --git a/src/components/AudioDetail.vue b/src/components/AudioDetail.vue index 670e940a9f..4c22ac2671 100644 --- a/src/components/AudioDetail.vue +++ b/src/components/AudioDetail.vue @@ -491,7 +491,7 @@ const changeMoraData = ( // audio play const play = async () => { try { - await store.dispatch("PLAY_AUDIO", { + await store.dispatch("FETCH_AND_PLAY_AUDIO", { audioKey: props.activeAudioKey, }); } catch (e) { @@ -513,8 +513,8 @@ const stop = () => { store.dispatch("STOP_AUDIO", { audioKey: props.activeAudioKey }); }; -const nowPlaying = computed( - () => store.state.audioStates[props.activeAudioKey]?.nowPlaying +const nowPlaying = computed(() => + store.state.nowPlayingAudioKeys.includes(props.activeAudioKey) ); const nowGenerating = computed( () => store.state.audioStates[props.activeAudioKey]?.nowGenerating @@ -522,7 +522,7 @@ const nowGenerating = computed( // continuously play const nowPlayingContinuously = computed( - () => store.state.nowPlayingContinuously + () => store.getters.NOW_PLAYING_CONTINUOUSLY ); const audioDetail = ref(); @@ -584,7 +584,9 @@ watch(nowPlaying, async (newState) => { // 現在再生されているaudio elementの再生時刻を0.01秒毎に取得(監視)し、 // それに合わせてフォーカスするアクセント句を変えていく focusInterval = setInterval(() => { - const currentTime = store.getters.ACTIVE_AUDIO_ELEM_CURRENT_TIME; + const currentTime = store.getters.AUDIO_CURRENT_TIME( + props.activeAudioKey + ); for (let i = 1; i < accentPhraseOffsets.length; i++) { if ( currentTime !== undefined && diff --git a/src/components/DictionaryManageDialog.vue b/src/components/DictionaryManageDialog.vue index 14bf7cbca3..0e7c654a38 100644 --- a/src/components/DictionaryManageDialog.vue +++ b/src/components/DictionaryManageDialog.vue @@ -253,6 +253,7 @@ import { computed, ref, watch } from "vue"; import { QInput } from "quasar"; import AudioAccent from "./AudioAccent.vue"; import { useStore } from "@/store"; +import { generateAudioKey } from "@/store/audio"; import { AccentPhrase, UserDictWord } from "@/openapi"; import { convertHiraToKana, @@ -432,8 +433,7 @@ const changeAccent = async (_: number, accent: number) => { } }; -const audioElem = new Audio(); -audioElem.pause(); +const audioKey = generateAudioKey(); const play = async () => { if (!accentPhrase.value) return; @@ -471,11 +471,12 @@ const play = async () => { } nowGenerating.value = false; nowPlaying.value = true; - await store.dispatch("PLAY_AUDIO_BLOB", { audioElem, audioBlob: blob }); + await store.dispatch("LOAD_AUDIO_PLAYER", { audioKey, blob }); + await store.dispatch("PLAY_AUDIO", { audioKey }); nowPlaying.value = false; }; const stop = () => { - audioElem.pause(); + store.dispatch("STOP_AUDIO", { audioKey }); }; // accent phraseにあるaccentと実際に登録するアクセントには差が生まれる diff --git a/src/components/HeaderBar.vue b/src/components/HeaderBar.vue index d6f72d2384..c62efca5c4 100644 --- a/src/components/HeaderBar.vue +++ b/src/components/HeaderBar.vue @@ -51,7 +51,7 @@ const canUndo = computed(() => store.getters.CAN_UNDO); const canRedo = computed(() => store.getters.CAN_REDO); const activeAudioKey = computed(() => store.getters.ACTIVE_AUDIO_KEY); const nowPlayingContinuously = computed( - () => store.state.nowPlayingContinuously + () => store.getters.NOW_PLAYING_CONTINUOUSLY ); const undoRedoHotkeyMap = new Map HotkeyReturnType>([ @@ -104,7 +104,7 @@ const redo = () => { }; const playContinuously = async () => { try { - await store.dispatch("PLAY_CONTINUOUSLY_AUDIO"); + await store.dispatch("PLAY_AUDIO_CONTINUOUSLY_WITH_UI_LOCK", {}); } catch (e) { let msg: string | undefined; // FIXME: GENERATE_AUDIO_FROM_AUDIO_ITEMのエラーを変えた場合変更する @@ -120,7 +120,7 @@ const playContinuously = async () => { } }; const stopContinuously = () => { - store.dispatch("STOP_CONTINUOUSLY_AUDIO"); + store.dispatch("STOP_PLAYLIST"); }; const generateAndSaveOneAudio = async () => { if (activeAudioKey.value == undefined) diff --git a/src/store/audio.ts b/src/store/audio.ts index f3b7add1e7..6fbf41f7e6 100644 --- a/src/store/audio.ts +++ b/src/store/audio.ts @@ -46,6 +46,10 @@ import { AudioQuery, AccentPhrase, Speaker, SpeakerInfo } from "@/openapi"; import { base64ImageToUri } from "@/helpers/imageHelper"; import { getValueOrThrow, ResultError } from "@/type/result"; +export function generateAudioKey() { + return AudioKey(uuidv4()); +} + async function generateUniqueIdAndQuery( state: State, audioItem: AudioItem @@ -265,7 +269,6 @@ export function applyAudioPresetToAudioItem( } const audioBlobCache: Record = {}; -const audioElements: Record = {}; export const audioStoreState: AudioStoreState = { characterInfos: {}, @@ -275,7 +278,6 @@ export const audioStoreState: AudioStoreState = { audioStates: {}, // audio elementの再生オフセット audioPlayStartPoint: undefined, - nowPlayingContinuously: false, }; export const audioStore = createPartialStore({ @@ -300,14 +302,6 @@ export const audioStore = createPartialStore({ }, }, - ACTIVE_AUDIO_ELEM_CURRENT_TIME: { - getter: (state) => { - return state._activeAudioKey !== undefined - ? audioElements[state._activeAudioKey]?.currentTime - : undefined; - }, - }, - LOAD_CHARACTER: { action: createUILockAction(async ({ commit, dispatch }, { engineId }) => { const speakers = await dispatch("INSTANTIATE_ENGINE_CONNECTOR", { @@ -485,14 +479,6 @@ export const audioStore = createPartialStore({ }, }, - GENERATE_AUDIO_KEY: { - action() { - const audioKey = AudioKey(uuidv4()); - audioElements[audioKey] = new Audio(); - return audioKey; - }, - }, - SETUP_SPEAKER: { /** * AudioItemに設定される話者(スタイルID)に対してエンジン側の初期化を行い、即座に音声合成ができるようにする。 @@ -544,15 +530,6 @@ export const audioStore = createPartialStore({ }, }, - SET_AUDIO_NOW_PLAYING: { - mutation( - state, - { audioKey, nowPlaying }: { audioKey: AudioKey; nowPlaying: boolean } - ) { - state.audioStates[audioKey].nowPlaying = nowPlaying; - }, - }, - SET_AUDIO_NOW_GENERATING: { mutation( state, @@ -565,12 +542,6 @@ export const audioStore = createPartialStore({ }, }, - SET_NOW_PLAYING_CONTINUOUSLY: { - mutation(state, { nowPlaying }: { nowPlaying: boolean }) { - state.nowPlayingContinuously = nowPlaying; - }, - }, - GENERATE_AUDIO_ITEM: { async action( { state, getters, dispatch }, @@ -669,13 +640,13 @@ export const audioStore = createPartialStore({ REGISTER_AUDIO_ITEM: { async action( - { dispatch, commit }, + { commit }, { audioItem, prevAudioKey, }: { audioItem: AudioItem; prevAudioKey?: AudioKey } ) { - const audioKey = await dispatch("GENERATE_AUDIO_KEY"); + const audioKey = generateAudioKey(); commit("INSERT_AUDIO_ITEM", { audioItem, audioKey, prevAudioKey }); return audioKey; }, @@ -701,7 +672,6 @@ export const audioStore = createPartialStore({ state.audioKeys.splice(index, 0, audioKey); state.audioItems[audioKey] = audioItem; state.audioStates[audioKey] = { - nowPlaying: false, nowGenerating: false, }; }, @@ -727,7 +697,6 @@ export const audioStore = createPartialStore({ for (const { audioKey, audioItem } of audioKeyItemPairs) { state.audioItems[audioKey] = audioItem; state.audioStates[audioKey] = { - nowPlaying: false, nowGenerating: false, }; } @@ -1687,124 +1656,50 @@ export const audioStore = createPartialStore({ ), }, - PLAY_AUDIO: { - action: createUILockAction( - async ({ commit, dispatch }, { audioKey }: { audioKey: AudioKey }) => { - const audioElem = audioElements[audioKey]; - audioElem.pause(); - - // 音声用意 - let blob = await dispatch("GET_AUDIO_CACHE", { audioKey }); - if (!blob) { + FETCH_AUDIO: { + async action({ commit, dispatch }, { audioKey }: { audioKey: AudioKey }) { + let blob = await dispatch("GET_AUDIO_CACHE", { audioKey }); + if (!blob) { + commit("SET_AUDIO_NOW_GENERATING", { + audioKey, + nowGenerating: true, + }); + try { + blob = await withProgress( + dispatch("GENERATE_AUDIO", { audioKey }), + dispatch + ); + } finally { commit("SET_AUDIO_NOW_GENERATING", { audioKey, - nowGenerating: true, + nowGenerating: false, }); - try { - blob = await withProgress( - dispatch("GENERATE_AUDIO", { audioKey }), - dispatch - ); - } finally { - commit("SET_AUDIO_NOW_GENERATING", { - audioKey, - nowGenerating: false, - }); - } } - - return dispatch("PLAY_AUDIO_BLOB", { - audioBlob: blob, - audioElem, - audioKey, - }); } - ), + return blob; + }, }, - PLAY_AUDIO_BLOB: { + FETCH_AND_PLAY_AUDIO: { action: createUILockAction( - async ( - { state, commit, dispatch }, - { - audioBlob, - audioElem, - audioKey, - }: { audioBlob: Blob; audioElem: HTMLAudioElement; audioKey?: AudioKey } - ) => { - audioElem.src = URL.createObjectURL(audioBlob); - // 途中再生用の処理 - if (audioKey) { - const accentPhraseOffsets = await dispatch("GET_AUDIO_PLAY_OFFSETS", { - audioKey, - }); - if (accentPhraseOffsets.length === 0) { - audioElem.currentTime = 0; - } else { - const startTime = - accentPhraseOffsets[state.audioPlayStartPoint ?? 0]; - if (startTime === undefined) throw Error("startTime === undefined"); - // 小さい値が切り捨てられることでフォーカスされるアクセントフレーズが一瞬元に戻るので、 - // 再生に影響のない程度かつ切り捨てられない値を加算する - audioElem.currentTime = startTime + 10e-6; - } - } - - // 一部ブラウザではsetSinkIdが実装されていないので、その環境では無視する - if (audioElem.setSinkId) { - audioElem - .setSinkId(state.savingSetting.audioOutputDevice) - .catch((err) => { - const stop = () => { - audioElem.pause(); - audioElem.removeEventListener("canplay", stop); - }; - audioElem.addEventListener("canplay", stop); - window.electron.showMessageDialog({ - type: "error", - title: "エラー", - message: "再生デバイスが見つかりません", - }); - throw new Error(err); - }); - } - - // 再生終了時にresolveされるPromiseを返す - const played = async () => { - if (audioKey) { - commit("SET_AUDIO_NOW_PLAYING", { audioKey, nowPlaying: true }); - } - }; - audioElem.addEventListener("play", played); + async ({ state, dispatch }, { audioKey }: { audioKey: AudioKey }) => { + const blob = await dispatch("FETCH_AUDIO", { audioKey }); + await dispatch("LOAD_AUDIO_PLAYER", { audioKey, blob }); - let paused: () => void; - const audioPlayPromise = new Promise((resolve) => { - paused = () => { - resolve(audioElem.ended); - }; - audioElem.addEventListener("pause", paused); - }).finally(async () => { - audioElem.removeEventListener("play", played); - audioElem.removeEventListener("pause", paused); - if (audioKey) { - commit("SET_AUDIO_NOW_PLAYING", { audioKey, nowPlaying: false }); - } + // 途中再生用の処理 + const accentPhraseOffsets = await dispatch("GET_AUDIO_PLAY_OFFSETS", { + audioKey, }); + const offset = + accentPhraseOffsets.length === 0 + ? 0 + : accentPhraseOffsets[state.audioPlayStartPoint ?? 0]; - audioElem.play(); - - return audioPlayPromise; + return dispatch("PLAY_AUDIO", { audioKey, offset }); } ), }, - STOP_AUDIO: { - action(_, { audioKey }: { audioKey: AudioKey }) { - const audioElem = audioElements[audioKey]; - audioElem.pause(); - }, - }, - SET_AUDIO_PRESET_KEY: { mutation( state, @@ -1821,44 +1716,37 @@ export const audioStore = createPartialStore({ }, }, - PLAY_CONTINUOUSLY_AUDIO: { - action: createUILockAction(async ({ state, commit, dispatch }) => { - const currentAudioKey = state._activeAudioKey; - const currentAudioPlayStartPoint = state.audioPlayStartPoint; + PLAY_AUDIO_CONTINUOUSLY: { + async action({ commit, dispatch, state }, { audioKey }) { + const bufStartPoint = state.audioPlayStartPoint; + const currentAudioKey = + audioKey ?? state._activeAudioKey ?? state.audioKeys[0]; + const fromIndex = state.audioKeys.indexOf(currentAudioKey); - let index = 0; - if (currentAudioKey !== undefined) { - index = state.audioKeys.findIndex((v) => v === currentAudioKey); - } - - commit("SET_NOW_PLAYING_CONTINUOUSLY", { nowPlaying: true }); try { - for (let i = index; i < state.audioKeys.length; ++i) { - const audioKey = state.audioKeys[i]; - commit("SET_ACTIVE_AUDIO_KEY", { audioKey }); - const isEnded = await dispatch("PLAY_AUDIO", { audioKey }); - if (!isEnded) { - break; - } - } + await dispatch("PLAY_ALONG_PLAYLIST", { + audioKeys: (async function* (): AsyncGenerator { + for (let i = fromIndex; i < state.audioKeys.length; ++i) { + const audioKey = state.audioKeys[i]; + dispatch("SET_ACTIVE_AUDIO_KEY", { audioKey }); + + const blob = await dispatch("FETCH_AUDIO", { audioKey }); + await dispatch("LOAD_AUDIO_PLAYER", { audioKey, blob }); + yield audioKey; + } + })(), + }); } finally { commit("SET_ACTIVE_AUDIO_KEY", { audioKey: currentAudioKey }); - commit("SET_AUDIO_PLAY_START_POINT", { - startPoint: currentAudioPlayStartPoint, - }); - commit("SET_NOW_PLAYING_CONTINUOUSLY", { nowPlaying: false }); + commit("SET_AUDIO_PLAY_START_POINT", { startPoint: bufStartPoint }); } - }), + }, }, - STOP_CONTINUOUSLY_AUDIO: { - action({ state, dispatch }) { - for (const audioKey of state.audioKeys) { - if (state.audioStates[audioKey].nowPlaying) { - dispatch("STOP_AUDIO", { audioKey }); - } - } - }, + PLAY_AUDIO_CONTINUOUSLY_WITH_UI_LOCK: { + action: createUILockAction(({ dispatch }, { audioKey }) => + dispatch("PLAY_AUDIO_CONTINUOUSLY", { audioKey }) + ), }, }); @@ -1878,7 +1766,7 @@ export const audioCommandStore = transformCommandStore( audioStore.mutations.INSERT_AUDIO_ITEM(draft, payload); }, async action( - { dispatch, commit }, + { commit }, { audioItem, prevAudioKey, @@ -1887,7 +1775,7 @@ export const audioCommandStore = transformCommandStore( prevAudioKey: AudioKey | undefined; } ) { - const audioKey = await dispatch("GENERATE_AUDIO_KEY"); + const audioKey = generateAudioKey(); commit("COMMAND_REGISTER_AUDIO_ITEM", { audioItem, audioKey, @@ -2779,7 +2667,7 @@ export const audioCommandStore = transformCommandStore( ); } const audioKeys: AudioKey[] = await Promise.all( - audioItems.map(() => dispatch("GENERATE_AUDIO_KEY")) + audioItems.map(() => generateAudioKey()) ); const audioKeyItemPairs = audioItems.map((audioItem, index) => ({ audioItem, @@ -2832,7 +2720,7 @@ export const audioCommandStore = transformCommandStore( } for (const text of texts.filter((value) => value != "")) { - const audioKey: AudioKey = await dispatch("GENERATE_AUDIO_KEY"); + const audioKey = generateAudioKey(); const audioItem = await dispatch("GENERATE_AUDIO_ITEM", { text, voice, diff --git a/src/store/audioPlayer.ts b/src/store/audioPlayer.ts new file mode 100644 index 0000000000..dd8be72b60 --- /dev/null +++ b/src/store/audioPlayer.ts @@ -0,0 +1,166 @@ +import { createPartialStore } from "./vuex"; +import { AudioPlayerStoreState, AudioPlayerStoreTypes } from "./type"; +import { AudioKey } from "@/type/preload"; + +export const audioPlayerStoreState: AudioPlayerStoreState = { + nowPlayingAudioKeys: [], + nowPlayingContinuouslyAudioKey: undefined, +}; + +// AudioKey 毎に一つ +const audioElements: Map = new Map(); + +export const audioPlayerStore = createPartialStore({ + AUDIO_CURRENT_TIME: { + getter: (state) => (audioKey: AudioKey) => + state.nowPlayingAudioKeys.includes(audioKey) + ? audioElements.get(audioKey)?.currentTime ?? undefined + : undefined, + }, + + NOW_PLAYING_CONTINUOUSLY: { + getter(state) { + return state.nowPlayingContinuouslyAudioKey !== undefined; + }, + }, + + LOAD_AUDIO_PLAYER: { + action(_, { audioKey, blob }: { audioKey: AudioKey; blob: Blob }) { + let audioElement = audioElements.get(audioKey); + if (audioElement === undefined) { + audioElement = new Audio(); + } + audioElement.pause(); + audioElement.src = URL.createObjectURL(blob); + audioElements.set(audioKey, audioElement); + }, + }, + + UNLOAD_AUDIO_PLAYER: { + action({ dispatch }, { audioKey }: { audioKey?: AudioKey }) { + let audioElement; + if ( + audioKey === undefined || + (audioElement = audioElements.get(audioKey)) === undefined + ) { + return; + } + dispatch("STOP_AUDIO", { audioKey }); + audioElement.removeAttribute("src"); + audioElements.delete(audioKey); + }, + }, + + PLAY_AUDIO: { + mutation(state, { audioKey }: { audioKey: AudioKey }) { + state.nowPlayingAudioKeys.push(audioKey); + }, + async action( + { state, dispatch, commit }, + { audioKey, offset }: { audioKey: AudioKey; offset?: number } + ) { + const audioElem = audioElements.get(audioKey); + if (audioElem === undefined) + throw new Error( + "音声の読み込み前に再生されようとしました。先に LOAD_AUDIO_PLAYER を行ってください。" + ); + + if (offset !== undefined) { + // 小さい値が切り捨てられることでフォーカスされるアクセントフレーズが一瞬元に戻るので、 + // 再生に影響のない程度かつ切り捨てられない値を加算する + audioElem.currentTime = offset + 10e-6; + } + + // 一部ブラウザではsetSinkIdが実装されていないので、その環境では無視する + if (audioElem.setSinkId) { + audioElem + .setSinkId(state.savingSetting.audioOutputDevice) + .catch((err) => { + const stop = () => { + audioElem.pause(); + audioElem.removeEventListener("canplay", stop); + }; + audioElem.addEventListener("canplay", stop); + dispatch("SHOW_ALERT_DIALOG", { + title: "再生エラー", + message: + "再生デバイスが見つかりませんでした。設定 / オプション から再生デバイスを設定しなおしてみてください。", + }); + throw new Error(err); + }); + } + + // 再生終了時にresolveされるPromiseを返す + const played = async () => { + commit("PLAY_AUDIO", { audioKey }); + }; + audioElem.addEventListener("play", played); + + let paused: () => void; + const audioPlayPromise = new Promise((resolve) => { + paused = () => { + resolve(audioElem.ended); + }; + audioElem.addEventListener("pause", paused); + }).finally(async () => { + audioElem.removeEventListener("play", played); + audioElem.removeEventListener("pause", paused); + if (audioKey) { + commit("STOP_AUDIO", { audioKey }); + } + }); + + audioElem.play(); + + return audioPlayPromise; + }, + }, + + STOP_AUDIO: { + mutation(state, { audioKey }: { audioKey: AudioKey }) { + const audioKeys = state.nowPlayingAudioKeys; + if (audioKeys.includes(audioKey)) { + delete audioKeys[audioKeys.indexOf(audioKey)]; + } + }, + action({ commit }, { audioKey }: { audioKey: AudioKey }) { + const audioElem = audioElements.get(audioKey); + if (audioElem === undefined) throw new Error("audioElem === undefined"); + audioElem.pause(); + commit("STOP_AUDIO", { audioKey }); + }, + }, + + PLAY_ALONG_PLAYLIST: { + mutation(state, { audioKey }: { audioKey: AudioKey }) { + state.nowPlayingContinuouslyAudioKey = audioKey; + }, + async action({ commit, dispatch }, { audioKeys }) { + const offset = 0; + try { + for await (const audioKey of audioKeys) { + commit("PLAY_ALONG_PLAYLIST", { audioKey }); + const isEnded = await dispatch("PLAY_AUDIO", { audioKey, offset }); + if (!isEnded) { + break; + } + } + } finally { + commit("STOP_PLAYLIST"); + } + }, + }, + + STOP_PLAYLIST: { + mutation(state) { + state.nowPlayingContinuouslyAudioKey = undefined; + }, + action({ state, commit, dispatch }) { + const audioKey = state.nowPlayingContinuouslyAudioKey; + if (audioKey !== undefined) { + dispatch("STOP_AUDIO", { audioKey }); + } + commit("STOP_PLAYLIST"); + }, + }, +}); diff --git a/src/store/index.ts b/src/store/index.ts index fb99766866..7a3bf8e572 100644 --- a/src/store/index.ts +++ b/src/store/index.ts @@ -17,6 +17,7 @@ import { audioCommandStoreState, getCharacterInfo, } from "./audio"; +import { audioPlayerStore, audioPlayerStoreState } from "./audioPlayer"; import { projectStoreState, projectStore } from "./project"; import { uiStoreState, uiStore } from "./ui"; import { settingStoreState, settingStore } from "./setting"; @@ -349,6 +350,7 @@ export const store = createStore({ state: { ...uiStoreState, ...audioStoreState, + ...audioPlayerStoreState, ...commandStoreState, ...engineStoreState, ...projectStoreState, @@ -363,6 +365,7 @@ export const store = createStore({ getters: { ...uiStore.getters, ...audioStore.getters, + ...audioPlayerStore.getters, ...commandStore.getters, ...engineStore.getters, ...projectStore.getters, @@ -377,6 +380,7 @@ export const store = createStore({ mutations: { ...uiStore.mutations, ...audioStore.mutations, + ...audioPlayerStore.mutations, ...commandStore.mutations, ...engineStore.mutations, ...projectStore.mutations, @@ -391,6 +395,7 @@ export const store = createStore({ actions: { ...uiStore.actions, ...audioStore.actions, + ...audioPlayerStore.actions, ...engineStore.actions, ...commandStore.actions, ...projectStore.actions, diff --git a/src/store/type.ts b/src/store/type.ts index dc312c1f20..55568040b8 100644 --- a/src/store/type.ts +++ b/src/store/type.ts @@ -73,7 +73,6 @@ export type AudioItem = { }; export type AudioState = { - nowPlaying: boolean; nowGenerating: boolean; }; @@ -131,7 +130,6 @@ export type AudioStoreState = { audioStates: Record; _activeAudioKey?: AudioKey; audioPlayStartPoint?: number; - nowPlayingContinuously: boolean; }; export type AudioStoreTypes = { @@ -147,10 +145,6 @@ export type AudioStoreTypes = { getter(audioKey: AudioKey): boolean; }; - ACTIVE_AUDIO_ELEM_CURRENT_TIME: { - getter: number | undefined; - }; - LOAD_CHARACTER: { action(payload: { engineId: EngineId }): void; }; @@ -171,10 +165,6 @@ export type AudioStoreTypes = { getter: CharacterInfo[] | undefined; }; - GENERATE_AUDIO_KEY: { - action(): AudioKey; - }; - SETUP_SPEAKER: { action(payload: { audioKey: AudioKey; @@ -197,18 +187,10 @@ export type AudioStoreTypes = { action(payload: { startPoint?: number }): void; }; - SET_AUDIO_NOW_PLAYING: { - mutation: { audioKey: AudioKey; nowPlaying: boolean }; - }; - SET_AUDIO_NOW_GENERATING: { mutation: { audioKey: AudioKey; nowGenerating: boolean }; }; - SET_NOW_PLAYING_CONTINUOUSLY: { - mutation: { nowPlaying: boolean }; - }; - GENERATE_AUDIO_ITEM: { action(payload: { text?: string; @@ -435,20 +417,12 @@ export type AudioStoreTypes = { action(payload: { filePath?: string }): SaveResultObject | undefined; }; - PLAY_AUDIO: { - action(payload: { audioKey: AudioKey }): boolean; - }; - - PLAY_AUDIO_BLOB: { - action(payload: { - audioBlob: Blob; - audioElem: HTMLAudioElement; - audioKey?: AudioKey; - }): boolean; + FETCH_AUDIO: { + action(payload: { audioKey: AudioKey }): Promise; }; - STOP_AUDIO: { - action(payload: { audioKey: AudioKey }): void; + FETCH_AND_PLAY_AUDIO: { + action(payload: { audioKey: AudioKey }): boolean; }; SET_AUDIO_PRESET_KEY: { @@ -458,12 +432,12 @@ export type AudioStoreTypes = { }; }; - PLAY_CONTINUOUSLY_AUDIO: { - action(): void; + PLAY_AUDIO_CONTINUOUSLY: { + action(payload: { audioKey?: AudioKey }): void; }; - STOP_CONTINUOUSLY_AUDIO: { - action(): void; + PLAY_AUDIO_CONTINUOUSLY_WITH_UI_LOCK: { + action(payload: { audioKey?: AudioKey }): void; }; }; @@ -679,6 +653,52 @@ export type AudioCommandStoreTypes = { }; }; +/* + * Audio Player Store Types + */ +export type AudioPlayerStoreState = { + nowPlayingAudioKeys: AudioKey[]; + nowPlayingContinuouslyAudioKey?: AudioKey; +}; + +export type AudioPlayerStoreTypes = { + AUDIO_CURRENT_TIME: { + getter: (audioKey: AudioKey) => number | undefined; + }; + + NOW_PLAYING_CONTINUOUSLY: { + getter: boolean; + }; + + LOAD_AUDIO_PLAYER: { + action(payload: { audioKey: AudioKey; blob: Blob }): void; + }; + + UNLOAD_AUDIO_PLAYER: { + action(payload: { audioKey?: AudioKey }): void; + }; + + PLAY_AUDIO: { + mutation: { audioKey: AudioKey }; + action(payload: { audioKey: AudioKey; offset?: number }): Promise; + }; + + STOP_AUDIO: { + mutation: { audioKey: AudioKey }; + action(payload: { audioKey: AudioKey }): void; + }; + + PLAY_ALONG_PLAYLIST: { + mutation: { audioKey: AudioKey }; + action(payload: { audioKeys: AsyncIterable }): void; + }; + + STOP_PLAYLIST: { + mutation: void; + action(): void; + }; +}; + /* * Command Store Types */ @@ -1455,6 +1475,7 @@ export type ProxyStoreTypes = { */ export type State = AudioStoreState & + AudioPlayerStoreState & AudioCommandStoreState & CommandStoreState & EngineStoreState & @@ -1467,6 +1488,7 @@ export type State = AudioStoreState & ProxyStoreState; type AllStoreTypes = AudioStoreTypes & + AudioPlayerStoreTypes & AudioCommandStoreTypes & CommandStoreTypes & EngineStoreTypes & diff --git a/tests/unit/store/Vuex.spec.ts b/tests/unit/store/Vuex.spec.ts index 8598a7a9b3..6eb579f757 100644 --- a/tests/unit/store/Vuex.spec.ts +++ b/tests/unit/store/Vuex.spec.ts @@ -13,6 +13,7 @@ import { proxyStore } from "@/store/proxy"; import { dictionaryStore } from "@/store/dictionary"; import { engineStore } from "@/store/engine"; import { EngineId } from "@/type/preload"; +import { audioPlayerStore } from "@/store/audioPlayer"; const isDevelopment = process.env.NODE_ENV == "development"; // TODO: Swap external files to Mock @@ -34,10 +35,10 @@ describe("store/vuex.js test", () => { audioKeys: [], audioStates: {}, audioPlayStartPoint: 0, + nowPlayingAudioKeys: [], uiLockCount: 0, dialogLockCount: 0, reloadingLock: false, - nowPlayingContinuously: false, undoCommands: [], redoCommands: [], inheritAudioInfo: true, @@ -148,6 +149,7 @@ describe("store/vuex.js test", () => { getters: { ...uiStore.getters, ...audioStore.getters, + ...audioPlayerStore.getters, ...commandStore.getters, ...engineStore.getters, ...projectStore.getters, @@ -161,6 +163,7 @@ describe("store/vuex.js test", () => { mutations: { ...uiStore.mutations, ...audioStore.mutations, + ...audioPlayerStore.mutations, ...commandStore.mutations, ...engineStore.mutations, ...projectStore.mutations, @@ -174,6 +177,7 @@ describe("store/vuex.js test", () => { actions: { ...uiStore.actions, ...audioStore.actions, + ...audioPlayerStore.actions, ...commandStore.actions, ...engineStore.actions, ...projectStore.actions, @@ -204,8 +208,9 @@ describe("store/vuex.js test", () => { assert.isObject(store.state.audioStates); assert.isEmpty(store.state.audioStates); assert.equal(store.state.audioPlayStartPoint, 0); + assert.isArray(store.state.nowPlayingAudioKeys); + assert.isEmpty(store.state.nowPlayingAudioKeys); assert.equal(store.state.uiLockCount, 0); - assert.equal(store.state.nowPlayingContinuously, false); assert.isArray(store.state.undoCommands); assert.isEmpty(store.state.undoCommands); assert.isArray(store.state.redoCommands); From f20b0b3d2bbc409a0dd9e90bb7075a200ce040ff Mon Sep 17 00:00:00 2001 From: tiramisu_oTATo Date: Tue, 8 Aug 2023 22:38:11 +0900 Subject: [PATCH 02/22] =?UTF-8?q?=E4=B8=80=E9=83=A8=E3=82=92computed?= =?UTF-8?q?=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/DictionaryManageDialog.vue | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/DictionaryManageDialog.vue b/src/components/DictionaryManageDialog.vue index 0e7c654a38..41f55b5a9b 100644 --- a/src/components/DictionaryManageDialog.vue +++ b/src/components/DictionaryManageDialog.vue @@ -280,7 +280,9 @@ const dictionaryManageDialogOpenedComputed = computed({ }); const uiLocked = ref(false); // ダイアログ内でstore.getters.UI_LOCKEDは常にtrueなので独自に管理 const nowGenerating = ref(false); -const nowPlaying = ref(false); +const nowPlaying = computed(() => + store.state.nowPlayingAudioKeys.includes(audioKey) +); const loadingDictState = ref("loading"); const userDict = ref>({}); @@ -470,10 +472,8 @@ const play = async () => { } } nowGenerating.value = false; - nowPlaying.value = true; await store.dispatch("LOAD_AUDIO_PLAYER", { audioKey, blob }); await store.dispatch("PLAY_AUDIO", { audioKey }); - nowPlaying.value = false; }; const stop = () => { store.dispatch("STOP_AUDIO", { audioKey }); From 44e0e43c71b4aee4070b88103eccfe6c8c2279d0 Mon Sep 17 00:00:00 2001 From: tiramisu_oTATo Date: Tue, 8 Aug 2023 22:51:01 +0900 Subject: [PATCH 03/22] =?UTF-8?q?=E4=B8=8D=E8=A6=81=E3=81=AAPromise?= =?UTF-8?q?=E3=82=92=E5=89=8A=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/store/audio.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/store/audio.ts b/src/store/audio.ts index 6fbf41f7e6..9c1d0e395b 100644 --- a/src/store/audio.ts +++ b/src/store/audio.ts @@ -2666,9 +2666,7 @@ export const audioCommandStore = transformCommandStore( }) ); } - const audioKeys: AudioKey[] = await Promise.all( - audioItems.map(() => generateAudioKey()) - ); + const audioKeys = audioItems.map(() => generateAudioKey()); const audioKeyItemPairs = audioItems.map((audioItem, index) => ({ audioItem, audioKey: audioKeys[index], From 2e3c38264206a62c2b91fe50605ce5cdfb3d4f63 Mon Sep 17 00:00:00 2001 From: tiramisu_oTATo Date: Tue, 15 Aug 2023 00:36:32 +0900 Subject: [PATCH 04/22] =?UTF-8?q?`NOW=5FPLAYING=5FCONTINUOUSLY`=E3=81=AE?= =?UTF-8?q?=E5=90=8D=E5=89=8D=E3=82=92`IS=5F...`=E3=81=AB=E5=A4=89?= =?UTF-8?q?=E6=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/AudioDetail.vue | 2 +- src/components/HeaderBar.vue | 2 +- src/store/audioPlayer.ts | 2 +- src/store/type.ts | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/AudioDetail.vue b/src/components/AudioDetail.vue index 4c22ac2671..f49f3c77cc 100644 --- a/src/components/AudioDetail.vue +++ b/src/components/AudioDetail.vue @@ -522,7 +522,7 @@ const nowGenerating = computed( // continuously play const nowPlayingContinuously = computed( - () => store.getters.NOW_PLAYING_CONTINUOUSLY + () => store.getters.IS_PLAYING_CONTINUOUSLY ); const audioDetail = ref(); diff --git a/src/components/HeaderBar.vue b/src/components/HeaderBar.vue index c62efca5c4..558bf4f72e 100644 --- a/src/components/HeaderBar.vue +++ b/src/components/HeaderBar.vue @@ -51,7 +51,7 @@ const canUndo = computed(() => store.getters.CAN_UNDO); const canRedo = computed(() => store.getters.CAN_REDO); const activeAudioKey = computed(() => store.getters.ACTIVE_AUDIO_KEY); const nowPlayingContinuously = computed( - () => store.getters.NOW_PLAYING_CONTINUOUSLY + () => store.getters.IS_PLAYING_CONTINUOUSLY ); const undoRedoHotkeyMap = new Map HotkeyReturnType>([ diff --git a/src/store/audioPlayer.ts b/src/store/audioPlayer.ts index dd8be72b60..348b371e7d 100644 --- a/src/store/audioPlayer.ts +++ b/src/store/audioPlayer.ts @@ -18,7 +18,7 @@ export const audioPlayerStore = createPartialStore({ : undefined, }, - NOW_PLAYING_CONTINUOUSLY: { + IS_PLAYING_CONTINUOUSLY: { getter(state) { return state.nowPlayingContinuouslyAudioKey !== undefined; }, diff --git a/src/store/type.ts b/src/store/type.ts index 55568040b8..25c5cce70f 100644 --- a/src/store/type.ts +++ b/src/store/type.ts @@ -666,7 +666,7 @@ export type AudioPlayerStoreTypes = { getter: (audioKey: AudioKey) => number | undefined; }; - NOW_PLAYING_CONTINUOUSLY: { + IS_PLAYING_CONTINUOUSLY: { getter: boolean; }; From f6ac612a263743b6414d9a4424bbb1fb3d69b8fa Mon Sep 17 00:00:00 2001 From: tiramisu_oTATo Date: Tue, 15 Aug 2023 00:48:41 +0900 Subject: [PATCH 05/22] =?UTF-8?q?`AUDIO=5FCURRENT=5FTIME`=E3=81=AB?= =?UTF-8?q?=E3=82=A8=E3=83=A9=E3=83=BC=E3=82=92=E5=90=90=E3=81=8B=E3=81=9B?= =?UTF-8?q?=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/store/audioPlayer.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/store/audioPlayer.ts b/src/store/audioPlayer.ts index 348b371e7d..4bba1aa297 100644 --- a/src/store/audioPlayer.ts +++ b/src/store/audioPlayer.ts @@ -12,10 +12,12 @@ const audioElements: Map = new Map(); export const audioPlayerStore = createPartialStore({ AUDIO_CURRENT_TIME: { - getter: (state) => (audioKey: AudioKey) => - state.nowPlayingAudioKeys.includes(audioKey) - ? audioElements.get(audioKey)?.currentTime ?? undefined - : undefined, + getter: () => (audioKey: AudioKey) => { + const audioElement = audioElements.get(audioKey); + if (audioElement === undefined) + throw new Error("audioElement === undefined"); + return audioElement.currentTime; + }, }, IS_PLAYING_CONTINUOUSLY: { From 7235a629ac7512c8d0785cdf6fa2bbe1396c0759 Mon Sep 17 00:00:00 2001 From: tiramisu_oTATo Date: Tue, 15 Aug 2023 02:26:24 +0900 Subject: [PATCH 06/22] =?UTF-8?q?`FETCH=5FAND=5F`=E3=82=92`PLAY=5FAUDIO=5F?= =?UTF-8?q?CONTINUOUSLY`=E3=81=AE=E9=A0=AD=E3=81=AB=E4=BB=98=E3=81=91?= =?UTF-8?q?=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/store/audio.ts | 6 +++--- src/store/type.ts | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/store/audio.ts b/src/store/audio.ts index 9c1d0e395b..8ce6fcb392 100644 --- a/src/store/audio.ts +++ b/src/store/audio.ts @@ -1716,7 +1716,7 @@ export const audioStore = createPartialStore({ }, }, - PLAY_AUDIO_CONTINUOUSLY: { + FETCH_AND_PLAY_AUDIO_CONTINUOUSLY: { async action({ commit, dispatch, state }, { audioKey }) { const bufStartPoint = state.audioPlayStartPoint; const currentAudioKey = @@ -1743,9 +1743,9 @@ export const audioStore = createPartialStore({ }, }, - PLAY_AUDIO_CONTINUOUSLY_WITH_UI_LOCK: { + FETCH_AND_PLAY_AUDIO_CONTINUOUSLY_WITH_UI_LOCK: { action: createUILockAction(({ dispatch }, { audioKey }) => - dispatch("PLAY_AUDIO_CONTINUOUSLY", { audioKey }) + dispatch("FETCH_AND_PLAY_AUDIO_CONTINUOUSLY", { audioKey }) ), }, }); diff --git a/src/store/type.ts b/src/store/type.ts index 25c5cce70f..9bdee335f8 100644 --- a/src/store/type.ts +++ b/src/store/type.ts @@ -432,11 +432,11 @@ export type AudioStoreTypes = { }; }; - PLAY_AUDIO_CONTINUOUSLY: { + FETCH_AND_PLAY_AUDIO_CONTINUOUSLY: { action(payload: { audioKey?: AudioKey }): void; }; - PLAY_AUDIO_CONTINUOUSLY_WITH_UI_LOCK: { + FETCH_AND_PLAY_AUDIO_CONTINUOUSLY_WITH_UI_LOCK: { action(payload: { audioKey?: AudioKey }): void; }; }; From 793f572dfc2755c1bb8c3391ab0ec735abb9583b Mon Sep 17 00:00:00 2001 From: tiramisu_oTATo Date: Tue, 15 Aug 2023 02:29:31 +0900 Subject: [PATCH 07/22] =?UTF-8?q?=E4=BF=9D=E5=AD=98=E6=BC=8F=E3=82=8C?= =?UTF-8?q?=E5=88=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/HeaderBar.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/HeaderBar.vue b/src/components/HeaderBar.vue index 558bf4f72e..33162da176 100644 --- a/src/components/HeaderBar.vue +++ b/src/components/HeaderBar.vue @@ -104,7 +104,7 @@ const redo = () => { }; const playContinuously = async () => { try { - await store.dispatch("PLAY_AUDIO_CONTINUOUSLY_WITH_UI_LOCK", {}); + await store.dispatch("FETCH_AND_PLAY_AUDIO_CONTINUOUSLY_WITH_UI_LOCK", {}); } catch (e) { let msg: string | undefined; // FIXME: GENERATE_AUDIO_FROM_AUDIO_ITEMのエラーを変えた場合変更する From 8477d98b9e1f40734f7763b68cf62444b6adc9ea Mon Sep 17 00:00:00 2001 From: tiramisu_oTATo Date: Thu, 17 Aug 2023 03:28:58 +0900 Subject: [PATCH 08/22] Update src/store/audioPlayer.ts Co-authored-by: Hiroshiba --- src/store/audioPlayer.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/store/audioPlayer.ts b/src/store/audioPlayer.ts index 4bba1aa297..ebe0931aa7 100644 --- a/src/store/audioPlayer.ts +++ b/src/store/audioPlayer.ts @@ -1,3 +1,6 @@ +/** + * HTMLAudioElement周りの音声再生・停止などを担当する。 + */ import { createPartialStore } from "./vuex"; import { AudioPlayerStoreState, AudioPlayerStoreTypes } from "./type"; import { AudioKey } from "@/type/preload"; From 4610921acf733a276496b99f6428383a87db72e7 Mon Sep 17 00:00:00 2001 From: tiramisu_oTATo Date: Thu, 17 Aug 2023 04:12:50 +0900 Subject: [PATCH 09/22] =?UTF-8?q?=E5=A4=89=E6=95=B0=E5=90=8D=E3=83=BB?= =?UTF-8?q?=E9=96=A2=E6=95=B0=E5=90=8D=E3=82=92=E5=A4=89=E6=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `PLAYLIST`をAUDIOS`に `STOP_AUDIO`の引数名を変更 --- src/components/HeaderBar.vue | 2 +- src/store/audioPlayer.ts | 35 +++++++++++++++++++---------------- src/store/type.ts | 8 ++++---- 3 files changed, 24 insertions(+), 21 deletions(-) diff --git a/src/components/HeaderBar.vue b/src/components/HeaderBar.vue index 33162da176..b7f4037d95 100644 --- a/src/components/HeaderBar.vue +++ b/src/components/HeaderBar.vue @@ -120,7 +120,7 @@ const playContinuously = async () => { } }; const stopContinuously = () => { - store.dispatch("STOP_PLAYLIST"); + store.dispatch("STOP_AUDIOS"); }; const generateAndSaveOneAudio = async () => { if (activeAudioKey.value == undefined) diff --git a/src/store/audioPlayer.ts b/src/store/audioPlayer.ts index ebe0931aa7..961b4abbc6 100644 --- a/src/store/audioPlayer.ts +++ b/src/store/audioPlayer.ts @@ -50,7 +50,7 @@ export const audioPlayerStore = createPartialStore({ ) { return; } - dispatch("STOP_AUDIO", { audioKey }); + dispatch("STOP_AUDIO", { nowPlayingAudioKey: audioKey }); audioElement.removeAttribute("src"); audioElements.delete(audioKey); }, @@ -111,7 +111,7 @@ export const audioPlayerStore = createPartialStore({ audioElem.removeEventListener("play", played); audioElem.removeEventListener("pause", paused); if (audioKey) { - commit("STOP_AUDIO", { audioKey }); + commit("STOP_AUDIO", { nowPlayingAudioKey: audioKey }); } }); @@ -122,21 +122,24 @@ export const audioPlayerStore = createPartialStore({ }, STOP_AUDIO: { - mutation(state, { audioKey }: { audioKey: AudioKey }) { + mutation(state, { nowPlayingAudioKey }: { nowPlayingAudioKey: AudioKey }) { const audioKeys = state.nowPlayingAudioKeys; - if (audioKeys.includes(audioKey)) { - delete audioKeys[audioKeys.indexOf(audioKey)]; + if (audioKeys.includes(nowPlayingAudioKey)) { + delete audioKeys[audioKeys.indexOf(nowPlayingAudioKey)]; } }, - action({ commit }, { audioKey }: { audioKey: AudioKey }) { - const audioElem = audioElements.get(audioKey); + action( + { commit }, + { nowPlayingAudioKey }: { nowPlayingAudioKey: AudioKey } + ) { + const audioElem = audioElements.get(nowPlayingAudioKey); if (audioElem === undefined) throw new Error("audioElem === undefined"); audioElem.pause(); - commit("STOP_AUDIO", { audioKey }); + commit("STOP_AUDIO", { nowPlayingAudioKey }); }, }, - PLAY_ALONG_PLAYLIST: { + PLAY_AUDIOS: { mutation(state, { audioKey }: { audioKey: AudioKey }) { state.nowPlayingContinuouslyAudioKey = audioKey; }, @@ -144,28 +147,28 @@ export const audioPlayerStore = createPartialStore({ const offset = 0; try { for await (const audioKey of audioKeys) { - commit("PLAY_ALONG_PLAYLIST", { audioKey }); + commit("PLAY_AUDIOS", { audioKey }); const isEnded = await dispatch("PLAY_AUDIO", { audioKey, offset }); if (!isEnded) { break; } } } finally { - commit("STOP_PLAYLIST"); + commit("STOP_AUDIOS"); } }, }, - STOP_PLAYLIST: { + STOP_AUDIOS: { mutation(state) { state.nowPlayingContinuouslyAudioKey = undefined; }, action({ state, commit, dispatch }) { - const audioKey = state.nowPlayingContinuouslyAudioKey; - if (audioKey !== undefined) { - dispatch("STOP_AUDIO", { audioKey }); + const nowPlayingAudioKey = state.nowPlayingContinuouslyAudioKey; + if (nowPlayingAudioKey !== undefined) { + dispatch("STOP_AUDIO", { nowPlayingAudioKey }); } - commit("STOP_PLAYLIST"); + commit("STOP_AUDIOS"); }, }, }); diff --git a/src/store/type.ts b/src/store/type.ts index 9bdee335f8..fd705af44d 100644 --- a/src/store/type.ts +++ b/src/store/type.ts @@ -684,16 +684,16 @@ export type AudioPlayerStoreTypes = { }; STOP_AUDIO: { - mutation: { audioKey: AudioKey }; - action(payload: { audioKey: AudioKey }): void; + mutation: { nowPlayingAudioKey: AudioKey }; + action(payload: { nowPlayingAudioKey: AudioKey }): void; }; - PLAY_ALONG_PLAYLIST: { + PLAY_AUDIOS: { mutation: { audioKey: AudioKey }; action(payload: { audioKeys: AsyncIterable }): void; }; - STOP_PLAYLIST: { + STOP_AUDIOS: { mutation: void; action(): void; }; From 7abe9c736bce886074b813de8a503e4b348a5317 Mon Sep 17 00:00:00 2001 From: tiramisu_oTATo Date: Thu, 17 Aug 2023 04:13:29 +0900 Subject: [PATCH 10/22] =?UTF-8?q?=E6=BC=8F=E3=82=8C=E3=82=92=E4=BF=AE?= =?UTF-8?q?=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/store/audio.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/store/audio.ts b/src/store/audio.ts index 8ce6fcb392..f0832da3b4 100644 --- a/src/store/audio.ts +++ b/src/store/audio.ts @@ -1724,7 +1724,7 @@ export const audioStore = createPartialStore({ const fromIndex = state.audioKeys.indexOf(currentAudioKey); try { - await dispatch("PLAY_ALONG_PLAYLIST", { + await dispatch("PLAY_AUDIOS", { audioKeys: (async function* (): AsyncGenerator { for (let i = fromIndex; i < state.audioKeys.length; ++i) { const audioKey = state.audioKeys[i]; From 43e1ff904ff7122eb749ce0d847ec92b0ad04bb3 Mon Sep 17 00:00:00 2001 From: tiramisu_oTATo Date: Thu, 17 Aug 2023 04:32:19 +0900 Subject: [PATCH 11/22] =?UTF-8?q?`WITH=5FUI=5FLOCK`=E7=89=88=E3=82=92?= =?UTF-8?q?=E3=83=87=E3=83=95=E3=82=A9=E3=83=AB=E3=83=88=E3=81=AB=E3=81=97?= =?UTF-8?q?=E3=81=A6=E7=B5=B1=E5=90=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/HeaderBar.vue | 2 +- src/store/audio.ts | 52 +++++++++++++++++------------------- src/store/type.ts | 4 --- 3 files changed, 25 insertions(+), 33 deletions(-) diff --git a/src/components/HeaderBar.vue b/src/components/HeaderBar.vue index b7f4037d95..bb964fb5a5 100644 --- a/src/components/HeaderBar.vue +++ b/src/components/HeaderBar.vue @@ -104,7 +104,7 @@ const redo = () => { }; const playContinuously = async () => { try { - await store.dispatch("FETCH_AND_PLAY_AUDIO_CONTINUOUSLY_WITH_UI_LOCK", {}); + await store.dispatch("FETCH_AND_PLAY_AUDIO_CONTINUOUSLY", {}); } catch (e) { let msg: string | undefined; // FIXME: GENERATE_AUDIO_FROM_AUDIO_ITEMのエラーを変えた場合変更する diff --git a/src/store/audio.ts b/src/store/audio.ts index f0832da3b4..33d84f51c6 100644 --- a/src/store/audio.ts +++ b/src/store/audio.ts @@ -1717,35 +1717,31 @@ export const audioStore = createPartialStore({ }, FETCH_AND_PLAY_AUDIO_CONTINUOUSLY: { - async action({ commit, dispatch, state }, { audioKey }) { - const bufStartPoint = state.audioPlayStartPoint; - const currentAudioKey = - audioKey ?? state._activeAudioKey ?? state.audioKeys[0]; - const fromIndex = state.audioKeys.indexOf(currentAudioKey); - - try { - await dispatch("PLAY_AUDIOS", { - audioKeys: (async function* (): AsyncGenerator { - for (let i = fromIndex; i < state.audioKeys.length; ++i) { - const audioKey = state.audioKeys[i]; - dispatch("SET_ACTIVE_AUDIO_KEY", { audioKey }); - - const blob = await dispatch("FETCH_AUDIO", { audioKey }); - await dispatch("LOAD_AUDIO_PLAYER", { audioKey, blob }); - yield audioKey; - } - })(), - }); - } finally { - commit("SET_ACTIVE_AUDIO_KEY", { audioKey: currentAudioKey }); - commit("SET_AUDIO_PLAY_START_POINT", { startPoint: bufStartPoint }); - } - }, - }, + action: createUILockAction( + async ({ commit, dispatch, state }, { audioKey }) => { + const bufStartPoint = state.audioPlayStartPoint; + const currentAudioKey = + audioKey ?? state._activeAudioKey ?? state.audioKeys[0]; + const fromIndex = state.audioKeys.indexOf(currentAudioKey); - FETCH_AND_PLAY_AUDIO_CONTINUOUSLY_WITH_UI_LOCK: { - action: createUILockAction(({ dispatch }, { audioKey }) => - dispatch("FETCH_AND_PLAY_AUDIO_CONTINUOUSLY", { audioKey }) + try { + await dispatch("PLAY_AUDIOS", { + audioKeys: (async function* (): AsyncGenerator { + for (let i = fromIndex; i < state.audioKeys.length; ++i) { + const audioKey = state.audioKeys[i]; + dispatch("SET_ACTIVE_AUDIO_KEY", { audioKey }); + + const blob = await dispatch("FETCH_AUDIO", { audioKey }); + await dispatch("LOAD_AUDIO_PLAYER", { audioKey, blob }); + yield audioKey; + } + })(), + }); + } finally { + commit("SET_ACTIVE_AUDIO_KEY", { audioKey: currentAudioKey }); + commit("SET_AUDIO_PLAY_START_POINT", { startPoint: bufStartPoint }); + } + } ), }, }); diff --git a/src/store/type.ts b/src/store/type.ts index fd705af44d..bee7bdd91e 100644 --- a/src/store/type.ts +++ b/src/store/type.ts @@ -435,10 +435,6 @@ export type AudioStoreTypes = { FETCH_AND_PLAY_AUDIO_CONTINUOUSLY: { action(payload: { audioKey?: AudioKey }): void; }; - - FETCH_AND_PLAY_AUDIO_CONTINUOUSLY_WITH_UI_LOCK: { - action(payload: { audioKey?: AudioKey }): void; - }; }; /* From 72805bd75f57719a2555e95cd498341133cbbe81 Mon Sep 17 00:00:00 2001 From: tiramisu_oTATo Date: Thu, 17 Aug 2023 04:45:24 +0900 Subject: [PATCH 12/22] =?UTF-8?q?=E9=96=A2=E6=95=B0=E5=90=8D=E4=BF=AE?= =?UTF-8?q?=E6=AD=A3=E3=83=BB=E6=BC=8F=E3=82=8C=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/AudioDetail.vue | 4 ++-- src/components/DictionaryManageDialog.vue | 2 +- src/store/audioPlayer.ts | 2 +- src/store/type.ts | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/components/AudioDetail.vue b/src/components/AudioDetail.vue index f49f3c77cc..47ebe2fe3a 100644 --- a/src/components/AudioDetail.vue +++ b/src/components/AudioDetail.vue @@ -510,7 +510,7 @@ const play = async () => { }; const stop = () => { - store.dispatch("STOP_AUDIO", { audioKey: props.activeAudioKey }); + store.dispatch("STOP_AUDIO", { nowPlayingAudioKey: props.activeAudioKey }); }; const nowPlaying = computed(() => @@ -584,7 +584,7 @@ watch(nowPlaying, async (newState) => { // 現在再生されているaudio elementの再生時刻を0.01秒毎に取得(監視)し、 // それに合わせてフォーカスするアクセント句を変えていく focusInterval = setInterval(() => { - const currentTime = store.getters.AUDIO_CURRENT_TIME( + const currentTime = store.getters.CALC_AUDIO_CURRENT_TIME( props.activeAudioKey ); for (let i = 1; i < accentPhraseOffsets.length; i++) { diff --git a/src/components/DictionaryManageDialog.vue b/src/components/DictionaryManageDialog.vue index 41f55b5a9b..6b4527849d 100644 --- a/src/components/DictionaryManageDialog.vue +++ b/src/components/DictionaryManageDialog.vue @@ -476,7 +476,7 @@ const play = async () => { await store.dispatch("PLAY_AUDIO", { audioKey }); }; const stop = () => { - store.dispatch("STOP_AUDIO", { audioKey }); + store.dispatch("STOP_AUDIO", { nowPlayingAudioKey: audioKey }); }; // accent phraseにあるaccentと実際に登録するアクセントには差が生まれる diff --git a/src/store/audioPlayer.ts b/src/store/audioPlayer.ts index 961b4abbc6..03f67a4b8b 100644 --- a/src/store/audioPlayer.ts +++ b/src/store/audioPlayer.ts @@ -14,7 +14,7 @@ export const audioPlayerStoreState: AudioPlayerStoreState = { const audioElements: Map = new Map(); export const audioPlayerStore = createPartialStore({ - AUDIO_CURRENT_TIME: { + CALC_AUDIO_CURRENT_TIME: { getter: () => (audioKey: AudioKey) => { const audioElement = audioElements.get(audioKey); if (audioElement === undefined) diff --git a/src/store/type.ts b/src/store/type.ts index bee7bdd91e..c48e906590 100644 --- a/src/store/type.ts +++ b/src/store/type.ts @@ -658,7 +658,7 @@ export type AudioPlayerStoreState = { }; export type AudioPlayerStoreTypes = { - AUDIO_CURRENT_TIME: { + CALC_AUDIO_CURRENT_TIME: { getter: (audioKey: AudioKey) => number | undefined; }; From 96d3d6ad4a726199a3cd3f01e3824ff0233cea6b Mon Sep 17 00:00:00 2001 From: tiramisu_oTATo Date: Thu, 17 Aug 2023 05:31:17 +0900 Subject: [PATCH 13/22] =?UTF-8?q?offset=E3=81=AE=E5=BE=AE=E9=87=8F?= =?UTF-8?q?=E5=8A=A0=E7=AE=97=E3=82=92`audio.ts`=E5=81=B4=E3=81=AB?= =?UTF-8?q?=E6=88=BB=E3=81=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/store/audio.ts | 4 +++- src/store/audioPlayer.ts | 4 +--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/store/audio.ts b/src/store/audio.ts index 33d84f51c6..8c1db137dd 100644 --- a/src/store/audio.ts +++ b/src/store/audio.ts @@ -1693,7 +1693,9 @@ export const audioStore = createPartialStore({ const offset = accentPhraseOffsets.length === 0 ? 0 - : accentPhraseOffsets[state.audioPlayStartPoint ?? 0]; + : // 小さい値が切り捨てられることでフォーカスされるアクセントフレーズが一瞬元に戻るので、 + // 再生に影響のない程度かつ切り捨てられない値を加算する + accentPhraseOffsets[state.audioPlayStartPoint ?? 0] + 10e-6; return dispatch("PLAY_AUDIO", { audioKey, offset }); } diff --git a/src/store/audioPlayer.ts b/src/store/audioPlayer.ts index 03f67a4b8b..fea2978916 100644 --- a/src/store/audioPlayer.ts +++ b/src/store/audioPlayer.ts @@ -71,9 +71,7 @@ export const audioPlayerStore = createPartialStore({ ); if (offset !== undefined) { - // 小さい値が切り捨てられることでフォーカスされるアクセントフレーズが一瞬元に戻るので、 - // 再生に影響のない程度かつ切り捨てられない値を加算する - audioElem.currentTime = offset + 10e-6; + audioElem.currentTime = offset; } // 一部ブラウザではsetSinkIdが実装されていないので、その環境では無視する From 5fa4201a1f44c9379d32752d04ab973da8e182b7 Mon Sep 17 00:00:00 2001 From: tiramisu_oTATo Date: Fri, 18 Aug 2023 02:54:52 +0900 Subject: [PATCH 14/22] =?UTF-8?q?=E7=94=9F=E6=88=90=E4=B8=AD=E3=81=8B?= =?UTF-8?q?=E3=81=AE=E5=88=B6=E5=BE=A1=E3=82=92`GENERATE=5FAUDIO`=E3=81=AB?= =?UTF-8?q?=E7=A7=BB=E3=81=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/store/audio.ts | 47 ++++++++++++++++++++++++---------------------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/src/store/audio.ts b/src/store/audio.ts index 8c1db137dd..3c5b5127e4 100644 --- a/src/store/audio.ts +++ b/src/store/audio.ts @@ -1197,11 +1197,29 @@ export const audioStore = createPartialStore({ }, GENERATE_AUDIO: { - async action({ dispatch, state }, { audioKey }: { audioKey: AudioKey }) { + async action( + { dispatch, commit, state }, + { audioKey }: { audioKey: AudioKey } + ) { const audioItem: AudioItem = JSON.parse( JSON.stringify(state.audioItems[audioKey]) ); - return dispatch("GENERATE_AUDIO_FROM_AUDIO_ITEM", { audioItem }); + commit("SET_AUDIO_NOW_GENERATING", { + audioKey, + nowGenerating: true, + }); + let resultBlob; + try { + resultBlob = await dispatch("GENERATE_AUDIO_FROM_AUDIO_ITEM", { + audioItem, + }); + } finally { + commit("SET_AUDIO_NOW_GENERATING", { + audioKey, + nowGenerating: false, + }); + } + return resultBlob; }, }, @@ -1657,26 +1675,11 @@ export const audioStore = createPartialStore({ }, FETCH_AUDIO: { - async action({ commit, dispatch }, { audioKey }: { audioKey: AudioKey }) { - let blob = await dispatch("GET_AUDIO_CACHE", { audioKey }); - if (!blob) { - commit("SET_AUDIO_NOW_GENERATING", { - audioKey, - nowGenerating: true, - }); - try { - blob = await withProgress( - dispatch("GENERATE_AUDIO", { audioKey }), - dispatch - ); - } finally { - commit("SET_AUDIO_NOW_GENERATING", { - audioKey, - nowGenerating: false, - }); - } - } - return blob; + async action({ dispatch }, { audioKey }: { audioKey: AudioKey }) { + return ( + (await dispatch("GET_AUDIO_CACHE", { audioKey })) ?? + (await withProgress(dispatch("GENERATE_AUDIO", { audioKey }), dispatch)) + ); }, }, From 048f23b92ef6b9668a0e1dfe315de8638e1184db Mon Sep 17 00:00:00 2001 From: tiramisu_oTATo Date: Fri, 18 Aug 2023 03:10:50 +0900 Subject: [PATCH 15/22] =?UTF-8?q?`=20LOAD=5FAUDIO=5FPLAYER`=E3=81=AE?= =?UTF-8?q?=E5=90=8D=E5=89=8D=E3=82=92`PREPARE=5F...`=E3=81=AB=E5=A4=89?= =?UTF-8?q?=E6=9B=B4=E3=81=97=E8=AA=AC=E6=98=8E=E3=82=92=E6=9B=B8=E3=81=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Hiroshiba --- src/store/audioPlayer.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/store/audioPlayer.ts b/src/store/audioPlayer.ts index fea2978916..0bdc82b9e8 100644 --- a/src/store/audioPlayer.ts +++ b/src/store/audioPlayer.ts @@ -29,7 +29,10 @@ export const audioPlayerStore = createPartialStore({ }, }, - LOAD_AUDIO_PLAYER: { + /** + * Audioインスタンスを作成して音声blobをセットし、`audioElements`へ登録する。 + */ + PREPARE_AUDIO_PLAYER: { action(_, { audioKey, blob }: { audioKey: AudioKey; blob: Blob }) { let audioElement = audioElements.get(audioKey); if (audioElement === undefined) { From da6404722d72715be41a3a5f38dc81ef9be91d4d Mon Sep 17 00:00:00 2001 From: tiramisu_oTATo Date: Fri, 18 Aug 2023 03:15:15 +0900 Subject: [PATCH 16/22] =?UTF-8?q?`PREPARE=5F...`=E3=81=AB=E5=90=88?= =?UTF-8?q?=E3=82=8F=E3=81=9B=E3=81=A6=E5=90=84=E9=83=A8=E3=82=92=E8=AA=BF?= =?UTF-8?q?=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/DictionaryManageDialog.vue | 2 +- src/store/audio.ts | 4 ++-- src/store/audioPlayer.ts | 6 +++--- src/store/type.ts | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/components/DictionaryManageDialog.vue b/src/components/DictionaryManageDialog.vue index 6b4527849d..c827a6c000 100644 --- a/src/components/DictionaryManageDialog.vue +++ b/src/components/DictionaryManageDialog.vue @@ -472,7 +472,7 @@ const play = async () => { } } nowGenerating.value = false; - await store.dispatch("LOAD_AUDIO_PLAYER", { audioKey, blob }); + await store.dispatch("PREPARE_AUDIO_PLAYER", { audioKey, blob }); await store.dispatch("PLAY_AUDIO", { audioKey }); }; const stop = () => { diff --git a/src/store/audio.ts b/src/store/audio.ts index 3c5b5127e4..4bcc76d2ff 100644 --- a/src/store/audio.ts +++ b/src/store/audio.ts @@ -1687,7 +1687,7 @@ export const audioStore = createPartialStore({ action: createUILockAction( async ({ state, dispatch }, { audioKey }: { audioKey: AudioKey }) => { const blob = await dispatch("FETCH_AUDIO", { audioKey }); - await dispatch("LOAD_AUDIO_PLAYER", { audioKey, blob }); + await dispatch("PREPARE_AUDIO_PLAYER", { audioKey, blob }); // 途中再生用の処理 const accentPhraseOffsets = await dispatch("GET_AUDIO_PLAY_OFFSETS", { @@ -1737,7 +1737,7 @@ export const audioStore = createPartialStore({ dispatch("SET_ACTIVE_AUDIO_KEY", { audioKey }); const blob = await dispatch("FETCH_AUDIO", { audioKey }); - await dispatch("LOAD_AUDIO_PLAYER", { audioKey, blob }); + await dispatch("PREPARE_AUDIO_PLAYER", { audioKey, blob }); yield audioKey; } })(), diff --git a/src/store/audioPlayer.ts b/src/store/audioPlayer.ts index 0bdc82b9e8..3c25ca77aa 100644 --- a/src/store/audioPlayer.ts +++ b/src/store/audioPlayer.ts @@ -30,17 +30,17 @@ export const audioPlayerStore = createPartialStore({ }, /** - * Audioインスタンスを作成して音声blobをセットし、`audioElements`へ登録する。 + * 音声blobをセットする。また、必要ならセット前にAudioインスタンスを作成して`audioElements`へ登録する。 */ PREPARE_AUDIO_PLAYER: { action(_, { audioKey, blob }: { audioKey: AudioKey; blob: Blob }) { let audioElement = audioElements.get(audioKey); if (audioElement === undefined) { audioElement = new Audio(); + audioElements.set(audioKey, audioElement); } audioElement.pause(); audioElement.src = URL.createObjectURL(blob); - audioElements.set(audioKey, audioElement); }, }, @@ -70,7 +70,7 @@ export const audioPlayerStore = createPartialStore({ const audioElem = audioElements.get(audioKey); if (audioElem === undefined) throw new Error( - "音声の読み込み前に再生されようとしました。先に LOAD_AUDIO_PLAYER を行ってください。" + "音声の読み込み前に再生されようとしました。先に PREPARE_AUDIO_PLAYER を行ってください。" ); if (offset !== undefined) { diff --git a/src/store/type.ts b/src/store/type.ts index c48e906590..c5009bf233 100644 --- a/src/store/type.ts +++ b/src/store/type.ts @@ -666,7 +666,7 @@ export type AudioPlayerStoreTypes = { getter: boolean; }; - LOAD_AUDIO_PLAYER: { + PREPARE_AUDIO_PLAYER: { action(payload: { audioKey: AudioKey; blob: Blob }): void; }; From 0ea6df9f7ee00b7466c0220a90e5faa7178d9c22 Mon Sep 17 00:00:00 2001 From: tiramisu_oTATo Date: Sun, 20 Aug 2023 12:33:14 +0900 Subject: [PATCH 17/22] =?UTF-8?q?Revert=20"=E7=94=9F=E6=88=90=E4=B8=AD?= =?UTF-8?q?=E3=81=8B=E3=81=AE=E5=88=B6=E5=BE=A1=E3=82=92`GENERATE=5FAUDIO`?= =?UTF-8?q?=E3=81=AB=E7=A7=BB=E3=81=99"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 5fa4201a1f44c9379d32752d04ab973da8e182b7. --- src/store/audio.ts | 47 ++++++++++++++++++++++------------------------ 1 file changed, 22 insertions(+), 25 deletions(-) diff --git a/src/store/audio.ts b/src/store/audio.ts index 4bcc76d2ff..171bcb7bd3 100644 --- a/src/store/audio.ts +++ b/src/store/audio.ts @@ -1197,29 +1197,11 @@ export const audioStore = createPartialStore({ }, GENERATE_AUDIO: { - async action( - { dispatch, commit, state }, - { audioKey }: { audioKey: AudioKey } - ) { + async action({ dispatch, state }, { audioKey }: { audioKey: AudioKey }) { const audioItem: AudioItem = JSON.parse( JSON.stringify(state.audioItems[audioKey]) ); - commit("SET_AUDIO_NOW_GENERATING", { - audioKey, - nowGenerating: true, - }); - let resultBlob; - try { - resultBlob = await dispatch("GENERATE_AUDIO_FROM_AUDIO_ITEM", { - audioItem, - }); - } finally { - commit("SET_AUDIO_NOW_GENERATING", { - audioKey, - nowGenerating: false, - }); - } - return resultBlob; + return dispatch("GENERATE_AUDIO_FROM_AUDIO_ITEM", { audioItem }); }, }, @@ -1675,11 +1657,26 @@ export const audioStore = createPartialStore({ }, FETCH_AUDIO: { - async action({ dispatch }, { audioKey }: { audioKey: AudioKey }) { - return ( - (await dispatch("GET_AUDIO_CACHE", { audioKey })) ?? - (await withProgress(dispatch("GENERATE_AUDIO", { audioKey }), dispatch)) - ); + async action({ commit, dispatch }, { audioKey }: { audioKey: AudioKey }) { + let blob = await dispatch("GET_AUDIO_CACHE", { audioKey }); + if (!blob) { + commit("SET_AUDIO_NOW_GENERATING", { + audioKey, + nowGenerating: true, + }); + try { + blob = await withProgress( + dispatch("GENERATE_AUDIO", { audioKey }), + dispatch + ); + } finally { + commit("SET_AUDIO_NOW_GENERATING", { + audioKey, + nowGenerating: false, + }); + } + } + return blob; }, }, From c86ba4e33ecf86ef61c48bccf85b819d95764f51 Mon Sep 17 00:00:00 2001 From: tiramisu_oTATo Date: Sun, 20 Aug 2023 12:38:01 +0900 Subject: [PATCH 18/22] =?UTF-8?q?`audioPlayer.ts`=E3=81=AE`FETCH`=E3=82=92?= =?UTF-8?q?`PREPARE`=E3=81=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/AudioDetail.vue | 2 +- src/components/HeaderBar.vue | 2 +- src/store/audio.ts | 10 +++++----- src/store/type.ts | 6 +++--- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/components/AudioDetail.vue b/src/components/AudioDetail.vue index 47ebe2fe3a..37e5f9b971 100644 --- a/src/components/AudioDetail.vue +++ b/src/components/AudioDetail.vue @@ -491,7 +491,7 @@ const changeMoraData = ( // audio play const play = async () => { try { - await store.dispatch("FETCH_AND_PLAY_AUDIO", { + await store.dispatch("PREPARE_AND_PLAY_AUDIO", { audioKey: props.activeAudioKey, }); } catch (e) { diff --git a/src/components/HeaderBar.vue b/src/components/HeaderBar.vue index bb964fb5a5..33fce998a7 100644 --- a/src/components/HeaderBar.vue +++ b/src/components/HeaderBar.vue @@ -104,7 +104,7 @@ const redo = () => { }; const playContinuously = async () => { try { - await store.dispatch("FETCH_AND_PLAY_AUDIO_CONTINUOUSLY", {}); + await store.dispatch("PREPARE_AND_PLAY_AUDIO_CONTINUOUSLY", {}); } catch (e) { let msg: string | undefined; // FIXME: GENERATE_AUDIO_FROM_AUDIO_ITEMのエラーを変えた場合変更する diff --git a/src/store/audio.ts b/src/store/audio.ts index 171bcb7bd3..7b47c71844 100644 --- a/src/store/audio.ts +++ b/src/store/audio.ts @@ -1656,7 +1656,7 @@ export const audioStore = createPartialStore({ ), }, - FETCH_AUDIO: { + PREPARE_AUDIO: { async action({ commit, dispatch }, { audioKey }: { audioKey: AudioKey }) { let blob = await dispatch("GET_AUDIO_CACHE", { audioKey }); if (!blob) { @@ -1680,10 +1680,10 @@ export const audioStore = createPartialStore({ }, }, - FETCH_AND_PLAY_AUDIO: { + PREPARE_AND_PLAY_AUDIO: { action: createUILockAction( async ({ state, dispatch }, { audioKey }: { audioKey: AudioKey }) => { - const blob = await dispatch("FETCH_AUDIO", { audioKey }); + const blob = await dispatch("PREPARE_AUDIO", { audioKey }); await dispatch("PREPARE_AUDIO_PLAYER", { audioKey, blob }); // 途中再生用の処理 @@ -1718,7 +1718,7 @@ export const audioStore = createPartialStore({ }, }, - FETCH_AND_PLAY_AUDIO_CONTINUOUSLY: { + PREPARE_AND_PLAY_AUDIO_CONTINUOUSLY: { action: createUILockAction( async ({ commit, dispatch, state }, { audioKey }) => { const bufStartPoint = state.audioPlayStartPoint; @@ -1733,7 +1733,7 @@ export const audioStore = createPartialStore({ const audioKey = state.audioKeys[i]; dispatch("SET_ACTIVE_AUDIO_KEY", { audioKey }); - const blob = await dispatch("FETCH_AUDIO", { audioKey }); + const blob = await dispatch("PREPARE_AUDIO", { audioKey }); await dispatch("PREPARE_AUDIO_PLAYER", { audioKey, blob }); yield audioKey; } diff --git a/src/store/type.ts b/src/store/type.ts index c5009bf233..c2f1d2083d 100644 --- a/src/store/type.ts +++ b/src/store/type.ts @@ -417,11 +417,11 @@ export type AudioStoreTypes = { action(payload: { filePath?: string }): SaveResultObject | undefined; }; - FETCH_AUDIO: { + PREPARE_AUDIO: { action(payload: { audioKey: AudioKey }): Promise; }; - FETCH_AND_PLAY_AUDIO: { + PREPARE_AND_PLAY_AUDIO: { action(payload: { audioKey: AudioKey }): boolean; }; @@ -432,7 +432,7 @@ export type AudioStoreTypes = { }; }; - FETCH_AND_PLAY_AUDIO_CONTINUOUSLY: { + PREPARE_AND_PLAY_AUDIO_CONTINUOUSLY: { action(payload: { audioKey?: AudioKey }): void; }; }; From 1fdcccdc327eb8a63933ac50c4035661f77ef797 Mon Sep 17 00:00:00 2001 From: tiramisu_oTATo Date: Sun, 20 Aug 2023 13:00:28 +0900 Subject: [PATCH 19/22] =?UTF-8?q?=E9=80=A3=E7=B6=9A=E5=86=8D=E7=94=9F?= =?UTF-8?q?=E3=82=92=E3=82=B8=E3=82=A7=E3=83=8D=E3=83=AC=E3=83=BC=E3=82=BF?= =?UTF-8?q?=E3=81=8B=E3=82=89=E3=82=B3=E3=83=BC=E3=83=AB=E3=83=90=E3=83=83?= =?UTF-8?q?=E3=82=AF=E3=81=AB=E5=A4=89=E6=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/store/audio.ts | 17 +++++++---------- src/store/audioPlayer.ts | 14 ++++++++++++-- src/store/type.ts | 5 ++++- 3 files changed, 23 insertions(+), 13 deletions(-) diff --git a/src/store/audio.ts b/src/store/audio.ts index 7b47c71844..1bdfa2d821 100644 --- a/src/store/audio.ts +++ b/src/store/audio.ts @@ -1728,16 +1728,13 @@ export const audioStore = createPartialStore({ try { await dispatch("PLAY_AUDIOS", { - audioKeys: (async function* (): AsyncGenerator { - for (let i = fromIndex; i < state.audioKeys.length; ++i) { - const audioKey = state.audioKeys[i]; - dispatch("SET_ACTIVE_AUDIO_KEY", { audioKey }); - - const blob = await dispatch("PREPARE_AUDIO", { audioKey }); - await dispatch("PREPARE_AUDIO_PLAYER", { audioKey, blob }); - yield audioKey; - } - })(), + audioKeys: state.audioKeys.slice(fromIndex), + beforePlayFn: async (audioKey: AudioKey) => { + dispatch("SET_ACTIVE_AUDIO_KEY", { audioKey }); + + const blob = await dispatch("PREPARE_AUDIO", { audioKey }); + await dispatch("PREPARE_AUDIO_PLAYER", { audioKey, blob }); + }, }); } finally { commit("SET_ACTIVE_AUDIO_KEY", { audioKey: currentAudioKey }); diff --git a/src/store/audioPlayer.ts b/src/store/audioPlayer.ts index 3c25ca77aa..4b63537c81 100644 --- a/src/store/audioPlayer.ts +++ b/src/store/audioPlayer.ts @@ -144,10 +144,20 @@ export const audioPlayerStore = createPartialStore({ mutation(state, { audioKey }: { audioKey: AudioKey }) { state.nowPlayingContinuouslyAudioKey = audioKey; }, - async action({ commit, dispatch }, { audioKeys }) { + async action( + { commit, dispatch }, + { + audioKeys, + beforePlayFn, + }: { + audioKeys: AudioKey[]; + beforePlayFn: (audioKey: AudioKey) => Promise; + } + ) { const offset = 0; try { - for await (const audioKey of audioKeys) { + for (const audioKey of audioKeys) { + await beforePlayFn(audioKey); commit("PLAY_AUDIOS", { audioKey }); const isEnded = await dispatch("PLAY_AUDIO", { audioKey, offset }); if (!isEnded) { diff --git a/src/store/type.ts b/src/store/type.ts index c2f1d2083d..0ff8925f5c 100644 --- a/src/store/type.ts +++ b/src/store/type.ts @@ -686,7 +686,10 @@ export type AudioPlayerStoreTypes = { PLAY_AUDIOS: { mutation: { audioKey: AudioKey }; - action(payload: { audioKeys: AsyncIterable }): void; + action(payload: { + audioKeys: AudioKey[]; + beforePlayFn: (audioKey: AudioKey) => Promise; + }): void; }; STOP_AUDIOS: { From bcb57bbb2980a7f12323a92240313d05f79ce42d Mon Sep 17 00:00:00 2001 From: tiramisu_oTATo Date: Sun, 20 Aug 2023 13:34:23 +0900 Subject: [PATCH 20/22] =?UTF-8?q?`commit("STOP=5FAUDIO")`=E5=91=A8?= =?UTF-8?q?=E3=82=8A=E3=81=AE=E8=A6=8B=E7=9B=B4=E3=81=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/store/audioPlayer.ts | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/store/audioPlayer.ts b/src/store/audioPlayer.ts index 4b63537c81..36232eea7f 100644 --- a/src/store/audioPlayer.ts +++ b/src/store/audioPlayer.ts @@ -111,9 +111,7 @@ export const audioPlayerStore = createPartialStore({ }).finally(async () => { audioElem.removeEventListener("play", played); audioElem.removeEventListener("pause", paused); - if (audioKey) { - commit("STOP_AUDIO", { nowPlayingAudioKey: audioKey }); - } + commit("STOP_AUDIO", { nowPlayingAudioKey: audioKey }); }); audioElem.play(); @@ -127,16 +125,16 @@ export const audioPlayerStore = createPartialStore({ const audioKeys = state.nowPlayingAudioKeys; if (audioKeys.includes(nowPlayingAudioKey)) { delete audioKeys[audioKeys.indexOf(nowPlayingAudioKey)]; + } else { + // もしかするとユーザー操作と自動停止が同時に実行されるかもしれないので警告出力に留めておく + console.warn("再生中でないオーディオが停止されようとしました。"); } }, - action( - { commit }, - { nowPlayingAudioKey }: { nowPlayingAudioKey: AudioKey } - ) { + action(_, { nowPlayingAudioKey }: { nowPlayingAudioKey: AudioKey }) { const audioElem = audioElements.get(nowPlayingAudioKey); if (audioElem === undefined) throw new Error("audioElem === undefined"); audioElem.pause(); - commit("STOP_AUDIO", { nowPlayingAudioKey }); + // PLAY_AUDIO 時に"pause"イベントでcommitされるよう登録してあるため追加で何かする必要はない }, }, From fb9948704365c6443ace5a9e19d3a0c52626b5d1 Mon Sep 17 00:00:00 2001 From: tiramisu_oTATo Date: Sun, 20 Aug 2023 13:37:57 +0900 Subject: [PATCH 21/22] =?UTF-8?q?=E6=9C=AA=E4=BD=BF=E7=94=A8=E3=81=AE`UNLO?= =?UTF-8?q?AD=5FAUDIO=5FPLAYER`=E3=82=92=E5=89=8A=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/store/audioPlayer.ts | 15 --------------- src/store/type.ts | 4 ---- 2 files changed, 19 deletions(-) diff --git a/src/store/audioPlayer.ts b/src/store/audioPlayer.ts index 36232eea7f..183f2d352d 100644 --- a/src/store/audioPlayer.ts +++ b/src/store/audioPlayer.ts @@ -44,21 +44,6 @@ export const audioPlayerStore = createPartialStore({ }, }, - UNLOAD_AUDIO_PLAYER: { - action({ dispatch }, { audioKey }: { audioKey?: AudioKey }) { - let audioElement; - if ( - audioKey === undefined || - (audioElement = audioElements.get(audioKey)) === undefined - ) { - return; - } - dispatch("STOP_AUDIO", { nowPlayingAudioKey: audioKey }); - audioElement.removeAttribute("src"); - audioElements.delete(audioKey); - }, - }, - PLAY_AUDIO: { mutation(state, { audioKey }: { audioKey: AudioKey }) { state.nowPlayingAudioKeys.push(audioKey); diff --git a/src/store/type.ts b/src/store/type.ts index 0ff8925f5c..daae039e12 100644 --- a/src/store/type.ts +++ b/src/store/type.ts @@ -670,10 +670,6 @@ export type AudioPlayerStoreTypes = { action(payload: { audioKey: AudioKey; blob: Blob }): void; }; - UNLOAD_AUDIO_PLAYER: { - action(payload: { audioKey?: AudioKey }): void; - }; - PLAY_AUDIO: { mutation: { audioKey: AudioKey }; action(payload: { audioKey: AudioKey; offset?: number }): Promise; From 7709d8b2d223b16b69bf6f9002953d3314ff91d0 Mon Sep 17 00:00:00 2001 From: tiramisu_oTATo Date: Sun, 20 Aug 2023 19:33:01 +0900 Subject: [PATCH 22/22] =?UTF-8?q?`console.warn`=E3=81=8B=E3=82=89window.el?= =?UTF-8?q?ectron.logWarn`=E3=81=AB=E5=A4=89=E6=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/store/audioPlayer.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/store/audioPlayer.ts b/src/store/audioPlayer.ts index 183f2d352d..f9642567b6 100644 --- a/src/store/audioPlayer.ts +++ b/src/store/audioPlayer.ts @@ -112,7 +112,9 @@ export const audioPlayerStore = createPartialStore({ delete audioKeys[audioKeys.indexOf(nowPlayingAudioKey)]; } else { // もしかするとユーザー操作と自動停止が同時に実行されるかもしれないので警告出力に留めておく - console.warn("再生中でないオーディオが停止されようとしました。"); + window.electron.logWarn( + "再生中でないオーディオが停止されようとしました。" + ); } }, action(_, { nowPlayingAudioKey }: { nowPlayingAudioKey: AudioKey }) {