librosa 的使用

音频质量的评估
音频质量的评估通常涉及到信号的各种属性,包括信噪比、失真度、频率响应等。

在处理连续的音频信号时,直接对整个音频文件进行分析往往难以捕捉到局部细节和瞬态特征,特别是对于非稳态的语音和音乐信号。

分帧处理音频的主要原因有以下几点:

  1. 短时平稳性:声音信号在较短的时间尺度上可以认为是平稳或近似平稳的,而在长时间尺度上则表现出非平稳特性。

例如,在语音信号中,单个音素或音节在短时间内具有相对稳定的频谱结构。通过将音频分割成短时间窗(即帧),

我们可以针对每一帧独立地计算其声学特征,这些特征更稳定且具有实际意义。

  1. 重叠窗口平滑过渡:相邻帧之间采用一定的重叠量(帧移小于帧长的一半),这样可以确保在帧边界处特征参数的连续性和稳定性,

避免了由于帧间切换导致的不连续性问题。

  1. 降低计算复杂度:实时处理和分析大型音频文件时,一次性加载整个文件并进行处理可能会消耗大量的内存和计算资源。

而分帧处理允许我们在有限的计算能力下高效地提取和分析特征。

  1. 适应多种算法需求:许多音频处理和分析技术,如MFCC(梅尔频率倒谱系数)、LPC(线性预测编码)以及噪声抑制、回声消除等,都依赖于短时分析的结果。

这些算法通常应用于分帧后的信号片段。

因此,为了准确评估音频质量和有效应用各种音频处理算法,音频信号被分成一个个小的帧进行处理是音频信号处理领域中的标准做法。

帧时长
librosa.feature.mfcc函数用于计算MFCC(梅尔频率倒谱系数)

帧的时长(每帧多少秒)并不直接由mfcc函数决定,而是在处理音频信号分帧阶段确定。

帧长度(frame_length)和帧移(hop_length)是通过不同的参数配置的,例如:

  • n_fft: 表示FFT(快速傅里叶变换)的窗口大小,它通常用来设置帧的长度。默认情况下,如果未指定帧长度,则帧的大小为n_fft个采样点。

  • hop_length: 指定帧与帧之间的重叠数量,也就是帧移。它决定了连续帧开始点之间的距离(以采样点为单位)。

要计算每帧对应的秒数,你可以使用以下公式:

frame_duration_seconds = n_fft / sr # 其中sr是采样率(samples per second)

举例来说,如果采样率为22050Hz,n_fft设置为2048,则一帧的时长大约为:

frame_duration_seconds = 2048 / 22050 ≈ 0.0926秒

要调整帧移对应的秒数,同样可以计算:

hop_duration_seconds = hop_length / sr

获取音频的质量每帧时长多少合适

音频质量评估和帧时长的选择是两个不同的概念,但它们在音频处理中相互关联。

音频质量评估

音频质量评估通常与信号的保真度、清晰度、噪声水平等因素有关,这些因素并不直接依赖于帧时长。音频质量可以通过客观指标(如信噪比SNR、失真度、频谱平坦度等)或主观听感测试来评估。

帧时长的选择

在进行音频信号处理,特别是特征提取和语音识别等相关任务时,通常会对音频信号进行分帧操作。帧时长的选择一般基于音频信号的短时平稳性原则,即假设在较短的时间窗口内信号可以被视为相对平稳的。

对于语音信号来说,常见的帧长选择范围为20毫秒至40毫秒,这是因为语音信号在这样时间段内的频率内容相对稳定。例如,一个采样率为16kHz的音频,每帧的样本数大约为320至640个样本(16000 samples/sec * 0.02 sec = 320 samples/frame 或者 16000 samples/sec * 0.04 sec = 640 samples/frame)。

帧长度的选择还会考虑重叠率(hop_length),以确保相邻帧之间有足够的信息重叠,以便平滑地计算连续帧间的参数变化。常用的重叠比例为50%到75%,这有助于保留时间上的连续性。

因此,在选择音频帧时长时,应综合考虑所使用的算法需求、信号本身的特性以及硬件/软件系统的实时处理能力。而对于音频质量的评估,帧时长只是一个实现高质量分析的辅助参数,并非决定音频质量本身的因素。

过零率
过零率(Zero Crossing Rate, ZCR)是音频信号分析中的一个基本特征,它表示单位时间内信号穿越零点的次数。过零率可以反映信号的变化速率和瞬态特性,但直接基于过零率来计算信噪比(Signal-to-Noise Ratio, SNR)并不常见。

