diff --git a/image/user/data/equalizer/earspeaker_routing.json b/image/user/data/equalizer/earspeaker_routing.json new file mode 100644 index 000000000..9acd11053 --- /dev/null +++ b/image/user/data/equalizer/earspeaker_routing.json @@ -0,0 +1,46 @@ +{ + "samplerate": 16000, + "bitWidth": 16, + "flags": 5, + "outputVolume": 1, + "inputGain": 0, + "inputPath": 1, + "outputPath": 1, + "filterParams": [ + { + "filterType": "HighPass", + "frequency": 700, + "samplerate": 44100, + "Q": 0.701, + "gain": 10 + }, + { + "filterType": "LowPass", + "frequency": 4993.7, + "samplerate": 44100, + "Q": 0.701, + "gain": -5 + }, + { + "filterType": "LowPass", + "frequency": 6000, + "samplerate": 44100, + "Q": 0.701, + "gain": 10 + }, + { + "filterType": "HighPass", + "frequency": 100.4, + "samplerate": 44100, + "Q": 0.701, + "gain": 10 + }, + { + "filterType": "Notch", + "frequency": 1500.7, + "samplerate": 44100, + "Q": 0.701, + "gain": -3 + } + ] +} diff --git a/image/user/data/equalizer/headphones_playback.json b/image/user/data/equalizer/headphones_playback.json new file mode 100644 index 000000000..d46ddee06 --- /dev/null +++ b/image/user/data/equalizer/headphones_playback.json @@ -0,0 +1,46 @@ +{ + "samplerate": 0, + "bitWidth": 16, + "flags": 0, + "outputVolume": 0, + "inputGain": 0, + "inputPath": 2, + "outputPath": 0, + "filterParams": [ + { + "filterType": "HighPass", + "frequency": 100.2, + "samplerate": 44100, + "Q": 0.701, + "gain": 0 + }, + { + "filterType": "LowPass", + "frequency": 17996.2, + "samplerate": 44100, + "Q": 0.701, + "gain": 0 + }, + { + "filterType": "HighShelf", + "frequency": 13984.7, + "samplerate": 44100, + "Q": 0.701, + "gain": -10 + }, + { + "filterType": "LowShelf", + "frequency": 200.4, + "samplerate": 44100, + "Q": 0.701, + "gain": -10 + }, + { + "filterType": "None", + "frequency": 1496.7, + "samplerate": 44100, + "Q": 0.701, + "gain": -4 + } + ] +} diff --git a/image/user/data/equalizer/headphones_routing.json b/image/user/data/equalizer/headphones_routing.json new file mode 100644 index 000000000..660b00a31 --- /dev/null +++ b/image/user/data/equalizer/headphones_routing.json @@ -0,0 +1,46 @@ +{ + "samplerate": 0, + "bitWidth": 16, + "flags": 0, + "outputVolume": 0, + "inputGain": 0, + "inputPath": 2, + "outputPath": 0, + "filterParams": [ + { + "filterType": "HighPass", + "frequency": 997, + "samplerate": 44100, + "Q": 0.701, + "gain": 0 + }, + { + "filterType": "LowPass", + "frequency": 4993.7, + "samplerate": 44100, + "Q": 0.701, + "gain": 0 + }, + { + "filterType": "None", + "frequency": 13984.7, + "samplerate": 44100, + "Q": 0.701, + "gain": -10 + }, + { + "filterType": "None", + "frequency": 200.4, + "samplerate": 44100, + "Q": 0.701, + "gain": -10 + }, + { + "filterType": "None", + "frequency": 1496.7, + "samplerate": 44100, + "Q": 0.701, + "gain": -4 + } + ] +} diff --git a/image/user/data/equalizer/loudspeaker_playback.json b/image/user/data/equalizer/loudspeaker_playback.json new file mode 100644 index 000000000..6a1d84cb4 --- /dev/null +++ b/image/user/data/equalizer/loudspeaker_playback.json @@ -0,0 +1,46 @@ +{ + "samplerate": 0, + "bitWidth": 16, + "flags": 0, + "outputVolume": 1, + "inputGain": 0, + "inputPath": 2, + "outputPath": 2, + "filterParams": [ + { + "filterType": "HighPass", + "frequency": 501.8, + "samplerate": 44100, + "Q": 0.701, + "gain": 0 + }, + { + "filterType": "LowPass", + "frequency": 14999.5, + "samplerate": 44100, + "Q": 0.701, + "gain": 0 + }, + { + "filterType": "HighShelf", + "frequency": 15975.7, + "samplerate": 44100, + "Q": 0.701, + "gain": -10 + }, + { + "filterType": "LowShelf", + "frequency": 401, + "samplerate": 44100, + "Q": 0.701, + "gain": -10 + }, + { + "filterType": "Parametric", + "frequency": 1496.7, + "samplerate": 44100, + "Q": 0.701, + "gain": -4 + } + ] +} diff --git a/image/user/data/equalizer/loudspeaker_routing.json b/image/user/data/equalizer/loudspeaker_routing.json new file mode 100644 index 000000000..c7c1eb845 --- /dev/null +++ b/image/user/data/equalizer/loudspeaker_routing.json @@ -0,0 +1,46 @@ +{ + "samplerate": 16000, + "bitWidth": 16, + "flags": 5, + "outputVolume": 1, + "inputGain": 0, + "inputPath": 1, + "outputPath": 2, + "filterParams": [ + { + "filterType": "HighPass", + "frequency": 307.3, + "samplerate": 16000, + "Q": 0.701, + "gain": 0 + }, + { + "filterType": "LowPass", + "frequency": 5080.1, + "samplerate": 16000, + "Q": 0.847, + "gain": 0 + }, + { + "filterType": "None", + "frequency": 15975.7, + "samplerate": 16000, + "Q": 0.701, + "gain": -10 + }, + { + "filterType": "None", + "frequency": 200.4, + "samplerate": 16000, + "Q": 0.701, + "gain": -10 + }, + { + "filterType": "None", + "frequency": 1496.7, + "samplerate": 44100, + "Q": 0.701, + "gain": -4 + } + ] +} diff --git a/module-audio/Audio/Profiles/Profile.cpp b/module-audio/Audio/Profiles/Profile.cpp index 6dfb40ecc..bf47339b7 100644 --- a/module-audio/Audio/Profiles/Profile.cpp +++ b/module-audio/Audio/Profiles/Profile.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved. +// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved. // For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md #include "Profile.hpp" @@ -21,6 +21,7 @@ #include "ProfileRoutingBluetoothHFP.hpp" #include "ProfileRecordingBluetoothHFP.hpp" +#include "ProfileConfigUtils.hpp" #include namespace audio @@ -94,6 +95,22 @@ namespace audio : audioConfiguration(fmt), audioDeviceType(devType), name(name), type(type) {} + Profile::Profile(const std::string &name, + const Type type, + const std::filesystem::path &configurationPath, + const audio::codec::Configuration &fallbackConfig, + AudioDevice::Type devType) + : audioDeviceType(devType), name(name), type(type) + { + try { + audioConfiguration = loadConfigurationFromFile(configurationPath); + } + catch (std::invalid_argument &e) { + LOG_ERROR("Failed loading the profile configuration from file, using fallback! Cause: %s", e.what()); + audioConfiguration = fallbackConfig; + } + } + void Profile::SetInputGain(Gain gain) { audioConfiguration.inputGain = gain; @@ -131,4 +148,5 @@ namespace audio } return utils::enumToString(profileType); } + } // namespace audio diff --git a/module-audio/Audio/Profiles/Profile.hpp b/module-audio/Audio/Profiles/Profile.hpp index 4bc5352c6..2ecdb0a9e 100644 --- a/module-audio/Audio/Profiles/Profile.hpp +++ b/module-audio/Audio/Profiles/Profile.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved. +// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved. // For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md #pragma once @@ -9,6 +9,8 @@ #include #include #include +#include +#include namespace audio { @@ -128,6 +130,12 @@ namespace audio const audio::codec::Configuration &fmt, AudioDevice::Type devType); + Profile(const std::string &name, + const Type type, + const std::filesystem::path &configurationPath, + const audio::codec::Configuration &fallbackConfig, + AudioDevice::Type devType); + audio::codec::Configuration audioConfiguration; AudioDevice::Type audioDeviceType = AudioDevice::Type::Audiocodec; diff --git a/module-audio/Audio/Profiles/ProfileConfigUtils.cpp b/module-audio/Audio/Profiles/ProfileConfigUtils.cpp new file mode 100644 index 000000000..c9f3fb70d --- /dev/null +++ b/module-audio/Audio/Profiles/ProfileConfigUtils.cpp @@ -0,0 +1,108 @@ +// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved. +// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md + +#include "ProfileConfigUtils.hpp" +#include +#include +#include +#include +namespace audio +{ + namespace strings + { + constexpr inline auto samplerate = "samplerate"; + constexpr inline auto bitWidth = "bitWidth"; + constexpr inline auto flags = "flags"; + constexpr inline auto outputVolume = "outputVolume"; + constexpr inline auto outputPath = "outputPath"; + constexpr inline auto inputGain = "inputGain"; + constexpr inline auto inputPath = "inputPath"; + constexpr inline auto filterParams = "filterParams"; + constexpr inline auto filterType = "filterType"; + constexpr inline auto frequency = "frequency"; + constexpr inline auto Q = "Q"; + constexpr inline auto gain = "gain"; + } // namespace strings + + namespace utils + { + + template + constexpr inline typename std::enable_if::value && std::is_integral::value, E>::type toEnum( + T value) noexcept + { + return static_cast(value); + } + + equalizer::FilterType toFilterType(const std::string &filterName) + { + auto filterType = magic_enum::enum_cast(filterName); + if (filterType.has_value()) { + return filterType.value(); + } + else { + LOG_ERROR("Unknown filter type, using none"); + return equalizer::FilterType::None; + } + } + + const std::string readFileToString(std::filesystem::path filePath) + { + std::ifstream file; + std::string configString; + LOG_DEBUG("Reading %s ...", filePath.c_str()); + file.open(filePath); + if (not file.is_open()) { + LOG_ERROR("Can't open profile configuration file, using defaults!"); + throw std::invalid_argument("Can't open file!"); + } + while (file) { + std::string line; + std::getline(file, line); + configString += line; + } + file.close(); + return configString; + } + } // namespace utils + + const audio::codec::Configuration loadConfigurationFromFile(std::filesystem::path filePath) + { + + auto configString = utils::readFileToString(filePath); + audio::codec::Configuration config; + + json11::Json configJson; + std::string err; + configJson = json11::Json::parse(configString.c_str(), err); + if (!err.empty()) { + LOG_ERROR("Failed parsing device string!"); + throw std::invalid_argument("Can't parse the file!"); + } + config.sampleRate_Hz = configJson[strings::samplerate].int_value(); + config.bitWidth = configJson[strings::bitWidth].int_value(); + config.flags = configJson[strings::flags].int_value(); + config.outputVolume = configJson[strings::outputVolume].number_value(); + config.inputGain = configJson[strings::inputGain].number_value(); + config.inputPath = utils::toEnum(configJson[strings::inputPath].int_value()); + config.outputPath = utils::toEnum(configJson[strings::outputPath].int_value()); + + json11::Json::array paramsArray; + audio::equalizer::Equalizer filterParams; + paramsArray = configJson[strings::filterParams].array_items(); + + for (size_t i = 0; i < equalizer::bands; i++) { + auto filterType = utils::toFilterType(paramsArray[i][strings::filterType].string_value()); + auto frequency = paramsArray[i][strings::frequency].number_value(); + auto samplerate = paramsArray[i][strings::samplerate].int_value(); + auto Q = paramsArray[i][strings::Q].number_value(); + auto gain = paramsArray[i][strings::gain].number_value(); + + filterParams.at(i) = qfilter_CalculateCoeffs(filterType, frequency, samplerate, Q, gain); + } + + config.filterCoefficients = filterParams; + return config; + } + +} // namespace audio diff --git a/module-audio/Audio/Profiles/ProfileConfigUtils.hpp b/module-audio/Audio/Profiles/ProfileConfigUtils.hpp new file mode 100644 index 000000000..b9dece03d --- /dev/null +++ b/module-audio/Audio/Profiles/ProfileConfigUtils.hpp @@ -0,0 +1,13 @@ +// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved. +// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md + +#pragma once +#include +#include