diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..9c42730 --- /dev/null +++ b/.clang-format @@ -0,0 +1,138 @@ +--- +Language: Cpp +# BasedOnStyle: Nothing lol +AccessModifierOffset: -4 +AlignAfterOpenBracket: DontAlign +AlignConsecutiveMacros: Consecutive +AlignConsecutiveAssignments: false +AlignConsecutiveBitFields: None +AlignConsecutiveDeclarations: false +AlignEscapedNewlines: Left +AlignOperands: true +AlignTrailingComments: true +AllowAllParametersOfDeclarationOnNextLine: false +AllowShortBlocksOnASingleLine: true +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: Empty +AllowShortIfStatementsOnASingleLine: Never +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: Yes +BinPackArguments: false +BinPackParameters: false +BraceWrapping: + AfterClass: false + AfterCaseLabel: false + AfterControlStatement: Never + AfterEnum: false + AfterFunction: false + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + BeforeCatch: false + BeforeElse: false + IndentBraces: false + SplitEmptyFunction: false + SplitEmptyNamespace: false + SplitEmptyRecord: false +BreakAfterJavaFieldAnnotations: true +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Custom +BreakBeforeConceptDeclarations: true +BreakBeforeTernaryOperators: false +BreakConstructorInitializers: AfterColon +BreakStringLiterals: true +ColumnLimit: 120 +CommentPragmas: '^ IWYU pragma:' +CompactNamespaces: false +ConstructorInitializerAllOnOneLineOrOnePerLine: true +ConstructorInitializerIndentWidth: 8 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DeriveLineEnding: false +DerivePointerAlignment: false +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +StatementAttributeLikeMacros: + - Q_EMIT +IncludeBlocks: Regroup +IncludeCategories: + - Regex: '^"(llvm|llvm-c|clang|clang-c)/' + Priority: 2 + SortPriority: 0 + CaseSensitive: false + - Regex: '^(<|"(gtest|gmock|isl|json)/)' + Priority: 3 + SortPriority: 0 + CaseSensitive: false + - Regex: '.*' + Priority: 1 + SortPriority: 0 + CaseSensitive: false +IncludeIsMainRegex: '(Test)?$' +IncludeIsMainSourceRegex: '' +IndentCaseLabels: true +IndentRequires: false +IndentWidth: 4 +IndentWrappedFunctionNames: true +JavaScriptQuotes: Double +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: false +Language: Cpp +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 3 +NamespaceIndentation: Inner +ObjCBlockIndentWidth: 7 +ObjCSpaceAfterProperty: true +ObjCSpaceBeforeProtocolList: false +PenaltyBreakBeforeFirstCallParameter: 100 +PenaltyBreakComment: 100 +PenaltyBreakFirstLessLess: 0 +PenaltyBreakString: 100 +PenaltyExcessCharacter: 1 +PenaltyReturnTypeOnItsOwnLine: 20 +PointerAlignment: Right +ReflowComments: true +SortIncludes: true +SortUsingDeclarations: true +SpaceAfterCStyleCast: false +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: false +SpaceBeforeAssignmentOperators: true +SpaceBeforeCpp11BracedList: true +SpaceBeforeCtorInitializerColon: false +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: ControlStatements +SpaceAroundPointerQualifiers: Default +SpaceBeforeRangeBasedForLoopColon: true +SpaceBeforeSquareBrackets: false +SpaceInEmptyBlock: false +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 2 +SpacesInAngles: false +SpacesInCStyleCastParentheses: false +SpacesInContainerLiterals: false +SpacesInParentheses: false +SpacesInConditionalStatement: false +SpacesInSquareBrackets: false +BitFieldColonSpacing: After +Standard: c++20 +TabWidth: 4 +UseCRLF: false +UseTab: Never +WhitespaceSensitiveMacros: + - STRINGIZE + - PP_STRINGIZE + - BOOST_PP_STRINGIZE + - NS_SWIFT_NAME + - CF_SWIFT_NAME +... diff --git a/.clang-tidy b/.clang-tidy new file mode 100644 index 0000000..47dada1 --- /dev/null +++ b/.clang-tidy @@ -0,0 +1,88 @@ +--- +Checks: + 'boost-use-to-string, + bugprone-*, + cert-dcl21-cpp, + cert-dcl50-cpp, + cert-dcl58-cpp, + cert-env33-c, + cert-err34-c, + cert-err52-cpp, + cert-err58-cpp, + cert-err60-cpp, + cert-flp30-c, + cert-mem57-cpp, + cert-msc50-cpp, + cert-oop57-cpp, + cert-oop58-cpp, + clang-analyzer-core.DynamicTypePropagation, + clang-analyzer-core.uninitialized.CapturedBlockVariable, + clang-analyzer-cplusplus.InnerPointer, + clang-analyzer-optin.portability.UnixAPI, + clang-analyzer-valist.CopyToSelf, + clang-analyzer-valist.Uninitialized, + clang-analyzer-valist.Unterminated, + concurrency-mt-unsafe, + concurrency-thread-canceltype-asynchronous, + cppcoreguidelines-avoid-goto, + cppcoreguidelines-avoid-non-const-global-variables, + cppcoreguidelines-interfaces-global-init, + cppcoreguidelines-macro-usage, + cppcoreguidelines-narrowing-conversions, + cppcoreguidelines-no-malloc, + cppcoreguidelines-owning-memory, + cppcoreguidelines-prefer-member-initializer, + cppcoreguidelines-pro-bounds-array-to-pointer-decay, + cppcoreguidelines-pro-bounds-constant-array-index, + cppcoreguidelines-pro-type-const-cast, + cppcoreguidelines-pro-type-cstyle-cast, + cppcoreguidelines-pro-type-member-init, + cppcoreguidelines-pro-type-static-cast-downcast, + cppcoreguidelines-pro-type-union-access, + cppcoreguidelines-slicing, + cppcoreguidelines-special-member-functions, + fuchsia-multiple-inheritance, + fuchsia-statically-constructed-objects, + fuchsia-virtual-inheritance, + google-build-explicit-make-pair, + google-build-namespaces, + google-build-using-namespace, + google-default-arguments, + google-explicit-constructor, + google-global-names-in-headers, + google-readability-casting, + google-runtime-int, + google-runtime-operator, + google-upgrade-googletest-case, + hicpp-exception-baseclass, + hicpp-multiway-paths-covered, + hicpp-no-assembler, + hicpp-signed-bitwise, + llvm-header-guard, + llvm-include-order, + llvm-namespace-comment, + misc-definitions-in-headers, + misc-misplaced-const, + misc-new-delete-overloads, + misc-non-copyable-objects, + misc-non-private-member-variables-in-classes, + misc-redundant-expression, + misc-static-assert, + misc-throw-by-value-catch-by-reference, + misc-unconventional-assign-operator, + misc-uniqueptr-reset-release, + misc-unused-alias-decls, + misc-unused-parameters, + misc-unused-using-decls, + modernize-*, + -modernize-use-trailing-return-type, + performance-*, + portability-*, + readability-*' +WarningsAsErrors: '*' +HeaderFilterRegex: '' +FormatStyle: none +CheckOptions: + - key: readability-uppercase-literal-suffix.NewSuffixes + value: 'u;ul;ull;l;ll;z;uz;f' + diff --git a/.cmake-format.yaml b/.cmake-format.yaml new file mode 100644 index 0000000..e26da9d --- /dev/null +++ b/.cmake-format.yaml @@ -0,0 +1,10 @@ +bullet_char: '*' +dangle_parens: true +enum_char: . +line_ending: unix +line_width: 120 +max_pargs_hwrap: 3 +separate_ctrl_name_with_space: true +separate_fn_name_with_space: false +tab_size: 4 + diff --git a/.github/cp.js b/.github/cp.js new file mode 100644 index 0000000..e51208b --- /dev/null +++ b/.github/cp.js @@ -0,0 +1,32 @@ +const fs = require('fs'); +const path = require('path'); + +const USAGE = "Usage: node cp.js [SOURCE_FILES]... [DESTINATION_DIR]\n"; + +const args = process.argv.slice(2); + +if (args.length < 2) { + console.error(USAGE); + throw new SyntaxError(); +} +const src = args.slice(0, -1); +const dest = args[args.length - 1] + +if (!fs.existsSync(dest)) { + console.error(`${dest} no such file or directory`) +} +if (!fs.statSync(dest).isDirectory()) { + console.error(`${dest} is not a directory`); + throw new TypeError(); +} + +for (const f of src) { + if (!fs.existsSync(f)) { + console.error(`${f} no such file or directory`) + } + if (!fs.statSync(f).isFile()) { + console.error(`${f} is not a file`); + throw new TypeError(); + } + fs.copyFileSync(f, path.join(dest, path.basename(f))); +} diff --git a/.github/mkdir.js b/.github/mkdir.js new file mode 100644 index 0000000..b452e3d --- /dev/null +++ b/.github/mkdir.js @@ -0,0 +1,27 @@ +const fs = require('fs'); + +const WARNINGS_ON = true; + +const USAGE = "Usage: node mkdir.js [DIR_NAME]\n"; + +const args = process.argv.slice(2); + +if(args.length != 1){ + console.error(USAGE); + throw new SyntaxError(); +} +const dir = args[0]; + +if(dir.includes("*")){ + throw new SyntaxError("globbing is not supported"); +} + +if(fs.existsSync(dir)){ + if(fs.statSync(dir).isFile()){ + throw new Error(`${dir} is a file`); + } + fs.statSync(dir).isDirectory() && WARNINGS_ON && console.warn(`${dir} already exists, doing nothing`); + return; +} + +fs.mkdirSync(dir); diff --git a/.github/rm.js b/.github/rm.js new file mode 100644 index 0000000..6c1cb54 --- /dev/null +++ b/.github/rm.js @@ -0,0 +1,19 @@ +const fs = require('fs'); +const path = require('path'); + +const USAGE = "Usage: node rm.js [FILES/DIRS]...\n"; + +const args = process.argv.slice(2); + +if (args.length < 1) { + console.error(USAGE); + throw new SyntaxError(); +} + +for (const f of args) { + if (!fs.existsSync(f)) { + console.warn(`${f} no such file or directory`) + continue; + } + fs.rmSync(f, {recursive: true}); +} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6d0f98b..d2db453 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -91,19 +91,11 @@ jobs: - name: Install run: | - yarn global add node-gyp yarn install --immutable - name: Build - if: startsWith(matrix.os, 'macos') run: yarn release - - name: Build - if: startsWith(matrix.os, 'windows') - run: | - mkdir dist - yarn release:win - - name: Artifact uses: actions/upload-artifact@v2 with: diff --git a/.gitignore b/.gitignore index 16c62af..993035b 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ build dist node_modules +native/compile_commands.json diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..c7a5d03 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,39 @@ +cmake_minimum_required(VERSION 3.15) + +# Set the project name to your project name, my project isn't very descriptive +project(VAD LANGUAGES C CXX) +include(cmake/CompileCommands.cmake) +include(cmake/StandardProjectSettings.cmake) +include(cmake/PreventInSourceBuilds.cmake) + +# Link this 'library' to set the c++ standard / compile-time options requested +add_library(project_options INTERFACE) +target_compile_features(project_options INTERFACE cxx_std_20) +target_compile_features(project_options INTERFACE c_std_11) + +# Link this 'library' to use the warnings specified in CompilerWarnings.cmake +add_library(project_warnings INTERFACE) + +# standard compiler warnings +include(cmake/CompilerWarnings.cmake) +set_project_warnings(project_warnings) + +# sanitizer options if supported by compiler +include(cmake/Sanitizers.cmake) +enable_sanitizers(project_options) + +# allow for static analysis options +include(cmake/StaticAnalyzers.cmake) + +# Should use boost? +option(USE_BOOST "Get boost through conan. Configurable in cmake/boost.cmake" OFF) +include(cmake/boost.cmake) +config_boost() + +# Set up some extra Conan dependencies based on our needs before loading Conan +set(CONAN_EXTRA_REQUIRES ${BOOST_REQ}) +set(CONAN_EXTRA_OPTIONS ${BOOST_OPTS}) +include(cmake/Conan.cmake) +run_conan() + +add_subdirectory(native) diff --git a/binding.gyp b/binding.gyp deleted file mode 100644 index 7eabb44..0000000 --- a/binding.gyp +++ /dev/null @@ -1,57 +0,0 @@ -{ - "targets": [ - { - "target_name": "vad", - "cflags!": ["-fexceptions"], - "cflags_cc!": ["-fexceptions", "-std=c++11", "-stdlib=libc++"], - "sources": [ - "native/webrtcvad.cc", - "native/vad.cc", - "native/webrtc/common_audio/signal_processing/complex_bit_reverse.c", - "native/webrtc/common_audio/signal_processing/complex_fft.c", - "native/webrtc/common_audio/signal_processing/cross_correlation.c", - "native/webrtc/common_audio/signal_processing/division_operations.c", - "native/webrtc/common_audio/signal_processing/downsample_fast.c", - "native/webrtc/common_audio/signal_processing/energy.c", - "native/webrtc/common_audio/signal_processing/get_scaling_square.c", - "native/webrtc/common_audio/signal_processing/min_max_operations.c", - "native/webrtc/common_audio/signal_processing/resample_48khz.c", - "native/webrtc/common_audio/signal_processing/resample_by_2_internal.c", - "native/webrtc/common_audio/signal_processing/resample_fractional.c", - "native/webrtc/common_audio/signal_processing/spl_init.c", - "native/webrtc/common_audio/signal_processing/spl_inl.c", - "native/webrtc/common_audio/signal_processing/spl_sqrt.c", - "native/webrtc/common_audio/signal_processing/vector_scaling_operations.c", - "native/webrtc/common_audio/third_party/spl_sqrt_floor/spl_sqrt_floor.c", - "native/webrtc/common_audio/vad/vad_core.c", - "native/webrtc/common_audio/vad/vad_filterbank.c", - "native/webrtc/common_audio/vad/vad_gmm.c", - "native/webrtc/common_audio/vad/vad_sp.c", - "native/webrtc/common_audio/vad/webrtc_vad.c", - "native/webrtc/rtc_base/checks.cc" - ], - "include_dirs": [ - ":_CRT_SECURE_NO_WARNINGS> # To silence MSVC about *_s functions + $,WEBRTC_WIN,WEBRTC_POSIX> # To silence MSVC about *_s functions +) diff --git a/native/vad.cc b/native/vad.cc index 66e5e1f..ce78ef1 100644 --- a/native/vad.cc +++ b/native/vad.cc @@ -1,71 +1,78 @@ #include "vad.h" +#include + + +#ifdef NDEBUG +#define SET_LOG_LEVEL() spdlog::set_level(spdlog::level::info) +#else +#define SET_LOG_LEVEL() spdlog::set_level(spdlog::level::debug) +#endif + + Napi::FunctionReference VAD::constructor; Napi::Object VAD::Init(Napi::Env env, Napi::Object exports) { - Napi::HandleScope scope(env); - Napi::Function func = - DefineClass(env, "VAD", {InstanceMethod("process", &VAD::Process)}); + spdlog::set_pattern("%^[%l]%$: %v"); + SET_LOG_LEVEL(); + Napi::HandleScope scope(env); + Napi::Function func = DefineClass(env, "VAD", {InstanceMethod("process", &VAD::Process)}); + + constructor = Napi::Persistent(func); + constructor.SuppressDestruct(); - constructor = Napi::Persistent(func); - constructor.SuppressDestruct(); + exports.Set("VAD", func); - exports.Set("VAD", func); - return exports; + return exports; } -VAD::VAD(const Napi::CallbackInfo& info) : Napi::ObjectWrap(info) { - Napi::Env env = info.Env(); - Napi::HandleScope scope(env); +VAD::VAD(const Napi::CallbackInfo &info): Napi::ObjectWrap(info) { + Napi::Env env = info.Env(); + Napi::HandleScope scope(env); - if (info.Length() != 2) { - Napi::TypeError::New(env, "Expected two arguments") - .ThrowAsJavaScriptException(); - } + if (info.Length() != 2) { + Napi::TypeError::New(env, "Expected two arguments").ThrowAsJavaScriptException(); + } - if (!info[0].IsNumber()) { - Napi::TypeError::New(env, "Expected number for first argument") - .ThrowAsJavaScriptException(); - } + if (!info[0].IsNumber()) { + Napi::TypeError::New(env, "Expected number for first argument").ThrowAsJavaScriptException(); + } - if (!info[1].IsNumber()) { - Napi::TypeError::New(env, "Expected number for second argument") - .ThrowAsJavaScriptException(); - } + if (!info[1].IsNumber()) { + Napi::TypeError::New(env, "Expected number for second argument").ThrowAsJavaScriptException(); + } - this->sample_rate_ = info[0].As().Int32Value(); - int level = info[1].As().Int32Value(); + this->sample_rate_ = info[0].As().Int32Value(); + int level = info[1].As().Int32Value(); - this->instance_ = WebRtcVad_Create(); - WebRtcVad_Init(this->instance_); - WebRtcVad_set_mode(this->instance_, level); + this->instance_ = WebRtcVad_Create(); + WebRtcVad_Init(this->instance_); + WebRtcVad_set_mode(this->instance_, level); } -VAD::~VAD() { WebRtcVad_Free(this->instance_); } +VAD::~VAD() { + WebRtcVad_Free(this->instance_); +} -Napi::Value VAD::Process(const Napi::CallbackInfo& info) { - Napi::Env env = info.Env(); - Napi::HandleScope scope(env); +Napi::Value VAD::Process(const Napi::CallbackInfo &info) { + Napi::Env env = info.Env(); + Napi::HandleScope scope(env); - if (info.Length() != 2) { - Napi::TypeError::New(env, "Expected two arguments") - .ThrowAsJavaScriptException(); - } + if (info.Length() != 2) { + Napi::TypeError::New(env, "Expected two arguments").ThrowAsJavaScriptException(); + } - if (!info[0].IsBuffer()) { - Napi::TypeError::New(env, "Expected buffer for first argument") - .ThrowAsJavaScriptException(); - } + if (!info[0].IsBuffer()) { + Napi::TypeError::New(env, "Expected buffer for first argument").ThrowAsJavaScriptException(); + } - if (!info[1].IsNumber()) { - Napi::TypeError::New(env, "Expected number for second argument") - .ThrowAsJavaScriptException(); - } + if (!info[1].IsNumber()) { + Napi::TypeError::New(env, "Expected number for second argument").ThrowAsJavaScriptException(); + } - Napi::Buffer audio = info[0].As>(); - uint32_t length = info[1].As().Uint32Value(); - int result = WebRtcVad_Process(this->instance_, this->sample_rate_, - audio.Data(), length); + Napi::Buffer audio = info[0].As>(); + uint32_t length = info[1].As().Uint32Value(); + int result = WebRtcVad_Process(this->instance_, this->sample_rate_, audio.Data(), length); - return Napi::Value::From(info.Env(), result == 1); + return Napi::Value::From(info.Env(), result == 1); } diff --git a/native/vad.h b/native/vad.h index 6659c68..826f76f 100644 --- a/native/vad.h +++ b/native/vad.h @@ -8,17 +8,17 @@ extern "C" { } class VAD : public Napi::ObjectWrap { - public: - VAD(const Napi::CallbackInfo& info); - ~VAD(); - static Napi::Object Init(Napi::Env env, Napi::Object exports); +public: + VAD(const Napi::CallbackInfo &info); + ~VAD(); + static Napi::Object Init(Napi::Env env, Napi::Object exports); - private: - VadInst* instance_; - int sample_rate_; +private: + VadInst *instance_; + int sample_rate_; - Napi::Value Process(const Napi::CallbackInfo& info); - static Napi::FunctionReference constructor; + Napi::Value Process(const Napi::CallbackInfo &info); + static Napi::FunctionReference constructor; }; #endif diff --git a/native/webrtc/rtc_base/checks.cc b/native/webrtc/rtc_base/checks.cc index 03baf31..d6e6b18 100644 --- a/native/webrtc/rtc_base/checks.cc +++ b/native/webrtc/rtc_base/checks.cc @@ -48,9 +48,9 @@ __attribute__((__format__(__printf__, 2, 3))) if (predicted_length > 0) { const size_t size = s->size(); - s->resize(size + predicted_length); + s->resize(size + static_cast(predicted_length)); // Pass "+ 1" to vsnprintf to include space for the '\0'. - std::vsnprintf(&((*s)[size]), predicted_length + 1, fmt, args); + std::vsnprintf(&((*s)[size]), static_cast(predicted_length) + 1, fmt, args); } va_end(args); } diff --git a/native/webrtcvad.cc b/native/webrtcvad.cc index 59734e1..69f0a56 100644 --- a/native/webrtcvad.cc +++ b/native/webrtcvad.cc @@ -1,9 +1,9 @@ -#include - #include "vad.h" +#include + Napi::Object InitAll(Napi::Env env, Napi::Object exports) { - return VAD::Init(env, exports); + return VAD::Init(env, exports); } NODE_API_MODULE(vad, InitAll); diff --git a/package.json b/package.json index 9e005c5..f3398f9 100644 --- a/package.json +++ b/package.json @@ -4,17 +4,18 @@ "types": "./dist/index.d.ts", "version": "0.0.1", "scripts": { - "ts:build": "tsc && cp package.json ./dist/", - "c:release": "node-gyp rebuild --release && yarn dylib", - "c:release:win": "node-gyp rebuild --release && yarn dylib:win", - "dylib": "if [ -f ./build/Release/vad.node ]; then mv -f ./build/Release/vad.node ./dist/vad.node; fi", - "dylib:win": "copy .\\build\\Release\\vad.node .\\dist\\vad.node", - "electron": "electron-build-env yarn c:release", - "electron:win": "electron-build-env yarn c:release:win", - "release": "rm -rf ./dist && mkdir -p ./dist && yarn electron && yarn ts:build && cp ./lib/*.d.ts ./dist", - "release:win": "erase /q .\\dist\\*.* && rmdir /q dist && mkdir dist && yarn electron:win && tsc && copy .\\lib\\*.d.ts .\\dist && copy package.json .\\dist\\", - "test": "yarn release && node dist/test.js", - "test:win": "yarn release:win && node .\\dist\\test.js" + "cp": "node .github/cp.js", + "rm": "node .github/rm.js", + "mkdir": "node .github/mkdir.js", + "ts:build": "tsc && yarn cp package.json ./dist/", + "c:debug": "cmake-js compile --debug && yarn mkdir dist && yarn cp ./build/lib/vad.node ./dist/", + "c:release": "cmake-js compile && yarn mkdir dist && yarn cp ./build/lib/vad.node ./dist/", + "electron:debug": "electron-build-env yarn c:debug", + "electron:release": "electron-build-env yarn c:release", + "release": "yarn rm ./dist && yarn mkdir ./dist && yarn electron:release && yarn ts:build && yarn cp ./lib/*.d.ts ./dist", + "debug": "yarn rm ./dist && yarn mkdir ./dist && yarn electron:debug && yarn ts:build && yarn cp ./lib/*.d.ts ./dist", + "test:debug": "yarn debug && node dist/test.js", + "test:release": "yarn release && node dist/test.js" }, "dependencies": { "electron": "^9.1.1",