WebRTC_ANS——noise_suppression.c基础讲解(1)

设置特征提取参数的函数


static void set_feature_extraction_parameters(NoiseSuppressionC *self) {
	// 直方图的bin大小设置。
	self->featureExtractionParams.binSizeLrt = 0.1f; // LRT(长时平均比率测试)的bin大小。
	self->featureExtractionParams.binSizeSpecFlat = 0.05f; // 频谱平坦度的bin大小。
	self->featureExtractionParams.binSizeSpecDiff = 0.1f; // 频谱差异的bin大小。

	// 计算LRT阈值的直方图范围。
	self->featureExtractionParams.rangeAvgHistLrt = 1.f; // LRT直方图的平均范围。

	// 缩放参数:通过缩放因子乘以直方图的主要峰值,以获取先验模型的阈值。
	// 用于LRT和频谱差异的缩放因子。
	self->featureExtractionParams.factor1ModelPars = 1.2f;
	// 用于频谱平坦度:当噪声比语音更平坦时使用。
	self->featureExtractionParams.factor2ModelPars = 0.9f;

	// 频谱平坦度的峰值限制(在0到1之间变化)。
	self->featureExtractionParams.thresPosSpecFlat = 0.6f;

	// 直方图中两个最高峰之间间距的限制:间距由bin大小决定。
	self->featureExtractionParams.limitPeakSpacingSpecFlat =
		2 * self->featureExtractionParams.binSizeSpecFlat; // 频谱平坦度。
	self->featureExtractionParams.limitPeakSpacingSpecDiff =
		2 * self->featureExtractionParams.binSizeSpecDiff; // 频谱差异。

// 第二个峰值相关性的限制。
	self->featureExtractionParams.limitPeakWeightsSpecFlat = 0.5f; // 频谱平坦度。
	self->featureExtractionParams.limitPeakWeightsSpecDiff = 0.5f; // 频谱差异。

	// LRT特征的波动限制。
	self->featureExtractionParams.thresFluctLrt = 0.05f;

	// 特征阈值的最大值和最小值的限制。
	self->featureExtractionParams.maxLrt = 1.f; // LRT的最大值。
	self->featureExtractionParams.minLrt = 0.2f; // LRT的最小值。

	self->featureExtractionParams.maxSpecFlat = 0.95f; // 频谱平坦度的最大值。
	self->featureExtractionParams.minSpecFlat = 0.1f; // 频谱平坦度的最小值。

	self->featureExtractionParams.maxSpecDiff = 1.f; // 频谱差异的最大值。
	self->featureExtractionParams.minSpecDiff = 0.16f; // 频谱差异的最小值。

	// 接受/拒绝特征的直方图峰值权重标准。
	self->featureExtractionParams.thresWeightSpecFlat =
		(int)(0.3 * (self->modelUpdatePars[1]));  // 频谱平坦度。
	self->featureExtractionParams.thresWeightSpecDiff =
		(int)(0.3 * (self->modelUpdatePars[1]));  // 频谱差异。
}

初始化状态的函数


