Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions include/mostly_harmless/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,6 @@ set(MOSTLYHARMLESS_HEADERS
${CMAKE_CURRENT_SOURCE_DIR}/utils/mostlyharmless_Directories.h
${CMAKE_CURRENT_SOURCE_DIR}/utils/mostlyharmless_OnScopeExit.h
${CMAKE_CURRENT_SOURCE_DIR}/utils/mostlyharmless_Proxy.h
${CMAKE_CURRENT_SOURCE_DIR}/utils/mostlyharmless_NoDenormals.h
${PLATFORM_HEADERS}
PARENT_SCOPE)
30 changes: 30 additions & 0 deletions include/mostly_harmless/utils/mostlyharmless_NoDenormals.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
//
// Created by Syl Morrison on 21/03/2025.
//

#ifndef MOSTLYHARMLESS_NODENORMALS_H
#define MOSTLYHARMLESS_NODENORMALS_H
#include <memory>
namespace mostly_harmless::utils {
/**
\brief RAII mechanism to disable denormals while an instance of this class is alive.
Supports SSE or NEON instruction sets, will have no effect if neither of those are present.
Goes without saying, but doesn't allocate (I deliberately didn't use pImpl for this reason)
*/
class NoDenormals final {
public:
/**
* Disables denormals on construction, by setting FTZ (and DAZ in SSE)
*/
NoDenormals();

/**
* Resets the FTZ / DAZ bits to their original states
*/
~NoDenormals() noexcept;

private:
std::variant<std::uint8_t, std::uintptr_t> m_controlFlag;
};
} // namespace mostly_harmless::utils
#endif // MOSTLYHARMLESS_NODENORMALS_H
3 changes: 2 additions & 1 deletion source/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ if (APPLE)
${CMAKE_CURRENT_SOURCE_DIR}/gui/platform/mostlyharmless_GuiHelpersMacOS.mm
${CMAKE_CURRENT_SOURCE_DIR}/utils/platform/mostlyharmless_DirectoriesMacOS.mm
)
else()
else ()
set(PLATFORM_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/utils/platform/mostlyharmless_DirectoriesWindows.cpp
)
Expand All @@ -24,6 +24,7 @@ set(MOSTLYHARMLESS_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/utils/mostlyharmless_TaskThread.cpp
${CMAKE_CURRENT_SOURCE_DIR}/utils/mostlyharmless_Timer.cpp
${CMAKE_CURRENT_SOURCE_DIR}/utils/mostlyharmless_OnScopeExit.cpp
${CMAKE_CURRENT_SOURCE_DIR}/utils/mostlyharmless_NoDenormals.cpp
${PLATFORM_SOURCES}
PARENT_SCOPE)
message(STATUS ${MOSTLYHARMLESS_PLATFORM_SOURCES})
4 changes: 4 additions & 0 deletions source/mostlyharmless_PluginBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
#include <mostly_harmless/mostlyharmless_PluginBase.h>
#include <mostly_harmless/utils/mostlyharmless_Macros.h>
#include <mostly_harmless/audio/mostlyharmless_AudioHelpers.h>
#include <mostly_harmless/utils/mostlyharmless_NoDenormals.h>
#include <clap/helpers/plugin.hxx>

namespace mostly_harmless::internal {
PluginBase::PluginBase(const clap_host* host) : clap::helpers::Plugin<clap::helpers::MisbehaviourHandler::Ignore, clap::helpers::CheckingLevel::Maximal>(&getDescriptor(), host) {
MH_LOG("PROC: Creating plugin instance...");
Expand Down Expand Up @@ -46,6 +48,8 @@ namespace mostly_harmless::internal {
}

clap_process_status PluginBase::process(const clap_process* processContext) noexcept {

[[maybe_unused]] utils::NoDenormals stopDenormals;
if (processContext->audio_outputs_count == 0) {
return CLAP_PROCESS_SLEEP;
}
Expand Down
32 changes: 32 additions & 0 deletions source/utils/mostlyharmless_NoDenormals.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
//
// Created by Syl Morrison on 21/03/2025.
//
#include <mostly_harmless/utils/mostlyharmless_NoDenormals.h>
#include <cstdint>
namespace mostly_harmless::utils {
#if defined(__SSE__) || defined(_M_X64)
#include <xmmintrin.h>
#endif
NoDenormals::NoDenormals() {
#if defined(__SSE__) || defined(_M_X64)
m_controlFlag = _mm_getcsr();
constexpr static auto FTZ_AND_DAZ = 0x8040;
_mm_setcsr(std::get<std::uint8_t>(m_controlFlag) | FTZ_AND_DAZ);
#elif defined(__ARM_NEON) || defined(__ARM_NEON__)
constexpr static auto FTZ = 0x01000000U;
uintptr_t asmStatus;
asm volatile("mrs %0, fpcr" : "=r"(asmStatus));
m_controlFlag = asmStatus = asmStatus | FTZ;
asm volatile("msr fpcr, %0" : : "ri"(asmStatus));
#endif
}

NoDenormals::~NoDenormals() noexcept {
#if defined(__SSE__) || defined(_M_X64)
_mm_setcsr(std::get<std::uint8_t>(m_controlFlag));
#elif defined(__ARM_NEON) || defined(__ARM_NEON__)
uintptr_t asmStatus = std::get<std::uintptr_t>(m_controlFlag);
asm volatile("msr fpcr, %0" : : "ri"(asmStatus));
#endif
}
}
Loading