def to_file(self, filename, subtype='PCM_U8'): """Save the sound to an audio file. The output format is selected based on the filename extension. For example, "file.wav" saves to WAV format. If the file has no extension, WAV format is used. See the PySoundFile documentation for possible values of 'subtype'. Possible values depend on the output format; if the given value is not supported, the format's default will be used. Special cases: ".lmp" saves the raw lump data, and ".raw" saves the raw sound data.""" format = os.path.splitext(filename)[1][1:].upper() or 'WAV' if format == 'LMP': writefile(filename, self.data) elif format == 'RAW': writefile(filename, self.to_raw()) elif self.format == 3: if check_format(format, subtype): pass elif check_format(format, 'PCM_U8'): subtype = 'PCM_U8' elif check_format(format, 'PCM_S8'): subtype = 'PCM_S8' else: subtype = None # use default for format with SoundFile(filename, 'w', self.sample_rate, 1, subtype, format=format) as file: # convert to signed 16-bit (since SoundFile doesn't directly support 8-bit input) # the result will just be converted back in the file though sound = (np.frombuffer(self.to_raw(), dtype='uint8').astype('int16') - 128) << 8 file.write(sound) else: raise TypeError("audio file export only supported for digitized sounds (format 3)")
def __init__(self, file: str, subtype: str, use_limiter: bool = True, normalize: bool = True): _, file_ext = os.path.splitext(file) file_ext = file_ext[1:].upper() if not sf.check_format(file_ext): raise TypeError(f"{file_ext} format is not supported") if not sf.check_format(file_ext, subtype): raise TypeError( f"{file_ext} format does not have {subtype} subtype") self.file = file self.subtype = subtype self.use_limiter = use_limiter self.normalize = normalize
def __init__(self, output_path, script_path=None, audio_format='wav', subtype=None, scp_sep=' '): self.output_path = output_path self.script_path = script_path self.audio_format = audio_format self.scp_sep = scp_sep assert '.' + self.audio_format in valid_ext if subtype is None: self.subtype = sf.default_subtype(self.audio_format) else: self.subtype = subtype assert sf.check_format(self.audio_format, self.subtype) if not os.path.exists(output_path): os.makedirs(output_path) if script_path is not None: self.f_script = open(script_path, 'w') else: self.f_script = None
def to_file(self, filename, subtype='PCM_U8'): """Save the sound to an audio file. The output format is selected based on the filename extension. For example, "file.wav" saves to WAV format. If the file has no extension, WAV format is used. See the PySoundFile documentation for possible values of 'subtype'. Possible values depend on the output format; if the given value is not supported, the format's default will be used. Special cases: ".lmp" saves the raw lump data, and ".raw" saves the raw sound data.""" format = os.path.splitext(filename)[1][1:].upper() or 'WAV' if format == 'LMP': writefile(filename, self.data) elif format == 'RAW': writefile(filename, self.to_raw()) elif self.format == 3: if check_format(format, subtype): pass elif check_format(format, 'PCM_U8'): subtype = 'PCM_U8' elif check_format(format, 'PCM_S8'): subtype = 'PCM_S8' else: subtype = None # use default for format with SoundFile(filename, 'w', self.sample_rate, 1, subtype, format=format) as file: # convert to signed 16-bit (since SoundFile doesn't directly support 8-bit input) # the result will just be converted back in the file though sound = (np.frombuffer( self.to_raw(), dtype='uint8').astype('int16') - 128) << 8 file.write(sound) else: raise TypeError( "audio file export only supported for digitized sounds (format 3)" )
def main(): carrier = 'anechoic.wav' carrier_signal, sr = soundfile.read(carrier) files = [ ('cardioid_away', ['receivers/cardioid_away.wav']), ('concert', ['receivers/concert.wav']), ('binaural', ['receivers/left_ear.wav', 'receivers/right_ear.wav']), ('0.02', ['room_materials/0.02.wav']), ('0.04', ['room_materials/0.04.wav']), ('0.08', ['room_materials/0.08.wav']), ('small', ['room_sizes/small.wav']), ('medium', ['room_sizes/medium.wav']), ('large', ['room_sizes/large.wav']), ('large_spaced', ['room_sizes/large_spaced.wav']), ('tunnel_no_scatter', ['tunnel/tunnel_near_no_scatter.wav']), ('tunnel', ['tunnel/tunnel_near.wav']), ('vault', ['vault/vault.wav']), ] if not soundfile.check_format('WAV', 'PCM_24'): raise RuntimeError('That format is not valid') def convolve_channel(channel): signal, _ = soundfile.read(channel) return scipy.signal.fftconvolve(carrier_signal, signal) for name, channels in files: convolved = numpy.transpose( numpy.array([convolve_channel(channel) for channel in channels], dtype='float32')) convolved /= numpy.max(numpy.abs(convolved)) soundfile.write('out_' + name + '.wav', convolved, sr, subtype='PCM_24', format='WAV')
def mk_reader_and_writer(sr: int, format='RAW', subtype='PCM_16', dtype='int16', channels: int = 1, endian=None, always_2d=False): """Makes a (bijective) pair of numerical arrays serializer and deserializer functions. A function returning bijective panel data reader and writer functions with simple interfaces (all parametrizations are fixed): `read(source)` and `write(source, data)`. The writer and reader are essentially matrix (or array) serializers and deserializers respectively, using the same serialization protocols as waveform (into PCM, WAV, etc.) Args: sr: Sample rate. When the serialization format handles this information (e.g. WAV format) the sample rate is actually written (in WAV, in the header bytes), and asserted on reads (that is, if you read a WAV file that doesn't have that exact sample rate in it's header, a WrongSampleRate error will be raised. When the serialization format doesn't (e.g. RAW format (a.k.a. PCM)), it is ignored both on reads and writes format: 'RAW', 'WAV' and others (see soundfile.available_formats() for a full list) subtype: 'FLOAT', 'PCM_16' and others (see soundfile.available_subtypes() for a full list) dtype: 'float64', 'float32', 'int32', 'int16' channels: Number of channels (should equal the number of columns of the data matrices that will be serialized -- or 1 if the data is flat) endian: see soundfile documentation ({'FILE', 'LITTLE', 'BIG', 'CPU'}, sometimes optional) always_2d: By default, reading a mono sound file will return a one-dimensional array. With always_2d=True, data is always returned as a two-dimensional array, even if the data has only one channel. Returns: read(k), write(k, v) functions >>> n_channels, dtype = 1, 'float64' >>> read, write = mk_reader_and_writer(sr=44100, channels=n_channels, subtype='FLOAT', format='RAW', dtype=dtype) >>> data = _random_matrix(n_channels=n_channels, dtype=dtype) >>> _test_data_write_read(data, writer=write, reader=read) >>> n_channels, dtype = 4, 'int16' >>> read, write = mk_reader_and_writer(sr=2, channels=n_channels, subtype='PCM_16', format='RAW', dtype=dtype) >>> data = _random_matrix(n_channels=n_channels, dtype=dtype) >>> _test_data_write_read(data, writer=write, reader=read) """ if not sf.check_format(format, subtype, endian): raise WrongSerializationParams( f"Not a valid combo: format={format}, subtype={subtype}, endian={endian}" ) subtype = subtype or sf.default_subtype(format) if format == 'RAW': def read(k): wf, _ = sf.read(k, samplerate=sr, channels=channels, format=format, subtype=subtype, dtype=dtype, endian=endian, always_2d=always_2d) return wf else: def read(k): wf, sr_read = sf.read(k, dtype=dtype, always_2d=always_2d) if sr != sr_read: raise WrongSampleRate( f"Sample rate was {sr_read}: Expected {sr}") return wf def write(k, v): return sf.write(k, v, samplerate=sr, format=format, subtype=subtype, endian=endian) # add some attributes to the functions, for diagnosis purposes read.sr = sr read.dtype = dtype read.format = format write.sr = sr write.format = format write.subtype = subtype return read, write