diff --git a/packages/react-native-audio-api/.clang-tidy b/packages/react-native-audio-api/.clang-tidy new file mode 100644 index 000000000..83175f767 --- /dev/null +++ b/packages/react-native-audio-api/.clang-tidy @@ -0,0 +1,29 @@ +# Full clang-tidy configuration for react-native-audio-api C++. +# See: https://clang.llvm.org/extra/clang-tidy/checks/list.html +# Tweak checks in .clangd (Diagnostics.ClangTidy.Remove) to disable noisy ones. + +Checks: '-*, + bugprone-*, + -bugprone-easily-swappable-parameters, + modernize-*, + -modernize-use-trailing-return-type, + performance-*, + readability-*, + -readability-uppercase-literal-suffix, + -readability-math-missing-parentheses, + -readability-isolate-declaration, + -readability-identifier-length, + cppcoreguidelines-*, + -cppcoreguidelines-non-private-member-variables-in-classes, + -cppcoreguidelines-pro-bounds-avoid-unchecked-container-access, + -cppcoreguidelines-pro-bounds-pointer-arithmetic, + -cppcoreguidelines-pro-type-union-access, + -cppcoreguidelines-pro-type-reinterpret-cast, + -cppcoreguidelines-avoid-do-while, + -cppcoreguidelines-pro-bounds-constant-array-index, + -cppcoreguidelines-init-variables, + concurrency-*' + +HeaderFilterRegex: '.*/(audioapi|common/cpp|src/main/cpp)/.*' + +FormatStyle: file diff --git a/packages/react-native-audio-api/.clangd b/packages/react-native-audio-api/.clangd new file mode 100644 index 000000000..3724509bc --- /dev/null +++ b/packages/react-native-audio-api/.clangd @@ -0,0 +1,10 @@ +Documentation: + CommentFormat: Doxygen + +CompileFlags: + Add: + - -std=c++20 + +Diagnostics: + ClangTidy: + FastCheckFilter: Loose diff --git a/packages/react-native-audio-api/android/src/main/cpp/audioapi/android/core/AndroidAudioRecorder.cpp b/packages/react-native-audio-api/android/src/main/cpp/audioapi/android/core/AndroidAudioRecorder.cpp index 11b5e3c29..e3d35c337 100644 --- a/packages/react-native-audio-api/android/src/main/cpp/audioapi/android/core/AndroidAudioRecorder.cpp +++ b/packages/react-native-audio-api/android/src/main/cpp/audioapi/android/core/AndroidAudioRecorder.cpp @@ -49,7 +49,7 @@ AndroidAudioRecorder::~AndroidAudioRecorder() { if (isConnected()) { isConnected_.store(false, std::memory_order_release); - adapterNode_->cleanup(); + adapterNode_->adapterCleanup(); } } @@ -198,7 +198,7 @@ Result, std::string> AndroidAudioRecorde } if (isConnected()) { - adapterNode_->cleanup(); + adapterNode_->adapterCleanup(); } filePath_ = ""; diff --git a/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/AudioParamHostObject.cpp b/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/AudioParamHostObject.cpp index 53d174d55..6d306b68c 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/AudioParamHostObject.cpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/AudioParamHostObject.cpp @@ -103,7 +103,7 @@ JSI_HOST_FUNCTION_IMPL(AudioParamHostObject, setTargetAtTime) { JSI_HOST_FUNCTION_IMPL(AudioParamHostObject, setValueCurveAtTime) { auto arrayBuffer = args[0].getObject(runtime).getPropertyAsObject(runtime, "buffer").getArrayBuffer(runtime); - auto rawValues = reinterpret_cast(arrayBuffer.data(runtime)); + auto *rawValues = reinterpret_cast(arrayBuffer.data(runtime)); auto length = static_cast(arrayBuffer.size(runtime) / sizeof(float)); auto values = std::make_shared(rawValues, length); diff --git a/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/events/AudioEventHandlerRegistryHostObject.cpp b/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/events/AudioEventHandlerRegistryHostObject.cpp index dcf42f30a..444101930 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/events/AudioEventHandlerRegistryHostObject.cpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/events/AudioEventHandlerRegistryHostObject.cpp @@ -7,9 +7,8 @@ namespace audioapi { AudioEventHandlerRegistryHostObject::AudioEventHandlerRegistryHostObject( - const std::shared_ptr &eventHandlerRegistry) { - eventHandlerRegistry_ = eventHandlerRegistry; - + const std::shared_ptr &eventHandlerRegistry) + : eventHandlerRegistry_(eventHandlerRegistry) { addFunctions( JSI_EXPORT_FUNCTION(AudioEventHandlerRegistryHostObject, addAudioEventListener), JSI_EXPORT_FUNCTION(AudioEventHandlerRegistryHostObject, removeAudioEventListener)); diff --git a/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/sources/AudioBufferHostObject.cpp b/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/sources/AudioBufferHostObject.cpp index 23cae13c2..34826456e 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/sources/AudioBufferHostObject.cpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/sources/AudioBufferHostObject.cpp @@ -56,7 +56,7 @@ JSI_HOST_FUNCTION_IMPL(AudioBufferHostObject, getChannelData) { JSI_HOST_FUNCTION_IMPL(AudioBufferHostObject, copyFromChannel) { auto arrayBuffer = args[0].getObject(runtime).getPropertyAsObject(runtime, "buffer").getArrayBuffer(runtime); - auto destination = reinterpret_cast(arrayBuffer.data(runtime)); + auto *destination = reinterpret_cast(arrayBuffer.data(runtime)); auto length = arrayBuffer.size(runtime) / sizeof(float); auto channelNumber = static_cast(args[1].getNumber()); auto startInChannel = static_cast(args[2].getNumber()); @@ -69,7 +69,7 @@ JSI_HOST_FUNCTION_IMPL(AudioBufferHostObject, copyFromChannel) { JSI_HOST_FUNCTION_IMPL(AudioBufferHostObject, copyToChannel) { auto arrayBuffer = args[0].getObject(runtime).getPropertyAsObject(runtime, "buffer").getArrayBuffer(runtime); - auto source = reinterpret_cast(arrayBuffer.data(runtime)); + auto *source = reinterpret_cast(arrayBuffer.data(runtime)); auto length = arrayBuffer.size(runtime) / sizeof(float); auto channelNumber = static_cast(args[1].getNumber()); auto startInChannel = static_cast(args[2].getNumber()); diff --git a/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/sources/AudioBufferHostObject.h b/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/sources/AudioBufferHostObject.h index 660836dbb..b03b988f3 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/sources/AudioBufferHostObject.h +++ b/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/sources/AudioBufferHostObject.h @@ -27,7 +27,9 @@ class AudioBufferHostObject : public JsiHostObject { return *this; } - [[nodiscard]] inline size_t getSizeInBytes() const { + ~AudioBufferHostObject() override = default; + + [[nodiscard]] size_t getSizeInBytes() const { // *2 because every time buffer is passed we create a copy of it. return audioBuffer_->getSize() * audioBuffer_->getNumberOfChannels() * sizeof(float) * 2; } diff --git a/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/sources/AudioBufferQueueSourceNodeHostObject.cpp b/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/sources/AudioBufferQueueSourceNodeHostObject.cpp index 57b071d8c..ec1d063b1 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/sources/AudioBufferQueueSourceNodeHostObject.cpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/sources/AudioBufferQueueSourceNodeHostObject.cpp @@ -74,8 +74,9 @@ JSI_HOST_FUNCTION_IMPL(AudioBufferQueueSourceNodeHostObject, enqueueBuffer) { std::shared_ptr tailBuffer = nullptr; if (pitchCorrection_ && !stretchHasBeenInit_) { - initStretch(copiedBuffer->getNumberOfChannels(), copiedBuffer->getSampleRate()); - int extraTailFrames = + initStretch( + static_cast(copiedBuffer->getNumberOfChannels()), copiedBuffer->getSampleRate()); + auto extraTailFrames = static_cast((inputLatency_ + outputLatency_) * copiedBuffer->getSampleRate()); tailBuffer = std::make_shared( copiedBuffer->getNumberOfChannels(), extraTailFrames, copiedBuffer->getSampleRate()); diff --git a/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/sources/AudioBufferSourceNodeHostObject.cpp b/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/sources/AudioBufferSourceNodeHostObject.cpp index 003e96d77..e726daefc 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/sources/AudioBufferSourceNodeHostObject.cpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/sources/AudioBufferSourceNodeHostObject.cpp @@ -180,7 +180,7 @@ void AudioBufferSourceNodeHostObject::setBuffer(const std::shared_ptr(buffer->getNumberOfChannels()), buffer->getSampleRate()); - int extraTailFrames = + auto extraTailFrames = static_cast((inputLatency_ + outputLatency_) * buffer->getSampleRate()); size_t totalSize = buffer->getSize() + extraTailFrames; copiedBuffer = std::make_shared( diff --git a/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/sources/StreamerNodeHostObject.h b/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/sources/StreamerNodeHostObject.h index 38fb94a8d..58352f693 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/sources/StreamerNodeHostObject.h +++ b/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/sources/StreamerNodeHostObject.h @@ -20,7 +20,7 @@ class StreamerNodeHostObject : public AudioScheduledSourceNodeHostObject { const StreamerOptions &options) : AudioScheduledSourceNodeHostObject(context->createStreamer(options), options) {} - [[nodiscard]] static inline size_t getSizeInBytes() { + [[nodiscard]] static size_t getSizeInBytes() { return SIZE; } diff --git a/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/utils/AudioDecoderHostObject.cpp b/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/utils/AudioDecoderHostObject.cpp index f8143b78b..105f7315a 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/utils/AudioDecoderHostObject.cpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/utils/AudioDecoderHostObject.cpp @@ -22,10 +22,10 @@ AudioDecoderHostObject::AudioDecoderHostObject( JSI_HOST_FUNCTION_IMPL(AudioDecoderHostObject, decodeWithMemoryBlock) { auto arrayBuffer = args[0].getObject(runtime).getPropertyAsObject(runtime, "buffer").getArrayBuffer(runtime); - auto data = arrayBuffer.data(runtime); + auto *data = arrayBuffer.data(runtime); auto size = static_cast(arrayBuffer.size(runtime)); - auto sampleRate = args[1].getNumber(); + auto sampleRate = static_cast(args[1].getNumber()); auto promise = promiseVendor_->createAsyncPromise([data, size, sampleRate]() -> PromiseResolver { auto result = AudioDecoder::decodeWithMemoryBlock(data, size, sampleRate); @@ -51,7 +51,7 @@ JSI_HOST_FUNCTION_IMPL(AudioDecoderHostObject, decodeWithMemoryBlock) { JSI_HOST_FUNCTION_IMPL(AudioDecoderHostObject, decodeWithFilePath) { auto sourcePath = args[0].getString(runtime).utf8(runtime); - auto sampleRate = args[1].getNumber(); + auto sampleRate = static_cast(args[1].getNumber()); auto promise = promiseVendor_->createAsyncPromise([sourcePath, sampleRate]() -> PromiseResolver { auto result = AudioDecoder::decodeWithFilePath(sourcePath, sampleRate); @@ -78,8 +78,8 @@ JSI_HOST_FUNCTION_IMPL(AudioDecoderHostObject, decodeWithFilePath) { JSI_HOST_FUNCTION_IMPL(AudioDecoderHostObject, decodeWithPCMInBase64) { auto b64 = args[0].getString(runtime).utf8(runtime); - auto inputSampleRate = args[1].getNumber(); - auto inputChannelCount = args[2].getNumber(); + auto inputSampleRate = static_cast(args[1].getNumber()); + auto inputChannelCount = static_cast(args[2].getNumber()); auto interleaved = args[3].getBool(); auto promise = promiseVendor_->createAsyncPromise( diff --git a/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/utils/JsEnumParser.cpp b/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/utils/JsEnumParser.cpp index 8c6f0ba44..9c205d830 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/utils/JsEnumParser.cpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/utils/JsEnumParser.cpp @@ -3,6 +3,8 @@ namespace audioapi::js_enum_parser { +// NOLINTBEGIN(readability-braces-around-statements) + BiquadFilterType filterTypeFromString(const std::string &type) { if (type == "lowpass") return BiquadFilterType::LOWPASS; @@ -187,3 +189,5 @@ std::string channelInterpretationToString(ChannelInterpretation interpretation) } } } // namespace audioapi::js_enum_parser + +// NOLINTEND(readability-braces-around-statements) diff --git a/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/utils/NodeOptionsParser.h b/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/utils/NodeOptionsParser.h index a5e0d2ff7..b242685d8 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/utils/NodeOptionsParser.h +++ b/packages/react-native-audio-api/common/cpp/audioapi/HostObjects/utils/NodeOptionsParser.h @@ -238,7 +238,7 @@ inline BaseAudioBufferSourceOptions parseBaseAudioBufferSourceOptions( auto pitchCorrectionValue = optionsObject.getProperty(runtime, "pitchCorrection"); if (pitchCorrectionValue.isBool()) { - options.pitchCorrection = static_cast(pitchCorrectionValue.getBool()); + options.pitchCorrection = pitchCorrectionValue.getBool(); } return options; @@ -258,7 +258,7 @@ inline AudioBufferSourceOptions parseAudioBufferSourceOptions( auto loopValue = optionsObject.getProperty(runtime, "loop"); if (loopValue.isBool()) { - options.loop = static_cast(loopValue.getBool()); + options.loop = loopValue.getBool(); } auto loopStartValue = optionsObject.getProperty(runtime, "loopStart"); diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/AudioContext.h b/packages/react-native-audio-api/common/cpp/audioapi/core/AudioContext.h index 5b3defe4c..da8977ada 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/AudioContext.h +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/AudioContext.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include @@ -21,6 +22,7 @@ class AudioContext : public BaseAudioContext { const std::shared_ptr &audioEventHandlerRegistry, const RuntimeRegistry &runtimeRegistry); ~AudioContext() override; + DELETE_COPY_AND_MOVE(AudioContext); void close(); bool resume(); diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/AudioNode.cpp b/packages/react-native-audio-api/common/cpp/audioapi/core/AudioNode.cpp index 0e8c19565..4232f7d10 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/AudioNode.cpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/AudioNode.cpp @@ -13,6 +13,7 @@ AudioNode::AudioNode( const std::shared_ptr &context, const AudioNodeOptions &options) : context_(context), + audioBuffer_(nullptr), numberOfInputs_(options.numberOfInputs), numberOfOutputs_(options.numberOfOutputs), channelCount_(options.channelCount), @@ -37,35 +38,43 @@ size_t AudioNode::getChannelCount() const { return channelCount_; } -void AudioNode::connect(const std::shared_ptr &node) { +void AudioNode::connect( + const std::shared_ptr + &node) { // NOLINT(readability-convert-member-functions-to-static) if (std::shared_ptr context = context_.lock()) { context->getGraphManager()->addPendingNodeConnection( shared_from_this(), node, AudioGraphManager::ConnectionType::CONNECT); } } -void AudioNode::connect(const std::shared_ptr ¶m) { +void AudioNode::connect( + const std::shared_ptr + ¶m) { // NOLINT(readability-convert-member-functions-to-static) if (std::shared_ptr context = context_.lock()) { context->getGraphManager()->addPendingParamConnection( shared_from_this(), param, AudioGraphManager::ConnectionType::CONNECT); } } -void AudioNode::disconnect() { +void AudioNode::disconnect() { // NOLINT(readability-convert-member-functions-to-static) if (std::shared_ptr context = context_.lock()) { context->getGraphManager()->addPendingNodeConnection( shared_from_this(), nullptr, AudioGraphManager::ConnectionType::DISCONNECT_ALL); } } -void AudioNode::disconnect(const std::shared_ptr &node) { +void AudioNode::disconnect( + const std::shared_ptr + &node) { // NOLINT(readability-convert-member-functions-to-static) if (std::shared_ptr context = context_.lock()) { context->getGraphManager()->addPendingNodeConnection( shared_from_this(), node, AudioGraphManager::ConnectionType::DISCONNECT); } } -void AudioNode::disconnect(const std::shared_ptr ¶m) { +void AudioNode::disconnect( + const std::shared_ptr + ¶m) { // NOLINT(readability-convert-member-functions-to-static) if (std::shared_ptr context = context_.lock()) { context->getGraphManager()->addPendingParamConnection( shared_from_this(), param, AudioGraphManager::ConnectionType::DISCONNECT); @@ -131,7 +140,7 @@ std::shared_ptr AudioNode::processAudio( return processNode(processingBuffer, framesToProcess); } -bool AudioNode::isAlreadyProcessed() { +bool AudioNode::isAlreadyProcessed() { // NOLINT(readability-convert-member-functions-to-static) if (std::shared_ptr context = context_.lock()) { std::size_t currentSampleFrame = context->getCurrentSampleFrame(); @@ -147,19 +156,18 @@ bool AudioNode::isAlreadyProcessed() { } // If context is invalid, consider it as already processed to avoid processing - return true; + return true; // NOLINT(readability-simplify-boolean-expr) } std::shared_ptr AudioNode::processInputs( const std::shared_ptr &outputBuffer, int framesToProcess, - bool checkIsAlreadyProcessed) { + bool checkIsAlreadyProcessed) { // NOLINT(readability-convert-member-functions-to-static) auto processingBuffer = audioBuffer_; processingBuffer->zero(); size_t maxNumberOfChannels = 0; - for (auto it = inputNodes_.begin(), end = inputNodes_.end(); it != end; ++it) { - auto inputNode = *it; + for (auto *inputNode : inputNodes_) { assert(inputNode != nullptr); if (!inputNode->isEnabled()) { diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/AudioNode.h b/packages/react-native-audio-api/common/cpp/audioapi/core/AudioNode.h index 8cdc71f34..a7fa5a817 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/AudioNode.h +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/AudioNode.h @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -25,7 +26,9 @@ class AudioNode : public std::enable_shared_from_this { const AudioNodeOptions &options = AudioNodeOptions()); virtual ~AudioNode(); - size_t getChannelCount() const; + DELETE_COPY_AND_MOVE(AudioNode); + + [[nodiscard]] size_t getChannelCount() const; void connect(const std::shared_ptr &node); void connect(const std::shared_ptr ¶m); void disconnect(); @@ -36,7 +39,8 @@ class AudioNode : public std::enable_shared_from_this { int framesToProcess, bool checkIsAlreadyProcessed); - float getContextSampleRate() const { + [[nodiscard]] float getContextSampleRate() + const { // NOLINT(readability-convert-member-functions-to-static) if (std::shared_ptr context = context_.lock()) { return context->getSampleRate(); } @@ -44,17 +48,18 @@ class AudioNode : public std::enable_shared_from_this { return DEFAULT_SAMPLE_RATE; } - float getNyquistFrequency() const { - return getContextSampleRate() / 2.0f; + [[nodiscard]] float getNyquistFrequency() const { + constexpr float kNyquistDivisor = 2.0f; + return getContextSampleRate() / kNyquistDivisor; } /// @note JS Thread only - bool isEnabled() const; + [[nodiscard]] bool isEnabled() const; /// @note JS Thread only - bool requiresTailProcessing() const; + [[nodiscard]] bool requiresTailProcessing() const; template - bool inline scheduleAudioEvent(F &&event) noexcept { + bool scheduleAudioEvent(F &&event) noexcept { if (std::shared_ptr context = context_.lock()) { return context->scheduleAudioEvent(std::forward(event)); } @@ -75,14 +80,14 @@ class AudioNode : public std::enable_shared_from_this { const int numberOfInputs_ = 1; const int numberOfOutputs_ = 1; - size_t channelCount_ = 2; + int channelCount_ = 2; const ChannelCountMode channelCountMode_ = ChannelCountMode::MAX; const ChannelInterpretation channelInterpretation_ = ChannelInterpretation::SPEAKERS; const bool requiresTailProcessing_; - std::unordered_set inputNodes_ = {}; - std::unordered_set> outputNodes_ = {}; - std::unordered_set> outputParams_ = {}; + std::unordered_set inputNodes_; + std::unordered_set> outputNodes_; + std::unordered_set> outputParams_; int numberOfEnabledInputNodes_ = 0; std::atomic isInitialized_ = false; @@ -94,7 +99,7 @@ class AudioNode : public std::enable_shared_from_this { private: bool isEnabled_ = true; - std::vector> inputBuffers_ = {}; + std::vector> inputBuffers_; virtual std::shared_ptr processInputs( const std::shared_ptr &outputBuffer, diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/AudioParam.cpp b/packages/react-native-audio-api/common/cpp/audioapi/core/AudioParam.cpp index f5a59e99a..02f44e3ff 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/AudioParam.cpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/AudioParam.cpp @@ -18,7 +18,6 @@ AudioParam::AudioParam( defaultValue_(defaultValue), minValue_(minValue), maxValue_(maxValue), - eventsQueue_(), startTime_(0), endTime_(0), startValue_(defaultValue), @@ -236,16 +235,17 @@ std::shared_ptr AudioParam::processARateParam(int framesToProces auto processingBuffer = calculateInputs(audioBuffer_, framesToProcess); std::shared_ptr context = context_.lock(); - if (context == nullptr) + if (context == nullptr) { return processingBuffer; + } float sampleRate = context->getSampleRate(); auto bufferData = processingBuffer->getChannel(0)->span(); - float timeCache = time; + double timeCache = time; float timeStep = 1.0f / sampleRate; float sample = 0.0f; // Add automated parameter value to each sample - for (size_t i = 0; i < framesToProcess; i++, timeCache += timeStep) { + for (int i = 0; i < framesToProcess; i++, timeCache += timeStep) { sample = getValueAtTime(timeCache); bufferData[i] += sample; } @@ -264,8 +264,7 @@ void AudioParam::processInputs( const std::shared_ptr &outputBuffer, int framesToProcess, bool checkIsAlreadyProcessed) { - for (auto it = inputNodes_.begin(), end = inputNodes_.end(); it != end; ++it) { - auto inputNode = *it; + for (auto *inputNode : inputNodes_) { assert(inputNode != nullptr); if (!inputNode->isEnabled()) { diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/AudioParam.h b/packages/react-native-audio-api/common/cpp/audioapi/core/AudioParam.h index 932e1a289..6606bc8c6 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/AudioParam.h +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/AudioParam.h @@ -23,23 +23,23 @@ class AudioParam { float maxValue, const std::shared_ptr &context); - [[nodiscard]] inline float getValue() const noexcept { + [[nodiscard]] float getValue() const noexcept { return value_.load(std::memory_order_relaxed); } - [[nodiscard]] inline float getDefaultValue() const noexcept { + [[nodiscard]] float getDefaultValue() const noexcept { return defaultValue_; } - [[nodiscard]] inline float getMinValue() const noexcept { + [[nodiscard]] float getMinValue() const noexcept { return minValue_; } - [[nodiscard]] inline float getMaxValue() const noexcept { + [[nodiscard]] float getMaxValue() const noexcept { return maxValue_; } - inline void setValue(float value) { + void setValue(float value) { value_.store(std::clamp(value, minValue_, maxValue_), std::memory_order_release); } @@ -71,7 +71,7 @@ class AudioParam { template < typename F, typename = std::enable_if_t, BaseAudioContext &>>> - bool inline scheduleAudioEvent(F &&event) noexcept { + bool scheduleAudioEvent(F &&event) noexcept { if (std::shared_ptr context = context_.lock()) { return context->scheduleAudioEvent(std::forward(event)); } @@ -118,7 +118,7 @@ class AudioParam { /// @brief Get the end time of the parameter queue. /// @return The end time of the parameter queue or last endTime_ if queue is empty. - inline double getQueueEndTime() const noexcept { + [[nodiscard]] double getQueueEndTime() const noexcept { if (eventsQueue_.isEmpty()) { return endTime_; } @@ -127,7 +127,7 @@ class AudioParam { /// @brief Get the end value of the parameter queue. /// @return The end value of the parameter queue or last endValue_ if queue is empty. - inline float getQueueEndValue() const noexcept { + [[nodiscard]] float getQueueEndValue() const noexcept { if (eventsQueue_.isEmpty()) { return endValue_; } @@ -137,7 +137,7 @@ class AudioParam { /// @brief Update the parameter queue with a new event. /// @param event The new event to add to the queue. /// @note Handles connecting start value of the new event to the end value of the previous event. - inline void updateQueue(ParamChangeEvent &&event) { + void updateQueue(ParamChangeEvent &&event) { eventsQueue_.pushBack(std::move(event)); } float getValueAtTime(double time); diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/BaseAudioContext.h b/packages/react-native-audio-api/common/cpp/audioapi/core/BaseAudioContext.h index e3f52fd28..01430188a 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/BaseAudioContext.h +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/BaseAudioContext.h @@ -54,6 +54,11 @@ struct WaveShaperOptions; class BaseAudioContext : public std::enable_shared_from_this { public: + BaseAudioContext(const BaseAudioContext &) = delete; + BaseAudioContext &operator=(const BaseAudioContext &) = delete; + BaseAudioContext(BaseAudioContext &&) = delete; + BaseAudioContext &operator=(BaseAudioContext &&) = delete; + explicit BaseAudioContext( float sampleRate, const std::shared_ptr &audioEventHandlerRegistry, @@ -64,7 +69,7 @@ class BaseAudioContext : public std::enable_shared_from_this { [[nodiscard]] float getSampleRate() const; [[nodiscard]] double getCurrentTime() const; [[nodiscard]] std::size_t getCurrentSampleFrame() const; - std::shared_ptr getDestination() const; + [[nodiscard]] std::shared_ptr getDestination() const; void setState(ContextState state); @@ -95,8 +100,9 @@ class BaseAudioContext : public std::enable_shared_from_this { const AudioBufferSourceOptions &options); std::shared_ptr createBufferQueueSource( const BaseAudioBufferSourceOptions &options); - std::shared_ptr createPeriodicWave( - const std::vector> &complexData, + [[nodiscard]] std::shared_ptr createPeriodicWave( + const std::vector> + &complexData, // NOLINT(readability-avoid-const-params-in-decls) bool disableNormalization, int length) const; std::shared_ptr createAnalyser(const AnalyserOptions &options); @@ -104,18 +110,18 @@ class BaseAudioContext : public std::enable_shared_from_this { std::shared_ptr createWaveShaper(const WaveShaperOptions &options); std::shared_ptr getBasicWaveForm(OscillatorType type); - std::shared_ptr getGraphManager() const; - std::shared_ptr getAudioEventHandlerRegistry() const; - const RuntimeRegistry &getRuntimeRegistry() const; + [[nodiscard]] std::shared_ptr getGraphManager() const; + [[nodiscard]] std::shared_ptr getAudioEventHandlerRegistry() const; + [[nodiscard]] const RuntimeRegistry &getRuntimeRegistry() const; virtual void initialize(); - void inline processAudioEvents() { + void processAudioEvents() { audioEventScheduler_.processAllEvents(*this); } template - bool inline scheduleAudioEvent(F &&event) noexcept { + bool scheduleAudioEvent(F &&event) noexcept { // NOLINT(cppcoreguidelines-missing-std-forward) if (getState() != ContextState::RUNNING) { processAudioEvents(); event(*this); diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/OfflineAudioContext.cpp b/packages/react-native-audio-api/common/cpp/audioapi/core/OfflineAudioContext.cpp index d78479a01..6aca0206d 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/OfflineAudioContext.cpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/OfflineAudioContext.cpp @@ -51,7 +51,7 @@ void OfflineAudioContext::suspend(double when, const std::function &call auto frame = static_cast(when * getSampleRate()); frame = RENDER_QUANTUM_SIZE * ((frame + RENDER_QUANTUM_SIZE - 1) / RENDER_QUANTUM_SIZE); - if (scheduledSuspends_.find(frame) != scheduledSuspends_.end()) { + if (scheduledSuspends_.contains(frame)) { throw std::runtime_error( "cannot schedule more than one suspend at frame " + std::to_string(frame) + " (" + std::to_string(when) + " seconds)"); diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/OfflineAudioContext.h b/packages/react-native-audio-api/common/cpp/audioapi/core/OfflineAudioContext.h index be9a3a546..c088e7c79 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/OfflineAudioContext.h +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/OfflineAudioContext.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include @@ -22,6 +23,7 @@ class OfflineAudioContext : public BaseAudioContext { const std::shared_ptr &audioEventHandlerRegistry, const RuntimeRegistry &runtimeRegistry); ~OfflineAudioContext() override; + DELETE_COPY_AND_MOVE(OfflineAudioContext); /// @note JS Thread only void resume(); diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/analysis/AnalyserNode.cpp b/packages/react-native-audio-api/common/cpp/audioapi/core/analysis/AnalyserNode.cpp index c2fe1d96b..6c32c1c73 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/analysis/AnalyserNode.cpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/analysis/AnalyserNode.cpp @@ -79,8 +79,9 @@ void AnalyserNode::getByteTimeDomainData(uint8_t *data, int length) { auto values = frame->timeDomain.span(); + constexpr float BYTE_CENTER = 128.0f; for (int i = 0; i < size; i++) { - float scaledValue = 128 * (values[i] + 1); + float scaledValue = BYTE_CENTER * (values[i] + 1); scaledValue = std::clamp(scaledValue, 0.0f, static_cast(UINT8_MAX)); data[i] = static_cast(scaledValue); @@ -140,9 +141,8 @@ void AnalyserNode::doFFTAnalysis() { for (int i = 0; i < magnitudeArray_->getSize(); i++) { auto scalarMagnitude = std::abs(complexData_[i]) * magnitudeScale; - magnitudeBufferData[i] = static_cast( - smoothingTimeConstant_ * magnitudeBufferData[i] + - (1 - smoothingTimeConstant_) * scalarMagnitude); + magnitudeBufferData[i] = smoothingTimeConstant_ * magnitudeBufferData[i] + + (1 - smoothingTimeConstant_) * scalarMagnitude; } } diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/analysis/AnalyserNode.h b/packages/react-native-audio-api/common/cpp/audioapi/core/analysis/AnalyserNode.h index fd7ef326c..b38ce3010 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/analysis/AnalyserNode.h +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/analysis/AnalyserNode.h @@ -26,21 +26,21 @@ class AnalyserNode : public AudioNode { const AnalyserOptions &options); /// @note JS Thread only - float getMinDecibels() const { + [[nodiscard]] float getMinDecibels() const { return minDecibels_; } /// @note JS Thread only - float getMaxDecibels() const { + [[nodiscard]] float getMaxDecibels() const { return maxDecibels_; } /// @note JS Thread only - float getSmoothingTimeConstant() const { + [[nodiscard]] float getSmoothingTimeConstant() const { return smoothingTimeConstant_; } - int getFFTSize() const { + [[nodiscard]] int getFFTSize() const { return fftSize_.load(std::memory_order_acquire); } @@ -107,6 +107,9 @@ class AnalyserNode : public AudioNode { AnalysisFrame(const AnalysisFrame &) = delete; AnalysisFrame &operator=(const AnalysisFrame &) = delete; + AnalysisFrame(AnalysisFrame &&) noexcept = default; + AnalysisFrame &operator=(AnalysisFrame &&) noexcept = default; + ~AnalysisFrame() = default; }; TripleBuffer analysisBuffer_{MAX_FFT_SIZE}; diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/destinations/AudioDestinationNode.h b/packages/react-native-audio-api/common/cpp/audioapi/core/destinations/AudioDestinationNode.h index 5135751da..2a61c844e 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/destinations/AudioDestinationNode.h +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/destinations/AudioDestinationNode.h @@ -30,7 +30,7 @@ class AudioDestinationNode : public AudioNode { // processNode function is not necessary and is never called. std::shared_ptr processNode( const std::shared_ptr &processingBuffer, - int) final { + int framesToProcess) final { return processingBuffer; }; diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/effects/BiquadFilterNode.cpp b/packages/react-native-audio-api/common/cpp/audioapi/core/effects/BiquadFilterNode.cpp index 3988093e6..c7dc8fb3a 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/effects/BiquadFilterNode.cpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/effects/BiquadFilterNode.cpp @@ -36,6 +36,7 @@ // https://webaudio.github.io/Audio-EQ-Cookbook/audio-eq-cookbook.html - math // formulas for filters +// NOLINTBEGIN(cppcoreguidelines-avoid-magic-numbers, readability-magic-numbers, readability-identifier-length) namespace audioapi { @@ -221,7 +222,7 @@ BiquadFilterNode::FilterCoefficients BiquadFilterNode::getLowshelfCoefficients( } float w0 = PI * frequency; - float alpha = 0.5f * std::sin(w0) * std::sqrt(2.0f); + float alpha = 0.5f * std::sin(w0) * std::numbers::sqrt2_v; float cosW = std::cos(w0); float gamma = 2.0f * std::sqrt(A) * alpha; @@ -250,7 +251,7 @@ BiquadFilterNode::FilterCoefficients BiquadFilterNode::getHighshelfCoefficients( float w0 = PI * frequency; // In the original formula: sqrt((A + 1/A) * (1/S - 1) + 2), but we assume // the maximum value S = 1, so it becomes 0 + 2 under the square root - float alpha = 0.5f * std::sin(w0) * std::sqrt(2.0f); + float alpha = 0.5f * std::sin(w0) * std::numbers::sqrt2_v; float cosW = std::cos(w0); float gamma = 2.0f * std::sqrt(A) * alpha; @@ -346,7 +347,7 @@ BiquadFilterNode::FilterCoefficients BiquadFilterNode::applyFilter( normalizedFrequency *= std::pow(2.0f, detune / 1200.0f); } - FilterCoefficients coeffs = {1.0, 0.0, 0.0, 0.0, 0.0}; + FilterCoefficients coeffs = {.b0 = 1.0, .b1 = 0.0, .b2 = 0.0, .a1 = 0.0, .a2 = 0.0}; switch (type) { case BiquadFilterType::LOWPASS: @@ -392,7 +393,7 @@ std::shared_ptr BiquadFilterNode::processNode( auto coeffs = applyFilter(frequency, Q, gain, detune, type_); - float x1, x2, y1, y2; + float x1, x2, y1, y2; // NOLINT(cppcoreguidelines-init-variables) auto numChannels = processingBuffer->getNumberOfChannels(); @@ -435,3 +436,5 @@ std::shared_ptr BiquadFilterNode::processNode( } } // namespace audioapi + +// NOLINTEND(cppcoreguidelines-avoid-magic-numbers, readability-magic-numbers, readability-identifier-length) diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/effects/ConvolverNode.cpp b/packages/react-native-audio-api/common/cpp/audioapi/core/effects/ConvolverNode.cpp index d2bf43911..fc1b6fa41 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/effects/ConvolverNode.cpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/effects/ConvolverNode.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -54,8 +55,8 @@ void ConvolverNode::setBuffer( internalBufferIndex_ = 0; } -float ConvolverNode::calculateNormalizationScale(const std::shared_ptr &buffer) { - int numberOfChannels = buffer->getNumberOfChannels(); +float ConvolverNode::calculateNormalizationScale(const std::shared_ptr &buffer) const { + auto numberOfChannels = buffer->getNumberOfChannels(); auto length = buffer->getSize(); float power = 0; @@ -63,7 +64,7 @@ float ConvolverNode::calculateNormalizationScale(const std::shared_ptrgetChannel(channel)->span(); - for (int i = 0; i < length; ++i) { + for (size_t i = 0; i < length; ++i) { float sample = channelData[i]; channelPower += sample * sample; } @@ -71,15 +72,12 @@ float ConvolverNode::calculateNormalizationScale(const std::shared_ptrgetSampleRate(); + power = std::max(power, MIN_IR_POWER); + power = 1 / power; + power *= std::pow(10, GAIN_CALIBRATION * 0.05f); + power *= gainCalibrationSampleRate_ / buffer->getSampleRate(); - return scaleFactor; + return power; } void ConvolverNode::onInputDisabled() { diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/effects/ConvolverNode.h b/packages/react-native-audio-api/common/cpp/audioapi/core/effects/ConvolverNode.h index 489fa191b..d24c0e3b5 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/effects/ConvolverNode.h +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/effects/ConvolverNode.h @@ -12,7 +12,7 @@ static constexpr int GAIN_CALIBRATION = -58; // magic number so that processed signal and dry signal have roughly the same volume -static constexpr double MIN_IR_POWER = 0.000125; +static constexpr float MIN_IR_POWER = 0.000125; namespace audioapi { @@ -33,7 +33,7 @@ class ConvolverNode : public AudioNode { const std::shared_ptr &intermediateBuffer, float scaleFactor); - float calculateNormalizationScale(const std::shared_ptr &buffer); + float calculateNormalizationScale(const std::shared_ptr &buffer) const; protected: std::shared_ptr processNode( diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/effects/DelayNode.cpp b/packages/react-native-audio-api/common/cpp/audioapi/core/effects/DelayNode.cpp index d33e376a6..d1c461ea4 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/effects/DelayNode.cpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/effects/DelayNode.cpp @@ -30,7 +30,7 @@ void DelayNode::onInputDisabled() { numberOfEnabledInputNodes_ -= 1; if (isEnabled() && numberOfEnabledInputNodes_ == 0) { signalledToStop_ = true; - remainingFrames_ = delayTimeParam_->getValue() * getContextSampleRate(); + remainingFrames_ = static_cast(delayTimeParam_->getValue() * getContextSampleRate()); } } @@ -43,7 +43,8 @@ void DelayNode::delayBufferOperation( // handle buffer wrap around if (operationStartingIndex + framesToProcess > delayBuffer_->getSize()) { - int framesToEnd = operationStartingIndex + framesToProcess - delayBuffer_->getSize(); + int framesToEnd = + static_cast(operationStartingIndex + framesToProcess - delayBuffer_->getSize()); if (action == BufferAction::WRITE) { delayBuffer_->sum( @@ -100,7 +101,8 @@ std::shared_ptr DelayNode::processNode( } auto delayTime = delayTimeParam_->processKRateParam(framesToProcess, context->getCurrentTime()); - size_t writeIndex = static_cast(readIndex_ + delayTime * context->getSampleRate()) % + size_t writeIndex = + static_cast(static_cast(readIndex_) + delayTime * context->getSampleRate()) % delayBuffer_->getSize(); delayBufferOperation( processingBuffer, framesToProcess, writeIndex, DelayNode::BufferAction::WRITE); diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/effects/DelayNode.h b/packages/react-native-audio-api/common/cpp/audioapi/core/effects/DelayNode.h index 38d1efe9f..48d705bf8 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/effects/DelayNode.h +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/effects/DelayNode.h @@ -23,7 +23,7 @@ class DelayNode : public AudioNode { private: void onInputDisabled() override; - enum class BufferAction { READ, WRITE }; + enum class BufferAction : uint8_t { READ, WRITE }; void delayBufferOperation( const std::shared_ptr &processingBuffer, int framesToProcess, diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/effects/GainNode.cpp b/packages/react-native-audio-api/common/cpp/audioapi/core/effects/GainNode.cpp index b14938f8d..5d0b8b822 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/effects/GainNode.cpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/effects/GainNode.cpp @@ -27,14 +27,15 @@ std::shared_ptr GainNode::processNode( const std::shared_ptr &processingBuffer, int framesToProcess) { std::shared_ptr context = context_.lock(); - if (context == nullptr) + if (context == nullptr) { return processingBuffer; + } double time = context->getCurrentTime(); auto gainParamValues = gainParam_->processARateParam(framesToProcess, time); - auto gainValues = gainParamValues->getChannel(0); + auto *gainValues = gainParamValues->getChannel(0); for (size_t i = 0; i < processingBuffer->getNumberOfChannels(); i++) { - auto channel = processingBuffer->getChannel(i); + auto *channel = processingBuffer->getChannel(i); channel->multiply(*gainValues, framesToProcess); } diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/effects/IIRFilterNode.cpp b/packages/react-native-audio-api/common/cpp/audioapi/core/effects/IIRFilterNode.cpp index 16e4b7b78..c9083d4ee 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/effects/IIRFilterNode.cpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/effects/IIRFilterNode.cpp @@ -83,12 +83,14 @@ void IIRFilterNode::getFrequencyResponse( float omega = -PI * normalizedFreq; auto z = std::complex(std::cos(omega), std::sin(omega)); - auto numerator = IIRFilterNode::evaluatePolynomial(feedforward_, z, feedforward_.getSize() - 1); - auto denominator = IIRFilterNode::evaluatePolynomial(feedback_, z, feedback_.getSize() - 1); + auto numerator = IIRFilterNode::evaluatePolynomial( + feedforward_, z, static_cast(feedforward_.getSize() - 1)); + auto denominator = + IIRFilterNode::evaluatePolynomial(feedback_, z, static_cast(feedback_.getSize() - 1)); auto response = numerator / denominator; - magResponseOutput[k] = static_cast(std::abs(response)); - phaseResponseOutput[k] = static_cast(atan2(imag(response), real(response))); + magResponseOutput[k] = std::abs(response); + phaseResponseOutput[k] = atan2(imag(response), real(response)); } } @@ -100,11 +102,11 @@ void IIRFilterNode::getFrequencyResponse( std::shared_ptr IIRFilterNode::processNode( const std::shared_ptr &processingBuffer, int framesToProcess) { - int numChannels = processingBuffer->getNumberOfChannels(); + int numChannels = static_cast(processingBuffer->getNumberOfChannels()); size_t feedforwardLength = feedforward_.getSize(); size_t feedbackLength = feedback_.getSize(); - int minLength = std::min(feedbackLength, feedforwardLength); + auto minLength = static_cast(std::min(feedbackLength, feedforwardLength)); int mask = bufferLength - 1; @@ -114,25 +116,27 @@ std::shared_ptr IIRFilterNode::processNode( auto &x = xBuffers_[c]; auto &y = yBuffers_[c]; size_t bufferIndex = bufferIndices_[c]; + size_t k; for (float &sample : channel) { const float x_n = sample; float y_n = feedforward_[0] * sample; - for (int k = 1; k < minLength; ++k) { - int m = (bufferIndex - k) & mask; + for (k = 1; k < minLength; ++k) { + size_t m = (bufferIndex - k) & mask; y_n = std::fma(feedforward_[k], x[m], y_n); y_n = std::fma(-feedback_[k], y[m], y_n); } - for (int k = minLength; k < feedforwardLength; ++k) { + for (k = minLength; k < feedforwardLength; ++k) { y_n = std::fma(feedforward_[k], x[(bufferIndex - k) & mask], y_n); } - for (int k = minLength; k < feedbackLength; ++k) { + for (k = minLength; k < feedbackLength; ++k) { y_n = std::fma(-feedback_[k], y[(bufferIndex - k) & (bufferLength - 1)], y_n); } // Avoid denormalized numbers + // NOLINTNEXTLINE(cppcoreguidelines-avoid-magic-numbers, readability-magic-numbers) if (std::abs(y_n) < 1e-15f) { y_n = 0.0f; } diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/effects/IIRFilterNode.h b/packages/react-native-audio-api/common/cpp/audioapi/core/effects/IIRFilterNode.h index dfffbe62b..8f9c97985 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/effects/IIRFilterNode.h +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/effects/IIRFilterNode.h @@ -70,8 +70,9 @@ class IIRFilterNode : public AudioNode { evaluatePolynomial(const AudioArray &coefficients, std::complex z, int order) { // Use Horner's method to evaluate the polynomial P(z) = sum(coef[k]*z^k, k, 0, order); std::complex result = 0; - for (int k = order; k >= 0; --k) + for (int k = order; k >= 0; --k) { result = result * z + std::complex(coefficients[k]); + } return result; } diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/effects/PeriodicWave.cpp b/packages/react-native-audio-api/common/cpp/audioapi/core/effects/PeriodicWave.cpp index 559d95de1..0dd9b7e28 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/effects/PeriodicWave.cpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/effects/PeriodicWave.cpp @@ -33,20 +33,23 @@ #include #include +// NOLINTBEGIN(readability-magic-numbers, cppcoreguidelines-avoid-magic-numbers) + constexpr unsigned NumberOfOctaveBands = 3; -constexpr float CentsPerRange = 1200.0f / NumberOfOctaveBands; +constexpr float CentsPerRange = static_cast(audioapi::OCTAVE_RANGE) / NumberOfOctaveBands; constexpr float interpolate2Point = 0.3; constexpr float interpolate3Point = 0.16; namespace audioapi { PeriodicWave::PeriodicWave(float sampleRate, bool disableNormalization) - : sampleRate_(sampleRate), disableNormalization_(disableNormalization) { - numberOfRanges_ = static_cast( - round(NumberOfOctaveBands * log2f(static_cast(getPeriodicWaveSize())))); - auto nyquistFrequency = sampleRate_ / 2; - lowestFundamentalFrequency_ = - static_cast(nyquistFrequency) / static_cast(getMaxNumberOfPartials()); - scale_ = static_cast(getPeriodicWaveSize()) / static_cast(sampleRate_); + : sampleRate_(sampleRate), + disableNormalization_(disableNormalization), + numberOfRanges_( + static_cast( + round(NumberOfOctaveBands * log2f(static_cast(getPeriodicWaveSize()))))), + lowestFundamentalFrequency_( + static_cast(sampleRate_ / 2) / static_cast(getMaxNumberOfPartials())), + scale_(static_cast(getPeriodicWaveSize()) / sampleRate_) { bandLimitedTables_ = std::make_unique(getPeriodicWaveSize(), numberOfRanges_, sampleRate_); @@ -102,7 +105,7 @@ int PeriodicWave::getNumberOfPartialsPerRange(int rangeIndex) const { auto centsToCull = static_cast(rangeIndex) * CentsPerRange; // A value from 0 -> 1 representing what fraction of the partials to keep. - auto cullingScale = std::pow(2, -centsToCull / 1200); + auto cullingScale = std::pow(2, -centsToCull / OCTAVE_RANGE); // The very top range will have all the partials culled. int numberOfPartials = @@ -134,17 +137,17 @@ void PeriodicWave::generateBasicWaveForm(OscillatorType type) { // https://mathworld.wolfram.com/FourierSeries.html // Coefficient for sin() - float b; + float coeff{}; auto piFactor = 1.0f / (PI * static_cast(i)); switch (type) { case OscillatorType::SINE: - b = (i == 1) ? 1.0f : 0.0f; + coeff = (i == 1) ? 1.0f : 0.0f; break; case OscillatorType::SQUARE: // https://mathworld.wolfram.com/FourierSeriesSquareWave.html - b = ((i & 1) == 1) ? 4 * piFactor : 0.0f; + coeff = ((i & 1) == 1) ? 4 * piFactor : 0.0f; break; case OscillatorType::SAWTOOTH: // https://mathworld.wolfram.com/FourierSeriesSawtoothWave.html - our @@ -152,21 +155,21 @@ void PeriodicWave::generateBasicWaveForm(OscillatorType type) { // similar. our function - f(x) = 2(x / (2 * pi) - floor(x / (2 * pi) + // 0.5))); // https://www.wolframalpha.com/input?i=2%28x+%2F+%282+*+pi%29+-+floor%28x+%2F+%282+*+pi%29+%2B+0.5%29%29%29%3B - b = 2 * piFactor * ((i & 1) == 1 ? 1.0f : -1.0f); + coeff = 2 * piFactor * ((i & 1) == 1 ? 1.0f : -1.0f); break; case OscillatorType::TRIANGLE: // https://mathworld.wolfram.com/FourierSeriesTriangleWave.html if ((i & 1) == 1) { - b = 8.0f * piFactor * piFactor * ((i & 3) == 1 ? 1.0f : -1.0f); + coeff = 8.0f * piFactor * piFactor * ((i & 3) == 1 ? 1.0f : -1.0f); } else { - b = 0.0f; + coeff = 0.0f; } break; case OscillatorType::CUSTOM: throw std::invalid_argument("Custom waveforms are not supported."); } - complexData[i] = std::complex(0.0f, b); + complexData[i] = std::complex(0.0f, coeff); } createBandLimitedTables(complexData, halfSize); @@ -207,7 +210,7 @@ void PeriodicWave::createBandLimitedTables( // Zero out the DC and nquist components. complexFFTData[0] = {0.0f, 0.0f}; - auto channel = bandLimitedTables_->getChannel(rangeIndex); + auto *channel = bandLimitedTables_->getChannel(rangeIndex); // Perform the inverse FFT to get the time domain representation of the // band-limited waveform. @@ -245,9 +248,10 @@ WaveTableSource PeriodicWave::getWaveDataForFundamentalFrequency(float fundament // get the wave data for the lower and higher range index. // calculate the interpolation factor between the lower and higher range data. return { - bandLimitedTables_->getChannel(lowerRangeIndex), - bandLimitedTables_->getChannel(higherRangeIndex), - pitchRange - static_cast(lowerRangeIndex)}; + .lower = bandLimitedTables_->getChannel(lowerRangeIndex), + .higher = bandLimitedTables_->getChannel(higherRangeIndex), + .interpolationFactor = pitchRange - static_cast(lowerRangeIndex), + }; } float PeriodicWave::doInterpolation( @@ -266,12 +270,9 @@ float PeriodicWave::doInterpolation( auto factor = phase - static_cast(index); if (phaseIncrement >= interpolate2Point) { // linear interpolation - int indices[2]; - - for (int i = 0; i < 2; i++) { - indices[i] = (index + i) & - (getPeriodicWaveSize() - 1); // more efficient alternative to % getPeriodicWaveSize() - } + auto indices = std::array{}; + indices[0] = (index + 0) & (getPeriodicWaveSize() - 1); + indices[1] = (index + 1) & (getPeriodicWaveSize() - 1); auto lowerWaveDataSample1 = lowerWaveData[indices[0]]; auto lowerWaveDataSample2 = lowerWaveData[indices[1]]; @@ -282,13 +283,13 @@ float PeriodicWave::doInterpolation( higherWaveDataSample = (1 - factor) * higherWaveDataSample1 + factor * higherWaveDataSample2; } else if (phaseIncrement >= interpolate3Point) { // 3-point Lagrange // interpolation - int indices[3]; + auto indices = std::array{}; for (int i = 0; i < 3; i++) { indices[i] = (index + i - 1) & (getPeriodicWaveSize() - 1); } - float A[3]; + auto A = std::array{}; A[0] = factor * (factor - 1) / 2; A[1] = 1 - factor * factor; @@ -299,13 +300,13 @@ float PeriodicWave::doInterpolation( higherWaveDataSample += higherWaveData[indices[i]] * A[i]; } } else { // 5-point Lagrange interpolation - int indices[5]; + auto indices = std::array{}; for (int i = 0; i < 5; i++) { indices[i] = (index + i - 2) & (getPeriodicWaveSize() - 1); } - float A[5]; + auto A = std::array{}; A[0] = factor * (factor * factor - 1) * (factor - 2) / 24; A[1] = -factor * (factor - 1) * (factor * factor - 4) / 6; @@ -322,3 +323,5 @@ float PeriodicWave::doInterpolation( return std::lerp(higherWaveDataSample, lowerWaveDataSample, waveTableInterpolationFactor); } } // namespace audioapi + +// NOLINTEND(readability-magic-numbers, cppcoreguidelines-avoid-magic-numbers) diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/effects/PeriodicWave.h b/packages/react-native-audio-api/common/cpp/audioapi/core/effects/PeriodicWave.h index a5dbeffa5..6716b306d 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/effects/PeriodicWave.h +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/effects/PeriodicWave.h @@ -49,7 +49,8 @@ class PeriodicWave { explicit PeriodicWave(float sampleRate, OscillatorType type, bool disableNormalization); explicit PeriodicWave( float sampleRate, - const std::vector> &complexData, + const std::vector> + &complexData, // NOLINT(readability-avoid-const-params-in-decls) int length, bool disableNormalization); @@ -81,7 +82,9 @@ class PeriodicWave { // The higher frequencies are culled to band-limit the waveform. // For each range, the inverse FFT is performed to get the time domain // representation of the band-limited waveform. - void createBandLimitedTables(const std::vector> &complexData, int size); + void createBandLimitedTables( + const std::vector> &complexData, + int size); // NOLINT(readability-avoid-const-params-in-decls) // This function returns the interpolation factor between the lower and higher // range data and sets the lower and higher wave data for the given @@ -94,7 +97,7 @@ class PeriodicWave { // interpolation is determined by the phase increment. Returns the // interpolated sample. [[nodiscard]] float doInterpolation( - float bufferIndex, + float phase, float phaseIncrement, float waveTableInterpolationFactor, const DSPAudioArray &lowerWaveData, diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/effects/StereoPannerNode.cpp b/packages/react-native-audio-api/common/cpp/audioapi/core/effects/StereoPannerNode.cpp index b47f05c4d..ba8b818d5 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/effects/StereoPannerNode.cpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/effects/StereoPannerNode.cpp @@ -26,8 +26,9 @@ std::shared_ptr StereoPannerNode::processNode( const std::shared_ptr &processingBuffer, int framesToProcess) { std::shared_ptr context = context_.lock(); - if (context == nullptr) + if (context == nullptr) { return processingBuffer; + } double time = context->getCurrentTime(); double deltaTime = 1.0 / context->getSampleRate(); @@ -57,8 +58,8 @@ std::shared_ptr StereoPannerNode::processNode( for (int i = 0; i < framesToProcess; i++) { const auto pan = std::clamp(panParamValues[i], -1.0f, 1.0f); const auto x = (pan <= 0 ? pan + 1 : pan); - const auto gainL = static_cast(cos(x * PI / 2)); - const auto gainR = static_cast(sin(x * PI / 2)); + const auto gainL = cos(x * PI / 2); + const auto gainR = sin(x * PI / 2); const float inputL = inputLeft[i]; const float inputR = inputRight[i]; diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/effects/WaveShaperNode.cpp b/packages/react-native-audio-api/common/cpp/audioapi/core/effects/WaveShaperNode.cpp index a2b8c776f..7886face4 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/effects/WaveShaperNode.cpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/effects/WaveShaperNode.cpp @@ -13,7 +13,7 @@ WaveShaperNode::WaveShaperNode( : AudioNode(context, options), oversample_(options.oversample) { waveShapers_.reserve(6); - for (size_t i = 0; i < channelCount_; i++) { + for (int i = 0; i < channelCount_; i++) { waveShapers_.emplace_back(std::make_unique(nullptr, context->getSampleRate())); } setCurve(options.curve); @@ -44,7 +44,7 @@ std::shared_ptr WaveShaperNode::processNode( } for (size_t channel = 0; channel < processingBuffer->getNumberOfChannels(); channel++) { - auto channelData = processingBuffer->getChannel(channel); + auto *channelData = processingBuffer->getChannel(channel); waveShapers_[channel]->process(*channelData, framesToProcess); } diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/effects/WaveShaperNode.h b/packages/react-native-audio-api/common/cpp/audioapi/core/effects/WaveShaperNode.h index f47bb9ab5..e0e6f697f 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/effects/WaveShaperNode.h +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/effects/WaveShaperNode.h @@ -34,7 +34,7 @@ class WaveShaperNode : public AudioNode { OverSampleType oversample_; std::shared_ptr curve_; - std::vector> waveShapers_{}; + std::vector> waveShapers_; }; } // namespace audioapi diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/effects/WorkletNode.cpp b/packages/react-native-audio-api/common/cpp/audioapi/core/effects/WorkletNode.cpp index 3c772bbbe..f1da29450 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/effects/WorkletNode.cpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/effects/WorkletNode.cpp @@ -9,9 +9,9 @@ WorkletNode::WorkletNode( const std::shared_ptr &context, size_t bufferLength, size_t inputChannelCount, - WorkletsRunner &&runtime) + WorkletsRunner &&workletRunner) : AudioNode(context), - workletRunner_(std::move(runtime)), + workletRunner_(std::move(workletRunner)), buffer_( std::make_shared(bufferLength, inputChannelCount, context->getSampleRate())), bufferLength_(bufferLength), @@ -23,9 +23,8 @@ WorkletNode::WorkletNode( std::shared_ptr WorkletNode::processNode( const std::shared_ptr &processingBuffer, int framesToProcess) { - size_t processed = 0; - size_t channelCount_ = - std::min(inputChannelCount_, static_cast(processingBuffer->getNumberOfChannels())); + int processed = 0; + size_t channelCount_ = std::min(inputChannelCount_, processingBuffer->getNumberOfChannels()); while (processed < framesToProcess) { size_t framesToWorkletInvoke = bufferLength_ - curBuffIndex_; size_t needsToProcess = framesToProcess - processed; @@ -36,7 +35,7 @@ std::shared_ptr WorkletNode::processNode( /// from [processed, processed + shouldProcess] buffer_->copy(*processingBuffer, processed, curBuffIndex_, shouldProcess); - processed += shouldProcess; + processed += static_cast(shouldProcess); curBuffIndex_ += shouldProcess; /// If we filled the entire buffer, we need to execute the worklet diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/effects/WorkletNode.h b/packages/react-native-audio-api/common/cpp/audioapi/core/effects/WorkletNode.h index 8d8d3b6e1..698ec872a 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/effects/WorkletNode.h +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/effects/WorkletNode.h @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -40,7 +41,7 @@ class WorkletNode : public AudioNode { size_t bufferLength, size_t inputChannelCount, WorkletsRunner &&workletRunner); - + DELETE_COPY_AND_MOVE(WorkletNode); ~WorkletNode() override = default; protected: diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/effects/WorkletProcessingNode.cpp b/packages/react-native-audio-api/common/cpp/audioapi/core/effects/WorkletProcessingNode.cpp index 2095ce87c..05f76b8c5 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/effects/WorkletProcessingNode.cpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/effects/WorkletProcessingNode.cpp @@ -27,7 +27,7 @@ std::shared_ptr WorkletProcessingNode::processNode( int framesToProcess) { size_t channelCount = std::min( static_cast(2), // Fixed to stereo for now - static_cast(processingBuffer->getNumberOfChannels())); + processingBuffer->getNumberOfChannels()); // Copy input data to pre-allocated input buffers for (size_t ch = 0; ch < channelCount; ch++) { @@ -66,7 +66,7 @@ std::shared_ptr WorkletProcessingNode::processNode( // Copy processed output data back to the processing buffer or zero on failure for (size_t ch = 0; ch < channelCount; ch++) { - auto channelData = processingBuffer->getChannel(ch); + auto *channelData = processingBuffer->getChannel(ch); if (result.has_value()) { // Copy processed output data diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/inputs/AudioRecorder.h b/packages/react-native-audio-api/common/cpp/audioapi/core/inputs/AudioRecorder.h index 1a384b8b2..bd725a434 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/inputs/AudioRecorder.h +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/inputs/AudioRecorder.h @@ -18,10 +18,14 @@ class AudioEventHandlerRegistry; class AudioRecorder { public: - enum class RecorderState { Idle = 0, Recording, Paused }; + enum class RecorderState : uint8_t { Idle = 0, Recording, Paused }; explicit AudioRecorder( const std::shared_ptr &audioEventHandlerRegistry) : audioEventHandlerRegistry_(audioEventHandlerRegistry) {} + AudioRecorder(const AudioRecorder &) = delete; + AudioRecorder(AudioRecorder &&) = delete; + AudioRecorder &operator=(const AudioRecorder &) = delete; + AudioRecorder &operator=(AudioRecorder &&) = delete; virtual ~AudioRecorder() = default; virtual Result start(const std::string &fileNameOverride) = 0; @@ -71,7 +75,7 @@ class AudioRecorder { std::atomic errorCallbackId_{0}; - std::string filePath_{""}; + std::string filePath_; std::shared_ptr fileWriter_ = nullptr; std::shared_ptr adapterNode_ = nullptr; std::shared_ptr dataCallback_ = nullptr; diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/sources/AudioBufferBaseSourceNode.cpp b/packages/react-native-audio-api/common/cpp/audioapi/core/sources/AudioBufferBaseSourceNode.cpp index 3da3480d4..3904cac1f 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/sources/AudioBufferBaseSourceNode.cpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/sources/AudioBufferBaseSourceNode.cpp @@ -35,8 +35,8 @@ AudioBufferBaseSourceNode::AudioBufferBaseSourceNode( MOST_POSITIVE_SINGLE_FLOAT, context)), vReadIndex_(0.0), - onPositionChangedInterval_(static_cast(context->getSampleRate() * 0.1)) {} - + onPositionChangedInterval_( + static_cast(context->getSampleRate() * ON_POSITION_CHANGED_INTERVAL_SECONDS)) {} void AudioBufferBaseSourceNode::initStretch( const std::shared_ptr> &stretch) { stretch_ = stretch; @@ -55,8 +55,9 @@ void AudioBufferBaseSourceNode::setOnPositionChangedCallbackId(uint64_t callback } void AudioBufferBaseSourceNode::setOnPositionChangedInterval(int interval) { - onPositionChangedInterval_ = - static_cast(getContextSampleRate() * static_cast(interval) / 1000); + onPositionChangedInterval_ = static_cast( + getContextSampleRate() * static_cast(interval) * + 1e-3f); //NOLINT(cppcoreguidelines-avoid-magic-numbers, readability-magic-numbers) } int AudioBufferBaseSourceNode::getOnPositionChangedInterval() const { @@ -92,10 +93,14 @@ void AudioBufferBaseSourceNode::processWithPitchCorrection( return; } auto time = context->getCurrentTime(); - auto playbackRate = - std::clamp(playbackRateParam_->processKRateParam(framesToProcess, time), 0.0f, 3.0f); - auto detune = - std::clamp(detuneParam_->processKRateParam(framesToProcess, time) / 100.0f, -12.0f, 12.0f); + auto playbackRate = std::clamp( + playbackRateParam_->processKRateParam(framesToProcess, time), + MIN_PLAYBACK_RATE, + MAX_PLAYBACK_RATE); + auto detune = std::clamp( + detuneParam_->processKRateParam(framesToProcess, time) / 100.0f, + static_cast(-SEMITONES_PER_OCTAVE), + static_cast(SEMITONES_PER_OCTAVE)); playbackRateBuffer_->zero(); @@ -166,7 +171,9 @@ void AudioBufferBaseSourceNode::processWithoutPitchCorrection( float AudioBufferBaseSourceNode::getComputedPlaybackRateValue(int framesToProcess, double time) { auto playbackRate = playbackRateParam_->processKRateParam(framesToProcess, time); - auto detune = std::pow(2.0f, detuneParam_->processKRateParam(framesToProcess, time) / 1200.0f); + auto detune = std::pow( + 2.0f, //NOLINT(cppcoreguidelines-avoid-magic-numbers, readability-magic-numbers) + detuneParam_->processKRateParam(framesToProcess, time) / static_cast(OCTAVE_RANGE)); return playbackRate * detune; } diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/sources/AudioBufferBaseSourceNode.h b/packages/react-native-audio-api/common/cpp/audioapi/core/sources/AudioBufferBaseSourceNode.h index 2898750a4..5472b81f0 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/sources/AudioBufferBaseSourceNode.h +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/sources/AudioBufferBaseSourceNode.h @@ -41,6 +41,8 @@ class AudioBufferBaseSourceNode : public AudioScheduledSourceNode { // pitch correction std::shared_ptr> stretch_; std::shared_ptr playbackRateBuffer_; + static constexpr float MAX_PLAYBACK_RATE = 3.0f; + static constexpr float MIN_PLAYBACK_RATE = 0.0f; // k-rate params const std::shared_ptr detuneParam_; @@ -52,6 +54,7 @@ class AudioBufferBaseSourceNode : public AudioScheduledSourceNode { uint64_t onPositionChangedCallbackId_ = 0; // 0 means no callback int onPositionChangedInterval_; int onPositionChangedTime_ = 0; + static constexpr float ON_POSITION_CHANGED_INTERVAL_SECONDS = 0.1f; virtual double getCurrentPosition() const = 0; diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/sources/AudioBufferQueueSourceNode.cpp b/packages/react-native-audio-api/common/cpp/audioapi/core/sources/AudioBufferQueueSourceNode.cpp index 05abf41c5..2040625de 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/sources/AudioBufferQueueSourceNode.cpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/sources/AudioBufferQueueSourceNode.cpp @@ -171,6 +171,7 @@ void AudioBufferQueueSourceNode::sendOnBufferEndedEvent(size_t bufferId, bool is * Helper functions */ +// todo: refactor so its less complex and more readable void AudioBufferQueueSourceNode::processWithoutInterpolation( const std::shared_ptr &processingBuffer, size_t startOffset, @@ -236,6 +237,7 @@ void AudioBufferQueueSourceNode::processWithoutInterpolation( } } +// todo: refactor so its less complex and more readable void AudioBufferQueueSourceNode::processWithInterpolation( const std::shared_ptr &processingBuffer, size_t startOffset, @@ -303,7 +305,7 @@ void AudioBufferQueueSourceNode::processWithInterpolation( } context->getGraphManager()->addAudioBufferForDestruction(std::move(buffer)); - vReadIndex_ = vReadIndex_ - buffer->getSize(); + vReadIndex_ = vReadIndex_ - static_cast(buffer->getSize()); data = buffers_.front(); bufferId = data.first; buffer = data.second; diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/sources/AudioBufferQueueSourceNode.h b/packages/react-native-audio-api/common/cpp/audioapi/core/sources/AudioBufferQueueSourceNode.h index be0ade515..c79e6941b 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/sources/AudioBufferQueueSourceNode.h +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/sources/AudioBufferQueueSourceNode.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -58,7 +59,7 @@ class AudioBufferQueueSourceNode : public AudioBufferBaseSourceNode { private: // User provided buffers - std::list>> buffers_{}; + std::list>> buffers_; bool isPaused_ = false; bool addExtraTailFrames_ = false; @@ -79,6 +80,15 @@ class AudioBufferQueueSourceNode : public AudioBufferBaseSourceNode { size_t startOffset, size_t offsetLength, float playbackRate) override; + + bool advanceToNextBuffer( + BaseAudioContext &context, + const std::shared_ptr &processingBuffer, + size_t bufferId, + std::shared_ptr consumedBuffer, + size_t writeIndex, + size_t framesLeft, + bool forInterpolation = false); }; } // namespace audioapi diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/sources/AudioBufferSourceNode.cpp b/packages/react-native-audio-api/common/cpp/audioapi/core/sources/AudioBufferSourceNode.cpp index e5bf7ec4a..86076a03e 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/sources/AudioBufferSourceNode.cpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/sources/AudioBufferSourceNode.cpp @@ -75,7 +75,7 @@ void AudioBufferSourceNode::setBuffer( buffer_ = buffer; playbackRateBuffer_ = playbackRateBuffer; audioBuffer_ = audioBuffer; - channelCount_ = buffer_->getNumberOfChannels(); + channelCount_ = static_cast(buffer_->getNumberOfChannels()); loopEnd_ = buffer_->getDuration(); } @@ -146,6 +146,7 @@ void AudioBufferSourceNode::sendOnLoopEndedEvent() { * Helper functions */ +// todo: refactor so its less complex and more readable void AudioBufferSourceNode::processWithoutInterpolation( const std::shared_ptr &processingBuffer, size_t startOffset, diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/sources/AudioScheduledSourceNode.cpp b/packages/react-native-audio-api/common/cpp/audioapi/core/sources/AudioScheduledSourceNode.cpp index b98c5375f..aa9d12478 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/sources/AudioScheduledSourceNode.cpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/sources/AudioScheduledSourceNode.cpp @@ -27,7 +27,7 @@ AudioScheduledSourceNode::AudioScheduledSourceNode( void AudioScheduledSourceNode::start(double when) { #if !RN_AUDIO_API_TEST if (std::shared_ptr context = context_.lock()) { - if (auto audioContext = dynamic_cast(context.get())) { + if (auto *audioContext = dynamic_cast(context.get())) { audioContext->start(); } } diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/sources/AudioScheduledSourceNode.h b/packages/react-native-audio-api/common/cpp/audioapi/core/sources/AudioScheduledSourceNode.h index fdabaf152..85c65fd19 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/sources/AudioScheduledSourceNode.h +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/sources/AudioScheduledSourceNode.h @@ -5,6 +5,7 @@ #include #include +#include #include namespace audioapi { @@ -18,7 +19,13 @@ class AudioScheduledSourceNode : public AudioNode { // PLAYING: The node is currently playing. // STOP_SCHEDULED: The node is scheduled to stop at a specific time, but is still playing. // FINISHED: The node has finished playing. - enum class PlaybackState { UNSCHEDULED, SCHEDULED, PLAYING, STOP_SCHEDULED, FINISHED }; + enum class PlaybackState : std::uint8_t { + UNSCHEDULED, + SCHEDULED, + PLAYING, + STOP_SCHEDULED, + FINISHED + }; explicit AudioScheduledSourceNode( const std::shared_ptr &context, const AudioScheduledSourceNodeOptions &options = AudioScheduledSourceNodeOptions()); diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/sources/ConstantSourceNode.cpp b/packages/react-native-audio-api/common/cpp/audioapi/core/sources/ConstantSourceNode.cpp index a31ee464a..0c7fce17d 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/sources/ConstantSourceNode.cpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/sources/ConstantSourceNode.cpp @@ -49,7 +49,7 @@ std::shared_ptr ConstantSourceNode::processNode( return processingBuffer; } - auto offsetChannel = + auto *offsetChannel = offsetParam_->processARateParam(framesToProcess, context->getCurrentTime())->getChannel(0); for (size_t channel = 0; channel < processingBuffer->getNumberOfChannels(); ++channel) { diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/sources/OscillatorNode.cpp b/packages/react-native-audio-api/common/cpp/audioapi/core/sources/OscillatorNode.cpp index 8916495ba..60be3d8ae 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/sources/OscillatorNode.cpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/sources/OscillatorNode.cpp @@ -12,15 +12,14 @@ namespace audioapi { OscillatorNode::OscillatorNode( const std::shared_ptr &context, const OscillatorOptions &options) - : AudioScheduledSourceNode(context, options) { + : AudioScheduledSourceNode(context, options), type_(options.type) { frequencyParam_ = std::make_shared( options.frequency, -getNyquistFrequency(), getNyquistFrequency(), context); detuneParam_ = std::make_shared( options.detune, - -1200 * LOG2_MOST_POSITIVE_SINGLE_FLOAT, - 1200 * LOG2_MOST_POSITIVE_SINGLE_FLOAT, + -static_cast(OCTAVE_RANGE) * LOG2_MOST_POSITIVE_SINGLE_FLOAT, + static_cast(OCTAVE_RANGE) * LOG2_MOST_POSITIVE_SINGLE_FLOAT, context); - type_ = options.type; if (options.periodicWave) { periodicWave_ = options.periodicWave; } else { diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/sources/RecorderAdapterNode.cpp b/packages/react-native-audio-api/common/cpp/audioapi/core/sources/RecorderAdapterNode.cpp index 7b99755e8..9401b22c9 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/sources/RecorderAdapterNode.cpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/sources/RecorderAdapterNode.cpp @@ -29,7 +29,7 @@ void RecorderAdapterNode::init(size_t bufferSize, int channelCount, float sample buff_.resize(channelCount_); - for (size_t i = 0; i < channelCount_; ++i) { + for (int i = 0; i < channelCount_; ++i) { buff_[i] = std::make_shared(bufferSize); } @@ -58,7 +58,7 @@ void RecorderAdapterNode::init(size_t bufferSize, int channelCount, float sample isInitialized_.store(true, std::memory_order_release); } -void RecorderAdapterNode::cleanup() { +void RecorderAdapterNode::adapterCleanup() { needsResampling_ = false; buff_.clear(); resampler_.reset(); @@ -89,7 +89,7 @@ void RecorderAdapterNode::processResampled(int framesToProcess) { adapterOutputBuffer_->zero(); size_t outputWritten = 0; - const size_t needed = static_cast(framesToProcess); + const auto needed = static_cast(framesToProcess); // Drain leftover resampled samples from the previous call if (overflowSize_ > 0) { diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/sources/RecorderAdapterNode.h b/packages/react-native-audio-api/common/cpp/audioapi/core/sources/RecorderAdapterNode.h index 7b58de462..8769d2fac 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/sources/RecorderAdapterNode.h +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/sources/RecorderAdapterNode.h @@ -27,7 +27,7 @@ class RecorderAdapterNode : public AudioNode { /// @param channelCount The number of channels. /// @param sampleRate The recorder's native sample rate. void init(size_t bufferSize, int channelCount, float sampleRate); - void cleanup(); + void adapterCleanup(); // TODO: CircularOverflowableAudioBuffer std::vector> buff_; diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/types/BiquadFilterType.h b/packages/react-native-audio-api/common/cpp/audioapi/core/types/BiquadFilterType.h index f9e67a665..39a953d98 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/types/BiquadFilterType.h +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/types/BiquadFilterType.h @@ -1,8 +1,10 @@ #pragma once +#include + namespace audioapi { -enum class BiquadFilterType { +enum class BiquadFilterType : std::uint8_t { LOWPASS, HIGHPASS, BANDPASS, diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/types/ChannelCountMode.h b/packages/react-native-audio-api/common/cpp/audioapi/core/types/ChannelCountMode.h index a91aa930d..e3fa2e893 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/types/ChannelCountMode.h +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/types/ChannelCountMode.h @@ -1,7 +1,9 @@ #pragma once +#include + namespace audioapi { -enum class ChannelCountMode { MAX, CLAMPED_MAX, EXPLICIT }; +enum class ChannelCountMode : std::uint8_t { MAX, CLAMPED_MAX, EXPLICIT }; } diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/types/ChannelInterpretation.h b/packages/react-native-audio-api/common/cpp/audioapi/core/types/ChannelInterpretation.h index 45dc1ad74..73ea52e03 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/types/ChannelInterpretation.h +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/types/ChannelInterpretation.h @@ -1,7 +1,9 @@ #pragma once +#include + namespace audioapi { -enum class ChannelInterpretation { SPEAKERS, DISCRETE }; +enum class ChannelInterpretation : std::uint8_t { SPEAKERS, DISCRETE }; } diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/types/ContextState.h b/packages/react-native-audio-api/common/cpp/audioapi/core/types/ContextState.h index 6a93b0625..c40d7070f 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/types/ContextState.h +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/types/ContextState.h @@ -1,7 +1,9 @@ #pragma once +#include + namespace audioapi { -enum class ContextState { SUSPENDED, RUNNING, CLOSED }; +enum class ContextState : std::uint8_t { SUSPENDED, RUNNING, CLOSED }; } diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/types/OscillatorType.h b/packages/react-native-audio-api/common/cpp/audioapi/core/types/OscillatorType.h index c25d9e72a..d702830f7 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/types/OscillatorType.h +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/types/OscillatorType.h @@ -1,7 +1,9 @@ #pragma once +#include + namespace audioapi { -enum class OscillatorType { SINE, SQUARE, SAWTOOTH, TRIANGLE, CUSTOM }; +enum class OscillatorType : std::uint8_t { SINE, SQUARE, SAWTOOTH, TRIANGLE, CUSTOM }; } // namespace audioapi diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/types/OverSampleType.h b/packages/react-native-audio-api/common/cpp/audioapi/core/types/OverSampleType.h index 8ba765169..28254993a 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/types/OverSampleType.h +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/types/OverSampleType.h @@ -1,7 +1,9 @@ #pragma once +#include + namespace audioapi { -enum class OverSampleType { OVERSAMPLE_NONE, OVERSAMPLE_2X, OVERSAMPLE_4X }; +enum class OverSampleType : std::uint8_t { OVERSAMPLE_NONE, OVERSAMPLE_2X, OVERSAMPLE_4X }; } // namespace audioapi diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/types/ParamChangeEventType.h b/packages/react-native-audio-api/common/cpp/audioapi/core/types/ParamChangeEventType.h index e5bd6b52a..dab646ba9 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/types/ParamChangeEventType.h +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/types/ParamChangeEventType.h @@ -1,8 +1,10 @@ #pragma once +#include + namespace audioapi { -enum class ParamChangeEventType { +enum class ParamChangeEventType : std::uint8_t { LINEAR_RAMP, EXPONENTIAL_RAMP, SET_VALUE, diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/utils/AudioDecoder.cpp b/packages/react-native-audio-api/common/cpp/audioapi/core/utils/AudioDecoder.cpp index 79154a11c..026dbcd5e 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/utils/AudioDecoder.cpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/utils/AudioDecoder.cpp @@ -142,7 +142,7 @@ AudioBufferResult AudioDecoder::decodeWithPCMInBase64( int inputChannelCount, bool interleaved) { auto decodedData = base64_decode(data, false); - const auto uint8Data = reinterpret_cast(decodedData.data()); + const auto *uint8Data = reinterpret_cast(decodedData.data()); size_t numFramesDecoded = decodedData.size() / (inputChannelCount * sizeof(int16_t)); auto audioBuffer = diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/utils/AudioDecoder.h b/packages/react-native-audio-api/common/cpp/audioapi/core/utils/AudioDecoder.h index 0c44d7419..e7936b21d 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/utils/AudioDecoder.h +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/utils/AudioDecoder.h @@ -48,61 +48,69 @@ class AudioDecoder { const std::vector &buffer, float outputSampleRate, int outputChannels); + // NOLINTBEGIN(readability-magic-numbers, cppcoreguidelines-avoid-magic-numbers) static AudioFormat detectAudioFormat(const void *data, size_t size) { - if (size < 12) + if (size < 12) { return AudioFormat::UNKNOWN; + } const auto *bytes = static_cast(data); // WAV/RIFF - if (std::memcmp(bytes, "RIFF", 4) == 0 && std::memcmp(bytes + 8, "WAVE", 4) == 0) + if (std::memcmp(bytes, "RIFF", 4) == 0 && std::memcmp(bytes + 8, "WAVE", 4) == 0) { return AudioFormat::WAV; + } // OGG - if (std::memcmp(bytes, "OggS", 4) == 0) + if (std::memcmp(bytes, "OggS", 4) == 0) { return AudioFormat::OGG; + } // FLAC - if (std::memcmp(bytes, "fLaC", 4) == 0) + if (std::memcmp(bytes, "fLaC", 4) == 0) { return AudioFormat::FLAC; + } // AAC starts with 0xFF 0xF1 or 0xFF 0xF9 - if (bytes[0] == 0xFF && (bytes[1] & 0xF6) == 0xF0) + if (bytes[0] == 0xFF && (bytes[1] & 0xF6) == 0xF0) { return AudioFormat::AAC; + } // MP3: "ID3" or 11-bit frame sync (0xFF 0xE0) - if (std::memcmp(bytes, "ID3", 3) == 0) + if (std::memcmp(bytes, "ID3", 3) == 0) { return AudioFormat::MP3; - if (bytes[0] == 0xFF && (bytes[1] & 0xE0) == 0xE0) + } + if (bytes[0] == 0xFF && (bytes[1] & 0xE0) == 0xE0) { return AudioFormat::MP3; + } if (std::memcmp(bytes + 4, "ftyp", 4) == 0) { - if (std::memcmp(bytes + 8, "M4A ", 4) == 0) + if (std::memcmp(bytes + 8, "M4A ", 4) == 0) { return AudioFormat::M4A; - else if (std::memcmp(bytes + 8, "qt ", 4) == 0) + } + if (std::memcmp(bytes + 8, "qt ", 4) == 0) { return AudioFormat::MOV; + } return AudioFormat::MP4; } return AudioFormat::UNKNOWN; } - static inline bool pathHasExtension( + // NOLINTEND(readability-magic-numbers, cppcoreguidelines-avoid-magic-numbers) + static bool pathHasExtension( const std::string &path, const std::vector &extensions) { std::string pathLower = path; - std::transform(pathLower.begin(), pathLower.end(), pathLower.begin(), ::tolower); - for (const auto &ext : extensions) { - if (pathLower.ends_with(ext)) - return true; - } - return false; + std::ranges::transform(pathLower, pathLower.begin(), ::tolower); + return std::ranges::any_of( + extensions, [&pathLower](const std::string &ext) { return pathLower.ends_with(ext); }); } - [[nodiscard]] static inline int16_t floatToInt16(float sample) { + [[nodiscard]] static int16_t floatToInt16(float sample) { return static_cast(sample * INT16_MAX); } - [[nodiscard]] static inline float int16ToFloat(int16_t sample) { + [[nodiscard]] static float int16ToFloat(int16_t sample) { return static_cast(sample) / INT16_MAX; } - [[nodiscard]] static inline float uint8ToFloat(uint8_t byte1, uint8_t byte2) { - return static_cast(static_cast((byte2 << 8) | byte1)) / INT16_MAX; + [[nodiscard]] static float uint8ToFloat(uint8_t byte1, uint8_t byte2) { + return static_cast(static_cast((byte2 << CHAR_BIT) | byte1)) / INT16_MAX; } }; diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/utils/AudioDestructor.hpp b/packages/react-native-audio-api/common/cpp/audioapi/core/utils/AudioDestructor.hpp index 28f768993..2e8b94189 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/utils/AudioDestructor.hpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/utils/AudioDestructor.hpp @@ -1,11 +1,11 @@ #pragma once +#include #include #include #include #include #include -#include namespace audioapi { @@ -14,6 +14,8 @@ namespace audioapi { template class AudioDestructor { public: + DELETE_COPY_AND_MOVE(AudioDestructor); + AudioDestructor() : isExiting_(false) { auto [sender, receiver] = channels::spsc::channel< std::shared_ptr, diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/utils/AudioFileWriter.h b/packages/react-native-audio-api/common/cpp/audioapi/core/utils/AudioFileWriter.h index 464ac82e8..352e140b3 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/utils/AudioFileWriter.h +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/utils/AudioFileWriter.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -12,11 +13,13 @@ namespace audioapi { class AudioFileProperties; class AudioEventHandlerRegistry; -typedef Result OpenFileResult; -typedef Result, std::string> CloseFileResult; +using OpenFileResult = Result; +using CloseFileResult = Result, std::string>; class AudioFileWriter { public: + DELETE_COPY_AND_MOVE(AudioFileWriter); + AudioFileWriter( const std::shared_ptr &audioEventHandlerRegistry, const std::shared_ptr &fileProperties); diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/utils/AudioGraphManager.h b/packages/react-native-audio-api/common/cpp/audioapi/core/utils/AudioGraphManager.h index 462fbddb0..0d6e6eec1 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/utils/AudioGraphManager.h +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/utils/AudioGraphManager.h @@ -1,9 +1,9 @@ #pragma once #include +#include #include #include - #include #include #include @@ -26,9 +26,9 @@ concept HasCleanupMethod = requires(T t) { class AudioGraphManager { public: - enum class ConnectionType { CONNECT, DISCONNECT, DISCONNECT_ALL, ADD }; - typedef ConnectionType EventType; // for backwards compatibility - enum class EventPayloadType { NODES, PARAMS, SOURCE_NODE, AUDIO_PARAM, NODE }; + enum class ConnectionType : uint8_t { CONNECT, DISCONNECT, DISCONNECT_ALL, ADD }; + using EventType = ConnectionType; // for backwards compatibility + enum class EventPayloadType : uint8_t { NODES, PARAMS, SOURCE_NODE, AUDIO_PARAM, NODE }; union EventPayload { struct { std::shared_ptr from; @@ -49,17 +49,18 @@ class AudioGraphManager { ~EventPayload() {} }; struct Event { - EventType type; - EventPayloadType payloadType; + EventType type = ConnectionType::CONNECT; + EventPayloadType payloadType = EventPayloadType::NODES; EventPayload payload; Event(Event &&other) noexcept; Event &operator=(Event &&other) noexcept; - Event() : type(ConnectionType::CONNECT), payloadType(EventPayloadType::NODES), payload() {} + Event() = default; ~Event(); }; AudioGraphManager(); + DELETE_COPY_AND_MOVE(AudioGraphManager); ~AudioGraphManager(); void preProcessGraph(); @@ -127,19 +128,19 @@ class AudioGraphManager { channels::spsc::Sender sender_; void settlePendingConnections(); - void handleConnectEvent(std::unique_ptr event); - void handleDisconnectEvent(std::unique_ptr event); - void handleDisconnectAllEvent(std::unique_ptr event); + static void handleConnectEvent(std::unique_ptr event); + static void handleDisconnectEvent(std::unique_ptr event); + static void handleDisconnectAllEvent(std::unique_ptr event); void handleAddToDeconstructionEvent(std::unique_ptr event); template - inline static bool canBeDestructed(const std::shared_ptr &object) { + static bool canBeDestructed(const std::shared_ptr &object) { return object.use_count() == 1; } template requires std::derived_from - inline static bool canBeDestructed(std::shared_ptr const &node) { + static bool canBeDestructed(std::shared_ptr const &node) { // If the node is an AudioScheduledSourceNode, we need to check if it is // playing if constexpr (std::is_base_of_v) { diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/utils/AudioParamEventQueue.cpp b/packages/react-native-audio-api/common/cpp/audioapi/core/utils/AudioParamEventQueue.cpp index 7270a5a9c..a42c6c1f4 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/utils/AudioParamEventQueue.cpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/utils/AudioParamEventQueue.cpp @@ -4,7 +4,7 @@ namespace audioapi { -AudioParamEventQueue::AudioParamEventQueue() : eventQueue_() {} +AudioParamEventQueue::AudioParamEventQueue() = default; void AudioParamEventQueue::pushBack(ParamChangeEvent &&event) { if (eventQueue_.isEmpty()) { @@ -33,7 +33,7 @@ bool AudioParamEventQueue::popFront(ParamChangeEvent &event) { void AudioParamEventQueue::cancelScheduledValues(double cancelTime) { while (!eventQueue_.isEmpty()) { - auto &back = eventQueue_.peekBack(); + const auto &back = eventQueue_.peekBack(); if (back.getEndTime() < cancelTime) { break; } @@ -46,7 +46,7 @@ void AudioParamEventQueue::cancelScheduledValues(double cancelTime) { void AudioParamEventQueue::cancelAndHoldAtTime(double cancelTime, double &endTimeCache) { while (!eventQueue_.isEmpty()) { - auto &back = eventQueue_.peekBack(); + const auto &back = eventQueue_.peekBack(); if (back.getEndTime() < cancelTime || back.getStartTime() <= cancelTime) { break; } diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/utils/AudioParamEventQueue.h b/packages/react-native-audio-api/common/cpp/audioapi/core/utils/AudioParamEventQueue.h index 37abe6ef8..1dd95c570 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/utils/AudioParamEventQueue.h +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/utils/AudioParamEventQueue.h @@ -32,25 +32,25 @@ class AudioParamEventQueue { /// @brief Get the first event in the queue. /// @return The first event in the queue. - inline const ParamChangeEvent &front() const noexcept { + [[nodiscard]] const ParamChangeEvent &front() const noexcept { return eventQueue_.peekFront(); } /// @brief Get the last event in the queue. /// @return The last event in the queue. - inline const ParamChangeEvent &back() const noexcept { + [[nodiscard]] const ParamChangeEvent &back() const noexcept { return eventQueue_.peekBack(); } /// @brief Check if the event queue is empty. /// @return True if the queue is empty, false otherwise. - inline bool isEmpty() const noexcept { + [[nodiscard]] bool isEmpty() const noexcept { return eventQueue_.isEmpty(); } /// @brief Check if the event queue is full. /// @return True if the queue is full, false otherwise. - inline bool isFull() const noexcept { + [[nodiscard]] bool isFull() const noexcept { return eventQueue_.isFull(); } diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/utils/AudioRecorderCallback.cpp b/packages/react-native-audio-api/common/cpp/audioapi/core/utils/AudioRecorderCallback.cpp index 44e303300..5638cc4ad 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/utils/AudioRecorderCallback.cpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/utils/AudioRecorderCallback.cpp @@ -30,7 +30,7 @@ AudioRecorderCallback::AudioRecorderCallback( channelCount_(channelCount), callbackId_(callbackId), audioEventHandlerRegistry_(audioEventHandlerRegistry) { - ringBufferSize_ = std::max(bufferLength * 2, static_cast(8192)); + ringBufferSize_ = std::max(bufferLength * 2, static_cast(DEFAULT_RING_BUFFER_SIZE)); circularBuffer_.resize(channelCount_); for (size_t i = 0; i < channelCount_; ++i) { diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/utils/AudioRecorderCallback.h b/packages/react-native-audio-api/common/cpp/audioapi/core/utils/AudioRecorderCallback.h index 9ea18d306..8800b318e 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/utils/AudioRecorderCallback.h +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/utils/AudioRecorderCallback.h @@ -23,6 +23,10 @@ class AudioRecorderCallback { size_t bufferLength, int channelCount, uint64_t callbackId); + AudioRecorderCallback(const AudioRecorderCallback &) = delete; + AudioRecorderCallback(AudioRecorderCallback &&) = delete; + AudioRecorderCallback &operator=(const AudioRecorderCallback &) = delete; + AudioRecorderCallback &operator=(AudioRecorderCallback &&) = delete; virtual ~AudioRecorderCallback(); virtual void cleanup() = 0; @@ -48,6 +52,7 @@ class AudioRecorderCallback { std::shared_ptr audioEventHandlerRegistry_; // TODO: CircularAudioBuffer + static constexpr size_t DEFAULT_RING_BUFFER_SIZE = 8192; std::vector> circularBuffer_; static constexpr auto RECORDER_CALLBACK_SPSC_OVERFLOW_STRATEGY = channels::spsc::OverflowStrategy::OVERWRITE_ON_FULL; diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/utils/AudioStretcher.cpp b/packages/react-native-audio-api/common/cpp/audioapi/core/utils/AudioStretcher.cpp index c618031e9..5449eb7db 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/utils/AudioStretcher.cpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/utils/AudioStretcher.cpp @@ -38,10 +38,10 @@ std::shared_ptr AudioStretcher::changePlaybackSpeed( std::vector int16Buffer = castToInt16Buffer(buffer); - auto stretcher = stretch_init( + auto *stretcher = stretch_init( static_cast(sampleRate / UPPER_FREQUENCY_LIMIT_DETECTION), static_cast(sampleRate / LOWER_FREQUENCY_LIMIT_DETECTION), - outputChannels, + static_cast(outputChannels), 0x1); int maxOutputFrames = @@ -55,7 +55,7 @@ std::shared_ptr AudioStretcher::changePlaybackSpeed( stretchedBuffer.data(), 1 / playbackSpeed); - outputFrames += stretch_flush(stretcher, stretchedBuffer.data() + (outputFrames)); + outputFrames += stretch_flush(stretcher, stretchedBuffer.data() + outputFrames); stretchedBuffer.resize(outputFrames * outputChannels); stretch_deinit(stretcher); diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/utils/AudioStretcher.h b/packages/react-native-audio-api/common/cpp/audioapi/core/utils/AudioStretcher.h index ba248cce4..8901b4fcd 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/utils/AudioStretcher.h +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/utils/AudioStretcher.h @@ -17,10 +17,10 @@ class AudioStretcher { private: static std::vector castToInt16Buffer(AudioBuffer &buffer); - [[nodiscard]] static inline int16_t floatToInt16(float sample) { + [[nodiscard]] static int16_t floatToInt16(float sample) { return static_cast(sample * INT16_MAX); } - [[nodiscard]] static inline float int16ToFloat(int16_t sample) { + [[nodiscard]] static float int16ToFloat(int16_t sample) { return static_cast(sample) / INT16_MAX; } }; diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/utils/Constants.h b/packages/react-native-audio-api/common/cpp/audioapi/core/utils/Constants.h index 79a9a3f69..1d6897af0 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/utils/Constants.h +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/utils/Constants.h @@ -14,6 +14,7 @@ inline constexpr size_t MAX_FFT_SIZE = 32768; inline constexpr int MAX_CHANNEL_COUNT = 32; inline constexpr float DEFAULT_SAMPLE_RATE = 44100.0f; inline constexpr int OCTAVE_RANGE = 1200; +inline constexpr int SEMITONES_PER_OCTAVE = 12; inline constexpr int BIQUAD_GAIN_DB_FACTOR = 40; inline constexpr float CENTS_TO_RATIO = 1.0f / 1200.0f; @@ -26,8 +27,8 @@ inline constexpr float MOST_POSITIVE_SINGLE_FLOAT = static_cast(std::numeric_limits::max()); inline constexpr float MOST_NEGATIVE_SINGLE_FLOAT = static_cast(std::numeric_limits::lowest()); -inline float LOG2_MOST_POSITIVE_SINGLE_FLOAT = std::log2(MOST_POSITIVE_SINGLE_FLOAT); -inline float LOG10_MOST_POSITIVE_SINGLE_FLOAT = std::log10(MOST_POSITIVE_SINGLE_FLOAT); +inline const float LOG2_MOST_POSITIVE_SINGLE_FLOAT = std::log2(MOST_POSITIVE_SINGLE_FLOAT); +inline const float LOG10_MOST_POSITIVE_SINGLE_FLOAT = std::log10(MOST_POSITIVE_SINGLE_FLOAT); inline constexpr float PI = std::numbers::pi_v; // buffer sizes diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/utils/Locker.h b/packages/react-native-audio-api/common/cpp/audioapi/core/utils/Locker.h index 36fa77807..34c292635 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/utils/Locker.h +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/utils/Locker.h @@ -16,18 +16,33 @@ class Locker { unlock(); } + Locker(const Locker &) = delete; + Locker &operator=(const Locker &) = delete; + + Locker(Locker &&other) noexcept : lockPtr_(other.lockPtr_) { + other.lockPtr_ = nullptr; + } + Locker &operator=(Locker &&other) noexcept { + if (this != &other) { + unlock(); + lockPtr_ = other.lockPtr_; + other.lockPtr_ = nullptr; + } + return *this; + } + explicit operator bool() const { return lockPtr_ != nullptr; } void lock() { - if (lockPtr_) { + if (lockPtr_ != nullptr) { lockPtr_->lock(); } } void unlock() { - if (lockPtr_) { + if (lockPtr_ != nullptr) { lockPtr_->unlock(); } } diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/utils/Macros.h b/packages/react-native-audio-api/common/cpp/audioapi/core/utils/Macros.h new file mode 100644 index 000000000..d246df6c4 --- /dev/null +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/utils/Macros.h @@ -0,0 +1,7 @@ +#pragma once + +#define DELETE_COPY_AND_MOVE(ClassName) \ + ClassName(const ClassName &) = delete; \ + ClassName &operator=(const ClassName &) = delete; \ + ClassName(ClassName &&) = delete; \ + ClassName &operator=(ClassName &&) = delete diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/utils/ParamChangeEvent.hpp b/packages/react-native-audio-api/common/cpp/audioapi/core/utils/ParamChangeEvent.hpp index 22b35a647..fb95e024c 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/utils/ParamChangeEvent.hpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/utils/ParamChangeEvent.hpp @@ -47,33 +47,33 @@ class ParamChangeEvent { return *this; } - [[nodiscard]] inline double getEndTime() const noexcept { + [[nodiscard]] double getEndTime() const noexcept { return endTime_; } - [[nodiscard]] inline double getStartTime() const noexcept { + [[nodiscard]] double getStartTime() const noexcept { return startTime_; } - [[nodiscard]] inline float getEndValue() const noexcept { + [[nodiscard]] float getEndValue() const noexcept { return endValue_; } - [[nodiscard]] inline float getStartValue() const noexcept { + [[nodiscard]] float getStartValue() const noexcept { return startValue_; } - [[nodiscard]] inline const std::function & + [[nodiscard]] const std::function & getCalculateValue() const noexcept { return calculateValue_; } - [[nodiscard]] inline ParamChangeEventType getType() const noexcept { + [[nodiscard]] ParamChangeEventType getType() const noexcept { return type_; } - inline void setEndTime(double endTime) noexcept { + void setEndTime(double endTime) noexcept { endTime_ = endTime; } - inline void setStartValue(float startValue) noexcept { + void setStartValue(float startValue) noexcept { startValue_ = startValue; } - inline void setEndValue(float endValue) noexcept { + void setEndValue(float endValue) noexcept { endValue_ = endValue; } @@ -83,7 +83,7 @@ class ParamChangeEvent { std::function calculateValue_; float startValue_ = 0.0f; float endValue_ = 0.0f; - ParamChangeEventType type_; + ParamChangeEventType type_ = ParamChangeEventType::SET_VALUE; }; } // namespace audioapi diff --git a/packages/react-native-audio-api/common/cpp/audioapi/core/utils/worklets/SafeIncludes.h b/packages/react-native-audio-api/common/cpp/audioapi/core/utils/worklets/SafeIncludes.h index 9ccc7824d..6569e6dc5 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/core/utils/worklets/SafeIncludes.h +++ b/packages/react-native-audio-api/common/cpp/audioapi/core/utils/worklets/SafeIncludes.h @@ -36,16 +36,23 @@ class MessageQueueThread {}; class WorkletsModuleProxy {}; class WorkletRuntime { public: + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init) -- dummy type, members unused explicit WorkletRuntime( uint64_t, const std::shared_ptr &, const std::string &, - const bool){throw RN_AUDIO_API_WORKLETS_DISABLED_ERROR} jsi::Runtime &getJSIRuntime() const { + const bool) { + throw RN_AUDIO_API_WORKLETS_DISABLED_ERROR + } + [[nodiscard]] jsi::Runtime &getJSIRuntime() const { + throw RN_AUDIO_API_WORKLETS_DISABLED_ERROR + } + [[nodiscard]] jsi::Value executeSync(jsi::Runtime &rt, const jsi::Value &worklet) const { + throw RN_AUDIO_API_WORKLETS_DISABLED_ERROR + } + [[nodiscard]] jsi::Value executeSync(std::function &&job) const { + // NOLINT(cppcoreguidelines-rvalue-reference-param-not-moved) throw RN_AUDIO_API_WORKLETS_DISABLED_ERROR} jsi::Value - executeSync(jsi::Runtime &rt, const jsi::Value &worklet) const { - throw RN_AUDIO_API_WORKLETS_DISABLED_ERROR} jsi::Value - executeSync(std::function &&job) const { - throw RN_AUDIO_API_WORKLETS_DISABLED_ERROR} jsi::Value executeSync(const std::function &job) const { throw RN_AUDIO_API_WORKLETS_DISABLED_ERROR } @@ -65,7 +72,8 @@ class SerializableWorklet { /// @brief Struct to hold references to different runtimes used in the AudioAPI /// @note it is used to pass them around and avoid creating multiple instances of the same runtime -struct RuntimeRegistry { +struct + RuntimeRegistry { // NOLINT(cppcoreguidelines-pro-type-member-init) -- weak_ptr/shared_ptr default-init std::weak_ptr uiRuntime; std::shared_ptr audioRuntime; diff --git a/packages/react-native-audio-api/common/cpp/audioapi/dsp/AudioUtils.hpp b/packages/react-native-audio-api/common/cpp/audioapi/dsp/AudioUtils.hpp index bf0371669..af2b27e12 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/dsp/AudioUtils.hpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/dsp/AudioUtils.hpp @@ -14,6 +14,7 @@ namespace audioapi::dsp { return static_cast(sampleFrame) / sampleRate; } +// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) -- function, not variable [[nodiscard]] inline float linearInterpolate( std::span source, size_t firstIndex, @@ -28,11 +29,14 @@ namespace audioapi::dsp { } [[nodiscard]] inline float linearToDecibels(float value) { - return 20.0f * log10f(value); + constexpr float kDecibelsLinearFactor = 20.0f; + return kDecibelsLinearFactor * log10f(value); } [[nodiscard]] inline float decibelsToLinear(float value) { - return static_cast(pow(10, value / 20)); + constexpr float kDecibelsDenominator = 20.0f; + // NOLINTNEXTLINE(cppcoreguidelines-avoid-magic-numbers, readability-magic-numbers) + return static_cast(pow(10, value / kDecibelsDenominator)); } } // namespace audioapi::dsp diff --git a/packages/react-native-audio-api/common/cpp/audioapi/dsp/Convolver.cpp b/packages/react-native-audio-api/common/cpp/audioapi/dsp/Convolver.cpp index 74cb7b786..d766a4754 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/dsp/Convolver.cpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/dsp/Convolver.cpp @@ -20,10 +20,7 @@ Convolver::Convolver() _segSize(0), _segCount(0), _fftComplexSize(0), - _segments(), - _segmentsIR(), _fft(nullptr), - _preMultiplied(), _current(0) {} void Convolver::reset() { @@ -185,8 +182,7 @@ void Convolver::process(const DSPAudioArray &input, DSPAudioArray &output) { // The P sub filter spectra are pairwisely multiplied with the input spectra // in the FDL. The results are accumulated in the frequency-domain. memset(_preMultiplied.data(), 0, _preMultiplied.size() * sizeof(std::complex)); - // this is a bottleneck of the algorithm - for (int i = 0; i < _segCount; ++i) { + for (size_t i = 0; i < _segCount; ++i) { const int indexAudio = (_current + i) % _segCount; const auto &impulseResponseSegment = _segmentsIR[i]; const auto &audioSegment = _segments[indexAudio]; diff --git a/packages/react-native-audio-api/common/cpp/audioapi/dsp/Convolver.h b/packages/react-native-audio-api/common/cpp/audioapi/dsp/Convolver.h index 2796c729a..9d3396c0f 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/dsp/Convolver.h +++ b/packages/react-native-audio-api/common/cpp/audioapi/dsp/Convolver.h @@ -20,7 +20,7 @@ class Convolver { bool init(size_t blockSize, const AudioArray &ir, size_t irLen); void process(const DSPAudioArray &input, DSPAudioArray &output); void reset(); - [[nodiscard]] inline size_t getSegCount() const { + [[nodiscard]] size_t getSegCount() const { return _trueSegmentCount; } diff --git a/packages/react-native-audio-api/common/cpp/audioapi/dsp/FFT.cpp b/packages/react-native-audio-api/common/cpp/audioapi/dsp/FFT.cpp index 00a11fbdf..cc0e4983d 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/dsp/FFT.cpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/dsp/FFT.cpp @@ -2,10 +2,10 @@ namespace audioapi::dsp { -FFT::FFT(int size) : size_(size) { - pffftSetup_ = pffft_new_setup(size_, PFFFT_REAL); - work_ = reinterpret_cast(pffft_aligned_malloc(size_ * sizeof(float))); -} +FFT::FFT(int size) + : size_(size), + pffftSetup_(pffft_new_setup(size_, PFFFT_REAL)), + work_(reinterpret_cast(pffft_aligned_malloc(size_ * sizeof(float)))) {} FFT::~FFT() { pffft_destroy_setup(pffftSetup_); diff --git a/packages/react-native-audio-api/common/cpp/audioapi/dsp/FFT.h b/packages/react-native-audio-api/common/cpp/audioapi/dsp/FFT.h index ccb390e59..f1fd73461 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/dsp/FFT.h +++ b/packages/react-native-audio-api/common/cpp/audioapi/dsp/FFT.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -13,6 +14,7 @@ class FFT { public: explicit FFT(int size); ~FFT(); + DELETE_COPY_AND_MOVE(FFT); template void doFFT( diff --git a/packages/react-native-audio-api/common/cpp/audioapi/dsp/VectorMath.cpp b/packages/react-native-audio-api/common/cpp/audioapi/dsp/VectorMath.cpp index b4d34cf07..17133f983 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/dsp/VectorMath.cpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/dsp/VectorMath.cpp @@ -41,7 +41,7 @@ namespace audioapi::dsp { -#if defined(HAVE_ACCELERATE) +#ifdef HAVE_ACCELERATE void multiplyByScalar( const float *inputVector, @@ -119,7 +119,7 @@ void interleaveStereo( #else -#if defined(HAVE_X86_SSE2) +#ifdef HAVE_X86_SSE2 static inline bool is16ByteAligned(const float *vector) { return !(reinterpret_cast(vector) & 0x0F); } @@ -132,7 +132,7 @@ void multiplyByScalar( size_t numberOfElementsToProcess) { size_t n = numberOfElementsToProcess; -#if defined(HAVE_X86_SSE2) +#ifdef HAVE_X86_SSE2 // If the inputVector address is not 16-byte aligned, the first several frames // (at most three) should be processed separately. @@ -199,7 +199,7 @@ void addScalar( size_t numberOfElementsToProcess) { size_t n = numberOfElementsToProcess; -#if defined(HAVE_X86_SSE2) +#ifdef HAVE_X86_SSE2 // If the inputVector address is not 16-byte aligned, the first several frames // (at most three) should be processed separately. while (!is16ByteAligned(inputVector) && n) { @@ -267,7 +267,7 @@ void add( size_t numberOfElementsToProcess) { size_t n = numberOfElementsToProcess; -#if defined(HAVE_X86_SSE2) +#ifdef HAVE_X86_SSE2 // If the inputVector address is not 16-byte aligned, the first several frames // (at most three) should be processed separately. while (!is16ByteAligned(inputVector1) && n) { @@ -372,7 +372,7 @@ void subtract( size_t numberOfElementsToProcess) { size_t n = numberOfElementsToProcess; -#if defined(HAVE_X86_SSE2) +#ifdef HAVE_X86_SSE2 // If the inputVector address is not 16-byte aligned, the first several frames // (at most three) should be processed separately. while (!is16ByteAligned(inputVector1) && n) { @@ -475,7 +475,7 @@ void multiply( size_t numberOfElementsToProcess) { size_t n = numberOfElementsToProcess; -#if defined(HAVE_X86_SSE2) +#ifdef HAVE_X86_SSE2 // If the inputVector1 address is not 16-byte aligned, the first several // frames (at most three) should be processed separately. while (!is16ByteAligned(inputVector1) && n) { @@ -544,7 +544,7 @@ float maximumMagnitude(const float *inputVector, size_t numberOfElementsToProces size_t n = numberOfElementsToProcess; float max = 0; -#if defined(HAVE_X86_SSE2) +#ifdef HAVE_X86_SSE2 // If the inputVector address is not 16-byte aligned, the first several frames // (at most three) should be processed separately. while (!is16ByteAligned(inputVector) && n) { @@ -682,7 +682,7 @@ void deinterleaveStereo( size_t n = numberOfFrames; -#if defined(HAVE_ARM_NEON_INTRINSICS) +#ifdef HAVE_ARM_NEON_INTRINSICS // process 4 frames (8 samples) at a time using NEON size_t group = n / 4; while (group--) { @@ -734,7 +734,7 @@ void interleaveStereo( size_t n = numberOfFrames; -#if defined(HAVE_ARM_NEON_INTRINSICS) +#ifdef HAVE_ARM_NEON_INTRINSICS // process 4 frames (8 samples) at a time size_t group = n / 4; while (group--) { diff --git a/packages/react-native-audio-api/common/cpp/audioapi/dsp/WaveShaper.cpp b/packages/react-native-audio-api/common/cpp/audioapi/dsp/WaveShaper.cpp index 7432b89f0..5a8610a98 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/dsp/WaveShaper.cpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/dsp/WaveShaper.cpp @@ -47,8 +47,6 @@ void WaveShaper::process(DSPAudioArray &channelData, int framesToProcess) { switch (oversample_) { case OverSampleType::OVERSAMPLE_2X: - processResampled(channelData, framesToProcess); - break; case OverSampleType::OVERSAMPLE_4X: processResampled(channelData, framesToProcess); break; diff --git a/packages/react-native-audio-api/common/cpp/audioapi/events/AudioEvent.h b/packages/react-native-audio-api/common/cpp/audioapi/events/AudioEvent.h index 1b6339b93..2f669d76a 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/events/AudioEvent.h +++ b/packages/react-native-audio-api/common/cpp/audioapi/events/AudioEvent.h @@ -1,8 +1,10 @@ #pragma once +#include + namespace audioapi { -enum class AudioEvent { +enum class AudioEvent : uint8_t { PLAYBACK_NOTIFICATION_PLAY, PLAYBACK_NOTIFICATION_PAUSE, PLAYBACK_NOTIFICATION_STOP, diff --git a/packages/react-native-audio-api/common/cpp/audioapi/events/AudioEventHandlerRegistry.cpp b/packages/react-native-audio-api/common/cpp/audioapi/events/AudioEventHandlerRegistry.cpp index e1a055f00..e5f58e79a 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/events/AudioEventHandlerRegistry.cpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/events/AudioEventHandlerRegistry.cpp @@ -65,6 +65,8 @@ void AudioEventHandlerRegistry::unregisterHandler(AudioEvent eventName, uint64_t }); } +// todo: refactor this method to be less complex and more readable +// NOLINTNEXTLINE(readability-function-cognitive-complexity) void AudioEventHandlerRegistry::invokeHandlerWithEventBody( AudioEvent eventName, const std::unordered_map &body) { @@ -122,6 +124,8 @@ void AudioEventHandlerRegistry::invokeHandlerWithEventBody( }); } +// todo: refactor this method to be less complex and more readable +// NOLINTNEXTLINE(readability-function-cognitive-complexity) void AudioEventHandlerRegistry::invokeHandlerWithEventBody( AudioEvent eventName, uint64_t listenerId, @@ -193,7 +197,7 @@ jsi::Object AudioEventHandlerRegistry::createEventObject( auto eventObject = jsi::Object(*runtime_); for (const auto &pair : body) { - const auto name = pair.first.data(); + const auto *name = pair.first.data(); const auto &value = pair.second; if (std::holds_alternative(value)) { diff --git a/packages/react-native-audio-api/common/cpp/audioapi/types/NodeOptions.h b/packages/react-native-audio-api/common/cpp/audioapi/types/NodeOptions.h index b2df4a479..756a7183e 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/types/NodeOptions.h +++ b/packages/react-native-audio-api/common/cpp/audioapi/types/NodeOptions.h @@ -48,20 +48,20 @@ struct StereoPannerOptions : AudioNodeOptions { channelCountMode = ChannelCountMode::CLAMPED_MAX; } - explicit StereoPannerOptions(AudioNodeOptions &&options) : AudioNodeOptions(options) { + explicit StereoPannerOptions(AudioNodeOptions options) : AudioNodeOptions(options) { channelCountMode = ChannelCountMode::CLAMPED_MAX; } }; struct ConvolverOptions : AudioNodeOptions { bool disableNormalization = false; - std::shared_ptr buffer; + std::shared_ptr buffer = nullptr; ConvolverOptions() { requiresTailProcessing = true; } - explicit ConvolverOptions(AudioNodeOptions &&options) : AudioNodeOptions(options) { + explicit ConvolverOptions(AudioNodeOptions options) : AudioNodeOptions(options) { requiresTailProcessing = true; } }; @@ -71,23 +71,29 @@ struct ConstantSourceOptions : AudioScheduledSourceNodeOptions { }; struct AnalyserOptions : AudioNodeOptions { - int fftSize = 2048; - float minDecibels = -100.0f; - float maxDecibels = -30.0f; - float smoothingTimeConstant = 0.8f; + static constexpr int kDefaultFftSize = 2048; + static constexpr float kDefaultMinDecibels = -100.0f; + static constexpr float kDefaultMaxDecibels = -30.0f; + static constexpr float kDefaultSmoothingTimeConstant = 0.8f; + int fftSize = kDefaultFftSize; + float minDecibels = kDefaultMinDecibels; + float maxDecibels = kDefaultMaxDecibels; + float smoothingTimeConstant = kDefaultSmoothingTimeConstant; }; struct BiquadFilterOptions : AudioNodeOptions { + static constexpr float kDefaultFrequency = 350.0f; BiquadFilterType type = BiquadFilterType::LOWPASS; - float frequency = 350.0f; + float frequency = kDefaultFrequency; float detune = 0.0f; float Q = 1.0f; float gain = 0.0f; }; struct OscillatorOptions : AudioScheduledSourceNodeOptions { - std::shared_ptr periodicWave; - float frequency = 440.0f; + static constexpr float kDefaultFrequency = 440.0f; + std::shared_ptr periodicWave = nullptr; + float frequency = kDefaultFrequency; float detune = 0.0f; OscillatorType type = OscillatorType::SINE; }; @@ -99,13 +105,13 @@ struct BaseAudioBufferSourceOptions : AudioScheduledSourceNodeOptions { }; struct AudioBufferSourceOptions : BaseAudioBufferSourceOptions { - std::shared_ptr buffer; + std::shared_ptr buffer = nullptr; float loopStart = 0.0f; float loopEnd = 0.0f; bool loop = false; bool loopSkip = false; - explicit AudioBufferSourceOptions(BaseAudioBufferSourceOptions &&options) + explicit AudioBufferSourceOptions(BaseAudioBufferSourceOptions options) : BaseAudioBufferSourceOptions(options) { channelCount = 1; } @@ -123,7 +129,7 @@ struct DelayOptions : AudioNodeOptions { requiresTailProcessing = true; } - explicit DelayOptions(AudioNodeOptions &&options) : AudioNodeOptions(options) { + explicit DelayOptions(AudioNodeOptions options) : AudioNodeOptions(options) { requiresTailProcessing = true; } }; @@ -134,7 +140,7 @@ struct IIRFilterOptions : AudioNodeOptions { IIRFilterOptions() = default; - explicit IIRFilterOptions(const AudioNodeOptions options) : AudioNodeOptions(options) {} + explicit IIRFilterOptions(AudioNodeOptions options) : AudioNodeOptions(options) {} IIRFilterOptions(const std::vector &ff, const std::vector &fb) : feedforward(ff), feedback(fb) {} @@ -144,7 +150,7 @@ struct IIRFilterOptions : AudioNodeOptions { }; struct WaveShaperOptions : AudioNodeOptions { - std::shared_ptr curve; + std::shared_ptr curve = nullptr; OverSampleType oversample = OverSampleType::OVERSAMPLE_NONE; WaveShaperOptions() { @@ -152,7 +158,7 @@ struct WaveShaperOptions : AudioNodeOptions { channelCountMode = ChannelCountMode::CLAMPED_MAX; } - explicit WaveShaperOptions(const AudioNodeOptions &&options) : AudioNodeOptions(options) { + explicit WaveShaperOptions(const AudioNodeOptions &options) : AudioNodeOptions(options) { // to change after graph processing improvement - should be max channelCountMode = ChannelCountMode::CLAMPED_MAX; } diff --git a/packages/react-native-audio-api/common/cpp/audioapi/utils/AudioBuffer.h b/packages/react-native-audio-api/common/cpp/audioapi/utils/AudioBuffer.h new file mode 100644 index 000000000..12a7c94e9 --- /dev/null +++ b/packages/react-native-audio-api/common/cpp/audioapi/utils/AudioBuffer.h @@ -0,0 +1,182 @@ +#pragma once + +#include +#include +#include + +#include +#include +#include +#include + +namespace audioapi { + +class AudioArrayBuffer; + +class AudioBuffer { + public: + //NOLINTNEXTLINE(cppcoreguidelines-use-enum-class) + enum : uint8_t { + ChannelMono = 0, + ChannelLeft = 0, + ChannelRight = 1, + ChannelCenter = 2, + ChannelLFE = 3, + ChannelSurroundLeft = 4, + ChannelSurroundRight = 5, + }; + + explicit AudioBuffer() = default; + explicit AudioBuffer(size_t size, int numberOfChannels, float sampleRate); + AudioBuffer(const AudioBuffer &other); + AudioBuffer(AudioBuffer &&other) noexcept; + AudioBuffer &operator=(const AudioBuffer &other); + AudioBuffer &operator=(AudioBuffer &&other) noexcept; + ~AudioBuffer() = default; + + [[nodiscard]] size_t getNumberOfChannels() const noexcept { + return numberOfChannels_; + } + [[nodiscard]] float getSampleRate() const noexcept { + return sampleRate_; + } + [[nodiscard]] size_t getSize() const noexcept { + return size_; + } + + [[nodiscard]] double getDuration() const noexcept { + return static_cast(size_) / static_cast(getSampleRate()); + } + + /// @brief Get the AudioArray for a specific channel index. + /// @param index The channel index. + /// @return Pointer to the AudioArray for the specified channel - not owning. + [[nodiscard]] AudioArray *getChannel(size_t index) const; + + /// @brief Get the AudioArray for a specific channel type. + /// @param channelType The channel type: ChannelMono = 0, ChannelLeft = 0, + /// ChannelRight = 1, ChannelCenter = 2, ChannelLFE = 3, + /// ChannelSurroundLeft = 4, ChannelSurroundRight = 5 + /// @return Pointer to the AudioArray for the specified channel type - not owning. + [[nodiscard]] AudioArray *getChannelByType(int channelType) const; + + /// @brief Get a copy of shared pointer to the AudioArray for a specific channel index. + /// @param index The channel index. + /// @return Copy of shared pointer to the AudioArray for the specified channel + [[nodiscard]] std::shared_ptr getSharedChannel(size_t index) const; + + AudioArray &operator[](size_t index) { + return *channels_[index]; + } + const AudioArray &operator[](size_t index) const { + return *channels_[index]; + } + + void zero(); + void zero(size_t start, size_t length); + + /// @brief Sums audio data from a source AudioBuffer into this AudioBuffer. + /// @param source The source AudioBuffer to sum from. + /// @param interpretation The channel interpretation to use for summing (default is SPEAKERS). + /// @note Handles up-mixing and down-mixing based on the number of channels in both buffers. + /// Assumes that source and this are located in two distinct, non-overlapping memory locations. + void sum( + const AudioBuffer &source, + ChannelInterpretation interpretation = ChannelInterpretation::SPEAKERS); + + /// @brief Sums audio data from a source AudioBuffer into this AudioBuffer. + /// @param source The source AudioBuffer to sum from. + /// @param sourceStart The starting index in the source AudioBuffer. + /// @param destinationStart The starting index in this AudioBuffer. + /// @param length The number of samples to sum. + /// @param interpretation The channel interpretation to use for summing (default is SPEAKERS). + /// @note Handles up-mixing and down-mixing based on the number of channels in both buffers. + /// Assumes that source and this are located in two distinct, non-overlapping memory locations. + void sum( + const AudioBuffer &source, + size_t sourceStart, + size_t destinationStart, + size_t length, + ChannelInterpretation interpretation = ChannelInterpretation::SPEAKERS); + + /// @brief Copies audio data from a source AudioBuffer into this AudioBuffer. + /// @param source The source AudioBuffer to copy from. + /// @note Handles up-mixing and down-mixing based on the number of channels in both buffers. + /// Assumes that source and this are located in two distinct, non-overlapping memory locations. + void copy(const AudioBuffer &source); // NOLINT(build/include_what_you_use) + + /// @brief Copies audio data from a source AudioBuffer into this AudioBuffer. + /// @param source The source AudioBuffer to copy from. + /// @param sourceStart The starting index in the source AudioBuffer. + /// @param destinationStart The starting index in this AudioBuffer. + /// @param length The number of samples to copy. + /// @note Handles up-mixing and down-mixing based on the number of channels in both buffers. + /// Assumes that source and this are located in two distinct, non-overlapping memory locations. + void copy( + const AudioBuffer &source, + size_t sourceStart, + size_t destinationStart, + size_t length); // NOLINT(build/include_what_you_use) + + /// @brief Deinterleave audio data from a source buffer into this AudioBuffer. + /// @param source Pointer to the source buffer containing interleaved audio data. + /// @param frames Number of frames to deinterleave from the source buffer. + /// @note The source buffer should contain interleaved audio data according to the number of channels in this AudioBuffer. + /// Example of interleaved data for stereo (2 channels): + /// [L0, R0, L1, R1, L2, R2, ...] + /// Assumes that source and this are located in two distinct, non-overlapping memory locations. + void deinterleaveFrom(const float *source, size_t frames); + + /// @brief Interleave audio data from this AudioBuffer into a destination buffer. + /// @param destination Pointer to the destination buffer where interleaved audio data will be written. + /// @param frames Number of frames to interleave into the destination buffer. + /// @note The destination buffer should have enough space to hold the interleaved data + /// according to the number of channels in this AudioBuffer. + /// Example of interleaved data for stereo (2 channels): + /// [L0, R0, L1, R1, L2, R2, ...] + /// Assumes that this and destination are located in two distinct, non-overlapping memory locations. + void interleaveTo(float *destination, size_t frames) const; + + void normalize(); + void scale(float value); + [[nodiscard]] float maxAbsValue() const; + + private: + std::vector> channels_; + + size_t numberOfChannels_ = 0; + float sampleRate_ = 0.0f; + size_t size_ = 0; + + //NOLINTNEXTLINE(bugprone-throwing-static-initialization) + inline static const std::unordered_map> kChannelLayouts = { + {1, {ChannelMono}}, + {2, {ChannelLeft, ChannelRight}}, + {4, {ChannelLeft, ChannelRight, ChannelSurroundLeft, ChannelSurroundRight}}, + {5, {ChannelLeft, ChannelRight, ChannelCenter, ChannelSurroundLeft, ChannelSurroundRight}}, + {6, + {ChannelLeft, + ChannelRight, + ChannelCenter, + ChannelLFE, + ChannelSurroundLeft, + ChannelSurroundRight}}}; + + void discreteSum( + const AudioBuffer &source, + size_t sourceStart, + size_t destinationStart, + size_t length) const; + void sumByUpMixing( + const AudioBuffer &source, + size_t sourceStart, + size_t destinationStart, + size_t length); + void sumByDownMixing( + const AudioBuffer &source, + size_t sourceStart, + size_t destinationStart, + size_t length); +}; + +} // namespace audioapi diff --git a/packages/react-native-audio-api/common/cpp/audioapi/utils/Result.hpp b/packages/react-native-audio-api/common/cpp/audioapi/utils/Result.hpp index 2986fc981..fe3de6d2e 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/utils/Result.hpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/utils/Result.hpp @@ -50,10 +50,10 @@ class Result { struct OkTag {}; struct ErrTag {}; - explicit Result(OkTag, const T &value) : ok_value(value), is_ok_(true) {} - explicit Result(OkTag, T &&value) : ok_value(std::move(value)), is_ok_(true) {} - explicit Result(ErrTag, const E &error) : err_value(error), is_ok_(false) {} - explicit Result(ErrTag, E &&error) : err_value(std::move(error)), is_ok_(false) {} + explicit Result(OkTag okTag, const T &value) : ok_value(value), is_ok_(true) {} + explicit Result(OkTag okTag, T &&value) : ok_value(std::move(value)), is_ok_(true) {} + explicit Result(ErrTag errTag, const E &error) : err_value(error), is_ok_(false) {} + explicit Result(ErrTag errTag, E &&error) : err_value(std::move(error)), is_ok_(false) {} public: template @@ -66,8 +66,7 @@ class Result { new (&err_value) E(std::move(err.value)); } - Result(const Result &other) { - is_ok_ = other.is_ok_; + Result(const Result &other) : is_ok_(other.is_ok_) { if (is_ok_) { new (&ok_value) T(other.ok_value); } else { @@ -76,8 +75,8 @@ class Result { } Result(Result &&other) noexcept( - std::is_nothrow_move_constructible_v && std::is_nothrow_move_constructible_v) { - is_ok_ = other.is_ok_; + std::is_nothrow_move_constructible_v && std::is_nothrow_move_constructible_v) + : is_ok_(other.is_ok_) { if (is_ok_) { new (&ok_value) T(std::move(other.ok_value)); } else { @@ -86,13 +85,15 @@ class Result { } Result &operator=(const Result &other) { - if (this == &other) + if (this == &other) { return *this; + } if (is_ok_ == other.is_ok_) { - if (is_ok_) + if (is_ok_) { ok_value = other.ok_value; - else + } else { err_value = other.err_value; + } } else { if (is_ok_) { ok_value.~T(); @@ -110,13 +111,15 @@ class Result { Result &operator=(Result &&other) noexcept( std::is_nothrow_move_assignable_v && std::is_nothrow_move_assignable_v && std::is_nothrow_move_constructible_v && std::is_nothrow_move_constructible_v) { - if (this == &other) + if (this == &other) { return *this; + } if (is_ok_ == other.is_ok_) { - if (is_ok_) + if (is_ok_) { ok_value = std::move(other.ok_value); - else + } else { err_value = std::move(other.err_value); + } } else { if (is_ok_) { ok_value.~T(); @@ -284,9 +287,8 @@ class Result { using ResultType = Result; if (is_ok_) { return ResultType::Ok(ok_func(std::move(ok_value))); - } else { - return ResultType::Err(std::move(err_value)); } + return ResultType::Err(std::move(err_value)); } /// @brief Maps a Result to Result by applying a function to a contained Err value. @@ -296,9 +298,8 @@ class Result { using ResultType = Result; if (is_ok_) { return ResultType::Ok(std::move(ok_value)); - } else { - return ResultType::Err(err_func(std::move(err_value))); } + return ResultType::Err(err_func(std::move(err_value))); } /// @brief Returns the provided default (if Err), or applies a function to the contained value (if Ok). @@ -306,9 +307,8 @@ class Result { [[nodiscard]] auto map_or(F &&ok_func, U &&default_value) && { if (is_ok_) { return ok_func(std::move(ok_value)); - } else { - return std::forward(default_value); } + return std::forward(default_value); } /// @brief Maps a Result to U by applying fallback function default to a contained Err value, or function f to a contained Ok value. @@ -316,9 +316,8 @@ class Result { [[nodiscard]] auto map_or_else(FT &&ok_func, FE &&err_func) && { if (is_ok_) { return ok_func(std::move(ok_value)); - } else { - return err_func(std::move(err_value)); } + return err_func(std::move(err_value)); } /// @brief Calls the provided closure with the contained Ok value, if any, otherwise returns the Err value of self. @@ -328,9 +327,8 @@ class Result { using ResultType = std::invoke_result_t; if (is_ok_) { return ok_func(std::move(ok_value)); - } else { - return ResultType::Err(std::move(err_value)); } + return ResultType::Err(std::move(err_value)); } /// @brief Calls the provided closure with the contained Err value, if any, otherwise returns the Ok value of self. @@ -340,9 +338,8 @@ class Result { using ResultType = std::invoke_result_t; if (is_ok_) { return ResultType::Ok(std::move(ok_value)); - } else { - return err_func(std::move(err_value)); } + return err_func(std::move(err_value)); } private: diff --git a/packages/react-native-audio-api/common/cpp/audioapi/utils/RingBiDirectionalBuffer.hpp b/packages/react-native-audio-api/common/cpp/audioapi/utils/RingBiDirectionalBuffer.hpp index 40fd4322b..51c3f5c1a 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/utils/RingBiDirectionalBuffer.hpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/utils/RingBiDirectionalBuffer.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -17,10 +18,12 @@ template class RingBiDirectionalBuffer { public: /// @brief Constructor for RingBuffer. - RingBiDirectionalBuffer() : headIndex_(0), tailIndex_(0) { + RingBiDirectionalBuffer() + : buffer_( + static_cast(::operator new[]( + capacity_ * sizeof(T), + static_cast(alignof(T))))) { static_assert(isPowerOfTwo(capacity_), "RingBiDirectionalBuffer's capacity must be power of 2"); - buffer_ = static_cast( - ::operator new[](capacity_ * sizeof(T), static_cast(alignof(T)))); } /// @brief Destructor for RingBuffer. @@ -31,6 +34,8 @@ class RingBiDirectionalBuffer { ::operator delete[](buffer_, capacity_ * sizeof(T), static_cast(alignof(T))); } + DELETE_COPY_AND_MOVE(RingBiDirectionalBuffer); + /// @brief Push a value into the ring buffer. /// @tparam U The type of the value to push. /// @param value The value to push. @@ -111,74 +116,74 @@ class RingBiDirectionalBuffer { /// @brief Peek at the front of the buffer. /// @return A const reference to the front element of the buffer. - const inline T &peekFront() const noexcept { + [[nodiscard]] const T &peekFront() const noexcept { return buffer_[headIndex_]; } /// @brief Peek at the back of the buffer. /// @return A const reference to the back element of the buffer. - const inline T &peekBack() const noexcept { + [[nodiscard]] const T &peekBack() const noexcept { return buffer_[prevIndex(tailIndex_)]; } /// @brief Peek at the front of the buffer. /// @return A mutable reference to the front element of the buffer. - inline T &peekFrontMut() noexcept { + [[nodiscard]] T &peekFrontMut() noexcept { return buffer_[headIndex_]; } /// @brief Peek at the back of the buffer. /// @return A mutable reference to the back element of the buffer. - inline T &peekBackMut() noexcept { + [[nodiscard]] T &peekBackMut() noexcept { return buffer_[prevIndex(tailIndex_)]; } /// @brief Check if the buffer is empty. /// @return True if the buffer is empty, false otherwise. - inline bool isEmpty() const noexcept { + [[nodiscard]] bool isEmpty() const noexcept { return headIndex_ == tailIndex_; } /// @brief Check if the buffer is full. /// @return True if the buffer is full, false otherwise. - inline bool isFull() const noexcept { + [[nodiscard]] bool isFull() const noexcept { return nextIndex(tailIndex_) == headIndex_; } /// @brief Get the capacity of the buffer. /// @return The capacity of the buffer. - inline size_t getCapacity() const noexcept { + [[nodiscard]] size_t getCapacity() const noexcept { return capacity_; } /// @brief Get the real capacity of the buffer (excluding one slot for the empty state). /// @return The real capacity of the buffer. - inline size_t getRealCapacity() const noexcept { + [[nodiscard]] size_t getRealCapacity() const noexcept { return capacity_ - 1; } /// @brief Get the number of elements in the buffer. /// @return The number of elements in the buffer. - inline size_t size() const noexcept { + [[nodiscard]] size_t size() const noexcept { return (capacity_ + tailIndex_ - headIndex_) & (capacity_ - 1); } private: T *buffer_; - size_t headIndex_; - size_t tailIndex_; + size_t headIndex_ = 0; + size_t tailIndex_ = 0; /// @brief Get the next index in the buffer. /// @param n The current index. /// @return The next index in the buffer. - inline size_t nextIndex(const size_t n) const noexcept { + [[nodiscard]] size_t nextIndex(const size_t n) const noexcept { return (n + 1) & (capacity_ - 1); } /// @brief Get the previous index in the buffer. /// @param n The current index. /// @return The previous index in the buffer. - inline size_t prevIndex(const size_t n) const noexcept { + [[nodiscard]] size_t prevIndex(const size_t n) const noexcept { return (n - 1) & (capacity_ - 1); } diff --git a/packages/react-native-audio-api/common/cpp/audioapi/utils/SpscChannel.hpp b/packages/react-native-audio-api/common/cpp/audioapi/utils/SpscChannel.hpp index df9cf27d8..548a78227 100644 --- a/packages/react-native-audio-api/common/cpp/audioapi/utils/SpscChannel.hpp +++ b/packages/react-native-audio-api/common/cpp/audioapi/utils/SpscChannel.hpp @@ -12,7 +12,7 @@ namespace audioapi::channels::spsc { /// @brief Overflow strategy for sender when the channel is full -enum class OverflowStrategy { +enum class OverflowStrategy : uint8_t { /// @brief Block and wait for space (default behavior) WAIT_ON_FULL, @@ -21,7 +21,7 @@ enum class OverflowStrategy { }; /// @brief Wait strategy for receiver and sender when looping and trying -enum class WaitStrategy { +enum class WaitStrategy : uint8_t { /// @brief Busy loop waiting strategy /// @note should be used when low latency is required and channel is not expected to wait /// @note should be definitely used with OverflowStrategy::OVERWRITE_ON_FULL @@ -40,7 +40,7 @@ enum class WaitStrategy { }; /// @brief Response status for channel operations -enum class ResponseStatus { +enum class ResponseStatus : uint8_t { SUCCESS, CHANNEL_FULL, CHANNEL_EMPTY, @@ -230,11 +230,6 @@ class InnerChannel { capacity_mask_(capacity_ - 1), buffer_( static_cast(operator new[](capacity_ * sizeof(T), std::align_val_t{alignof(T)}))) { - - // Initialize cache values for better performance - rcvCursorCache_ = 0; - sendCursorCache_ = 0; - // Initialize reader state for overwrite strategy if constexpr (Strategy == OverflowStrategy::OVERWRITE_ON_FULL) { oldestOccupied_.store(false, std::memory_order_relaxed); @@ -319,7 +314,7 @@ class InnerChannel { private: /// @brief Try to send with WAIT_ON_FULL strategy (original behavior) template - inline ResponseStatus try_send_wait_on_full(U &&value) noexcept( + ResponseStatus try_send_wait_on_full(U &&value) noexcept( std::is_nothrow_constructible_v) { size_t sendCursor = sendCursor_.load(std::memory_order_relaxed); // only sender thread writes this @@ -328,8 +323,9 @@ class InnerChannel { if (next_sendCursor == rcvCursorCache_) { // Refresh the cache rcvCursorCache_ = rcvCursor_.load(std::memory_order_acquire); - if (next_sendCursor == rcvCursorCache_) + if (next_sendCursor == rcvCursorCache_) { return ResponseStatus::CHANNEL_FULL; + } } // Construct the new element in place @@ -346,7 +342,7 @@ class InnerChannel { /// @brief Try to send with OVERWRITE_ON_FULL strategy template - inline ResponseStatus try_send_overwrite_on_full(U &&value) noexcept( + ResponseStatus try_send_overwrite_on_full(U &&value) noexcept( std::is_nothrow_constructible_v) { size_t sendCursor = sendCursor_.load(std::memory_order_relaxed); // only sender thread writes this @@ -391,12 +387,12 @@ class InnerChannel { /// @param n The input value /// @return The next power of 2 static constexpr size_t next_power_of_2(const size_t n) noexcept { - if (n <= 1) + if (n <= 1) { return 1; - + } // Use bit manipulation for efficiency size_t power = 1; - while (power < n) { + while (power < n) [[likely]] { power <<= 1; } return power; @@ -406,7 +402,7 @@ class InnerChannel { /// @param val The current index /// @return The next index /// @note it might not be used for performance but it is a good reference - inline size_t next_index(const size_t val) const noexcept { + size_t next_index(const size_t val) const noexcept { return (val + 1) & capacity_mask_; } diff --git a/packages/react-native-audio-api/common/cpp/cursor/CMakeLists.txt b/packages/react-native-audio-api/common/cpp/clangd/CMakeLists.txt similarity index 100% rename from packages/react-native-audio-api/common/cpp/cursor/CMakeLists.txt rename to packages/react-native-audio-api/common/cpp/clangd/CMakeLists.txt diff --git a/packages/react-native-audio-api/common/cpp/cursor/SETUP.md b/packages/react-native-audio-api/common/cpp/clangd/SETUP.md similarity index 100% rename from packages/react-native-audio-api/common/cpp/cursor/SETUP.md rename to packages/react-native-audio-api/common/cpp/clangd/SETUP.md diff --git a/packages/react-native-audio-api/common/cpp/cursor/generate-and-copy.sh b/packages/react-native-audio-api/common/cpp/clangd/generate-and-copy.sh similarity index 100% rename from packages/react-native-audio-api/common/cpp/cursor/generate-and-copy.sh rename to packages/react-native-audio-api/common/cpp/clangd/generate-and-copy.sh diff --git a/packages/react-native-audio-api/common/cpp/test/src/core/AudioParamTest.cpp b/packages/react-native-audio-api/common/cpp/test/src/core/AudioParamTest.cpp index 47b36bd5f..758140a6a 100644 --- a/packages/react-native-audio-api/common/cpp/test/src/core/AudioParamTest.cpp +++ b/packages/react-native-audio-api/common/cpp/test/src/core/AudioParamTest.cpp @@ -7,6 +7,8 @@ using namespace audioapi; +// NOLINTBEGIN + class AudioParamTest : public ::testing::Test { protected: std::shared_ptr eventRegistry; @@ -209,3 +211,5 @@ TEST_F(AudioParamTest, CancelAndHoldAtTime) { value = param.processKRateParam(1, 0.25); EXPECT_FLOAT_EQ(value, 0.9); } + +// NOLINTEND diff --git a/packages/react-native-audio-api/common/cpp/test/src/core/effects/DelayTest.cpp b/packages/react-native-audio-api/common/cpp/test/src/core/effects/DelayTest.cpp index 095b90269..511c33beb 100644 --- a/packages/react-native-audio-api/common/cpp/test/src/core/effects/DelayTest.cpp +++ b/packages/react-native-audio-api/common/cpp/test/src/core/effects/DelayTest.cpp @@ -10,6 +10,8 @@ using namespace audioapi; +// NOLINTBEGIN + class DelayTest : public ::testing::Test { protected: std::shared_ptr eventRegistry; @@ -115,3 +117,5 @@ TEST_F(DelayTest, DelayHandlesTailCorrectly) { } } } + +// NOLINTEND diff --git a/packages/react-native-audio-api/common/cpp/test/src/core/effects/GainTest.cpp b/packages/react-native-audio-api/common/cpp/test/src/core/effects/GainTest.cpp index ebdfdcb5d..46c2bd5ac 100644 --- a/packages/react-native-audio-api/common/cpp/test/src/core/effects/GainTest.cpp +++ b/packages/react-native-audio-api/common/cpp/test/src/core/effects/GainTest.cpp @@ -10,6 +10,8 @@ using namespace audioapi; +// NOLINTBEGIN + class GainTest : public ::testing::Test { protected: std::shared_ptr eventRegistry; @@ -80,3 +82,5 @@ TEST_F(GainTest, GainModulatesVolumeCorrectlyMultiChannel) { EXPECT_FLOAT_EQ((*resultBuffer->getChannel(1))[i], (-i - 1) * GAIN_VALUE); } } + +// NOLINTEND diff --git a/packages/react-native-audio-api/common/cpp/test/src/core/effects/IIRFilterTest.cpp b/packages/react-native-audio-api/common/cpp/test/src/core/effects/IIRFilterTest.cpp index e5212511c..91fb54ce0 100644 --- a/packages/react-native-audio-api/common/cpp/test/src/core/effects/IIRFilterTest.cpp +++ b/packages/react-native-audio-api/common/cpp/test/src/core/effects/IIRFilterTest.cpp @@ -11,6 +11,8 @@ using namespace audioapi; +// NOLINTBEGIN + class IIRFilterTest : public ::testing::Test { protected: std::shared_ptr eventRegistry; @@ -151,3 +153,5 @@ TEST_F(IIRFilterTest, GetFrequencyResponse) { } } } + +// NOLINTEND diff --git a/packages/react-native-audio-api/common/cpp/test/src/core/effects/StereoPannerTest.cpp b/packages/react-native-audio-api/common/cpp/test/src/core/effects/StereoPannerTest.cpp index 02b4b54ba..b0f2649a2 100644 --- a/packages/react-native-audio-api/common/cpp/test/src/core/effects/StereoPannerTest.cpp +++ b/packages/react-native-audio-api/common/cpp/test/src/core/effects/StereoPannerTest.cpp @@ -10,6 +10,8 @@ using namespace audioapi; +// NOLINTBEGIN + class StereoPannerTest : public ::testing::Test { protected: std::shared_ptr eventRegistry; @@ -127,3 +129,5 @@ TEST_F(StereoPannerTest, PanModulatesInputStereoCorrectlyWithPositivePan) { 1e-4); } } + +// NOLINTEND diff --git a/packages/react-native-audio-api/common/cpp/test/src/core/effects/WaveShaperNodeTest.cpp b/packages/react-native-audio-api/common/cpp/test/src/core/effects/WaveShaperNodeTest.cpp index 4ee9a53ea..2dc398fcb 100644 --- a/packages/react-native-audio-api/common/cpp/test/src/core/effects/WaveShaperNodeTest.cpp +++ b/packages/react-native-audio-api/common/cpp/test/src/core/effects/WaveShaperNodeTest.cpp @@ -11,6 +11,8 @@ using namespace audioapi; +// NOLINTBEGIN + class WaveShaperNodeTest : public ::testing::Test { protected: std::shared_ptr eventRegistry; @@ -75,3 +77,5 @@ TEST_F(WaveShaperNodeTest, NoneOverSamplingProcessesCorrectly) { EXPECT_FLOAT_EQ(resultData[3], 1.0f); EXPECT_FLOAT_EQ(resultData[4], curveData[2]); } + +// NOLINTEND diff --git a/packages/react-native-audio-api/common/cpp/test/src/core/effects/biquad/BiquadFilterChromium.cpp b/packages/react-native-audio-api/common/cpp/test/src/core/effects/biquad/BiquadFilterChromium.cpp index 65301e454..5635a95c5 100644 --- a/packages/react-native-audio-api/common/cpp/test/src/core/effects/biquad/BiquadFilterChromium.cpp +++ b/packages/react-native-audio-api/common/cpp/test/src/core/effects/biquad/BiquadFilterChromium.cpp @@ -37,6 +37,8 @@ namespace audioapi { +// NOLINTBEGIN + // Compute 10^x = exp(x*log(10)) static double pow10(double x) { return std::exp(x * 2.30258509299404568402); @@ -369,4 +371,6 @@ BiquadCoefficients calculateBandpassCoefficients(double frequency, double q) { return normalizeCoefficients(0, 0, 0, 1, 0, 0); } } + +// NOLINTEND } // namespace audioapi diff --git a/packages/react-native-audio-api/common/cpp/test/src/core/effects/biquad/BiquadFilterTest.cpp b/packages/react-native-audio-api/common/cpp/test/src/core/effects/biquad/BiquadFilterTest.cpp index e4953169d..02ab5e7eb 100644 --- a/packages/react-native-audio-api/common/cpp/test/src/core/effects/biquad/BiquadFilterTest.cpp +++ b/packages/react-native-audio-api/common/cpp/test/src/core/effects/biquad/BiquadFilterTest.cpp @@ -6,6 +6,8 @@ namespace audioapi { +// NOLINTBEGIN + void BiquadFilterTest::expectCoefficientsNear( const BiquadFilterNode::FilterCoefficients &actual, const BiquadCoefficients &expected) { @@ -257,3 +259,5 @@ TEST_F(BiquadFilterTest, GetFrequencyResponse) { } } // namespace audioapi + +// NOLINTEND diff --git a/packages/react-native-audio-api/common/cpp/test/src/core/sources/AudioScheduledSourceTest.cpp b/packages/react-native-audio-api/common/cpp/test/src/core/sources/AudioScheduledSourceTest.cpp index 1f08b82b0..36039816c 100644 --- a/packages/react-native-audio-api/common/cpp/test/src/core/sources/AudioScheduledSourceTest.cpp +++ b/packages/react-native-audio-api/common/cpp/test/src/core/sources/AudioScheduledSourceTest.cpp @@ -8,6 +8,9 @@ #include using namespace audioapi; + +// NOLINTBEGIN + static constexpr int SAMPLE_RATE = 44100; static constexpr int RENDER_QUANTUM = 128; static constexpr double RENDER_QUANTUM_TIME = static_cast(RENDER_QUANTUM) / SAMPLE_RATE; @@ -129,3 +132,5 @@ TEST_F(AudioScheduledSourceTest, IsFinishedStateSetCorrectly) { sourceNode.playFrames(1); EXPECT_TRUE(sourceNode.isFinished()); } + +// NOLINTEND diff --git a/packages/react-native-audio-api/common/cpp/test/src/core/sources/ConstantSourceTest.cpp b/packages/react-native-audio-api/common/cpp/test/src/core/sources/ConstantSourceTest.cpp index 5e498c2bb..f0486260d 100644 --- a/packages/react-native-audio-api/common/cpp/test/src/core/sources/ConstantSourceTest.cpp +++ b/packages/react-native-audio-api/common/cpp/test/src/core/sources/ConstantSourceTest.cpp @@ -10,6 +10,8 @@ using namespace audioapi; +// NOLINTBEGIN + class ConstantSourceTest : public ::testing::Test { protected: std::shared_ptr eventRegistry; @@ -63,3 +65,5 @@ TEST_F(ConstantSourceTest, ConstantSourceOutputsConstantValue) { // EXPECT_FLOAT_EQ((*resultBuffer->getChannel(0))[i], 0.5f); // } } + +// NOLINTEND diff --git a/packages/react-native-audio-api/common/cpp/test/src/core/sources/OscillatorTest.cpp b/packages/react-native-audio-api/common/cpp/test/src/core/sources/OscillatorTest.cpp index fbe9c67ac..0bcd1fff4 100644 --- a/packages/react-native-audio-api/common/cpp/test/src/core/sources/OscillatorTest.cpp +++ b/packages/react-native-audio-api/common/cpp/test/src/core/sources/OscillatorTest.cpp @@ -8,6 +8,8 @@ using namespace audioapi; +// NOLINTBEGIN + class OscillatorTest : public ::testing::Test { protected: std::shared_ptr eventRegistry; @@ -25,3 +27,5 @@ TEST_F(OscillatorTest, OscillatorCanBeCreated) { auto osc = context->createOscillator(OscillatorOptions()); ASSERT_NE(osc, nullptr); } + +// NOLINTEND diff --git a/packages/react-native-audio-api/common/cpp/test/src/utils/AudioArrayTest.cpp b/packages/react-native-audio-api/common/cpp/test/src/utils/AudioArrayTest.cpp index cedf882ee..2d9352659 100644 --- a/packages/react-native-audio-api/common/cpp/test/src/utils/AudioArrayTest.cpp +++ b/packages/react-native-audio-api/common/cpp/test/src/utils/AudioArrayTest.cpp @@ -9,6 +9,8 @@ using namespace audioapi; static constexpr size_t ARR_SIZE = 128; +// NOLINTBEGIN + class AudioArrayTest : public ::testing::Test { protected: static void fill(AudioArray &arr, float value) { diff --git a/packages/react-native-audio-api/common/cpp/test/src/utils/AudioBufferTest.cpp b/packages/react-native-audio-api/common/cpp/test/src/utils/AudioBufferTest.cpp index bfef79e9c..6f458af68 100644 --- a/packages/react-native-audio-api/common/cpp/test/src/utils/AudioBufferTest.cpp +++ b/packages/react-native-audio-api/common/cpp/test/src/utils/AudioBufferTest.cpp @@ -7,6 +7,7 @@ using namespace audioapi; +// NOLINTBEGIN static const float SQRT_HALF = sqrtf(0.5f); static constexpr size_t BUF_SIZE = 10; static constexpr float SR = 44100.0f; @@ -632,3 +633,5 @@ TEST_F(AudioBufferTest, DeinterleaveZeroFramesIsNoop) { buf.deinterleaveFrom(dummy, 0); expectChannel(buf, 0, 42.0f); } + +// NOLINTEND diff --git a/packages/react-native-audio-api/common/cpp/test/src/utils/TripleBufferTest.cpp b/packages/react-native-audio-api/common/cpp/test/src/utils/TripleBufferTest.cpp index 339fad378..05dae5e59 100644 --- a/packages/react-native-audio-api/common/cpp/test/src/utils/TripleBufferTest.cpp +++ b/packages/react-native-audio-api/common/cpp/test/src/utils/TripleBufferTest.cpp @@ -12,6 +12,8 @@ struct IntVal { explicit IntVal(int v = 0) : value(v) {} }; +// NOLINTBEGIN + // --------------------------------------------------------------------------- // Functional Tests // --------------------------------------------------------------------------- @@ -265,3 +267,5 @@ TEST_F(TripleBufferTest, StressBothSidesMakeProgress) { EXPECT_GT(writeCount.load(), 1'000); EXPECT_GT(readCount.load(), 1'000); } + +// NOLINTEND diff --git a/packages/react-native-audio-api/ios/audioapi/ios/core/IOSAudioRecorder.mm b/packages/react-native-audio-api/ios/audioapi/ios/core/IOSAudioRecorder.mm index 3ead5ed1c..a8aaea27c 100644 --- a/packages/react-native-audio-api/ios/audioapi/ios/core/IOSAudioRecorder.mm +++ b/packages/react-native-audio-api/ios/audioapi/ios/core/IOSAudioRecorder.mm @@ -170,7 +170,7 @@ } if (isConnected()) { - adapterNode_->cleanup(); + adapterNode_->adapterCleanup(); } filePath_ = ""; diff --git a/packages/react-native-audio-api/scripts/check-audio-events-sync.sh b/packages/react-native-audio-api/scripts/check-audio-events-sync.sh index e351dace0..0d49f8e58 100755 --- a/packages/react-native-audio-api/scripts/check-audio-events-sync.sh +++ b/packages/react-native-audio-api/scripts/check-audio-events-sync.sh @@ -24,7 +24,7 @@ if [ ! -f "$KOTLIN_FILE" ]; then fi # Extract enum values from C++ file (lines between typedef enum { and } AudioEvent;) -CPP_ENUMS=$(sed -n '/enum class AudioEvent {/,/};/p' "$CPP_FILE" | \ +CPP_ENUMS=$(sed -n '/enum class AudioEvent : uint8_t {/,/};/p' "$CPP_FILE" | \ grep -E '^\s*[A-Z_]+' | \ sed 's/,//g' | \ sed 's/^[[:space:]]*//' | \ diff --git a/packages/react-native-audio-api/scripts/cpplint.sh b/packages/react-native-audio-api/scripts/cpplint.sh index 306b75c7a..2a41eaa66 100755 --- a/packages/react-native-audio-api/scripts/cpplint.sh +++ b/packages/react-native-audio-api/scripts/cpplint.sh @@ -1,7 +1,7 @@ #!/bin/bash if which cpplint >/dev/null; then - find common/cpp android/src/main/cpp -path 'common/cpp/audioapi/libs' -prune -o -path 'common/cpp/audioapi/external' -prune -o -path 'common/cpp/audioapi/dsp/r8brain' -prune -o \( -name '*.cpp' -o -name '*.h' -o -name '*.hpp' \) -print | xargs cpplint --linelength=100 --filter=-legal/copyright,-readability/todo,-build/namespaces,-build/include_order,-whitespace,-build/c++17,-build/c++20,-runtime/references,-runtime/string,-readability/braces --quiet --recursive "$@" + find common/cpp android/src/main/cpp -path 'common/cpp/audioapi/libs' -prune -o -path 'common/cpp/audioapi/external' -prune -o -path 'common/cpp/audioapi/dsp/r8brain' -prune -o \( -name '*.cpp' -o -name '*.h' -o -name '*.hpp' \) -print | xargs cpplint --linelength=100 --filter=-legal/copyright,-readability/todo,-readability/nolint,-build/namespaces,-build/include_order,-whitespace,-build/c++17,-build/c++20,-runtime/references,-runtime/string,-readability/braces --quiet --recursive "$@" else echo "error: cpplint not installed, download from https://github.com/cpplint/cpplint" 1>&2 exit 1