From 8b4471fad482abe8cdbde9d62a3a6ba8770863e5 Mon Sep 17 00:00:00 2001 From: Roy Shilkrot Date: Thu, 25 Jan 2024 11:44:05 -0500 Subject: [PATCH] Update save_srt option and add truncate_output_file option (#64) * Update save_srt option and add truncate_output_file option * Refactor code for readability and maintainability * Update clang-format version to 16.0.5 * Update .clang-format and model-downloader-ui.cpp * Fix is_lead_byte and is_trail_byte macros --- .clang-format | 130 ++++++++++++++++--- .github/actions/run-clang-format/action.yaml | 10 +- build-aux/.run-format.zsh | 14 +- data/locale/en-US.ini | 3 +- data/locale/pt_BR.ini | 1 + data/locale/ru_RU.ini | 1 + src/model-utils/model-downloader-ui.cpp | 3 +- src/transcription-filter-data.h | 1 + src/transcription-filter.cpp | 19 ++- 9 files changed, 148 insertions(+), 34 deletions(-) diff --git a/.clang-format b/.clang-format index 33a3b3a..afc3dcc 100644 --- a/.clang-format +++ b/.clang-format @@ -1,6 +1,6 @@ -# please use clang-format version 8 or later +# please use clang-format version 16 or later -Standard: Cpp11 +Standard: c++17 AccessModifierOffset: -8 AlignAfterOpenBracket: Align AlignConsecutiveAssignments: false @@ -8,14 +8,14 @@ AlignConsecutiveDeclarations: false AlignEscapedNewlines: Left AlignOperands: true AlignTrailingComments: true -#AllowAllArgumentsOnNextLine: false # requires clang-format 9 -#AllowAllConstructorInitializersOnNextLine: false # requires clang-format 9 +AllowAllArgumentsOnNextLine: false +AllowAllConstructorInitializersOnNextLine: false AllowAllParametersOfDeclarationOnNextLine: false AllowShortBlocksOnASingleLine: false AllowShortCaseLabelsOnASingleLine: false AllowShortFunctionsOnASingleLine: Inline AllowShortIfStatementsOnASingleLine: false -#AllowShortLambdasOnASingleLine: Inline # requires clang-format 9 +AllowShortLambdasOnASingleLine: Inline AllowShortLoopsOnASingleLine: false AlwaysBreakAfterDefinitionReturnType: None AlwaysBreakAfterReturnType: None @@ -52,7 +52,7 @@ ContinuationIndentWidth: 8 Cpp11BracedListStyle: true DerivePointerAlignment: false DisableFormat: false -FixNamespaceComments: false +FixNamespaceComments: true ForEachMacros: - 'json_object_foreach' - 'json_object_foreach_safe' @@ -66,7 +66,7 @@ IndentWrappedFunctionNames: false KeepEmptyLinesAtTheStartOfBlocks: true MaxEmptyLinesToKeep: 1 NamespaceIndentation: None -#ObjCBinPackProtocolList: Auto # requires clang-format 7 +ObjCBinPackProtocolList: Auto ObjCBlockIndentWidth: 8 ObjCSpaceAfterProperty: true ObjCSpaceBeforeProtocolList: true @@ -84,13 +84,13 @@ ReflowComments: false SortIncludes: false SortUsingDeclarations: false SpaceAfterCStyleCast: false -#SpaceAfterLogicalNot: false # requires clang-format 9 +SpaceAfterLogicalNot: false SpaceAfterTemplateKeyword: false SpaceBeforeAssignmentOperators: true -#SpaceBeforeCtorInitializerColon: true # requires clang-format 7 -#SpaceBeforeInheritanceColon: true # requires clang-format 7 +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true SpaceBeforeParens: ControlStatements -#SpaceBeforeRangeBasedForLoopColon: true # requires clang-format 7 +SpaceBeforeRangeBasedForLoopColon: true SpaceInEmptyParentheses: false SpacesBeforeTrailingComments: 1 SpacesInAngles: false @@ -98,11 +98,111 @@ SpacesInCStyleCastParentheses: false SpacesInContainerLiterals: false SpacesInParentheses: false SpacesInSquareBrackets: false -#StatementMacros: # requires clang-format 8 -# - 'Q_OBJECT' +StatementMacros: + - 'Q_OBJECT' TabWidth: 8 -#TypenameMacros: # requires clang-format 9 -# - 'DARRAY' +TypenameMacros: + - 'DARRAY' UseTab: ForContinuationAndIndentation --- Language: ObjC +AccessModifierOffset: 2 +AlignArrayOfStructures: Right +AlignConsecutiveAssignments: None +AlignConsecutiveBitFields: None +AlignConsecutiveDeclarations: None +AlignConsecutiveMacros: + Enabled: true + AcrossEmptyLines: false + AcrossComments: true +AllowShortBlocksOnASingleLine: Never +AllowShortEnumsOnASingleLine: false +AllowShortFunctionsOnASingleLine: Empty +AllowShortIfStatementsOnASingleLine: Never +AllowShortLambdasOnASingleLine: None +AttributeMacros: ['__unused', '__autoreleasing', '_Nonnull', '__bridge'] +BitFieldColonSpacing: Both +#BreakBeforeBraces: Webkit +BreakBeforeBraces: Custom +BraceWrapping: + AfterCaseLabel: false + AfterClass: true + AfterControlStatement: Never + AfterEnum: false + AfterFunction: true + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + AfterExternBlock: false + BeforeCatch: false + BeforeElse: false + BeforeLambdaBody: false + BeforeWhile: false + IndentBraces: false + SplitEmptyFunction: false + SplitEmptyRecord: false + SplitEmptyNamespace: true +BreakAfterAttributes: Never +BreakArrays: false +BreakBeforeConceptDeclarations: Allowed +BreakBeforeInlineASMColon: OnlyMultiline +BreakConstructorInitializers: AfterColon +BreakInheritanceList: AfterComma +ColumnLimit: 120 +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +EmptyLineAfterAccessModifier: Never +EmptyLineBeforeAccessModifier: LogicalBlock +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +IndentAccessModifiers: false +IndentCaseBlocks: false +IndentCaseLabels: true +IndentExternBlock: Indent +IndentGotoLabels: false +IndentRequiresClause: true +IndentWidth: 4 +IndentWrappedFunctionNames: true +InsertBraces: false +InsertNewlineAtEOF: true +KeepEmptyLinesAtTheStartOfBlocks: false +LambdaBodyIndentation: Signature +NamespaceIndentation: All +ObjCBinPackProtocolList: Auto +ObjCBlockIndentWidth: 4 +ObjCBreakBeforeNestedBlockParam: false +ObjCSpaceAfterProperty: true +ObjCSpaceBeforeProtocolList: true +PPIndentWidth: -1 +PackConstructorInitializers: NextLine +QualifierAlignment: Leave +ReferenceAlignment: Right +RemoveSemicolon: false +RequiresClausePosition: WithPreceding +RequiresExpressionIndentation: OuterScope +SeparateDefinitionBlocks: Always +ShortNamespaceLines: 1 +SortIncludes: false +#SortUsingDeclarations: LexicographicNumeric +SortUsingDeclarations: true +SpaceAfterCStyleCast: true +SpaceAfterLogicalNot: false +SpaceAroundPointerQualifiers: Default +SpaceBeforeCaseColon: false +SpaceBeforeCpp11BracedList: true +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: ControlStatements +SpaceBeforeRangeBasedForLoopColon: true +SpaceBeforeSquareBrackets: false +SpaceInEmptyBlock: false +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 2 +SpacesInConditionalStatement: false +SpacesInLineCommentPrefix: + Minimum: 1 + Maximum: -1 +Standard: c++17 +TabWidth: 4 +UseTab: Never diff --git a/.github/actions/run-clang-format/action.yaml b/.github/actions/run-clang-format/action.yaml index b92910d..b4c1636 100644 --- a/.github/actions/run-clang-format/action.yaml +++ b/.github/actions/run-clang-format/action.yaml @@ -28,7 +28,7 @@ runs: echo ::group::Install Dependencies eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)" echo "/home/linuxbrew/.linuxbrew/bin:/home/linuxbrew/.linuxbrew/sbin" >> $GITHUB_PATH - echo "/home/linuxbrew/.linuxbrew/opt/clang-format@13/bin" >> $GITHUB_PATH + echo "/home/linuxbrew/.linuxbrew/opt/clang-format@16/bin" >> $GITHUB_PATH brew install --quiet zsh echo ::endgroup:: @@ -50,12 +50,12 @@ runs: *) ;; } - if (( ${changes[(I)(*.c|*.h|*.cpp|*.hpp|*.m|*.mm)]} )) { - echo ::group::Install clang-format-13 - brew install --quiet obsproject/tools/clang-format@13 + if (( ${changes[(I)(*.c|*.h|*.cpp|*.hpp|*.m|*.mm|*.clang-format|*.run-format.zsh)]} )) { + echo ::group::Install clang-format-16 + brew install --quiet obsproject/tools/clang-format@16 echo ::endgroup:: - echo ::group::Run clang-format-13 + echo ::group::Run clang-format-16 ./build-aux/run-clang-format --fail-${{ inputs.failCondition }} --check echo ::endgroup:: } diff --git a/build-aux/.run-format.zsh b/build-aux/.run-format.zsh index a71ffff..a99ea91 100755 --- a/build-aux/.run-format.zsh +++ b/build-aux/.run-format.zsh @@ -29,23 +29,23 @@ invoke_formatter() { case ${1} { clang) - if (( ${+commands[clang-format-13]} )) { - local formatter=clang-format-13 + if (( ${+commands[clang-format-16]} )) { + local formatter=clang-format-16 } elif (( ${+commands[clang-format]} )) { local formatter=clang-format local -a formatter_version=($(clang-format --version)) - if ! is-at-least 13.0.1 ${formatter_version[-1]}; then - log_error "clang-format is not version 13.0.1 or above (found ${formatter_version[-1]}." + if ! is-at-least 16.0.5 ${formatter_version[-1]}; then + log_error "clang-format is not version 16.0.5 or above (found ${formatter_version[-1]}." exit 2 fi - if ! is-at-least ${formatter_version[-1]} 13.0.1; then - log_error "clang-format is more recent than version 13.0.1 (found ${formatter_version[-1]})." + if ! is-at-least ${formatter_version[-1]} 16.0.5; then + log_error "clang-format is more recent than version 16.0.5 (found ${formatter_version[-1]})." exit 2 fi } else { - log_error "No viable clang-format version found (required 13.0.1)" + log_error "No viable clang-format version found (required 16.0.5)" exit 2 } diff --git a/data/locale/en-US.ini b/data/locale/en-US.ini index b15210e..31a2293 100644 --- a/data/locale/en-US.ini +++ b/data/locale/en-US.ini @@ -37,7 +37,8 @@ suppress_non_speech_tokens="Suppress non-speech tokens" temperature="Temperature" max_initial_ts="Max initial timestamps" length_penalty="Length penalty" -save_srt="Save in SRT format (no file truncation)" +save_srt="Save in SRT format" +truncate_output_file="Truncate file on new sentence" only_while_recording="Write output only while recording" process_while_muted="Process speech while source is muted" rename_file_to_match_recording="Rename file to match recording" diff --git a/data/locale/pt_BR.ini b/data/locale/pt_BR.ini index 21acd9c..f416835 100644 --- a/data/locale/pt_BR.ini +++ b/data/locale/pt_BR.ini @@ -39,6 +39,7 @@ temperature="Temperatura" max_initial_ts="Tempo inicial máximo" length_penalty="Pena de comprimento" save_srt="Salvar no formato SRT" +truncate_output_file="Truncar arquivo em nova frase" only_while_recording="Escreva durante a gravação" process_while_muted="Processar enquanto está silenciada" rename_file_to_match_recording="Renomear arquivo para corresponder à gravação" diff --git a/data/locale/ru_RU.ini b/data/locale/ru_RU.ini index e4b5bac..6d3ce3f 100644 --- a/data/locale/ru_RU.ini +++ b/data/locale/ru_RU.ini @@ -38,6 +38,7 @@ temperature="Температура" max_initial_ts="Максимальное начальное время" length_penalty="Штраф за длину" save_srt="Сохранить в формате SRT" +truncate_output_file="Усечь файл при новом предложении" only_while_recording="Записывать вывод только во время записи" process_while_muted="Обрабатывать речь, пока источник отключен" rename_file_to_match_recording="Переименовать файл, чтобы соответствовать записи" diff --git a/src/model-utils/model-downloader-ui.cpp b/src/model-utils/model-downloader-ui.cpp index 737575b..c1368fc 100644 --- a/src/model-utils/model-downloader-ui.cpp +++ b/src/model-utils/model-downloader-ui.cpp @@ -17,7 +17,8 @@ size_t write_data(void *ptr, size_t size, size_t nmemb, FILE *stream) ModelDownloader::ModelDownloader(const std::string &model_name, download_finished_callback_t download_finished_callback_, QWidget *parent) - : QDialog(parent), download_finished_callback(download_finished_callback_) + : QDialog(parent), + download_finished_callback(download_finished_callback_) { this->setWindowTitle("LocalVocal: Downloading model..."); this->setWindowFlags(Qt::Dialog | Qt::WindowTitleHint | Qt::CustomizeWindowHint); diff --git a/src/transcription-filter-data.h b/src/transcription-filter-data.h index cebd4ad..1e877e5 100644 --- a/src/transcription-filter-data.h +++ b/src/transcription-filter-data.h @@ -76,6 +76,7 @@ struct transcription_filter_data { bool caption_to_stream; bool active = false; bool save_srt = false; + bool truncate_output_file = false; bool save_only_while_recording = false; bool process_while_muted = false; bool rename_file_to_match_recording = false; diff --git a/src/transcription-filter.cpp b/src/transcription-filter.cpp index ac5c708..04ae99d 100644 --- a/src/transcription-filter.cpp +++ b/src/transcription-filter.cpp @@ -288,18 +288,23 @@ void set_text_callback(struct transcription_filter_data *gf, // We are not recording, do not save the sentence to file return; } + // should the file be truncated? + std::ios_base::openmode openmode = std::ios::out; + if (gf->truncate_output_file) { + openmode |= std::ios::trunc; + } else { + openmode |= std::ios::app; + } if (!gf->save_srt) { - // Write raw sentence to file, do not append - std::ofstream output_file(gf->output_file_path, - std::ios::out | std::ios::trunc); + // Write raw sentence to file + std::ofstream output_file(gf->output_file_path, openmode); output_file << str_copy << std::endl; output_file.close(); } else { obs_log(gf->log_level, "Saving sentence to file %s, sentence #%d", gf->output_file_path.c_str(), gf->sentence_number); // Append sentence to file in .srt format - std::ofstream output_file(gf->output_file_path, - std::ios::out | std::ios::app); + std::ofstream output_file(gf->output_file_path, openmode); output_file << gf->sentence_number << std::endl; // use the start and end timestamps to calculate the start and end time in srt format auto format_ts_for_srt = [&output_file](uint64_t ts) { @@ -370,6 +375,7 @@ void transcription_filter_update(void *data, obs_data_t *s) gf->step_size_msec = step_by_step_processing ? (int)obs_data_get_int(s, "step_size_msec") : BUFFER_SIZE_MSEC; gf->save_srt = obs_data_get_bool(s, "subtitle_save_srt"); + gf->truncate_output_file = obs_data_get_bool(s, "truncate_output_file"); gf->save_only_while_recording = obs_data_get_bool(s, "only_while_recording"); gf->rename_file_to_match_recording = obs_data_get_bool(s, "rename_file_to_match_recording"); // Get the current timestamp using the system clock @@ -497,6 +503,7 @@ void *transcription_filter_create(obs_data_t *settings, obs_source_t *filter) gf->last_sub_render_time = 0; gf->log_level = (int)obs_data_get_int(settings, "log_level"); gf->save_srt = obs_data_get_bool(settings, "subtitle_save_srt"); + gf->truncate_output_file = obs_data_get_bool(settings, "truncate_output_file"); gf->save_only_while_recording = obs_data_get_bool(settings, "only_while_recording"); gf->rename_file_to_match_recording = obs_data_get_bool(settings, "rename_file_to_match_recording"); @@ -634,6 +641,7 @@ void transcription_filter_defaults(obs_data_t *s) obs_data_set_default_bool(s, "step_by_step_processing", false); obs_data_set_default_bool(s, "process_while_muted", false); obs_data_set_default_bool(s, "subtitle_save_srt", false); + obs_data_set_default_bool(s, "truncate_output_file", false); obs_data_set_default_bool(s, "only_while_recording", false); obs_data_set_default_bool(s, "rename_file_to_match_recording", true); obs_data_set_default_int(s, "step_size_msec", 1000); @@ -707,6 +715,7 @@ obs_properties_t *transcription_filter_properties(void *data) obs_properties_add_path(ppts, "subtitle_output_filename", MT_("output_filename"), OBS_PATH_FILE_SAVE, "Text (*.txt)", NULL); obs_properties_add_bool(ppts, "subtitle_save_srt", MT_("save_srt")); + obs_properties_add_bool(ppts, "truncate_output_file", MT_("truncate_output_file")); obs_properties_add_bool(ppts, "only_while_recording", MT_("only_while_recording")); obs_properties_add_bool(ppts, "rename_file_to_match_recording", MT_("rename_file_to_match_recording"));