133 lines
3.8 KiB
Dart
Executable File
133 lines
3.8 KiB
Dart
Executable File
import 'dart:async';
|
||
import 'dart:math';
|
||
import 'package:flutter/services.dart';
|
||
|
||
class G711 {
|
||
Future<List<int>> readAssetFile(String assetPath) async {
|
||
final ByteData data = await rootBundle.load(assetPath);
|
||
final List<int> bytes = data.buffer.asUint8List();
|
||
return bytes;
|
||
}
|
||
|
||
int ALawToLinear(int aVal) {
|
||
// 取反
|
||
aVal = ~aVal;
|
||
|
||
// 计算偏移
|
||
int t = ((aVal & 0x0F) << 3) + 0x84;
|
||
t <<= (aVal & 0x70) >> 4;
|
||
|
||
// 根据符号位决定返回值的正负
|
||
return (aVal & 0x80) != 0 ? 0x84 - t : t - 0x84;
|
||
}
|
||
|
||
int decodeG711(int encodedValue, bool isALaw) {
|
||
if (isALaw) {
|
||
// A律解码
|
||
encodedValue ^= 0x55; // 反转最高位
|
||
int sign = encodedValue & 0x80; // 符号位
|
||
int exponent = (encodedValue & 0x70) >> 4; // 指数位
|
||
int mantissa = encodedValue & 0x0F; // 尾数位
|
||
|
||
int pcmSample = (mantissa << 4) + 0x84; // 计算量化值
|
||
pcmSample <<= exponent; // 根据指数位移位
|
||
pcmSample = (sign == 0) ? pcmSample : -pcmSample; // 处理符号位
|
||
|
||
return pcmSample;
|
||
} else {
|
||
// μ律解码
|
||
encodedValue ^= 0xFF; // 反转最高位
|
||
int sign = encodedValue & 0x80; // 符号位
|
||
int exponent = (encodedValue & 0x70) >> 4; // 指数位
|
||
int mantissa = encodedValue & 0x0F; // 尾数位
|
||
|
||
int pcmSample = (mantissa << 3) + 0x84; // 计算量化值
|
||
pcmSample <<= exponent + 1; // 根据指数位移位(μ律需要额外加1)
|
||
pcmSample = (sign == 0) ? pcmSample : -pcmSample; // 处理符号位
|
||
|
||
return pcmSample;
|
||
}
|
||
}
|
||
|
||
/// 高通滤波
|
||
List<int> highPassFilter(
|
||
List<int> audioData, int sampleRate, double cutoffFreq) {
|
||
final double rc = 1.0 / (2 * pi * cutoffFreq);
|
||
final double dt = 1.0 / sampleRate;
|
||
final double alpha = rc / (rc + dt);
|
||
|
||
List<int> filteredData = [];
|
||
int prevInput = 0;
|
||
int prevOutput = 0;
|
||
|
||
for (int sample in audioData) {
|
||
int output = (alpha * (prevOutput + sample - prevInput)).round();
|
||
filteredData.add(output);
|
||
prevInput = sample;
|
||
prevOutput = output;
|
||
}
|
||
|
||
return filteredData;
|
||
}
|
||
|
||
/// 噪声门
|
||
List<int> noiseGate(List<int> audioData, int threshold) {
|
||
return audioData
|
||
.map((sample) => sample.abs() > threshold ? sample : 0)
|
||
.toList();
|
||
}
|
||
|
||
List<int> removeEcho(List<int> audioData, int delaySamples, double decay) {
|
||
final List<int> processedData = [];
|
||
for (int i = 0; i < audioData.length; i++) {
|
||
int sample = audioData[i];
|
||
if (i >= delaySamples) {
|
||
sample -= (audioData[i - delaySamples] * decay).round();
|
||
}
|
||
processedData.add(sample);
|
||
}
|
||
return processedData;
|
||
}
|
||
|
||
/// 解码并降噪
|
||
List<int> decodeAndDenoise(List<int> encodedData, bool isALaw, int sampleRate,
|
||
double cutoffFreq, int threshold) {
|
||
// 解码 G.711 数据
|
||
List<int> decodedData =
|
||
encodedData.map((value) => decodeG711(value, isALaw)).toList();
|
||
|
||
// 高通滤波
|
||
List<int> filteredData =
|
||
highPassFilter(decodedData, sampleRate, cutoffFreq);
|
||
|
||
// 噪声门
|
||
List<int> denoisedData = noiseGate(filteredData, threshold);
|
||
|
||
// 回声消除处理
|
||
final List<int> processedData = removeEcho(denoisedData, 160, 0.5);
|
||
|
||
return processedData;
|
||
}
|
||
|
||
//711解码为pcm数据
|
||
List<int> convertList(List<int> aLawList) {
|
||
// 将 ALawToLinear 函数应用于 List<int>
|
||
final List<int> linearList = aLawList.map(ALawToLinear).toList();
|
||
return linearList;
|
||
}
|
||
|
||
//List<int>转为Uint8List
|
||
Uint8List convertToInt8ListLittleEndian(List<int> intList) {
|
||
final List<int> int8List = [];
|
||
|
||
for (int intValue in intList) {
|
||
intValue = intValue * 2;
|
||
// 将 int 拆分为两个字节,采用小端序
|
||
int8List.add(intValue & 0xFF); // 低 8 位
|
||
int8List.add((intValue & 0xFF00) >> 8); // 高 8 位
|
||
}
|
||
|
||
return Uint8List.fromList(int8List);
|
||
}
|
||
}
|