【问题标题】:WAV file modifier using Python使用 Python 的 WAV 文件修饰符
【发布时间】:2015-11-23 07:26:45
【问题描述】:

我编写了一个简单的 Python 程序来读取波形文件,并在更改后将其存储为新文件。

import codecs, wave

#convert a number to its two's complemented value (For positive it is equal itself)
def convert_to_twos(value, wid_len=16):
    if value < 0 :
        value = value + (1 << wid_len)
    return value

#receive the value of a two's complemented number.
def twos_back_value(value, wid_len=16):
    if value & (1 << wid_len -1):
        value = value - (1 << wid_len)
    return value

#opening files
input_file = wave.open(r"<address of input wave file>", 'r')
output_file = wave.open(r"<an address for output wave file>", 'w')

#Get input file parameters and set them to the output file after modifing the channel number.
out_params = [None, None, None, None, None, None]
in_params = input_file.getparams()
out_params[0] = 1 # I want to have a mono type wave file in output. so I set the channels = 1
out_params[1] = in_params[1] #Frame Width
out_params[2] = in_params[2] #Sample Rate
out_params[3] = in_params[3] #Number of Frames
out_params[4] = in_params[4] #Type
out_params[5] = in_params[5] #Compressed or not
output_file.setparams(out_params)

#reading frames from first file and storing in the second file
for frame in range(out_params[2]):
    value = int(codecs.getencoder('hex')(input_file.readframes(1))[0][:4], 16) #converting first two bytes of each frame (let assume each channel has two bytes frame length) to int (from byte string).
    t_back_value = twos_back_value( value ,out_params[1]*8)
    new_value = int(t_back_value * 1)
    new_twos = convert_to_twos(new_value, out_params[1]*8)
    to_write = new_twos.to_bytes((new_twos.bit_length() + 7) // 8, 'big')
    output_file.writeframes(to_write)


#closing files
input_file.close()
output_file.close()

问题是当我运行上面的程序并播放输出文件时,我只能听到噪音,没有其他声音! (虽然我希望同一个文件只在一个通道模式下!)

更新:

我得到了一些奇怪的东西。根据文档,函数readframes(n) 读取并返回最多 n 帧音频,作为字节字符串。所以我希望这个函数只返回十六进制值。但实际上我可以看到一些奇怪的非十六进制值:

read_frame = input_file.readframes(1)
print (read_frame)
print (codecs.getencoder('hex')(read_frame)[0])
print ("")

以上代码,在 for 循环中返回:

b'\xe3\x00\xc7\xf5'
b'e300c7f5'

b'D\xe8\xa1\xfd'
b'44e8a1fd'

b'\xde\x08\xb2\x1c'
b'de08b21c'

b'\x17\xea\x10\xe9'
b'17ea10e9'

b'{\xf7\xbc\xf5'
b'7bf7bcf5'

b'*\xf6K\x08'
b'2af64b08'

如您所见,read_frame! 中有一些非十六进制值! (*, }, D, ... 例如)。这些是什么?

【问题讨论】:

  • 您要对 WAV 文件进行哪些修改?即对于每一帧,输出应该是什么?
  • @MartinEvans 我想更改 WAV 文件的 RMS(均方根)。这是一个心理学实验项目的一部分。例如,我想要一个新版本的先前文件,其 RMS 是第一个文件的一半。
  • @MartinEvans 请检查更新。

标签: python python-3.x mono wav wave


【解决方案1】:

您看到的值是每个帧的四个字节,即第一个通道的两个字节和第二个通道的两个字节。对于单声道 WAV,您只会看到两个字节。

以下方法应该让您走上正确的道路。您需要使用 Python 的 struct 库将二进制帧值转换为有符号整数。然后,您可以根据需要操作它们。对于我的示例,我只是乘以 2/3:

import wave
import codecs
import struct

#opening files
input_file = wave.open(r"sample.wav", 'rb')
output_file = wave.open(r"sample_out.wav", 'wb')

#Get input file parameters and set them to the output file after modifing the channel number.
in_params = list(input_file.getparams())

out_params = in_params[:]
out_params[0] = 1
output_file.setparams(out_params)

nchannels, sampwidth, framerate, nframes, comptype, compname = in_params
format = '<{}h'.format(nchannels)

#reading frames from first file and storing in the second file
for index in range(nframes):
    frame = input_file.readframes(1)
    data = struct.unpack(format, frame)
    value = data[0]     # first (left) channel only
    value = (value * 2) // 3    # apply a simple function to each value
    output_file.writeframes(struct.pack('<h', value))

#closing files
input_file.close()
output_file.close()

请注意,像这样一次处理一帧波形文件会非常缓慢。可以通过减少对writeframes 的调用次数来加快速度。

format 保存解压二进制值所需的格式。对于 2 通道 WAV 文件,这将包含 4 个字节。然后format 将被配置为&lt;hh,这意味着使用struct.unpack 将产生两个字段,每个字段都包含每个通道的整数表示。所以四个字节变成了两个整数的列表,每个通道一个。

【讨论】:

  • 谢谢你亲爱的马丁,但你试过了吗?不幸的是,我仍然有嘈杂的输出。我的意思是我只能听到噪音! (输入文件没问题)
  • 是的,我在立体声 WAV 文件上进行了测试。它产生了一个振幅降低的单声道 WAV 文件。文件大小减半。我还重现了你的版本所产生的噪音。
  • 如果我用一个短数字替换nframe 来测试程序会不会有问题?(例如100,000)。在for 循环和out_params 变量中。
  • 我刚试过nframes // 3,效果很好。
  • data[0] 已经保存了第一个通道的两个字节。 struct.unpack 做到了。
猜你喜欢
  • 1970-01-01
  • 2022-06-16
  • 1970-01-01
  • 2014-09-15
  • 2011-07-08
  • 2022-05-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多