diff options
author | Aidan MacDonald <amachronic@protonmail.com> | 2022-11-22 19:19:01 +0000 |
---|---|---|
committer | Aidan MacDonald <amachronic@protonmail.com> | 2023-01-22 15:43:00 -0500 |
commit | dc839639620352c5fa9b63db6679126ec5bcfba8 (patch) | |
tree | c551d2e6586b0439003a8c0bba66e0d349cc680d /apps | |
parent | 66519000f47cfb5c58be68ab2335b7cbc0bce35b (diff) | |
download | rockbox-dc839639620352c5fa9b63db6679126ec5bcfba8.tar.gz rockbox-dc839639620352c5fa9b63db6679126ec5bcfba8.zip |
Add helpers for converting to/from normalized (perceptual) volume
These routines were taken from alsamixer and converted to fixed
point for Rockbox.
Change-Id: I64e8bf08da02b1e6e3ef10fdc78254bf8e87ff20
Diffstat (limited to 'apps')
-rw-r--r-- | apps/misc.c | 102 | ||||
-rw-r--r-- | apps/misc.h | 8 |
2 files changed, 110 insertions, 0 deletions
diff --git a/apps/misc.c b/apps/misc.c index e17df02bff..d4c7108d28 100644 --- a/apps/misc.c +++ b/apps/misc.c | |||
@@ -1664,3 +1664,105 @@ int core_load_bmp(const char * filename, struct bitmap *bm, const int bmformat, | |||
1664 | return handle; | 1664 | return handle; |
1665 | } | 1665 | } |
1666 | #endif /* ndef __PCTOOL__ */ | 1666 | #endif /* ndef __PCTOOL__ */ |
1667 | |||
1668 | /* | ||
1669 | * Normalized volume routines adapted from alsamixer volume_mapping.c | ||
1670 | */ | ||
1671 | /* | ||
1672 | * Copyright (c) 2010 Clemens Ladisch <clemens@ladisch.de> | ||
1673 | * | ||
1674 | * Permission to use, copy, modify, and/or distribute this software for any | ||
1675 | * purpose with or without fee is hereby granted, provided that the above | ||
1676 | * copyright notice and this permission notice appear in all copies. | ||
1677 | * | ||
1678 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
1679 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
1680 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
1681 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
1682 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
1683 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
1684 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
1685 | */ | ||
1686 | /* | ||
1687 | * "The mapping is designed so that the position in the interval is proportional | ||
1688 | * to the volume as a human ear would perceive it (i.e., the position is the | ||
1689 | * cubic root of the linear sample multiplication factor). For controls with | ||
1690 | * a small range (24 dB or less), the mapping is linear in the dB values so | ||
1691 | * that each step has the same size visually. Only for controls without dB | ||
1692 | * information, a linear mapping of the hardware volume register values is used | ||
1693 | * (this is the same algorithm as used in the old alsamixer)." | ||
1694 | */ | ||
1695 | |||
1696 | #define NVOL_FRACBITS 16 | ||
1697 | #define NVOL_UNITY (1L << NVOL_FRACBITS) | ||
1698 | #define NVOL_FACTOR (600L << NVOL_FRACBITS) | ||
1699 | |||
1700 | #define NVOL_MAX_LINEAR_DB_SCALE (240L << NVOL_FRACBITS) | ||
1701 | |||
1702 | #define nvol_div(x,y) fp_div((x), (y), NVOL_FRACBITS) | ||
1703 | #define nvol_mul(x,y) fp_mul((x), (y), NVOL_FRACBITS) | ||
1704 | #define nvol_exp10(x) fp_exp10((x), NVOL_FRACBITS) | ||
1705 | #define nvol_log10(x) fp_log10((x), NVOL_FRACBITS) | ||
1706 | |||
1707 | static bool use_linear_dB_scale(long min_vol, long max_vol) | ||
1708 | { | ||
1709 | /* | ||
1710 | * Alsamixer uses a linear scale for small ranges. | ||
1711 | * Commented out so perceptual volume works as advertised on all targets. | ||
1712 | */ | ||
1713 | /* | ||
1714 | return max_vol - min_vol <= NVOL_MAX_LINEAR_DB_SCALE; | ||
1715 | */ | ||
1716 | |||
1717 | (void)min_vol; | ||
1718 | (void)max_vol; | ||
1719 | return false; | ||
1720 | } | ||
1721 | |||
1722 | long to_normalized_volume(long vol, long min_vol, long max_vol, long max_norm) | ||
1723 | { | ||
1724 | long norm, min_norm; | ||
1725 | |||
1726 | vol <<= NVOL_FRACBITS; | ||
1727 | min_vol <<= NVOL_FRACBITS; | ||
1728 | max_vol <<= NVOL_FRACBITS; | ||
1729 | max_norm <<= NVOL_FRACBITS; | ||
1730 | |||
1731 | if (use_linear_dB_scale(min_vol, max_vol)) | ||
1732 | { | ||
1733 | norm = nvol_div(vol - min_vol, max_vol - min_vol); | ||
1734 | } | ||
1735 | else | ||
1736 | { | ||
1737 | min_norm = nvol_exp10(nvol_div(min_vol - max_vol, NVOL_FACTOR)); | ||
1738 | norm = nvol_exp10(nvol_div(vol - max_vol, NVOL_FACTOR)); | ||
1739 | norm = nvol_div(norm - min_norm, NVOL_UNITY - min_norm); | ||
1740 | } | ||
1741 | |||
1742 | return nvol_mul(norm, max_norm) >> NVOL_FRACBITS; | ||
1743 | } | ||
1744 | |||
1745 | long from_normalized_volume(long norm, long min_vol, long max_vol, long max_norm) | ||
1746 | { | ||
1747 | long vol, min_norm; | ||
1748 | |||
1749 | norm <<= NVOL_FRACBITS; | ||
1750 | min_vol <<= NVOL_FRACBITS; | ||
1751 | max_vol <<= NVOL_FRACBITS; | ||
1752 | max_norm <<= NVOL_FRACBITS; | ||
1753 | |||
1754 | vol = nvol_div(norm, max_norm); | ||
1755 | |||
1756 | if (use_linear_dB_scale(min_vol, max_vol)) | ||
1757 | { | ||
1758 | vol = nvol_mul(vol, max_vol - min_vol) + min_vol; | ||
1759 | } | ||
1760 | else | ||
1761 | { | ||
1762 | min_norm = nvol_exp10(nvol_div(min_vol - max_vol, NVOL_FACTOR)); | ||
1763 | vol = nvol_mul(vol, NVOL_UNITY - min_norm) + min_norm; | ||
1764 | vol = nvol_mul(nvol_log10(vol), NVOL_FACTOR) + max_vol; | ||
1765 | } | ||
1766 | |||
1767 | return vol >> NVOL_FRACBITS; | ||
1768 | } | ||
diff --git a/apps/misc.h b/apps/misc.h index 403a8c53ac..72b8735c8a 100644 --- a/apps/misc.h +++ b/apps/misc.h | |||
@@ -238,4 +238,12 @@ int core_load_bmp(const char *filename, struct bitmap *bm, const int bmformat, | |||
238 | ssize_t *buf_reqd, struct buflib_callbacks *ops); | 238 | ssize_t *buf_reqd, struct buflib_callbacks *ops); |
239 | #endif | 239 | #endif |
240 | 240 | ||
241 | /* Convert a volume (in tenth dB) in the range [min_vol, max_vol] | ||
242 | * to a normalized linear value in the range [0, max_norm]. */ | ||
243 | long to_normalized_volume(long vol, long min_vol, long max_vol, long max_norm); | ||
244 | |||
245 | /* Inverse of to_normalized_volume(), returns the volume in tenth dB | ||
246 | * for the given normalized volume. */ | ||
247 | long from_normalized_volume(long norm, long min_vol, long max_vol, long max_norm); | ||
248 | |||
241 | #endif /* MISC_H */ | 249 | #endif /* MISC_H */ |