如何在Python中计算波形声音文件的逆?

发布于 2025-01-16 18:32:06 字数 1453 浏览 3 评论 0原文

我正在尝试使用 Python 计算 16 位单声道波形文件(8000Hz)的逆,而不使用几乎任何外部模块,除了用于从波形文件读取样本的 wave 之外。我尝试读取所有 16 位样本并计算每个样本的 0xFFFF - 样本并将其写入另一个波形文件。但是当我将两个音频文件混合在一起时,它们不会彼此静音。我在互联网上读过一些关于 DFT、FFT 等的内容,但即使我有很强的高中数学背景,但我对它们的理解并不多。任何提示表示赞赏。我的代码:

import wave
from dataclasses import dataclass
from typing import List


@dataclass
class SoundClip16b:
    data: List["int"]

    def __len__(self):
        return len(self.data)

    def inverted(self):
        inv = list()
        for d in self.data:
            inv.append(0xFFFF - d)
        return SoundClip16b(data=inv)

    def to_bytes(self):
        databyte = b""
        for i in self.data:
            b1 = i >> 8
            b2 = i & 0xFF
            databyte += bytes([b1, b2])
        return databyte

    @staticmethod
    def from_bytes(bytedata):
        data = list()
        for index, byte in enumerate(bytedata[:-1:2]):
            next_byte = bytedata[index+1]
            data.append((byte << 8) + next_byte)

        return SoundClip16b(data=data)


w_noise = wave.open("noise.wav")
w_antinoise = wave.open("antinoise.wav", "w")
clip = SoundClip16b.from_bytes(w_noise.readframes(-1))
inverted_clip = clip.inverted()
w_antinoise.setnchannels(1)
w_antinoise.setsampwidth(2)
w_antinoise.setframerate(8000)
w_antinoise.writeframes(inverted_clip.to_bytes())
w_antinoise.close()

编辑:我也尝试过假设 16 位样本是有符号整数而不是无符号整数。

I am trying to compute inverse of a 16 bit mono wave file(8000Hz) using Python without using almost any external module except wave which is used to read samples from the wave file. I've tried reading all the 16 bit samples and computing 0xFFFF - sample for each sample and writing that to another wave file. But when I mix the two audio files together, they don't silence each other. I've read some stuff on the internet about DFT, FFT and such these but I don't understand much from them even through I've got a strong mathematics background from highschool. Any hint is appreciated. My code:

import wave
from dataclasses import dataclass
from typing import List


@dataclass
class SoundClip16b:
    data: List["int"]

    def __len__(self):
        return len(self.data)

    def inverted(self):
        inv = list()
        for d in self.data:
            inv.append(0xFFFF - d)
        return SoundClip16b(data=inv)

    def to_bytes(self):
        databyte = b""
        for i in self.data:
            b1 = i >> 8
            b2 = i & 0xFF
            databyte += bytes([b1, b2])
        return databyte

    @staticmethod
    def from_bytes(bytedata):
        data = list()
        for index, byte in enumerate(bytedata[:-1:2]):
            next_byte = bytedata[index+1]
            data.append((byte << 8) + next_byte)

        return SoundClip16b(data=data)


w_noise = wave.open("noise.wav")
w_antinoise = wave.open("antinoise.wav", "w")
clip = SoundClip16b.from_bytes(w_noise.readframes(-1))
inverted_clip = clip.inverted()
w_antinoise.setnchannels(1)
w_antinoise.setsampwidth(2)
w_antinoise.setframerate(8000)
w_antinoise.writeframes(inverted_clip.to_bytes())
w_antinoise.close()

Edit: I also have tried by assuming that the 16 bit samples are signed integers rather than unsigned ones.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

蓝海 2025-01-23 18:32:06

感谢 Jan,问题出在字节顺序上。波是小端字节序,而我的代码假设它是大端字节序。这段代码对我有用:

import wave
import struct
from dataclasses import dataclass
from typing import List


@dataclass
class SoundClip16b:
    data: List["int"]

    def __len__(self):
        return len(self.data)

    def inverted(self):
        inv = list()
        for d in self.data:
            inv.append(~d)
        return SoundClip16b(data=inv)

    def to_bytes(self):
        databyte = b""
        for d in self.data:
            databyte += struct.pack("<h", d)
        return databyte

    @staticmethod
    def from_bytes(bytedata):
        return SoundClip16b(
            data=[x[0] for x in struct.iter_unpack("<h", bytedata)]
        )


w_noise = wave.open("noise.wav")
w_antinoise = wave.open("antinoise.wav", "w")
clip = SoundClip16b.from_bytes(w_noise.readframes(-1))
inverted_clip = clip.inverted()
w_antinoise.setnchannels(1)
w_antinoise.setsampwidth(2)
w_antinoise.setframerate(8000)
w_antinoise.writeframes(inverted_clip.to_bytes())
w_antinoise.close()

Thanks to Jan, the problem was with endianess. The wave was little endian while my code was assuming it was big endian. This code worked for me right:

import wave
import struct
from dataclasses import dataclass
from typing import List


@dataclass
class SoundClip16b:
    data: List["int"]

    def __len__(self):
        return len(self.data)

    def inverted(self):
        inv = list()
        for d in self.data:
            inv.append(~d)
        return SoundClip16b(data=inv)

    def to_bytes(self):
        databyte = b""
        for d in self.data:
            databyte += struct.pack("<h", d)
        return databyte

    @staticmethod
    def from_bytes(bytedata):
        return SoundClip16b(
            data=[x[0] for x in struct.iter_unpack("<h", bytedata)]
        )


w_noise = wave.open("noise.wav")
w_antinoise = wave.open("antinoise.wav", "w")
clip = SoundClip16b.from_bytes(w_noise.readframes(-1))
inverted_clip = clip.inverted()
w_antinoise.setnchannels(1)
w_antinoise.setsampwidth(2)
w_antinoise.setframerate(8000)
w_antinoise.writeframes(inverted_clip.to_bytes())
w_antinoise.close()
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文