int WebRtcNs_InitCore(NoiseSuppressionC *self, uint32_t fs) {
	int i;
	// 检查指针是否有效。
	if (self == NULL) {
		return -1; // 如果self指针无效,返回-1。
	}
	// 初始化结构体。
	if (fs == 8000 || fs == 16000) {
		self->fs = fs; // 只支持8000Hz或16000Hz的采样率。
	}
	else {
		return -1; // 如果采样率不是8000Hz或16000Hz,返回-1。
	}
	self->windShift = 0; // 初始化窗口偏移量。
	// 我们只支持10ms帧。
	if (fs == 8000) {
		self->blockLen = 80; // 对于8000Hz采样率,每个块的长度设置为80个样本。
		self->anaLen = 128; // 分析长度设置为128。
		self->window = kBlocks80w128; // 使用特定于8000Hz的窗函数。
	}
	else {
		self->blockLen = 160; // 对于16000Hz采样率,每个块的长度设置为160个样本。
		self->anaLen = 256; // 分析长度设置为256。
		self->window = kBlocks160w256; // 使用特定于16000Hz的窗函数。
	}
	self->magnLen = self->anaLen / 2 + 1;  // 计算频率bin的数量。
	self->normMagnLen = 1.f / self->magnLen; // 频率bin数量的倒数,用于归一化。
	// 初始化FFT工作数组。
	self->ip[0] = 0;  // 设置这个值触发初始化。
	memset(self->dataBuf, 0, sizeof(float) * ANAL_BLOCKL_MAX); // 初始化数据缓冲区。
	WebRtc_rdft(self->anaLen, 1, self->dataBuf, self->ip, self->wfft); // 执行一次FFT以触发FFT初始化。

	// 初始化各种缓冲区。
	memset(self->analyzeBuf, 0, sizeof(float) * ANAL_BLOCKL_MAX);
	memset(self->dataBuf, 0, sizeof(float) * ANAL_BLOCKL_MAX);
	memset(self->syntBuf, 0, sizeof(float) * ANAL_BLOCKL_MAX);

	// 高带处理的初始化。
	memset(self->dataBufHB, 0, sizeof(float) * NUM_HIGH_BANDS_MAX * ANAL_BLOCKL_MAX);

	// 用于量化噪声估计的初始化。
	memset(self->quantile, 0, sizeof(float) * HALF_ANAL_BLOCKL);
	for (i = 0; i < SIMULT * HALF_ANAL_BLOCKL; i++) {
		self->lquantile[i] = 8.f; // 初始化长期量化阈值。
		self->density[i] = 0.3f; // 初始化密度估计值。
	}

	// 初始化直方图计数器。
	for (i = 0; i < SIMULT; i++) {
		self->counter[i] = (int)floorf((float)(END_STARTUP_LONG * (i + 1)) / (float)SIMULT);
	}

	self->updates = 0; // 初始化更新计数器。

	// 维纳滤波器的初始化。
	for (i = 0; i < HALF_ANAL_BLOCKL; i++) {
		self->smooth[i] = 1.f; // 初始化平滑参数。
		self->log_lut[i] = log1pf((float)i); // 初始化对数查找表。
		self->log_lut_sqr[i] = self->log_lut[i] * self->log_lut[i]; // 初始化对数查找表的平方。
	}

	// 设置默认的侵略模式。
	self->aggrMode = 0;

	// 初始化新方法的变量。
	self->priorSpeechProb = 0.5f;  // 语音/噪声的先验概率。
	// 初始化各种频谱缓冲区。
	memset(self->magnPrevAnalyze, 0, sizeof(float) * HALF_ANAL_BLOCKL);
	memset(self->magnPrevProcess, 0, sizeof(float) * HALF_ANAL_BLOCKL);
	memset(self->noise, 0, sizeof(float) * HALF_ANAL_BLOCKL);
	memset(self->noisePrev, 0, sizeof(float) * HALF_ANAL_BLOCKL);
	memset(self->magnAvgPause, 0, sizeof(float) * HALF_ANAL_BLOCKL);
	memset(self->speechProb, 0, sizeof(float) * HALF_ANAL_BLOCKL);
	memset(self->initMagnEst, 0, sizeof(float) * HALF_ANAL_BLOCKL);
	for (i = 0; i < HALF_ANAL_BLOCKL; i++) {
		self->logLrtTimeAvg[i] = LRT_FEATURE_THR; // 初始化LRT特征的平滑长期比率测试阈值。
	}

	// 初始化特征量。
	self->featureData[0] = SF_FEATURE_THR; // 频谱平坦度(从阈值开始)。
	self->featureData[1] = 0.f;  // 频谱熵:在这个版本中不使用。
	self->featureData[2] = 0.f;  // 频谱方差:在这个版本中不使用。
	self->featureData[3] = LRT_FEATURE_THR; // 平均LRT因子(从阈值开始)。
	self->featureData[4] = SF_FEATURE_THR; // 频谱模板差异(从阈值开始)。
	self->featureData[5] = 0.f;  // 频谱差异的归一化。
	self->featureData[6] = 0.f;  // 输入幅度谱的窗口时间平均值。

	// 初始化直方图量:用于估计/更新特征的阈值。
	memset(self->histLrt, 0, sizeof(int) * HIST_PAR_EST);
	memset(self->histSpecFlat, 0, sizeof(int) * HIST_PAR_EST);
	memset(self->histSpecDiff, 0, sizeof(int) * HIST_PAR_EST);

	self->blockInd = -1;  // 帧计数器初始化。
	// 初始化模型参数。
	self->priorModelPars[0] = LRT_FEATURE_THR;
	self->priorModelPars[1] = 0.5f;
	self->priorModelPars[2] = 1.f;
	self->priorModelPars[3] = 0.5f;
	self->priorModelPars[4] = 1.f;
	self->priorModelPars[5] = 0.f;
	self->priorModelPars[6] = 0.f;

	// 初始化模型更新参数。
	self->modelUpdatePars[0] = 2;
	self->modelUpdatePars[1] = 500;  // 更新窗口。
	self->modelUpdatePars[2] = 0;  // 保守噪声谱更新计数器。
	self->modelUpdatePars[3] = self->modelUpdatePars[1]; // 特征阈值更新计数器。

	// 初始化声音能量和其他统计量。
	self->signalEnergy = 0;
	self->sumMagn = 0;
	self->whiteNoiseLevel = 0;
	self->pinkNoiseNumerator = 0;
	self->pinkNoiseExp = 0;

	// 设置特征提取参数。
	set_feature_extraction_parameters(self);

	// 设置默认策略。
	WebRtcNs_set_policy_core(self, 0);

	self->initFlag = 1; // 标记初始化完成。
	return 0; // 初始化成功返回0。
}

