~aleteoryx/muditaos

2fd3ea0c0663e75db67b9719944eac885c39e8ec — Mateusz Piesta 4 years ago 43c27e7
[BH-1175] Various sample rates support

Added 44.1/48kHz sample rate support.

[BH-1281] Software volume scaling.
M module-audio/Audio/AudioDevice.hpp => module-audio/Audio/AudioDevice.hpp +7 -1
@@ 16,6 16,9 @@ namespace audio
    {

      public:
        static constexpr auto minVolume = .0f;
        static constexpr auto maxVolume = 10.0f;

        enum class RetCode
        {
            Success = 0,


@@ 62,11 65,14 @@ namespace audio
        /// Set device input gain
        /// @param gain desired input gain from 0 to 100
        /// @return RetCode::Success if OK, or RetCode::Failure otherwise
        virtual RetCode setInputGain(float gain)   = 0;
        virtual RetCode setInputGain(float gain) = 0;

        auto getSinkFormat() -> AudioFormat override
        {
            return getSourceFormat();
        }

      private:
        static_assert(maxVolume > 0, "maxVolume needs to be bigger than 0");
    };
} // namespace audio

M module-audio/board/linux/LinuxAudioDevice.cpp => module-audio/board/linux/LinuxAudioDevice.cpp +5 -4
@@ 4,6 4,7 @@
#include "LinuxAudioDevice.hpp"
#include <Audio/Stream.hpp>
#include <log/log.hpp>
#include <cmath>

namespace audio
{


@@ 82,10 83,10 @@ namespace audio

    auto LinuxAudioDevice::setOutputVolume(float vol) -> RetCode
    {
        constexpr auto minVolume = .0f;
        constexpr auto maxVolume = 10.0f;
        vol                      = std::clamp(vol, minVolume, maxVolume);
        volumeFactor             = 1.0f * (vol / maxVolume);
        vol = std::clamp(vol, minVolume, maxVolume);
        /// Using y=x^4 function as an approximation seems very natural and sufficient
        /// For more info check: https://www.dr-lex.be/info-stuff/volumecontrols.html
        volumeFactor = std::pow(1.0f * (vol / maxVolume), 4);
        return RetCode::Success;
    }


M module-audio/board/rt1051/SAIAudioDevice.cpp => module-audio/board/rt1051/SAIAudioDevice.cpp +19 -0
@@ 5,6 5,8 @@

#include <Audio/Stream.hpp>

#include <cmath>

using namespace audio;

SAIAudioDevice::SAIAudioDevice(I2S_Type *base, sai_edma_handle_t *rxHandle, sai_edma_handle_t *txHandle)


@@ 41,6 43,7 @@ void SAIAudioDevice::onDataSend()
    /// pop previous read and peek next
    Sink::_stream->consume();
    Sink::_stream->peek(dataSpan);
    scaleOutputVolume(dataSpan);

    sai_transfer_t xfer{.data = dataSpan.data, .dataSize = dataSpan.dataSize};
    SAI_TransferSendEDMA(_base, tx, &xfer);


@@ 97,3 100,19 @@ void SAIAudioDevice::disableOutput()
{
    txEnabled = false;
}
AudioDevice::RetCode SAIAudioDevice::setOutputVolume(float vol)
{
    vol = std::clamp(vol, minVolume, maxVolume);
    /// Using y=x^4 function as an approximation seems very natural and sufficient
    /// For more info check: https://www.dr-lex.be/info-stuff/volumecontrols.html
    volumeFactor = std::pow(1.0f * (vol / maxVolume), 4);
    return AudioDevice::RetCode::Success;
}
void SAIAudioDevice::scaleOutputVolume(audio::Stream::Span &span)
{
    if (volumeFactor < 1.0) {
        const auto samples      = reinterpret_cast<std::int16_t *>(span.data);
        const auto samplesCount = samples + span.dataSize / 2;
        std::for_each(samples, samplesCount, [this](auto &sample) { sample *= volumeFactor; });
    }
}

M module-audio/board/rt1051/SAIAudioDevice.hpp => module-audio/board/rt1051/SAIAudioDevice.hpp +8 -0
@@ 4,6 4,7 @@
#pragma once

#include <Audio/AudioDevice.hpp>
#include <Audio/Stream.hpp>

#include "fsl_sai_edma.h"



@@ 25,11 26,18 @@ namespace audio
      protected:
        void initiateRxTransfer();
        void initiateTxTransfer();
        RetCode setOutputVolume(float vol) override;