信噪比通常是衡量原始信号与噪声之间强度关系的一个量化指标,通常定义为信号功率与噪声功率之比的对数形式:


SNR = 10 * log_{10} \left( \frac{P_{signal}}{P_{noise}} \right)

这里,P_signal 是信号的功率,P_noise 是噪声的功率。

要准确计算信噪比,需要对信号和噪声进行明确区分或估计。在实际应用中,我们可能会通过频域分析、谱减法或者基于某些假设下的统计模型来估计噪声和信号分量。

然而,过零率可以在一定程度上用于预处理阶段,例如作为语音活动检测(Voice Activity Detection, VAD)的一种特征,帮助识别出可能存在语音信号的时间段,

进而在这个基础上分离并计算信噪比。

但单纯依据过零率无法直接得到信噪比的具体数值。

过零率(ZCR)通常用于检测信号的变化程度或区分不同类型的音频内容,但直接计算信噪比(SNR)时并不基于过零率。信噪比的计算需要明确的信号和噪声功率估计。

不过,虽然过零率不能直接用来计算信噪比,但可以结合其他方法来辅助进行噪声抑制或者语音活动检测(VAD),进而间接地分析信噪比。以下是一个简化的流程示例,说明如何使用过零率作为预处理步骤来确定可能包含有效信号的时间段,然后在这些时间段内估计信噪比:


# 假设我们已经有了一个音频信号x,并且已经进行了分帧处理

import numpy as np

# 计算过零率

def zero_crossing_rate(x):

    x_diff = np.diff(np.sign(x))

    zcr = len(np.where(x_diff != 0)[0]) / (len(x) - 1)

    return zcr

# 分帧并计算每一帧的过零率

frame_length = ... # 设置帧长

hop_length = ... # 设置帧移

frames = librosa.util.frame(x, frame_length=frame_length, hop_length=hop_length)

zcrs = [zero_crossing_rate(frame) for frame in frames]

# 根据过零率筛选出潜在的有效信号帧

valid_frames_indices = np.where(zcrs > threshold_zcr)[0]  # 阈值根据实际情况设置

# 在有效信号帧中估计信号和噪声功率

signal_power = []  # 假定有效信号区域的功率较大

noise_power = []  # 假定非有效信号区域的功率较小,代表噪声

for i in valid_frames_indices:

    frame = frames[i]

    signal_power.append(np.mean(frame ** 2))  # 简化的信号功率计算,实际应用可能更复杂

    noise_power.append(...)  # 这里需要一种方式来估算噪声功率,例如选取过零率低的帧或利用背景噪声模型

# 计算平均信噪比(这里仅做简单示意)

if len(signal_power) > 0 and len(noise_power) > 0:

    average_snr = 10 * np.log10(np.mean(signal_power) / np.mean(noise_power))

else:

    print("无法计算信噪比,缺少足够的数据")

print(f"平均信噪比估计为: {average_snr} dB")

# 实际上,在真实情况下,信噪比计算可能涉及频域分析、谱减法或其他更精确的方法。

请注意上述代码仅为概念演示,并未提供完整的噪声功率估计部分。真实的噪声功率估计会更为复杂,通常需要更详尽的信号处理技术,

例如对静音片段的功率统计、频谱平坦区域的估计等。

评估音频噪声功率
在Python中,评估音频噪声功率通常涉及以下步骤:

  1. 预处理:首先对音频信号进行分帧和加窗处理,以便将连续的音频流分割成短时间片段(帧)。

  2. 计算每帧的能量或功率谱密度(PSD):可以通过计算每帧信号的平方和来估算能量,或者使用快速傅里叶变换(FFT)得到频谱后,计算功率谱密度。

  3. 识别并提取噪声段:可以选择在没有明显语音或目标信号的时间段(如静音区域)来估计噪声功率。这可以通过过零率、幅度阈值、语音活动检测(VAD)等方法实现。

  4. 噪声功率估计:计算所选噪声段的平均功率作为噪声功率估计值。

以下是一个简化的代码示例:


import numpy as np

import librosa

# 加载音频文件

audio, sr = librosa.load('your_audio_file.wav')

# 分帧处理

frame_length = 2048  # 帧长度(以样本点为单位)

hop_length = 512    # 帧移(以样本点为单位)

frames = librosa.util.frame(audio, frame_length=frame_length, hop_length=hop_length)

# 计算每帧的能量

frame_energy = np.sum(frames ** 2, axis=1) / frame_length

# 简单地通过选择能量较小的帧来估计噪声功率

