【问题标题】:how to get wav samples from a wav file?如何从 wav 文件中获取 wav 样本?
【发布时间】:2011-03-04 19:09:22
【问题描述】:

我想知道如何从 .wav 文件中获取样本以执行两个 .wav 文件的窗口连接。

谁能告诉我怎么做?

【问题讨论】:

    标签: python wav


    【解决方案1】:

    阅读样本后(例如使用 wave 模块,更多详细信息 here),您可能希望值​​在 -1 和 1 之间缩放(这是音频信号的约定)。

    在这种情况下,您可以添加:

    # scale to -1.0 -- 1.0
    max_nb_bit = float(2**(nb_bits-1))  
    samples = signal_int / (max_nb_bit + 1.0) 
    

    nb_bits 是位深度,signal_int 是整数值。

    【讨论】:

      【解决方案2】:

      这是一个从波形文件中读取样本的函数(用单声道和立体声测试):

      def read_samples(wave_file, nb_frames):
          frame_data = wave_file.readframes(nb_frames)
          if frame_data:
              sample_width = wave_file.getsampwidth()
              nb_samples = len(frame_data) // sample_width
              format = {1:"%db", 2:"<%dh", 4:"<%dl"}[sample_width] % nb_samples
              return struct.unpack(format, frame_data)
          else:
              return ()
      

      这是对多个.wav 文件进行窗口混合或连接的完整脚本。所有输入文件都需要具有相同的参数(通道数和样本宽度)。

      import argparse
      import itertools
      import struct
      import sys
      import wave
      
      def _struct_format(sample_width, nb_samples):
          return {1:"%db", 2:"<%dh", 4:"<%dl"}[sample_width] % nb_samples
      
      def _mix_samples(samples):
          return sum(samples)//len(samples)
      
      def read_samples(wave_file, nb_frames):
          frame_data = wave_file.readframes(nb_frames)
          if frame_data:
              sample_width = wave_file.getsampwidth()
              nb_samples = len(frame_data) // sample_width
              format = _struct_format(sample_width, nb_samples)
              return struct.unpack(format, frame_data)
          else:
              return ()
      
      def write_samples(wave_file, samples, sample_width):
          format = _struct_format(sample_width, len(samples))
          frame_data = struct.pack(format, *samples)
          wave_file.writeframes(frame_data)
      
      def compatible_input_wave_files(input_wave_files):
          nchannels, sampwidth, framerate, nframes, comptype, compname = input_wave_files[0].getparams()
          for input_wave_file in input_wave_files[1:]:
              nc,sw,fr,nf,ct,cn = input_wave_file.getparams()
              if (nc,sw,fr,ct,cn) != (nchannels, sampwidth, framerate, comptype, compname):
                  return False
          return True
      
      def mix_wave_files(output_wave_file, input_wave_files, buffer_size):
          output_wave_file.setparams(input_wave_files[0].getparams())
          sampwidth = input_wave_files[0].getsampwidth()
          max_nb_frames = max([input_wave_file.getnframes() for input_wave_file in input_wave_files])
          for frame_window in xrange(max_nb_frames // buffer_size + 1):
              all_samples = [read_samples(wave_file, buffer_size) for wave_file in input_wave_files]
              mixed_samples = [_mix_samples(samples) for samples in itertools.izip_longest(*all_samples, fillvalue=0)]
              write_samples(output_wave_file, mixed_samples, sampwidth)
      
      def concatenate_wave_files(output_wave_file, input_wave_files, buffer_size):
          output_wave_file.setparams(input_wave_files[0].getparams())
          sampwidth = input_wave_files[0].getsampwidth()
          for input_wave_file in input_wave_files:
              nb_frames = input_wave_file.getnframes()
              for frame_window in xrange(nb_frames // buffer_size + 1):
                  samples = read_samples(input_wave_file, buffer_size)
                  if samples:
                      write_samples(output_wave_file, samples, sampwidth)
      
      def argument_parser():
          parser = argparse.ArgumentParser(description='Mix or concatenate multiple .wav files')
          parser.add_argument('command', choices = ("mix", "concat"), help='command')
          parser.add_argument('output_file', help='ouput .wav file')
          parser.add_argument('input_files', metavar="input_file", help='input .wav files', nargs="+")
          parser.add_argument('--buffer_size', type=int, help='nb of frames to read per iteration', default=1000)
          return parser
      
      if __name__ == '__main__':
          args = argument_parser().parse_args()
      
          input_wave_files = [wave.open(name,"rb") for name in args.input_files]
          if not compatible_input_wave_files(input_wave_files):
              print "ERROR: mixed wave files must have the same params."
              sys.exit(2)
      
          output_wave_file = wave.open(args.output_file, "wb")
          if args.command == "mix":
              mix_wave_files(output_wave_file, input_wave_files, args.buffer_size)
          elif args.command == "concat":
              concatenate_wave_files(output_wave_file, input_wave_files, args.buffer_size)
      
          output_wave_file.close()
          for input_wave_file in input_wave_files:
              input_wave_file.close()
      

      【讨论】:

        【解决方案3】:

        标准库的wave 模块是关键:当然,在代码顶部的import wave 之后,wave.open('the.wav', 'r') 返回一个“wave read”对象,您可以使用.readframes 从中读取帧方法,它返回一个字节字符串,这些字节是样本......无论波形文件具有何种格式(您可以使用.getnchannels方法确定与将帧分解为样本相关的两个参数用于通道数,以及@每个样本的字节数为 987654328@)。

        将字节字符串转换为数值序列的最佳方法是使用array 模块,以及(分别)'B''H''L' 的类型,用于 1、2、4每个样本的字节数(在 Python 的 32 位版本上;您可以使用数组对象的 itemsize 值来仔细检查)。如果您的样本宽度与array 可以提供的不同,则需要对字节字符串进行切片(用值0 的字节适当地填充每个小切片)并改用struct 模块(但这更笨重且更慢,所以如果可以的话,请改用array)。

        【讨论】:

        • 当我尝试 .getsamplewidth 时,它给了我一个值 2,这意味着 2 个字节。当我尝试 .readframes(1) 应该返回 1 帧然后它为我返回,例如“/x03/x16”我猜是 2 个字节,所以这是否意味着 1 帧只有 1 个样本.. getnchannels 有什么用?我想分别从每个帧中取样并用整数表示它们,我该怎么做??
        • @kaki,在每一帧中,每个通道都有第一个样本,然后是每个通道的第二个样本,以此类推。因此,除非您的声音是单声道的,即只有 1 个通道,否则您必须决定如何处理这些通道(跳过除一个之外的所有通道,对它们进行平均,等等)。假设它是 1 通道(单声道),最简单,然后 x = array.array('h', w.getframes(1))x 中为您提供一个数组,其中第一帧(下一帧,如果在循环中)的所有样本作为整数,正如您所说的那样(@ 987654338@,而不是H:他们已签名)。如果立体声,2 个通道,甚至 x 的索引具有例如左声道样本。顺便说一句,小端序。
        • 顺便说一句,ccrma.stanford.edu/courses/422/projects/WaveFormat 上的格式文档不使用“帧”的概念,而是使用“块”和“子块”,但最后当然是相同的东西; -)。
        • @kaki,不客气——但请考虑接受对您有帮助的答案(通过单击 Q 左侧的复选标记大纲),因为这确实是基本的礼仪!跨度>
        • @AlexMartelli 抱歉挖坟,但我正在尝试使用 .readframes(1) 并且我需要它将两个样本分成两个单独的变量(基本上将第一个左侧样本放入变量 X ,并将第一个正确的样本放入变量 Y),但我不知道如何做到这一点,有什么建议吗?
        【解决方案4】:

        您可以使用wave 模块。首先,您应该阅读元数据,例如我们的样本大小或通道数。使用readframes() 方法,您可以读取样本,但只能作为字节字符串。根据样本格式,您必须使用struct.unpack() 将它们转换为样本。

        或者,如果您希望将样本作为浮点数数组,您可以使用 SciPy 的 io.wavfile 模块。

        【讨论】:

        • 你能告诉我如何在不使用 scipy 的情况下将样本作为浮点数数组获取
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-01-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多