Skip to content
This repository was archived by the owner on Feb 7, 2024. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 16 additions & 17 deletions acoustics/_signal.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ cimport cython
cimport numpy
import numpy as np
import matplotlib.pyplot as plt
from scipy.io import wavfile
import soundfile as sf
from scipy.signal import detrend, lfilter, bilinear, spectrogram, filtfilt, resample, fftconvolve
import acoustics
import itertools
Expand Down Expand Up @@ -1026,43 +1026,42 @@ class Signal(numpy.ndarray):
By default a 6 decibel gap is used.

"""
factor = (self.max() * 10.0**(gap/20.0))
factor = (np.abs(self).max() * 10.0**(gap/20.0))
Comment thread
adrian-stepien marked this conversation as resolved.
if inplace:
self /= factor
self /= factor[..., None]
return self
else:
return self / factor
return self / factor[..., None]


def to_wav(self, filename, depth=16):
def to_wav(self, filename, depth=16, format="WAV"):
"""Save signal as WAV file.

:param filename: Name of file to save to.
:param depth: If given, convert to integer with specified depth. Else, try to store using the original data type.
:param format: It can be either WAV or FLAC

By default, this function saves a normalized 16-bit version of the signal with at least 6 dB range till clipping occurs.
Note that the floating point samples are not yet supported.

"""
data = self
dtype = data.dtype if not depth else 'int'+str(depth)
if depth:
data = (data * 2**(depth-1)-1).astype(dtype)
wavfile.write(filename, int(self.fs), data.T)
#wavfile.write(filename, int(self.fs), self._data/np.abs(self._data).max() * 0.5)
#wavfile.write(filename, int(self.fs), np.int16(self._data/(np.abs(self._data).max()) * 32767) )
subtype = "PCM_{}".format(depth)
to_save = data
sf.write(filename, to_save.T, int(self.fs), format=format, subtype=subtype)

@classmethod
def from_wav(cls, filename):
def from_wav(cls, filename, normalize=False):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Separate commit. Don't change the default behavior. I'm not yet sure whether I agree on offering this, because typically the level of a WAV file is irrelevant; one always wants to scale with a reference.

@adrian-stepien adrian-stepien Feb 12, 2019

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In certain applications, knowing the level simplifies a lot. Currently that information is lost if the file is being saved. An example of that is given in #222.
As you said - normalisation is optional, so it can be done afterwards.

"""
Create an instance of `Signal` from a WAV file.

:param filename: Filename
:param normalize: Optionally normalize the input samples

"""
fs, data = wavfile.read(filename)
data = data.astype(np.float32, copy=False).T
data /= np.max(np.abs(data))
return cls(data, fs=fs)
data, fs = sf.read(filename)
if normalize:
data /= np.max(np.abs(data))
return cls(data.T, fs=fs)


_PLOTTING_PARAMS = {
Expand Down
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ six
cython
pandas
tabulate
pysoundfile
1 change: 1 addition & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ install_requires =
cython
pandas >= 0.15
tabulate
pysoundfile
tests_require =
pytest

Expand Down
5 changes: 4 additions & 1 deletion tests/test__signal.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,14 @@ class test_wav():
fs = 10025
samples = int(fs*duration)
channels = 3
values = np.random.randn(channels, samples)

signal = Signal(np.random.randn(channels, samples), fs)
signal = Signal(values, fs)
signal.normalize(inplace=True)

with tempfile.TemporaryFile() as file:
signal.to_wav(file)
file.seek(0)
signal = Signal.from_wav(file)
assert signal.samples == samples
assert signal.fs == fs
Expand Down