# 实际应用中可能需要更复杂的噪声段识别策略

threshold = np.percentile(frame_energy, 5)  # 设置一个低能量阈值

noise_frames_indices = np.where(frame_energy <= threshold)[0]

# 计算噪声功率

if len(noise_frames_indices) > 0:

    noise_power = np.mean(frame_energy[noise_frames_indices])

else:

    print("无法找到足够的噪声片段来估计噪声功率")

    noise_power = None

print(f"噪声功率估计值: {noise_power:.2f}")

# 如果需要在频域评估噪声功率,则可以先做STFT然后计算功率谱密度

stft = librosa.stft(audio)

psd = np.abs(stft) ** 2

# 对于噪声功率谱密度的估计,请选择合适的频带或整个频谱的一部分

对于实际场景,可能需要根据具体的应用和噪声特性调整噪声段的识别方法以及噪声功率的计算方式。

在Python中,我们可以使用librosa库来获取音频信号的过零率、噪声功率以及通过一定的假设和方法分离出噪声片段和静音片段。以下是一个简化的示例代码:


import librosa

import numpy as np

# 加载音频文件

filename = 'your_audio_file.wav'

y, sr = librosa.load(filename)

# 分帧处理

frame_length = 2048  # 帧长度(以样本点为单位)

hop_length = 512    # 帧移(以样本点为单位)

frames = librosa.util.frame(y, frame_length=frame_length, hop_length=hop_length)

# 计算过零率

zcrs = librosa.feature.zero_crossing_rate(y=y, frame_length=frame_length, hop_length=hop_length)

# 简单地估计噪声片段:这里我们选择能量较低的部分作为噪声候选

energy = librosa.feature.rmse(y=frames)**2  # 计算每帧的均方根能量

threshold = np.percentile(energy, 10)  # 设置一个阈值来区分可能的噪声片段

noise_frames_mask = energy <= threshold

# 计算噪声功率

if np.any(noise_frames_mask):

    noise_power = np.mean(energy[noise_frames_mask])

else:

    print("无法找到足够的噪声片段来估计噪声功率")

    noise_power = None

# 假设剩余部分是信号片段

signal_frames_mask = ~noise_frames_mask

# 计算信号功率

if np.any(signal_frames_mask):

    signal_power = np.mean(energy[signal_frames_mask])

else:

    print("无法找到有效的信号片段")

    signal_power = None

# 计算信噪比 (SNR)

if signal_power is not None and noise_power is not None:

    snr = 10 * np.log10(signal_power / noise_power)

    print(f"信噪比 (SNR): {snr:.2f} dB")

else:

    print("无法计算信噪比")

# 输出噪声片段和静音片段

if noise_frames_mask.any():

    noise_y = y[np.arange(len(y))[np.diff(librosa.util.frame_index_to_samples(np.flatnonzero(noise_frames_mask)))]]

    print("噪声片段: ", noise_y.shape)

else:

    print("未找到明显的噪声片段")

# 输出静音片段通常与噪声片段相同或更宽泛定义,根据应用需求可以调整阈值

silent_y = y[np.arange(len(y))[np.diff(librosa.util.frame_index_to_samples(np.flatnonzero(~signal_frames_mask)))]]

print("静音片段: ", silent_y.shape)

实际应用中噪声识别可能需要更复杂的策略,如基于短时平均幅度谱熵(TSAE)或语音活动检测(VAD)算法等。

此外,在真实场景下,噪声功率的估计往往更加复杂,可能会涉及到频域分析、谱减法或者利用更多的先验知识。

信噪比计算
计算音频中信号、噪声和静音部分的信噪比(Signal-to-Noise Ratio, SNR)通常涉及到对信号和噪声功率进行评估。

在实际应用中,区分信号、噪声和静音并不总是容易的,特别是在没有明确标记的情况下。下面是一个简化的示例,

说明如何使用librosa库对一段混合了信号、噪声和静音的音频片段尝试估算SNR:


import librosa

import numpy as np

# 加载音频文件或读取数据

audio_path = 'path_to_your_audio.wav'

y, sr = librosa.load(audio_path)

# 分帧处理

frame_length = 2048  # 帧长度(以样本点为单位)

hop_length = 512    # 帧移(以样本点为单位)

frames = librosa.util.frame(y, frame_length=frame_length, hop_length=hop_length)

# 计算每帧的能量

energy = librosa.feature.rmse(y=frames)**2  # 计算均方根能量

# 假设低能量段是噪声/静音,高能量段是信号