噪声估计函数

  
static void NoiseEstimation(NoiseSuppressionC *self, float *lmagn, float *noise) {
	size_t i, s, offset = 0; // 声明循环计数器和偏移量变量。
	float delta; // 声明用于更新量化估计的变量delta。

	// 如果更新次数少于END_STARTUP_LONG,更新计数。
	if (self->updates < END_STARTUP_LONG) {
		self->updates++;
	}

	// 遍历所有同时估计。
	for (s = 0; s < SIMULT; s++) {
		offset = s * self->magnLen; // 计算当前估计的偏移量。
		float norm_counter_weight = 1.f / (self->counter[s] + 1.f); // 计算归一化计数器权重。
		float density_plus_weight = norm_counter_weight / (2.f * WIDTH); // 计算密度加权。
		// 对每个频率bin进行新的量化估计。
		for (i = 0; i < self->magnLen; i++) {
			// 计算更新步长delta。
			if (self->density[offset + i] > 1.0) {
				delta = FACTOR / self->density[offset + i];
			}
			else {
				delta = FACTOR;
			}
			// 更新对数量化估计值。
			if (lmagn[i] > self->lquantile[offset + i]) {
				self->lquantile[offset + i] += QUANTILE * delta * norm_counter_weight;
			}
			else {
				self->lquantile[offset + i] -= (1.f - QUANTILE) * delta * norm_counter_weight;
			}

			// 更新密度估计值。
			if (fabsf(lmagn[i] - self->lquantile[offset + i]) < WIDTH) {
				self->density[offset + i] = self->counter[s] * self->density[offset + i] * norm_counter_weight + density_plus_weight;
			}
		}  // 结束频谱幅度循环。

		// 如果达到启动结束阶段,重置计数器。
		if (self->counter[s] >= END_STARTUP_LONG) {
			self->counter[s] = 0;
			if (self->updates >= END_STARTUP_LONG) {
				// 如果更新次数也超过启动阶段,更新噪声量化值。
				for (i = 0; i < self->magnLen; i++) {
					self->quantile[i] = expf(self->lquantile[offset + i]); // 将对数量化值转换回线性域。
				}
			}
		}

		self->counter[s]++; // 更新当前估计的计数器。
	}  // 结束所有同时估计的循环。

	// 在启动期间序列更新噪声。
	if (self->updates < END_STARTUP_LONG) {
		// 在启动阶段使用最后一个“s”获取非零的噪声估计值。
		for (i = 0; i < self->magnLen; i++) {
			self->quantile[i] = expf(self->lquantile[offset + i]); // 将对数量化值转换回线性域。
		}
		memcpy(noise, self->quantile, self->magnLen * sizeof(*noise)); // 将噪声估计值复制到输出数组。
	}
	else {
		memcpy(noise, self->quantile, self->magnLen * sizeof(*noise)); // 启动完成后,直接复制噪声估计值到输出数组。
	}
}

