diff --git a/lib/models/common/audio_normalization.dart b/lib/models/common/audio_normalization.dart new file mode 100644 index 00000000..c1936ac8 --- /dev/null +++ b/lib/models/common/audio_normalization.dart @@ -0,0 +1,12 @@ +enum AudioNormalization { disable, dynaudnorm, loudnorm, custom } + +extension AudioNormalizationExt on AudioNormalization { + String get title => ['禁用', '预设 dynaudnorm', '预设 loudnorm', '自定义参数'][index]; + String get param => [ + '', + // ref https://github.com/KRTirtho/spotube/commit/da10ab2e291d4ba4d3082b9a6ae535639fb8f1b7 + 'dynaudnorm=g=5:f=250:r=0.9:p=0.5', + 'loudnorm=I=-16:LRA=11:TP=-1.5', + '', + ][index]; +} diff --git a/lib/pages/setting/widgets/model.dart b/lib/pages/setting/widgets/model.dart index b2a505a2..b0ecae53 100644 --- a/lib/pages/setting/widgets/model.dart +++ b/lib/pages/setting/widgets/model.dart @@ -4,6 +4,7 @@ import 'dart:math'; import 'package:PiliPlus/common/widgets/refresh_indicator.dart' show kDragContainerExtentPercentage, displacement; import 'package:PiliPlus/http/interceptor_anonymity.dart'; +import 'package:PiliPlus/models/common/audio_normalization.dart'; import 'package:PiliPlus/models/common/dynamic_badge_mode.dart'; import 'package:PiliPlus/models/common/dynamics_type.dart'; import 'package:PiliPlus/models/common/nav_bar_config.dart'; @@ -1776,6 +1777,89 @@ List get extraSettings => [ } catch (_) {} }, ), + SettingsModel( + settingsType: SettingsType.normal, + title: '音量均衡', + setKey: SettingBoxKey.audioNormalization, + leading: const Icon(Icons.multitrack_audio), + getSubtitle: () { + String audioNormalization = GStorage.audioNormalization; + audioNormalization = switch (audioNormalization) { + '0' => AudioNormalization.disable.title, + '1' => AudioNormalization.dynaudnorm.title, + '2' => AudioNormalization.loudnorm.title, + _ => audioNormalization, + }; + return '当前:「$audioNormalization」'; + }, + onTap: (setState) async { + String? result = await showDialog( + context: Get.context!, + builder: (context) { + String audioNormalization = GStorage.audioNormalization; + Set values = {'0', '1', '2', audioNormalization, '3'}; + return SelectDialog( + title: '音量均衡', + value: audioNormalization, + values: values.map((e) { + return { + 'title': switch (e) { + '0' => AudioNormalization.disable.title, + '1' => AudioNormalization.dynaudnorm.title, + '2' => AudioNormalization.loudnorm.title, + '3' => AudioNormalization.custom.title, + _ => e, + }, + 'value': e, + }; + }).toList()); + }, + ); + if (result != null) { + if (result == '3') { + String param = ''; + showDialog( + context: Get.context!, + builder: (context) { + return AlertDialog( + title: const Text( + '自定义参数', + style: TextStyle(fontSize: 18), + ), + content: TextField( + autofocus: true, + onChanged: (value) => param = value, + ), + actions: [ + TextButton( + onPressed: Get.back, + child: Text( + '取消', + style: TextStyle( + color: Theme.of(context).colorScheme.outline, + ), + ), + ), + TextButton( + onPressed: () async { + Get.back(); + await GStorage.setting + .put(SettingBoxKey.audioNormalization, param); + setState(); + }, + child: Text('确定'), + ), + ], + ); + }); + } else { + await GStorage.setting + .put(SettingBoxKey.audioNormalization, result); + setState(); + } + } + }, + ), SettingsModel( settingsType: SettingsType.sw1tch, enableFeedback: true, diff --git a/lib/plugin/pl_player/controller.dart b/lib/plugin/pl_player/controller.dart index ea853366..7bddeb5b 100644 --- a/lib/plugin/pl_player/controller.dart +++ b/lib/plugin/pl_player/controller.dart @@ -3,6 +3,7 @@ import 'dart:io'; import 'dart:typed_data'; import 'package:PiliPlus/common/widgets/segment_progress_bar.dart'; +import 'package:PiliPlus/models/common/audio_normalization.dart'; import 'package:PiliPlus/utils/extension.dart'; import 'package:PiliPlus/utils/utils.dart'; import 'package:canvas_danmaku/canvas_danmaku.dart'; @@ -572,7 +573,19 @@ class PlPlayerController { ); var pp = player.platform as NativePlayer; // 解除倍速限制 - await pp.setProperty("af", "scaletempo2=max-speed=8"); + if (_videoPlayerController == null) { + String audioNormalization = GStorage.audioNormalization; + audioNormalization = switch (audioNormalization) { + '0' => '', + '1' => ',${AudioNormalization.dynaudnorm.param}', + '2' => ',${AudioNormalization.loudnorm.param}', + _ => ',$audioNormalization', + }; + await pp.setProperty( + "af", + "scaletempo2=max-speed=8$audioNormalization", + ); + } // 音量不一致 if (Platform.isAndroid) { await pp.setProperty("volume-max", "100"); @@ -834,7 +847,8 @@ class PlPlayerController { SmartDialog.showToast('无法加载解码器, $event,可能会切换至软解'); return; } - SmartDialog.showToast('视频加载错误, $event'); + // SmartDialog.showToast('视频加载错误, $event'); + debugPrint('视频加载错误, $event'); }), // videoPlayerController!.stream.volume.listen((event) { // if (!mute.value && _volumeBeforeMute != event) { diff --git a/lib/utils/storage.dart b/lib/utils/storage.dart index ed075f29..5363e163 100644 --- a/lib/utils/storage.dart +++ b/lib/utils/storage.dart @@ -345,6 +345,9 @@ class GStorage { static bool get showHotRcmd => GStorage.setting.get(SettingBoxKey.showHotRcmd, defaultValue: false); + static String get audioNormalization => + GStorage.setting.get(SettingBoxKey.audioNormalization, defaultValue: '0'); + static List get dynamicDetailRatio => List.from(setting .get(SettingBoxKey.dynamicDetailRatio, defaultValue: [60.0, 40.0])); @@ -566,6 +569,7 @@ class SettingBoxKey { showVipDanmaku = 'showVipDanmaku', mergeDanmaku = 'mergeDanmaku', showHotRcmd = 'showHotRcmd', + audioNormalization = 'audioNormalization', // Sponsor Block enableSponsorBlock = 'enableSponsorBlock',