signal_threshold = np.percentile(energy, 90)  # 设置一个较高的阈值来识别信号

noise_silent_threshold = np.percentile(energy, 10)  # 设置一个较低的阈值来识别可能的噪声/静音

# 简单地将高于阈值的部分视为信号功率,低于噪声阈值的部分视为噪声/静音功率

signal_power = np.mean(energy[energy > signal_threshold])

noise_silent_power = np.mean(energy[energy <= noise_silent_threshold])

# 计算信噪比,这里噪声与静音合并考虑,所以称为"载噪比"

if signal_power != 0:

    snr = 10 * np.log10(signal_power / noise_silent_power)

    print(f"信噪比 (SNR): {snr:.2f} dB")

else:

    print("无法计算信噪比,因为未检测到足够的信号功率")

# 注意:上述方法非常简化,并不适用于所有情况,特别是对于复杂的非平稳信号。

# 在真实场景下,噪声和信号的分离往往需要更复杂的分析方法,如基于VAD(语音活动检测)、谱减法或其他高级信号处理技术。

# 如果要分别计算噪声和静音的功率,可能需要进一步细化算法,例如通过统计分析找出明显的静音区域等。

此代码假设了一个相对简单的模型,即根据能量分布来粗略划分信号、噪声和静音。

在实际情况中,您可能需要根据具体的应用需求采用更精确的方法来区分不同的声音成分。

谱减法
谱减法是一种用于语音信号去噪的常见方法,它通过估计噪声功率谱,并从带噪语音的功率谱中减去噪声功率谱来分离噪声和信号。

在Python中可以使用librosa库等工具实现。以下是一个基于谱减法进行简单噪声与信号分离的示例:


import librosa

import numpy as np

# 加载音频文件(假设第一部分为带噪信号,第二部分为纯噪声样本)

signal_with_noise, sr = librosa.load('path_to_signal_with_noise.wav')

noise_only, _ = librosa.load('path_to_noise_only.wav')

# 分帧处理

frame_length = 2048  # 帧长度(以样本点为单位)

hop_length = 512    # 帧移(以样本点为单位)

# 对带噪信号和噪声单独进行分帧

frames_signal = librosa.util.frame(signal_with_noise, frame_length=frame_length, hop_length=hop_length)

frames_noise = librosa.util.frame(noise_only, frame_length=frame_length, hop_length=hop_length)

# 计算STFT

stft_signal = librosa.stft(frames_signal, n_fft=frame_length)

stft_noise = librosa.stft(frames_noise, n_fft=frame_length)

# 转换到幅度谱并取对数(dB),以便于能量比较

mag_signal = librosa.amplitude_to_db(np.abs(stft_signal), ref=np.max)

mag_noise = librosa.amplitude_to_db(np.abs(stft_noise), ref=np.max)

# 对噪声功率谱做归一化处理

normalized_noise = mag_noise - np.min(mag_noise)

# 谱减法:从信号的幅度谱中减去归一化的噪声幅度谱

# 注意,直接相减可能引入负值,需要处理负值问题(通常采用半波整流或谱平滑技术)

denoised_mag = mag_signal - normalized_noise

denoised_mag[denoised_mag < 0] = 0  # 简单地将负值设为0(可能会导致音乐噪声)

# 将去噪后的幅度谱转换回时域信号

denoised_frames = librosa.db_to_amplitude(denoised_mag) * np.exp(1j * np.angle(stft_signal))

denoised_audio = librosa.istft(denoised_frames)

# 输出去噪后的信号

librosa.output.write_wav('path_to_denoised_signal.wav', denoised_audio, sr)

# 提取原始信号功率与噪声功率,估算信噪比

signal_power = np.mean(librosa.power_to_db(np.abs(stft_signal)**2, ref=np.max))

noise_power = np.mean(librosa.power_to_db(np.abs(stft_noise)**2, ref=np.max))

if noise_power != 0:

    snr = 10 * np.log10(signal_power / noise_power)

    print(f"信噪比 (SNR): {snr:.2f} dB")

else:

    print("无法计算信噪比,因为未检测到足够的噪声功率")

# 上述代码仅展示了基本谱减法的一个简化版本。

# 在实际应用中,可能需要更复杂的预处理步骤,如噪声统计模型更新、谱平滑、防止过减等问题的处理。

请注意,在上述示例中,我们假定已经有了一个纯噪声样本,这在实际场景中并不总是可行。

此外,为了简化,我们采用了直接相减且将负值置零的简单处理方式,这种方法可能导致音乐噪声的问题。

