mirror of
https://github.com/HChaZZY/PiliPlus.git
synced 2025-12-06 09:13:48 +08:00
feat: audio normalization
Closes #182 Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
12
lib/models/common/audio_normalization.dart
Normal file
12
lib/models/common/audio_normalization.dart
Normal file
@@ -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];
|
||||
}
|
||||
@@ -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<SettingsModel> 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<String> values = {'0', '1', '2', audioNormalization, '3'};
|
||||
return SelectDialog<String>(
|
||||
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,
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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<double> get dynamicDetailRatio => List<double>.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',
|
||||
|
||||
Reference in New Issue
Block a user