fix:调整音频效果

This commit is contained in:
liyi 2025-04-02 17:36:27 +08:00
parent 295995abd7
commit 41a197f25e
2 changed files with 278 additions and 197 deletions

View File

@ -28,6 +28,7 @@ import 'package:star_lock/talk/starChart/proto/talk_data.pb.dart';
import 'package:star_lock/talk/starChart/proto/talk_expect.pb.dart';
import 'package:star_lock/talk/starChart/star_chart_manage.dart';
import 'package:star_lock/talk/starChart/views/talkView/talk_view_state.dart';
import 'package:star_lock/tools/G711Tool.dart';
import 'package:star_lock/tools/bugly/bugly_tool.dart';
import '../../../../tools/baseGetXController.dart';
@ -658,23 +659,11 @@ class TalkViewLogic extends BaseGetXController {
//
Future<void> _onFrame(List<int> frame) async {
//
int maxVal = 0;
int minVal = 0;
int sum = 0;
for (int val in frame) {
maxVal = max(maxVal, val);
minVal = min(minVal, val);
sum += val;
}
double average = sum / frame.length;
AppLog.log('音频数据特征 - 最大值: $maxVal, 最小值: $minVal, 平均值: $average');
final List<int> processedFrame = preprocessAudio(frame);
//
final List<int> smoothedFrame = smoothAudio(processedFrame);
final List<int> list = listLinearToALaw(smoothedFrame);
_bufferedAudioFrames.addAll(list);
// G711数据
List<int> encodedData = G711Tool.encode(frame, 0); // 0A-law
_bufferedAudioFrames.addAll(encodedData);
final int ms = DateTime.now().millisecondsSinceEpoch -
state.startRecordingAudioTime.value.millisecondsSinceEpoch;
@ -685,15 +674,6 @@ class TalkViewLogic extends BaseGetXController {
}
if (_bufferedAudioFrames.length >= getFrameLength) {
//
int maxVal = 0;
int minVal = 255;
for (int val in _bufferedAudioFrames) {
maxVal = max(maxVal, val);
minVal = min(minVal, val);
}
AppLog.log(
'发送音频数据 - G711编码后 - 最大值: $maxVal, 最小值: $minVal, 长度: ${_bufferedAudioFrames.length}');
// UDP
await StartChartManage()
.sendTalkDataMessage(
@ -714,177 +694,5 @@ class TalkViewLogic extends BaseGetXController {
AppLog.log(error.message!);
}
//
List<int> preprocessAudio(List<int> pcmList) {
final List<int> processedList = [];
final int noiseThreshold = 300; //
for (int pcmVal in pcmList) {
//
if (pcmVal.abs() < noiseThreshold) {
pcmVal = (pcmVal * 0.3).round(); //
}
//
if (pcmVal.abs() > 20000) {
double factor = 1.0 - ((pcmVal.abs() - 20000) / 12768) * 0.3;
pcmVal = (pcmVal * factor).round();
}
processedList.add(pcmVal);
}
return processedList;
}
//
List<int> smoothAudio(List<int> pcmList) {
final List<int> smoothedList = [];
for (int i = 0; i < pcmList.length; i++) {
if (i > 0 && i < pcmList.length - 1) {
//
int avg = (pcmList[i - 1] + pcmList[i] * 2 + pcmList[i + 1]) ~/ 4;
smoothedList.add(avg);
} else {
smoothedList.add(pcmList[i]);
}
}
return smoothedList;
}
//test测试降噪算法
// List<int> preprocessAudio(List<int> pcmList) {
// final List<int> processedList = [];
// final int windowSize = 5;
// final int thresholdFactor = 2; //
// for (int i = 0; i < pcmList.length; i++) {
// int pcmVal = pcmList[i];
// //
// int sum = 0;
// int count = 0;
// for (int j = i; j < i + windowSize && j < pcmList.length; j++) {
// sum += pcmList[j];
// count++;
// }
// int mean = sum ~/ count;
// //
// int varianceSum = 0;
// for (int j = i; j < i + windowSize && j < pcmList.length; j++) {
// varianceSum += (pcmList[j] - mean) * (pcmList[j] - mean);
// }
// double standardDeviation =
// sqrt(varianceSum / count); // Use sqrt from dart:math
// //
// int dynamicThreshold = (standardDeviation * thresholdFactor).toInt();
// // 0
// if (pcmVal.abs() < dynamicThreshold) {
// pcmVal = 0;
// }
// //
// int sumFilter = 0;
// int countFilter = 0;
// for (int j = i; j < i + windowSize && j < pcmList.length; j++) {
// sumFilter += pcmList[j];
// countFilter++;
// }
// int average = sumFilter ~/ countFilter;
// processedList.add(average);
// }
// return processedList;
// }
//
List<int> adjustVolume(List<int> pcmList, double volume) {
final List<int> adjustedPcmList = <int>[];
for (final int pcmVal in pcmList) {
int adjustedPcmVal = (pcmVal * volume).round();
adjustedPcmVal = adjustedPcmVal.clamp(-32768, 32767);
adjustedPcmList.add(adjustedPcmVal);
}
return adjustedPcmList;
}
// A-law编码
List<int> listLinearToALaw(List<int> pcmList) {
// 使
final List<int> adjustedPcmList = adjustVolume(pcmList, 2.2);
// A-law编码
final List<int> aLawList = <int>[];
for (final int pcmVal in adjustedPcmList) {
final int aLawVal = linearToALaw(pcmVal);
aLawList.add(aLawVal);
}
return aLawList;
}
int linearToALaw(int pcmVal) {
const int alawMax = 0x7FFF; // 32767
const int alawBias = 0x84; // 132
int mask;
int seg;
int aLawVal;
// Handle sign
if (pcmVal < 0) {
pcmVal = -pcmVal;
mask = 0x7F; // 127 (sign bit is 1)
} else {
mask = 0xFF; // 255 (sign bit is 0)
}
// Add bias and clamp to ALAW_MAX
pcmVal += alawBias;
if (pcmVal > alawMax) {
pcmVal = alawMax;
}
// Determine segment
seg = search(pcmVal);
// Calculate A-law value
if (seg >= 8) {
aLawVal = 0x7F ^ mask; // Clamp to maximum value
} else {
final int quantized = (pcmVal >> (seg + 3)) & 0xF;
aLawVal = (seg << 4) | quantized;
aLawVal ^= 0xD5; // XOR with 0xD5 to match standard A-law table
}
return aLawVal;
}
int search(int val) {
final List<int> table = <int>[
0xFF, // Segment 0
0x1FF, // Segment 1
0x3FF, // Segment 2
0x7FF, // Segment 3
0xFFF, // Segment 4
0x1FFF, // Segment 5
0x3FFF, // Segment 6
0x7FFF // Segment 7
];
const int size = 8;
for (int i = 0; i < size; i++) {
if (val <= table[i]) {
return i;
}
}
return size;
}
}

273
lib/tools/G711Tool.dart Normal file
View File

@ -0,0 +1,273 @@
/**
* G711Tool - G.711
*
* G.711ITU-T标准
* A-lawμ-law
*
* PCM线性音频数据与G.711 A-law/μ-law格式之间的转换功能
* 16线PCM样本压缩为8位
*/
class G711Tool {
//
static const int SIGN_BIT = 0x80; // A-law字节的符号位
static const int QUANT_MASK = 0xf; //
static const int NSEGS = 8; // A-law段数
static const int SEG_SHIFT = 4; //
static const int SEG_MASK = 0x70; //
static const int BIAS = 0x84; // 线
//
/**
* μ-law到A-law的转换表
* 线PCM
*/
static final List<int> _u2a = [
// u- to A-law conversions
1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8,
9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
25, 27, 29, 31, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
46, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62,
64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96,
97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112,
113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
128
];
/**
* A-law到μ-law的转换表
* 线PCM
*/
static final List<int> _a2u = [
// A- to u-law conversions
1, 3, 5, 7, 9, 11, 13, 15, 16, 17, 18, 19, 20, 21, 22, 23,
24, 25, 26, 27, 28, 29, 30, 31, 32, 32, 33, 33, 34, 34, 35, 35,
36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 48, 49, 49,
50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 64,
65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 79,
80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126,
127
];
/**
*
* PCM值应该映射到哪个段
*
*/
static final List<int> _segEnd = [
0xFF,
0x1FF,
0x3FF,
0x7FF,
0xFFF,
0x1FFF,
0x3FFF,
0x7FFF
];
/**
*
*
* @param val
* @param table
* @param size
* @return
*/
static int _search(int val, List<int> table, int size) {
for (int i = 0; i < size; i++) {
if (val <= table[i]) return i;
}
return size;
}
/**
* 线PCM值转换为A-law编码值
*
* :
* 1.
* 2.
* 3.
* 4. A-law值
*
* @param pcmVal 16线PCM值
* @return 8A-law编码值
*/
static int _linear2alaw(int pcmVal) {
int mask;
int seg;
int aval;
if (pcmVal >= 0) {
mask = 0xD5; // sign (7th) bit = 1
} else {
mask = 0x55; // sign bit = 0
pcmVal = -pcmVal - 1;
if (pcmVal < 0) pcmVal = 32767;
}
seg = _search(pcmVal, _segEnd, 8);
if (seg >= 8) return 0x7F ^ mask;
aval = seg << SEG_SHIFT;
if (seg < 2) {
aval |= (pcmVal >> 4) & QUANT_MASK;
} else {
aval |= (pcmVal >> (seg + 3)) & QUANT_MASK;
}
return aval ^ mask;
}
/**
* A-law编码值转换为线性PCM值
*
* :
* 1.
* 2.
* 3. 线
* 4.
*
* @param aVal 8A-law编码值
* @return 16线PCM值
*/
static int _alaw2linear(int aVal) {
int t;
int seg;
aVal ^= 0x55;
t = (aVal & QUANT_MASK) << 4;
seg = (aVal & SEG_MASK) >> SEG_SHIFT;
switch (seg) {
case 0:
t += 8;
break;
case 1:
t += 0x108;
break;
default:
t += 0x108;
t <<= seg - 1;
}
return (aVal & SIGN_BIT) != 0 ? t : -t;
}
/**
* 线PCM值转换为μ-law编码值
*
* A-law类似使
*
* @param pcmVal 16线PCM值
* @return 8μ-law编码值
*/
static int _linear2ulaw(int pcmVal) {
int mask;
int seg;
int uval;
if (pcmVal < 0) {
pcmVal = BIAS - pcmVal;
mask = 0x7F;
} else {
pcmVal += BIAS;
mask = 0xFF;
}
seg = _search(pcmVal, _segEnd, 8);
if (seg >= 8) return 0x7F ^ mask;
uval = (seg << 4) | ((pcmVal >> (seg + 3)) & 0xF);
return uval ^ mask;
}
/**
* μ-law编码值转换为线性PCM值
*
* @param uVal 8μ-law编码值
* @return 16线PCM值
*/
static int _ulaw2linear(int uVal) {
uVal = ~uVal;
int t = ((uVal & QUANT_MASK) << 3) + BIAS;
t <<= (uVal & SEG_MASK) >> SEG_SHIFT;
return (uVal & SIGN_BIT) != 0 ? (BIAS - t) : (t - BIAS);
}
/**
* A-law编码值转换为μ-law编码值
*
* 使
*
* @param aval 8A-law编码值
* @return 8μ-law编码值
*/
static int alaw2ulaw(int aval) {
aval &= 0xff;
return (aval & 0x80) != 0
? (0xFF ^ _a2u[aval ^ 0xD5])
: (0x7F ^ _a2u[aval ^ 0x55]);
}
/**
* μ-law编码值转换为A-law编码值
*
* 使
*
* @param uval 8μ-law编码值
* @return 8A-law编码值
*/
static int ulaw2alaw(int uval) {
uval &= 0xff;
return (uval & 0x80) != 0
? (0xD5 ^ (_u2a[0xFF ^ uval] - 1))
: (0x55 ^ (_u2a[0x7F ^ uval] - 1));
}
/**
* PCM数据编码为G.711
*
* @param pcm PCM数据
* @param lawFlag : 0A-law, 1μ-law
* @return G.711
*/
static List<int> encode(List<int> pcm, int lawFlag) {
List<int> code = List<int>.filled(pcm.length, 0);
if (lawFlag == 0) {
for (int i = 0; i < pcm.length; i++) {
code[i] = _linear2alaw(pcm[i]);
}
} else {
for (int i = 0; i < pcm.length; i++) {
code[i] = _linear2ulaw(pcm[i]);
}
}
return code;
}
/**
* G.711PCM格式
*
* @param code G.711
* @param lawFlag : 0A-law, 1μ-law
* @return PCM数据
*/
static List<int> decode(List<int> code, int lawFlag) {
List<int> pcm = List<int>.filled(code.length, 0);
if (lawFlag == 0) {
for (int i = 0; i < code.length; i++) {
pcm[i] = _alaw2linear(code[i]);
}
} else {
for (int i = 0; i < code.length; i++) {
pcm[i] = _ulaw2linear(code[i]);
}
}
return pcm;
}
}