在实际应用中,通常会采用改进的谱减算法,比如最小均方误差短时谱幅度减法(Wiener滤波器)或者基于深度学习的噪声抑制方法。

Wiener滤波器
在Python中,我们可以使用librosa库中的librosa.effects.wiener函数实现基于最小均方误差短时谱幅度减法(Wiener滤波器)的噪声与信号分离。以下是一个示例:


import librosa

# 加载带噪音频文件

noisy_signal, sr = librosa.load('path_to_noisy_signal.wav')

# 分帧处理

frame_length = 2048  # 帧长度(以样本点为单位)

hop_length = 512    # 帧移(以样本点为单位)

frames = librosa.util.frame(noisy_signal, frame_length=frame_length, hop_length=hop_length)

# 对于实际应用,通常需要一个噪声样本或根据静音片段估计噪声功率谱。

# 在此示例中,我们假设已经通过某种方式获取了噪声功率谱的估计值:noise_power_spectrum

# noise_power_spectrum 应该是一个和 frames 形状相同的复数数组,表示噪声的STFT结果。

# 计算Wiener滤波后的信号

denoised_frames = librosa.effects.wiener(frames, noise_power=noise_power_spectrum)

# 将去噪后的帧转换回连续信号

denoised_audio = librosa.istft(denoised_frames)

# 输出去噪后的信号

librosa.output.write_wav('path_to_denoised_signal.wav', denoised_audio, sr)

# 提取原始信号功率与噪声功率,估算信噪比

# 此处省略了计算信号和噪声功率的具体步骤,因为这通常依赖于对信号和噪声明确区分的能力。

# 若已知信号功率为 signal_power,噪声功率为 noise_power:

if noise_power != 0:

    snr = 10 * np.log10(signal_power / noise_power)

    print(f"信噪比 (SNR): {snr:.2f} dB")

else:

    print("无法计算信噪比,因为未检测到足够的噪声功率")

# 注意:在实际应用中,通常难以直接获取噪声功率谱的准确估计值。

# 可能需要通过分析信号中的静音段来估计噪声功率谱,或者利用先进的语音活动检测(VAD)算法识别出语音部分并从非语音部分估计噪声。

在上述代码中,关键步骤是调用librosa.effects.wiener函数进行去噪处理,但这要求提供噪声功率谱的估计。

在没有明确噪声样本的情况下,通常会通过统计分析信号中的背景部分来估计噪声谱。

获取音频的能量阈值,过零率阈值
获取音频的能量阈值和过零率阈值通常是为了实现语音活动检测(Voice Activity Detection, VAD)或其他信号处理任务,例如区分语音和背景噪声、分割音频片段等。这些阈值的选择往往依赖于具体应用场景,因为它们会受到诸多因素的影响,如录音环境、信号质量、噪声类型、采样率以及目标信号特性等。

以下是一个简化的示例说明如何基于librosa库计算能量阈值:


import librosa

# 加载音频文件

audio_path = 'path_to_your_audio_file.wav'

y, sr = librosa.load(audio_path)

# 分帧处理

frame_length = 2048  # 帧长度(以样本点为单位)

hop_length = 512    # 帧移(以样本点为单位)

frames = librosa.util.frame(y, frame_length=frame_length, hop_length=hop_length)

# 计算每帧的能量

energy_frames = librosa.feature.rmse(y=frames)**2  # 计算均方根能量

# 确定能量阈值的一种方法是取能量分布的百分位数

energy_threshold = np.percentile(energy_frames, percentile)  # percentile根据实际情况设置,比如90%代表较高能量段

# 过零率计算

zcrs = librosa.feature.zero_crossing_rate(y=y, frame_length=frame_length, hop_length=hop_length)

# 确定过零率阈值的方法类似

zcr_threshold = np.percentile(zcrs, percentile)  # 根据数据分布设定合适的过零率阈值

# 注意:实际应用中,过零率阈值可能需要结合其他特征一起使用,并且在不同场景下可能有不同的最优阈值。

在实际应用中,确定这些阈值通常需要结合经验或者通过训练数据集来调整优化,以确保在特定应用场景下的有效性和准确性。对于过零率阈值,其合理值取决于信号内容,静音或低能量时的过零率一般较低,而语音或高能量信号则可能会有较高的过零率。同样,能量阈值应能有效地将语音与背景噪声区分开来。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,591评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,448评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,823评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,204评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,228评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,190评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,078评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,923评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,334评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,550评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,727评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,428评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,022评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,672评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,826评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,734评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,619评论 2 354

推荐阅读更多精彩内容