        I2S_Type *_base;
        sai_edma_handle_t *rx = nullptr;
        sai_edma_handle_t *tx = nullptr;
        bool txEnabled        = false;
        bool rxEnabled        = false;

      private:
        void scaleOutputVolume(audio::Stream::Span &span);

        float volumeFactor{1.0};
    };

} // namespace audio

M module-audio/board/rt1051/bellpx/BellPxAudioCodec.cpp => module-audio/board/rt1051/bellpx/BellPxAudioCodec.cpp +6 -24
@@ 25,7 25,7 @@ namespace audio
    BellPxAudioCodec::~BellPxAudioCodec()
    {
        Stop();
        DeinitBsp();
        bsp::audio::deinit();
    }

    AudioDevice::RetCode BellPxAudioCodec::Start()


@@ 40,7 40,7 @@ namespace audio
            return AudioDevice::RetCode::Failure;
        };

        InitBsp();
        bsp::audio::init(currentFormat.sampleRate_Hz);

        saiInFormat.bitWidth      = currentFormat.bitWidth;
        saiInFormat.sampleRate_Hz = currentFormat.sampleRate_Hz;


@@ 71,8 71,10 @@ namespace audio
        }

        codecParams.sampleRate = sampleRate;
        codecParams.outVolume  = currentFormat.outputVolume;
        codecParams.inGain     = currentFormat.inputGain;
        /// Set the output volume to max possible value. Volume control is implemented
        /// using software scaling instead of hardware gain control.
        codecParams.outVolume = maxVolume;
        codecParams.inGain    = currentFormat.inputGain;

        txEnabled = true;
        initiateTxTransfer();


