Bugfix in exportAsWave, with normalize

This commit is contained in:
Anne de Jong 2021-04-29 20:48:21 +02:00
parent 5e32b6264d
commit 99b8553235

View File

@ -96,6 +96,9 @@ class IterRawData:
Args: Args:
f: Audio dataset in the h5 file, accessed as f['audio'] f: Audio dataset in the h5 file, accessed as f['audio']
channels: list of channel indices to use
istart: index of first sample
istop: index of last sample (not including istop)
""" """
assert isinstance(channels, list) assert isinstance(channels, list)
@ -173,22 +176,6 @@ class IterData(IterRawData):
return scaleBlockSens(nextraw, self.sens) return scaleBlockSens(nextraw, self.sens)
def exportAsWave(fn, fs, data, force=False):
if '.wav' not in fn[-4:]:
fn += '.wav'
nchannels = data.shape[1]
sampwidth = getSampWidth(data.dtype)
if os.path.exists(fn) and not force:
raise RuntimeError('File already exists: %s', fn)
with wave.open(fn, 'w') as wf:
wf.setparams((nchannels, sampwidth, fs, 0, 'NONE', 'NONE'))
wf.writeframes(np.asfortranarray(data).tobytes())
class Measurement: class Measurement:
"""Provides access to measurement data stored in the h5 measurement file """Provides access to measurement data stored in the h5 measurement file
format.""" format."""
@ -594,7 +581,7 @@ class Measurement:
def exportAsWave(self, fn=None, force=False, newsampwidth=None, def exportAsWave(self, fn=None, force=False, newsampwidth=None,
normalize=True, channels=None): normalize=True, **kwargs):
"""Export measurement file as wave. In case the measurement data is """Export measurement file as wave. In case the measurement data is
stored as floats, the values are scaled to the proper integer (PCM) stored as floats, the values are scaled to the proper integer (PCM)
data format. data format.
@ -626,20 +613,21 @@ class Measurement:
if not np.isclose(self.samplerate%1,0): if not np.isclose(self.samplerate%1,0):
raise RuntimeError(f'Sample rates should be approximately integer for exporting to Wave to work') raise RuntimeError(f'Sample rates should be approximately integer for exporting to Wave to work')
# TODO: With VERY large files, this is not possible! # TODO: With VERY large measurment files, this is not possible! Is this
data = self.rawData() # a theoretical case?
if np.issubdtype(data.dtype, np.floating): data = self.rawData(**kwargs)
if newsampwidth is None: if np.issubdtype(data.dtype, np.floating) and newsampwidth is None:
raise ValueError('Newsampwidth parameter should be given for floating point raw data') raise ValueError('Newsampwidth parameter should be given for floating point raw data')
if normalize: if normalize:
maxabs = np.max(np.abs(data), axis=0) # Scale back to maximum of absolute value
data /= maxabs[np.newaxis, :] maxabs = np.max(np.abs(data))
data /= maxabs
if newsampwidth is not None: if newsampwidth is not None:
# Convert to floats, then to new sample width # Convert to floats, then to new sample width
data = scaleBlockSens(data, self.sensitivity**0) sensone = np.ones_like(self.sensitivity)
data = scaleBlockSens(data, sensone)
if newsampwidth == 2: if newsampwidth == 2:
newtype = np.int16 newtype = np.int16
@ -648,11 +636,11 @@ class Measurement:
else: else:
raise ValueError('Invalid sample width, should be 2 or 4') raise ValueError('Invalid sample width, should be 2 or 4')
scalefac = 2**(8*(newsampwidth-1))-1 scalefac = 2**(8*newsampwidth-1)-1
# Scale data to integer range, and then convert to integers
data = (data*scalefac).astype(newtype) data = (data*scalefac).astype(newtype)
wavfile.write(fn, int(self.samplerate), data) wavfile.write(fn, int(self.samplerate), data)
@staticmethod @staticmethod