特征参数提取函数定义

// 该函数用于更新直方图或计算阈值和权重。
static void FeatureParameterExtraction(NoiseSuppressionC *self, int flag) {
	// 定义局部变量
	int i, useFeatureSpecFlat, useFeatureSpecDiff, numHistLrt;
	int maxPeak1, maxPeak2;
	int weightPeak1SpecFlat, weightPeak2SpecFlat, weightPeak1SpecDiff,
		weightPeak2SpecDiff;

	float binMid, featureSum;
	float posPeak1SpecFlat, posPeak2SpecFlat, posPeak1SpecDiff, posPeak2SpecDiff;
	float fluctLrt, avgHistLrt, avgSquareHistLrt, avgHistLrtCompl;

	// 定义三个特征:长时平均比(LRT)、平坦度(flatness)和差异(difference)。
	// lrt_feature = self->featureData[3];
	// flat_feature = self->featureData[0];
	// diff_feature = self->featureData[4];

	// 更新直方图。
	if (flag == 0) {
		// 长时平均比(LRT)
		if ((self->featureData[3] <
			HIST_PAR_EST * self->featureExtractionParams.binSizeLrt) &&
			(self->featureData[3] >= 0.0)) {
			i = (int)(self->featureData[3] /
				self->featureExtractionParams.binSizeLrt);
			self->histLrt[i]++;
		}
		// 频谱平坦度
		if ((self->featureData[0] <
			HIST_PAR_EST * self->featureExtractionParams.binSizeSpecFlat) &&
			(self->featureData[0] >= 0.0)) {
			i = (int)(self->featureData[0] /
				self->featureExtractionParams.binSizeSpecFlat);
			self->histSpecFlat[i]++;
		}
		// 频谱差异
		if ((self->featureData[4] <
			HIST_PAR_EST * self->featureExtractionParams.binSizeSpecDiff) &&
			(self->featureData[4] >= 0.0)) {
			i = (int)(self->featureData[4] /
				self->featureExtractionParams.binSizeSpecDiff);
			self->histSpecDiff[i]++;
		}
	}

	// 如果flag为1,则执行参数提取操作。
	if (flag == 1) {
		// 初始化局部变量
		avgHistLrt = 0;
		avgHistLrtCompl = 0;
		avgSquareHistLrt = 0;
		numHistLrt = 0;
		// 计算直方图的平均值和方差
		for (i = 0; i < HIST_PAR_EST; i++) {
			binMid = ((float)i + 0.5f) * self->featureExtractionParams.binSizeLrt;
			if (binMid <= self->featureExtractionParams.rangeAvgHistLrt) {
				avgHistLrt += self->histLrt[i] * binMid;
				numHistLrt += self->histLrt[i];
			}
			avgSquareHistLrt += self->histLrt[i] * binMid * binMid;
			avgHistLrtCompl += self->histLrt[i] * binMid;
		}
		// 计算平均值
		if (numHistLrt > 0) {
			avgHistLrt = avgHistLrt / ((float)numHistLrt);
		}
		avgHistLrtCompl = avgHistLrtCompl / ((float)self->modelUpdatePars[1]);
		avgSquareHistLrt = avgSquareHistLrt / ((float)self->modelUpdatePars[1]);
		fluctLrt = avgSquareHistLrt - avgHistLrt * avgHistLrtCompl;
		// 计算LRT特征的阈值
		if (fluctLrt < self->featureExtractionParams.thresFluctLrt) {
			// 如果波动很小,认为是噪声
			self->priorModelPars[0] = self->featureExtractionParams.maxLrt;
		}
		else {
			self->priorModelPars[0] =
				self->featureExtractionParams.factor1ModelPars * avgHistLrt;
			// 检查值是否在最小和最大范围内
			if (self->priorModelPars[0] < self->featureExtractionParams.minLrt) {
				self->priorModelPars[0] = self->featureExtractionParams.minLrt;
			}
			if (self->priorModelPars[0] > self->featureExtractionParams.maxLrt) {
				self->priorModelPars[0] = self->featureExtractionParams.maxLrt;
			}
		}
		// 完成LRT特征的处理

		// 对于频谱平坦度和频谱差异,计算直方图的主要峰值。
		maxPeak1 = 0;
		maxPeak2 = 0;
		posPeak1SpecFlat = 0;
		posPeak2SpecFlat = 0;
		weightPeak1SpecFlat = 0;
		weightPeak2SpecFlat = 0;

		// 计算平坦度的峰值
		for (i = 0; i < HIST_PAR_EST; i++) {
			binMid = (i + 0.5f) * self->featureExtractionParams.binSizeSpecFlat;
			if (self->histSpecFlat[i] > maxPeak1) {
				// 发现新的“第一”峰值
				maxPeak2 = maxPeak1;
				weightPeak2SpecFlat = weightPeak1SpecFlat;
				posPeak2SpecFlat = posPeak1SpecFlat;

				maxPeak1 = self->histSpecFlat[i];
				weightPeak1SpecFlat = self->histSpecFlat[i];
				posPeak1SpecFlat = binMid;
			}
			else if (self->histSpecFlat[i] > maxPeak2) {
				// 发现新的“第二”峰值
				maxPeak2 = self->histSpecFlat[i];
				weightPeak2SpecFlat = self->histSpecFlat[i];
				posPeak2SpecFlat = binMid;
			}
		}

		// 对于频谱差异也是同样的计算过程
		maxPeak1 = 0;
		maxPeak2 = 0;
		posPeak1SpecDiff = 0;
		posPeak2SpecDiff = 0;
		weightPeak1SpecDiff = 0;
		weightPeak2SpecDiff = 0;
		for (i = 0; i < HIST_PAR_EST; i++) {
			binMid =
				((float)i + 0.5f) * self->featureExtractionParams.binSizeSpecDiff;
			if (self->histSpecDiff[i] > maxPeak1) {
				// 同上,寻找“第一”和“第二”峰值
				maxPeak2 = maxPeak1;
				weightPeak2SpecDiff = weightPeak1SpecDiff;
				posPeak2SpecDiff = posPeak1SpecDiff;

				maxPeak1 = self->histSpecDiff[i];
				weightPeak1SpecDiff = self->histSpecDiff[i];
				posPeak1SpecDiff = binMid;
			}
			else if (self->histSpecDiff[i] > maxPeak2) {
				maxPeak2 = self->histSpecDiff[i];
				weightPeak2SpecDiff = self->histSpecDiff[i];
				posPeak2SpecDiff = binMid;
			}
		}

		// 对于频谱平坦度特征的处理
		useFeatureSpecFlat = 1;
		// 如果两个峰值很接近,则合并这两个峰值
		if ((fabsf(posPeak2SpecFlat - posPeak1SpecFlat) <
			self->featureExtractionParams.limitPeakSpacingSpecFlat) &&
			(weightPeak2SpecFlat >
				self->featureExtractionParams.limitPeakWeightsSpecFlat *
				weightPeak1SpecFlat)) {
			weightPeak1SpecFlat += weightPeak2SpecFlat;
			posPeak1SpecFlat = 0.5f * (posPeak1SpecFlat + posPeak2SpecFlat);
		}
		// 如果峰值的权重不够大,或峰值太小,则不使用此特征
		if (weightPeak1SpecFlat <
			self->featureExtractionParams.thresWeightSpecFlat ||
			posPeak1SpecFlat < self->featureExtractionParams.thresPosSpecFlat) {
			useFeatureSpecFlat = 0;
		}
		// 如果选中了此特征,计算阈值
		if (useFeatureSpecFlat == 1) {
			self->priorModelPars[1] =
				self->featureExtractionParams.factor2ModelPars * posPeak1SpecFlat;
			// 检查值是否在最小和最大范围内
			if (self->priorModelPars[1] < self->featureExtractionParams.minSpecFlat) {
				self->priorModelPars[1] = self->featureExtractionParams.minSpecFlat;
			}
			if (self->priorModelPars[1] > self->featureExtractionParams.maxSpecFlat) {
				self->priorModelPars[1] = self->featureExtractionParams.maxSpecFlat;
			}
		}
		// 完成平坦度特征的处理

		// 对于频谱差异特征的处理
		useFeatureSpecDiff = 1;
		// 如果两个峰值很接近,也合并这两个峰值
		if ((fabsf(posPeak2SpecDiff - posPeak1SpecDiff) <
			self->featureExtractionParams.limitPeakSpacingSpecDiff) &&
			(weightPeak2SpecDiff >
				self->featureExtractionParams.limitPeakWeightsSpecDiff *
				weightPeak1SpecDiff)) {
			weightPeak1SpecDiff += weightPeak2SpecDiff;
			posPeak1SpecDiff = 0.5f * (posPeak1SpecDiff + posPeak2SpecDiff);
		}
		// 计算阈值
		self->priorModelPars[3] =
			self->featureExtractionParams.factor1ModelPars * posPeak1SpecDiff;
		// 如果峰值的权重不够大,则不使用此特征
		if (weightPeak1SpecDiff <
			self->featureExtractionParams.thresWeightSpecDiff) {
			useFeatureSpecDiff = 0;
		}
		// 检查值是否在最小和最大范围内
		if (self->priorModelPars[3] < self->featureExtractionParams.minSpecDiff) {
			self->priorModelPars[3] = self->featureExtractionParams.minSpecDiff;
		}
		if (self->priorModelPars[3] > self->featureExtractionParams.maxSpecDiff) {
			self->priorModelPars[3] = self->featureExtractionParams.maxSpecDiff;
		}
		// 完成频谱差异特征的处理

		// 如果LRT特征的波动很小,大概率只是噪声状态,不使用频谱差异特征
		if (fluctLrt < self->featureExtractionParams.thresFluctLrt) {
			useFeatureSpecDiff = 0;
		}

		// 选择各特征之间的权重
		featureSum = (float)(1 + useFeatureSpecFlat + useFeatureSpecDiff);
		self->priorModelPars[4] = 1.f / featureSum;  // LRT特征的权重
		self->priorModelPars[5] = ((float)useFeatureSpecFlat) * self->priorModelPars[4];  // 频谱平坦度特征的权重
		self->priorModelPars[6] = ((float)useFeatureSpecDiff) * self->priorModelPars[4];  // 频谱差异特征的权重

		// 为下一次更新将直方图清零
		if (self->modelUpdatePars[0] >= 1) {
			for (i = 0; i < HIST_PAR_EST; i++) {
				self->histLrt[i] = 0;
				self->histSpecFlat[i] = 0;
				self->histSpecDiff[i] = 0;
			}
		}
	}  // flag == 1的处理结束。
}