@@ 100,16 102,6 @@ namespace audio
        return AudioDevice::RetCode::Success;
    }

    AudioDevice::RetCode BellPxAudioCodec::setOutputVolume(float vol)
    {
        currentFormat.outputVolume = vol;
        CodecParamsAW8898 params;
        params.outVolume = vol;
        params.opCmd     = CodecParams::Cmd::SetOutVolume;
        codec.Ioctrl(params);
        return AudioDevice::RetCode::Success;
    }

    AudioDevice::RetCode BellPxAudioCodec::setInputGain(float gain)
    {
        currentFormat.inputGain = gain;


@@ 120,16 112,6 @@ namespace audio
        return AudioDevice::RetCode::Success;
    }

    void BellPxAudioCodec::InitBsp()
    {
        bsp::audio::init();
    }

    void BellPxAudioCodec::DeinitBsp()
    {
        bsp::audio::deinit();
    }

    void BellPxAudioCodec::InStart()
    {
        sai_transfer_format_t sai_format;

M module-audio/board/rt1051/bellpx/BellPxAudioCodec.hpp => module-audio/board/rt1051/bellpx/BellPxAudioCodec.hpp +0 -3
@@ 39,7 39,6 @@ namespace audio

        AudioDevice::RetCode Start() final;
        AudioDevice::RetCode Stop() final;
        AudioDevice::RetCode setOutputVolume(float vol) final;
        AudioDevice::RetCode setInputGain(float gain) final;
        auto getSupportedFormats() -> std::vector<AudioFormat> final;
        auto getTraits() const -> Traits final;


@@ 76,8 75,6 @@ namespace audio
        static AT_NONCACHEABLE_SECTION_INIT(sai_edma_handle_t txHandle);
        static AT_NONCACHEABLE_SECTION_INIT(sai_edma_handle_t rxHandle);

        void InitBsp();
        void DeinitBsp();
        void OutStart();
        void InStart();
        void OutStop();

M module-audio/board/rt1051/puretx/PureTxAudioCodec.cpp => module-audio/board/rt1051/puretx/PureTxAudioCodec.cpp +1 -1
@@ 175,7 175,7 @@ namespace audio

    void PureTxAudioCodec::InitBsp()
    {
        bsp::audio::init();
        bsp::audio::init(currentFormat.sampleRate_Hz);
    }

    void PureTxAudioCodec::DeinitBsp()

M module-bsp/board/rt1051/bellpx/audio.cpp => module-bsp/board/rt1051/bellpx/audio.cpp +37 -2
@@ 16,10 16,45 @@ using namespace drivers;

AudioConfig audioConfig;

void bsp::audio::init()
namespace
{
    constexpr bool isDerivativeOf44100(const std::uint32_t sampleRate)
    {
        return sampleRate % 11025 == 0;
    }

    DriverPLLParams getPLLParams(const std::uint32_t sampleRate)
    {
        /// The basic formula for calculating PLL4:
        /// (fsclk * (loopDivider + numerator/denominator)) / postDivider

        if (isDerivativeOf44100(sampleRate)) {
            /// PLL4 set to 722.5344MHz, later it will be divided by SAI to generate 11,2896MHz BCLK
            return {
                .loopDivider = 30,
                .postDivider = 1,
                .numerator   = 1056,
                .denominator = 10000,
                .src         = 0,
            };
        }
        else {
            /// PLL4 set to 786.48MHz, later it will be divided by SAI to generate 12,28875MHz BCLK
            return {
                .loopDivider = 32,
                .postDivider = 1,
                .numerator   = 77,
                .denominator = 100,
                .src         = 0,
            };
        }
    }
} // namespace

void bsp::audio::init(const std::uint32_t sampleRate)
{
    audioConfig.pllAudio =
        DriverPLL::Create(static_cast<PLLInstances>(BoardDefinitions ::AUDIO_PLL), DriverPLLParams{});
        DriverPLL::Create(static_cast<PLLInstances>(BoardDefinitions ::AUDIO_PLL), getPLLParams(sampleRate));
    audioConfig.dmamux =
        DriverDMAMux::Create(static_cast<DMAMuxInstances>(BoardDefinitions ::AUDIOCODEC_DMAMUX), DriverDMAMuxParams{});
    audioConfig.dma =

M module-bsp/board/rt1051/bellpx/board/clock_config.h => module-bsp/board/rt1051/bellpx/board/clock_config.h +1 -1
@@ 125,7 125,7 @@ extern "C"
    void clkPLL3_PFD2setup(uint8_t enabled);
    void clkPLL3_PFD3setup(uint8_t enabled);

    void clkPLL4setup(uint8_t enabled);
    void clkPLL4setup(uint8_t enabled, const clock_audio_pll_config_t conf);

    void clkPLL5setup(uint8_t enabled);


M module-bsp/board/rt1051/bellpx/bsp/audio/CodecAW8898.cpp => module-bsp/board/rt1051/bellpx/bsp/audio/CodecAW8898.cpp +0 -1
@@ 95,7 95,6 @@ CodecRetCode CodecAW8898::Start(const CodecParams &param)

    // Store param configuration
    currentParams = params;

    SetOutputVolume(currentParams.outVolume);

    AW8898::ReadAllReg();

M module-bsp/board/rt1051/bellpx/clock_config.cpp => module-bsp/board/rt1051/bellpx/clock_config.cpp +3 -10
@@ 393,7 393,7 @@ void BOARD_BootClockRUN(void)
     */

    /* DeInit Audio PLL */
    clkPLL4setup(CLK_DISABLE);
    clkPLL4setup(CLK_DISABLE, {});
    CLOCK_SetPllBypass(CCM_ANALOG, kCLOCK_PllAudio, 1);

    /*


@@ 966,17 966,10 @@ void clkPLL3_PFD3setup(uint8_t enabled)
    }
}

void clkPLL4setup(uint8_t enabled)
void clkPLL4setup(uint8_t enabled, const clock_audio_pll_config_t conf)
{
    const clock_audio_pll_config_t audioPllConfig_BOARD_BootClockRUN = {
        .loopDivider = 32,  /* PLL loop divider. Valid range for DIV_SELECT divider value: 27~54. */
        .postDivider = 1,   /* Divider after the PLL, should only be 1, 2, 4, 8, 16. */
        .numerator   = 77,  /* 30 bit numerator of fractional loop divider. */
        .denominator = 100, /* 30 bit denominator of fractional loop divider */
        .src         = 0,
    };
    if (enabled) {
        CLOCK_InitAudioPll(&audioPllConfig_BOARD_BootClockRUN);
        CLOCK_InitAudioPll(&conf);
    }
    else {
        /* DeInit Audio PLL */

M module-bsp/board/rt1051/common/audio.hpp => module-bsp/board/rt1051/common/audio.hpp +1 -1
@@ 14,7 14,7 @@

namespace bsp::audio
{
    void init();
    void init(std::uint32_t sampleRate);
    void deinit();

    struct AudioConfig

M module-bsp/board/rt1051/drivers/RT1051DriverPLL.cpp => module-bsp/board/rt1051/drivers/RT1051DriverPLL.cpp +7 -2
@@ 14,7 14,12 @@ namespace drivers

        switch (instance) {
        case PLLInstances::PLL4_Audio: {
            clkPLL4setup(CLK_ENABLE);
            clkPLL4setup(CLK_ENABLE,
                         clock_audio_pll_config_t{.loopDivider = static_cast<uint8_t>(params.loopDivider),
                                                  .postDivider = static_cast<uint8_t>(params.postDivider),
                                                  .numerator   = params.numerator,
                                                  .denominator = params.denominator,
                                                  .src         = static_cast<uint8_t>(params.src)});
            name = "PLL4_Audio";
        } break;
        case PLLInstances::PLL3: {


@@ 54,7 59,7 @@ namespace drivers
    {
        switch (instance) {
        case PLLInstances::PLL4_Audio: {
            clkPLL4setup(CLK_DISABLE);
            clkPLL4setup(CLK_DISABLE, {});
        } break;
        case PLLInstances::PLL3: {
            clkPLL3setup(CLK_DISABLE);

M module-bsp/board/rt1051/puretx/audio.cpp => module-bsp/board/rt1051/puretx/audio.cpp +1 -1
@@ 16,7 16,7 @@ using namespace drivers;

bsp::audio::AudioConfig audioConfig;

void bsp::audio::init()
void bsp::audio::init([[maybe_unused]] const std::uint32_t sampleRate)
{
    audioConfig.pllAudio =
        DriverPLL::Create(static_cast<PLLInstances>(BoardDefinitions ::AUDIO_PLL), DriverPLLParams{});

M module-bsp/board/rt1051/puretx/board/clock_config.h => module-bsp/board/rt1051/puretx/board/clock_config.h +1 -1
@@ 128,7 128,7 @@ extern "C"
    void clkPLL3_PFD2setup(uint8_t enabled);
    void clkPLL3_PFD3setup(uint8_t enabled);

    void clkPLL4setup(uint8_t enabled);
    void clkPLL4setup(uint8_t enabled, const clock_audio_pll_config_t config);

    void clkPLL5setup(uint8_t enabled);


M module-bsp/board/rt1051/puretx/clock_config.cpp => module-bsp/board/rt1051/puretx/clock_config.cpp +4 -2
@@ 396,7 396,7 @@ void BOARD_BootClockRUN(void)
     */

    /* DeInit Audio PLL */
    clkPLL4setup(CLK_DISABLE);
    clkPLL4setup(CLK_DISABLE, {});
    CLOCK_SetPllBypass(CCM_ANALOG, kCLOCK_PllAudio, 1);

    /*


@@ 965,8 965,10 @@ void clkPLL3_PFD3setup(uint8_t enabled)
    }
}

void clkPLL4setup(uint8_t enabled)
void clkPLL4setup(uint8_t enabled, [[maybe_unused]] const clock_audio_pll_config_t config)
{
    /// Due to used audio codec, fixed PLL configuration can be used. Audio codec's internal PLL can generate
    /// all needed clocks using provided MCLK.
    const clock_audio_pll_config_t audioPllConfig_BOARD_BootClockRUN = {
        .loopDivider = 32,  /* PLL loop divider. Valid range for DIV_SELECT divider value: 27~54. */
        .postDivider = 1,   /* Divider after the PLL, should only be 1, 2, 4, 8, 16. */

M module-bsp/drivers/pll/DriverPLL.cpp => module-bsp/drivers/pll/DriverPLL.cpp +1 -3
@@ 7,8 7,6 @@
#if defined(TARGET_RT1051)
#include "board/rt1051/drivers/RT1051DriverPLL.hpp"
#elif defined(TARGET_Linux)

//#include ""
#else
#error "Unsupported target"
#endif


@@ 43,4 41,4 @@ namespace drivers
        }
    }

} // namespace drivers
\ No newline at end of file
} // namespace drivers

M module-bsp/drivers/pll/DriverPLL.hpp => module-bsp/drivers/pll/DriverPLL.hpp +10 -6
@@ 5,6 5,7 @@
#define PUREPHONE_DRIVERPLL_HPP

#include <memory>
#include <cstdint>

namespace drivers
{


@@ 23,17 24,20 @@ namespace drivers
    };

    struct DriverPLLParams
    {};
    {
        std::uint32_t loopDivider;
        std::uint32_t postDivider;
        std::uint32_t numerator;
        std::uint32_t denominator;
        std::uint32_t src;
    };

    class DriverPLL
    {
      public:
        static std::shared_ptr<DriverPLL> Create(const PLLInstances inst, const DriverPLLParams &params);

        DriverPLL(const DriverPLLParams &params) : parameters(params)
        {}
        static std::shared_ptr<DriverPLL> Create(PLLInstances inst, const DriverPLLParams &params);

        virtual ~DriverPLL()
        explicit DriverPLL(const DriverPLLParams &params) : parameters(params)
        {}

      protected: