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.
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()