Skip to content

Commit ea7e2a6

Browse files
committed
Add an alffplay option to set the playback gain
1 parent da72e19 commit ea7e2a6

1 file changed

Lines changed: 75 additions & 8 deletions

File tree

examples/alffplay.cpp

Lines changed: 75 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434

3535
#include "almalloc.h"
3636
#include "alnumeric.h"
37+
#include "alstring.h"
3738
#include "common/alhelpers.hpp"
3839
#include "fmt/core.h"
3940
#include "fmt/format.h"
@@ -99,6 +100,7 @@ using std::chrono::duration_cast;
99100

100101
constexpr auto AppName = std::to_array("alffplay");
101102

103+
auto PlaybackGain = 1.0f;
102104
auto DirectOutMode = ALenum{AL_FALSE};
103105
auto EnableWideStereo = false;
104106
auto EnableUhj = false;
@@ -1259,6 +1261,31 @@ void AudioState::handler()
12591261
alGenBuffers(gsl::narrow_cast<ALsizei>(mBuffers.size()), mBuffers.data());
12601262
alGenSources(1, &mSource);
12611263

1264+
if(PlaybackGain > 1.0f)
1265+
{
1266+
const auto maxgain = alIsExtensionPresent("AL_SOFT_gain_clamp_ex")
1267+
? alGetFloat(AL_GAIN_LIMIT_SOFT) : 1.0f;
1268+
1269+
auto gain = PlaybackGain;
1270+
if(gain > maxgain)
1271+
{
1272+
fmt::println(stderr, "Limiting requested gain {:+}db ({}) to max {:+}db ({})",
1273+
std::round(std::log10(double{gain})*2000.0) / 100.0, gain,
1274+
std::round(std::log10(double{maxgain})*2000.0) / 100.0, maxgain);
1275+
gain = maxgain;
1276+
}
1277+
else
1278+
fmt::println("Setting gain {:+}dB ({})",
1279+
std::round(std::log10(double{gain})*2000.0) / 100.0, gain);
1280+
alSourcef(mSource, AL_MAX_GAIN, gain);
1281+
alSourcef(mSource, AL_GAIN, gain);
1282+
}
1283+
else if(PlaybackGain < 1.0f)
1284+
{
1285+
fmt::println("Setting gain {:+}dB ({})",
1286+
std::round(std::log10(double{PlaybackGain})*2000.0) / 100.0, PlaybackGain);
1287+
alSourcef(mSource, AL_GAIN, PlaybackGain);
1288+
}
12621289
if(DirectOutMode)
12631290
alSourcei(mSource, AL_DIRECT_CHANNELS_SOFT, DirectOutMode);
12641291
if(EnableWideStereo)
@@ -2060,6 +2087,8 @@ auto main(std::span<std::string_view> args) -> int
20602087
{
20612088
fmt::println(stderr, "Usage: {} [-device <device name>] [options] <files...>", args[0]);
20622089
fmt::println(stderr, "\n Options:\n"
2090+
" -gain <g> Set audio playback gain (prepend +/- or append \"dB\" to \n"
2091+
" indicate decibels, otherwise it's linear amplitude)\n"
20632092
" -novideo Disable video playback\n"
20642093
" -direct Play audio directly on the output, bypassing virtualization\n"
20652094
" -superstereo Apply Super Stereo processing to stereo tracks\n"
@@ -2124,8 +2153,10 @@ auto main(std::span<std::string_view> args) -> int
21242153
}
21252154
/* NOLINTEND(cppcoreguidelines-pro-type-reinterpret-cast) */
21262155

2127-
auto curarg = std::ranges::find_if(args, [](const std::string_view argval)
2156+
auto curarg = args.begin();
2157+
for(auto args_end=args.end();curarg != args_end;++curarg)
21282158
{
2159+
const auto argval = *curarg;
21292160
if(argval == "-direct")
21302161
{
21312162
if(alIsExtensionPresent("AL_SOFT_direct_channels_remix"))
@@ -2140,7 +2171,7 @@ auto main(std::span<std::string_view> args) -> int
21402171
}
21412172
else
21422173
fmt::println(stderr, "AL_SOFT_direct_channels not supported for direct output");
2143-
return false;
2174+
continue;
21442175
}
21452176
if(argval == "-wide")
21462177
{
@@ -2151,7 +2182,7 @@ auto main(std::span<std::string_view> args) -> int
21512182
fmt::println("Found AL_EXT_STEREO_ANGLES");
21522183
EnableWideStereo = true;
21532184
}
2154-
return false;
2185+
continue;
21552186
}
21562187
if(argval == "-uhj")
21572188
{
@@ -2162,7 +2193,7 @@ auto main(std::span<std::string_view> args) -> int
21622193
fmt::println("Found AL_SOFT_UHJ");
21632194
EnableUhj = true;
21642195
}
2165-
return false;
2196+
continue;
21662197
}
21672198
if(argval == "-superstereo")
21682199
{
@@ -2173,15 +2204,51 @@ auto main(std::span<std::string_view> args) -> int
21732204
fmt::println("Found AL_SOFT_UHJ (Super Stereo)");
21742205
EnableSuperStereo = true;
21752206
}
2176-
return false;
2207+
continue;
21772208
}
21782209
if(argval == "-novideo")
21792210
{
21802211
DisableVideo = true;
2181-
return false;
2212+
continue;
21822213
}
2183-
return true;
2184-
});
2214+
if(argval == "-gain")
2215+
{
2216+
if(curarg+1 == args_end)
2217+
fmt::println(stderr, "Missing argument for -gain");
2218+
else
2219+
{
2220+
const auto optarg = *++curarg;
2221+
2222+
auto endpos = size_t{};
2223+
const auto gainval = std::invoke([optarg,&endpos]
2224+
{
2225+
try { return std::stof(std::string{optarg}, &endpos); }
2226+
catch(std::exception &e) {
2227+
fmt::println(stderr, "Exception reading gain value: {}", e.what());
2228+
}
2229+
return std::numeric_limits<float>::quiet_NaN();
2230+
});
2231+
if(optarg.starts_with("+") || optarg.starts_with("-")
2232+
|| al::case_compare(optarg.substr(endpos), "db") == 0)
2233+
{
2234+
if(!std::isfinite(gainval) || (endpos != optarg.size()
2235+
&& al::case_compare(optarg.substr(endpos), "db") != 0))
2236+
fmt::println(stderr, "Invalid dB gain value: {}", optarg);
2237+
else
2238+
PlaybackGain = std::pow(10.0f, gainval/20.0f);
2239+
}
2240+
else
2241+
{
2242+
if(endpos != optarg.size() || !(gainval >= 0.0f) || !std::isfinite(gainval))
2243+
fmt::println(stderr, "Invalid linear gain value: {}", optarg);
2244+
else
2245+
PlaybackGain = gainval;
2246+
}
2247+
}
2248+
continue;
2249+
}
2250+
break;
2251+
}
21852252

21862253
auto movState = std::unique_ptr<MovieState>{};
21872254
curarg = std::ranges::find_if(curarg, args.end(), [&movState](const std::string_view argval)

0 commit comments

Comments
 (0)