Python 实现简单音频数据压缩与解压算法

发布于:2025-02-26 ⋅ 阅读:(14) ⋅ 点赞:(0)

在数字信号处理中,压缩技术被广泛应用于减少文件大小或传输带宽。对于音频数据而言,通常会使用复杂的压缩算法如MP3、AAC等,但这些算法往往需要专门的库和对底层原理的理解。在这篇博客中,我们将探索一种简单的自定义压缩方法,并用Python实现它。

简介

我们所要介绍的压缩算法基于两种模式:“range”模式和“hold”模式。“range”模式用于连续递增的序列,“hold”模式则适用于重复值序列。通过识别这两种模式,我们可以将原始数据集压缩成更紧凑的形式,从而节省存储空间或提高传输效率。

压缩算法实现

首先,我们定义了一个compress_audio函数来执行实际的压缩操作。该函数接受一个整数列表作为输入,这个列表可以看作是未经压缩的音频样本数据。然后,它遍历整个列表,尝试找到最长的“range”或“hold”模式,并将匹配的结果以字符串形式添加到新的列表中。如果既不符合“range”也不符合“hold”,那么就直接添加原始数值。

def compress_audio(data):
    compressed = []
    i = 0
    
    while i < len(data):
        # 尝试匹配range模式(连续递增序列)
        range_start = i
        while i+1 < len(data) and data[i+1] == data[i] + 1:
            i += 1
        range_len = i - range_start + 1
        
        # 尝试匹配hold模式(重复值序列)
        hold_start = range_start
        while hold_start+1 < len(data) and data[hold_start+1] == data[hold_start]:
            hold_start += 1
        hold_len = hold_start - range_start + 1

        # 选择更长的压缩模式
        if range_len >= hold_len and range_len > 1:
            compressed.append(f"range({data[range_start]}, {data[i]})")
            i += 1
        elif hold_len > 1:
            compressed.append(f"hold({data[range_start]}, {hold_len})")
            i = range_start + hold_len
        else:
            compressed.append(str(data[range_start]))
            i = range_start + 1

    return compressed

解压缩算法实现

为了能够还原原始的数据,我们需要相应的解压缩逻辑。这里,decompress_audio函数根据之前保存的模式信息重新生成原始的音频样本数据。

def decompress_audio(compressed):
    data = []
    for token in compressed:
        if token.startswith("range"):
            _, params = token.split("(")
            start, end = map(int, params[:-1].split(","))
            data.extend(range(start, end+1))  # 包含结束值
        elif token.startswith("hold"):
            _, params = token.split("(")
            val, count = map(int, params[:-1].split(","))
            data.extend([val]*count)
        else:
            data.append(int(token))
    return data

示例演示

让我们来看一下如何使用这两个函数:

original = [1,23,24,25,0,0,0,2,3,7,5,6]
compressed = compress_audio(original)
print("压缩结果:", compressed)
# 输出:['1', 'range(23, 25)', 'hold(0, 3)', 'range(2, 3)', '7', 'range(5, 6)']

decompressed = decompress_audio(compressed)
print("解压验证:", decompressed == original)  # 输出:True

这段代码展示了我们的压缩算法是如何工作的,并且证明了它可以正确地压缩和解压缩数据。

结论

虽然这种简单的压缩方法可能不适用于高保真的音频文件,但它提供了一种基础的思路,帮助理解数据压缩的基本概念。如果你有兴趣进一步探索,可以考虑研究诸如pydub这样的Python库,它们提供了更加复杂和高效的音频处理功能。此外,了解像量化和编码这样的基本音频压缩原理也是非常有帮助的。希望这篇博客能激发你对音频处理领域的兴趣,并鼓励你进行更深入的学习。

完整代码

def compress_audio(data):
    compressed = []
    i = 0
    
    while i < len(data):
        # 尝试匹配range模式(连续递增序列)
        range_start = i
        while i+1 < len(data) and data[i+1] == data[i] + 1:
            i += 1
        range_len = i - range_start + 1
        
        # 尝试匹配hold模式(重复值序列)
        hold_start = range_start
        while hold_start+1 < len(data) and data[hold_start+1] == data[hold_start]:
            hold_start += 1
        hold_len = hold_start - range_start + 1

        # 选择更长的压缩模式
        if range_len >= hold_len and range_len > 1:
            compressed.append(f"range({data[range_start]}, {data[i]})")
            i += 1
        elif hold_len > 1:
            compressed.append(f"hold({data[range_start]}, {hold_len})")
            i = range_start + hold_len
        else:
            compressed.append(str(data[range_start]))
            i = range_start + 1

    return compressed

def decompress_audio(compressed):
    data = []
    for token in compressed:
        if token.startswith("range"):
            _, params = token.split("(")
            start, end = map(int, params[:-1].split(","))
            data.extend(range(start, end+1))  # 包含结束值
        elif token.startswith("hold"):
            _, params = token.split("(")
            val, count = map(int, params[:-1].split(","))
            data.extend([val]*count)
        else:
            data.append(int(token))
    return data

# 使用示例
original = [1,23,24,25,0,0,0,2,3,7,5,6]
compressed = compress_audio(original)
print("压缩结果:", compressed)
# 输出:['1', 'range(23, 25)', 'hold(0, 3)', 'range(2, 3)', '7', 'range(5, 6)']

decompressed = decompress_audio(compressed)
print("解压验证:", decompressed == original)  # 输出:True