计算输入频谱的频谱平坦度

// magnIn 是幅度谱。
// 频谱平坦度结果存储在 self->featureData[0] 中。
static void ComputeSpectralFlatness(NoiseSuppressionC *self,
	const float *magnIn, const float *logmagnIn) {
	size_t i;
	size_t shiftLP = 1;  // 用于从频谱计算中移除第一个bin(或多个bin)的选项。
	float avgSpectralFlatnessNum, avgSpectralFlatnessDen, spectralTmp;

	// 计算频谱指标。
	// 对于平坦度。
	avgSpectralFlatnessNum = 0;
	avgSpectralFlatnessDen = self->sumMagn;

	// 从频谱指标中移除前 shiftLP 个bin的影响。
	for (i = 0; i < shiftLP; i++) {
		avgSpectralFlatnessDen -= magnIn[i];
	}

	// 计算几何平均数与算术平均数之比的对数:检查 log(0) 的情况。
	for (i = shiftLP; i < self->magnLen; i++) {
		if (magnIn[i] > 0.0) {
			avgSpectralFlatnessNum += logmagnIn[i];
		}
		else {
			// 如果某个频率分量的幅度为零,更新频谱平坦度特征,并返回。
			self->featureData[0] -= SPECT_FL_TAVG * self->featureData[0];
			return;
		}
	}

	// 归一化。
	avgSpectralFlatnessDen = avgSpectralFlatnessDen * self->normMagnLen;
	avgSpectralFlatnessNum = avgSpectralFlatnessNum * self->normMagnLen;

	// 计算比值和对数的逆:检查 log(0) 的情况。
	spectralTmp = expf(avgSpectralFlatnessNum) / avgSpectralFlatnessDen;

	// 频谱平坦度特征的时间平均更新。
	self->featureData[0] += SPECT_FL_TAVG * (spectralTmp - self->featureData[0]);
	// 完成平坦度特征的计算。
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值