Skip to content

Commit

Permalink
Add: ソングの書き出しダイアログを追加 (#2287)
Browse files Browse the repository at this point in the history
* Add: ソングの書き出しダイアログを追加

* Add: ダイアログを完成させる

* Add: パラメータ適用以外は実装

* Add: 書き出せるように

* Change: wave -> audio

* Add: wav以外の書き出しを追加

* Change: メモ -> NOTE

Co-authored-by: Hiroshiba <[email protected]>

* Fix: ファイル名のプレビューを修正

* Fix: トーク側のファイル名を修正

* Change: DialogStatesに定義を置く

* Add: 出力ポップアップを追加

* Fix: プレビューを修正

* Delete: フォーマット選択を削除

* Change: テキストを変える

Co-Authored-By: sigprogramming <[email protected]>

* Update: 色々更新

* Change: モノラル時はpan=0を使う用に

* Change: ステレオでandをかける

* Change: wav -> WAV

Co-authored-by: Hiroshiba <[email protected]>

* Code: コメントを変える

Co-authored-by: Hiroshiba <[email protected]>

* Change: 書き出し -> 書き出す

Co-authored-by: Hiroshiba <[email protected]>

* Code: コメントを追加

Co-authored-by: Hiroshiba <[email protected]>

* Revert: package-lock.jsonの変更を戻す

* Change: TrackParametersをstore/type.tsに移動

* Change: isMonoに

* Code: コメントを追加

* Fix: デフォルト値を修正

* Fix: 条件を修正

Co-authored-by: Sig <[email protected]>

* Improvr: テキストをいい感じにする

* Change: isStereo -> isMono

* Improve: モノラル書き出しをオンにするとパンが無効化されるように

* 微調整

---------

Co-authored-by: Hiroshiba <[email protected]>
Co-authored-by: sigprogramming <[email protected]>
Co-authored-by: Sig <[email protected]>
  • Loading branch information
4 people authored Oct 12, 2024
1 parent 755d84b commit f45ec28
Show file tree
Hide file tree
Showing 21 changed files with 521 additions and 244 deletions.
7 changes: 7 additions & 0 deletions src/backend/common/ConfigManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,13 @@ const migrations: [string, (store: Record<string, unknown>) => unknown][] = [
delete experimentalSetting.shouldApplyDefaultPresetOnVoiceChanged;
}

// 書き出しテンプレートから拡張子を削除
const savingSetting = config.savingSetting as { fileNamePattern: string };
savingSetting.fileNamePattern = savingSetting.fileNamePattern.replace(
".wav",
"",
);

return config;
},
],
Expand Down
12 changes: 10 additions & 2 deletions src/backend/electron/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -584,7 +584,12 @@ registerIpcMainHandle<IpcMainHandle>({
dialog.showSaveDialog(win, {
title,
defaultPath,
filters: [{ name: "Wave File", extensions: ["wav"] }],
filters: [
{
name: "WAVファイル",
extensions: ["wav"],
},
],
properties: ["createDirectory"],
}),
);
Expand Down Expand Up @@ -872,7 +877,10 @@ registerIpcMainHandle<IpcMainHandle>({

WRITE_FILE: (_, { filePath, buffer }) => {
try {
fs.writeFileSync(filePath, new DataView(buffer));
fs.writeFileSync(
filePath,
new DataView(buffer instanceof Uint8Array ? buffer.buffer : buffer),
);
return success(undefined);
} catch (e) {
// throwだと`.code`の情報が消えるのでreturn
Expand Down
11 changes: 11 additions & 0 deletions src/components/Dialog/AllDialog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
<UpdateNotificationDialogContainer
:canOpenDialog="canOpenNotificationDialog"
/>
<ExportSongAudioDialog v-model="isExportSongAudioDialogOpen" />
<ImportSongProjectDialog v-model="isImportSongProjectDialogOpenComputed" />
</template>

Expand All @@ -39,6 +40,7 @@ import DictionaryManageDialog from "@/components/Dialog/DictionaryManageDialog.v
import EngineManageDialog from "@/components/Dialog/EngineManageDialog.vue";
import UpdateNotificationDialogContainer from "@/components/Dialog/UpdateNotificationDialog/Container.vue";
import ImportSongProjectDialog from "@/components/Dialog/ImportSongProjectDialog.vue";
import ExportSongAudioDialog from "@/components/Dialog/ExportSongAudioDialog/Container.vue";
import { useStore } from "@/store";
import { filterCharacterInfosByStyleType } from "@/store/utility";
Expand Down Expand Up @@ -159,6 +161,15 @@ const canOpenNotificationDialog = computed(() => {
);
});
// ソングのオーディオエクスポート時の設定ダイアログ
const isExportSongAudioDialogOpen = computed({
get: () => store.state.isExportSongAudioDialogOpen,
set: (val) =>
store.dispatch("SET_DIALOG_OPEN", {
isExportSongAudioDialogOpen: val,
}),
});
// ソングのプロジェクトファイルのインポート時の設定ダイアログ
const isImportSongProjectDialogOpenComputed = computed({
get: () => store.state.isImportSongProjectDialogOpen,
Expand Down
60 changes: 25 additions & 35 deletions src/components/Dialog/Dialog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -160,18 +160,8 @@ export async function generateAndSaveOneAudioWithDialog({
actions,
);

if (result.result === "CANCELED") return;

if (result.result === "SUCCESS") {
if (disableNotifyOnGenerate) return;
// 書き出し成功時に通知をする
showWriteSuccessNotify({
mediaType: "audio",
actions,
});
} else {
showWriteErrorDialog({ mediaType: "audio", result, actions });
}
if (result == undefined) return;
notifyResult(result, "audio", actions, disableNotifyOnGenerate);
}

export async function multiGenerateAndSaveAudioWithDialog({
Expand Down Expand Up @@ -260,17 +250,8 @@ export async function generateAndConnectAndSaveAudioWithDialog({
actions,
);

if (result == undefined || result.result === "CANCELED") return;

if (result.result === "SUCCESS") {
if (disableNotifyOnGenerate) return;
showWriteSuccessNotify({
mediaType: "audio",
actions,
});
} else {
showWriteErrorDialog({ mediaType: "audio", result, actions });
}
if (result == undefined) return;
notifyResult(result, "audio", actions, disableNotifyOnGenerate);
}

export async function connectAndExportTextWithDialog({
Expand All @@ -285,18 +266,8 @@ export async function connectAndExportTextWithDialog({
const result = await actions.CONNECT_AND_EXPORT_TEXT({
filePath,
});

if (result == undefined || result.result === "CANCELED") return;

if (result.result === "SUCCESS") {
if (disableNotifyOnGenerate) return;
showWriteSuccessNotify({
mediaType: "text",
actions,
});
} else {
showWriteErrorDialog({ mediaType: "text", result, actions });
}
if (!result) return;
notifyResult(result, "text", actions, disableNotifyOnGenerate);
}

// 書き出し成功時の通知を表示
Expand Down Expand Up @@ -352,6 +323,25 @@ const showWriteErrorDialog = ({
}
};

/** 保存結果に応じてユーザーに通知する。キャンセルされた場合は何もしない。 */
export const notifyResult = (
result: SaveResultObject,
mediaType: MediaType,
actions: DotNotationDispatch<AllActions>,
disableNotifyOnGenerate: boolean,
) => {
if (result.result === "CANCELED") return;
if (result.result === "SUCCESS") {
if (disableNotifyOnGenerate) return;
showWriteSuccessNotify({
mediaType,
actions,
});
} else {
showWriteErrorDialog({ mediaType, result, actions });
}
};

const NOTIFY_TIMEOUT = 7000;

export const showNotifyAndNotShowAgainButton = (
Expand Down
45 changes: 45 additions & 0 deletions src/components/Dialog/ExportSongAudioDialog/BaseCell.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<!--
NOTE: SettingDialogのBaseCellを参考にして作成
-->

<template>
<QCardActions :class="props.class">
<div>{{ title }}</div>
<div :aria-label="description">
<QIcon name="help_outline" size="sm" class="help-hover-icon">
<QTooltip
:delay="500"
anchor="center right"
self="center left"
transitionShow="jump-right"
transitionHide="jump-left"
>
{{ description }}
</QTooltip>
</QIcon>
</div>
<QSpace />
<slot />
</QCardActions>
</template>

<script setup lang="ts">
export type Props = {
title: string;
description: string;
class?: unknown; // 型はquasarの定義を真似ている
};

const props = defineProps<Props>();
</script>

<style scoped lang="scss">
@use "@/styles/visually-hidden" as visually-hidden;
@use "@/styles/colors" as colors;

.help-hover-icon {
margin-left: 6px;
color: colors.$display;
opacity: 0.5;
}
</style>
36 changes: 36 additions & 0 deletions src/components/Dialog/ExportSongAudioDialog/Container.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<template>
<Presentation v-model="modelValue" @exportAudio="handleExportAudio" />
</template>

<script setup lang="ts">
import { notifyResult } from "../Dialog";
import Presentation, { ExportTarget } from "./Presentation.vue";
import { useStore } from "@/store";
import { SaveResultObject, SongExportSetting } from "@/store/type";
defineOptions({
name: "ExportSongAudioDialog",
});
const modelValue = defineModel<boolean>();
const store = useStore();
const handleExportAudio = async (
target: ExportTarget,
setting: SongExportSetting,
) => {
let result: SaveResultObject;
if (target === "master") {
result = await store.dispatch("EXPORT_AUDIO_FILE", { setting });
} else {
result = await store.dispatch("EXPORT_STEM_AUDIO_FILE", { setting });
}
notifyResult(
result,
"audio",
store.actions,
store.state.confirmedTips.notifyOnGenerate,
);
};
</script>
Loading

0 comments on commit f45ec28

Please sign in to comment.