Add stereo and bass enhance APIs via PEQ overlay.
Expose POST /api/audio/stereo-enhance and bass-enhance with 0–100 levels, persist enhancements in AudioProfile, and document the virtual EQ mapping in the manual and SigmaStudio chapter. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* @file AudioEnhancements.hpp
|
||||
* @brief Stereo width and bass boost enhancement levels.
|
||||
*
|
||||
* DigiRadio firmware — https://github.com/manvalan/DigiRadio
|
||||
*
|
||||
* Copyright 2026 Michele Bigi
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* @author Michele Bigi
|
||||
* @date 2026-07-06
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "core/EnhanceLevel.hpp"
|
||||
|
||||
namespace core {
|
||||
|
||||
/**
|
||||
* @brief AudioEnhancements — psychoacoustic EQ overlays (0–100 each).
|
||||
*
|
||||
* @dname AudioEnhancements
|
||||
* @return n/a (type)
|
||||
* @pubstate Mapped to PEQ bands at runtime (Chapter~\ref{ch:sigmastudio}).
|
||||
* No dedicated SigmaStudio blocks; see \texttt{applyEnhancementsToEq}.
|
||||
*
|
||||
* @author Michele Bigi
|
||||
* @date 2026-07-06
|
||||
*/
|
||||
struct AudioEnhancements {
|
||||
EnhanceLevel stereo; ///< Stereo depth / presence (PEQ bands 3–5).
|
||||
EnhanceLevel bass; ///< Bass emphasis (PEQ bands 1–2).
|
||||
|
||||
/**
|
||||
* @brief factoryDefault — both enhancements off.
|
||||
*
|
||||
* @dname factoryDefault
|
||||
* @return AudioEnhancements at level 0.
|
||||
* @pubstate none
|
||||
*
|
||||
* @author Michele Bigi
|
||||
* @date 2026-07-06
|
||||
*/
|
||||
[[nodiscard]] static AudioEnhancements factoryDefault() noexcept;
|
||||
};
|
||||
|
||||
} // namespace core
|
||||
@@ -12,6 +12,7 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "core/AudioEnhancements.hpp"
|
||||
#include "core/EqProfile.hpp"
|
||||
#include "core/GainDb.hpp"
|
||||
#include "core/MixerState.hpp"
|
||||
@@ -32,8 +33,9 @@ namespace core {
|
||||
struct AudioProfile {
|
||||
MixerState mixer; ///< Input and stereo-mixer gains.
|
||||
EqProfile eq; ///< Six-band parametric EQ.
|
||||
GainDb masterLeft; ///< Multiple 1 master volume, left.
|
||||
GainDb masterRight; ///< Multiple 1 master volume, right.
|
||||
GainDb masterLeft; ///< Multiple 1 master volume, left.
|
||||
GainDb masterRight; ///< Multiple 1 master volume, right.
|
||||
AudioEnhancements enhancements; ///< Stereo depth and bass boost (PEQ overlay).
|
||||
|
||||
/**
|
||||
* @brief factoryDefault — factory-flat audio path (0 dB everywhere).
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
#include "core/AudioProfile.hpp"
|
||||
#include "core/ParseError.hpp"
|
||||
|
||||
#include "core/EnhanceLevel.hpp"
|
||||
|
||||
#include <expected>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
@@ -74,4 +76,18 @@ namespace core {
|
||||
*/
|
||||
[[nodiscard]] std::string serializeAudioErrorJson(std::string_view reason);
|
||||
|
||||
/**
|
||||
* @brief parseEnhanceLevelJson — parse POST body \texttt{\{"level":0..100\}}.
|
||||
*
|
||||
* @dname parseEnhanceLevelJson
|
||||
* @param json Untrusted request body.
|
||||
* @return EnhanceLevel on success, or ParseError.
|
||||
* @pubstate none
|
||||
*
|
||||
* @author Michele Bigi
|
||||
* @date 2026-07-06
|
||||
*/
|
||||
[[nodiscard]] std::expected<EnhanceLevel, ParseError> parseEnhanceLevelJson(
|
||||
std::string_view json);
|
||||
|
||||
} // namespace core
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
/**
|
||||
* @file EnhanceLevel.hpp
|
||||
* @brief Strong type for 0–100 enhancement intensity (stereo / bass).
|
||||
*
|
||||
* DigiRadio firmware — https://github.com/manvalan/DigiRadio
|
||||
*
|
||||
* Copyright 2026 Michele Bigi
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* @author Michele Bigi
|
||||
* @date 2026-07-06
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "core/ParseError.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <expected>
|
||||
|
||||
namespace core {
|
||||
|
||||
/**
|
||||
* @brief EnhanceLevel — validated enhancement intensity (0 = off, 100 = max).
|
||||
*
|
||||
* @dname EnhanceLevel
|
||||
* @return n/a (type)
|
||||
* @pubstate Owns level_ in 0..100 after construction.
|
||||
*
|
||||
* @author Michele Bigi
|
||||
* @date 2026-07-06
|
||||
*/
|
||||
class EnhanceLevel {
|
||||
public:
|
||||
/** Maximum enhancement intensity. */
|
||||
static constexpr std::uint8_t kMax = 100U;
|
||||
|
||||
/**
|
||||
* @brief tryFromLevel — validate an enhancement level at the boundary.
|
||||
*
|
||||
* @dname tryFromLevel
|
||||
* @param level Untrusted 0..100 value from JSON.
|
||||
* @return EnhanceLevel on success, or ParseError::MissingField.
|
||||
* @pubstate none
|
||||
*
|
||||
* @author Michele Bigi
|
||||
* @date 2026-07-06
|
||||
*/
|
||||
[[nodiscard]] static std::expected<EnhanceLevel, ParseError> tryFromLevel(
|
||||
std::uint32_t level) noexcept;
|
||||
|
||||
/**
|
||||
* @brief zero — enhancement disabled.
|
||||
*
|
||||
* @dname zero
|
||||
* @return EnhanceLevel at 0.
|
||||
* @pubstate none
|
||||
*
|
||||
* @author Michele Bigi
|
||||
* @date 2026-07-06
|
||||
*/
|
||||
[[nodiscard]] static EnhanceLevel zero() noexcept;
|
||||
|
||||
/**
|
||||
* @brief value — read the stored level.
|
||||
*
|
||||
* @dname value
|
||||
* @return Level 0..100.
|
||||
* @pubstate reads level_.
|
||||
*
|
||||
* @author Michele Bigi
|
||||
* @date 2026-07-06
|
||||
*/
|
||||
[[nodiscard]] std::uint8_t value() const noexcept;
|
||||
|
||||
/**
|
||||
* @brief fraction — normalised intensity in 0.0..1.0.
|
||||
*
|
||||
* @dname fraction
|
||||
* @return level / 100 as float.
|
||||
* @pubstate none
|
||||
*
|
||||
* @author Michele Bigi
|
||||
* @date 2026-07-06
|
||||
*/
|
||||
[[nodiscard]] float fraction() const noexcept;
|
||||
|
||||
private:
|
||||
explicit EnhanceLevel(std::uint8_t level) noexcept;
|
||||
|
||||
std::uint8_t level_;
|
||||
};
|
||||
|
||||
} // namespace core
|
||||
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* @file EnhancementsDesign.hpp
|
||||
* @brief Map enhancement levels onto Param EQ1 bands (host-testable).
|
||||
*
|
||||
* DigiRadio firmware — https://github.com/manvalan/DigiRadio
|
||||
*
|
||||
* Copyright 2026 Michele Bigi
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* @author Michele Bigi
|
||||
* @date 2026-07-06
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "core/AudioEnhancements.hpp"
|
||||
#include "core/EqProfile.hpp"
|
||||
|
||||
namespace core {
|
||||
|
||||
/**
|
||||
* @brief applyEnhancementsToEq — merge enhancement overlays into an EQ profile.
|
||||
*
|
||||
* @dname applyEnhancementsToEq
|
||||
* @param base User EQ settings (bands not touched stay unchanged).
|
||||
* @param enhancements Stereo and bass levels (0 = use base band only).
|
||||
* @return EqProfile with affected PEQ bands updated for safeload.
|
||||
* @pubstate none
|
||||
*
|
||||
* Stereo (bands 3–5): slight 1\,kHz cut plus 3/8\,kHz lift for depth.
|
||||
* Bass (bands 1–2): 100\,Hz and 400\,Hz peaking boost.
|
||||
* Band 0 (high-pass) is never modified.
|
||||
*
|
||||
* @author Michele Bigi
|
||||
* @date 2026-07-06
|
||||
*/
|
||||
[[nodiscard]] EqProfile applyEnhancementsToEq(
|
||||
const EqProfile& base, const AudioEnhancements& enhancements) noexcept;
|
||||
|
||||
} // namespace core
|
||||
Reference in New Issue
Block a user