Skip to content

Commit

Permalink
v1.4.0
Browse files Browse the repository at this point in the history
  • Loading branch information
ChromaticIsobar committed Mar 25, 2021
2 parents 6bc3ffa + 6709082 commit c6f8a1f
Show file tree
Hide file tree
Showing 7 changed files with 103 additions and 9 deletions.
12 changes: 12 additions & 0 deletions changelog/v1_4_0.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
## v1.4.0
### Features
#### Frequency reduction
A custom function can now be provided to reduce the array of frequency of each
track into a single frequency. This is mainly intended to provide a way to
switch between mean and median
#### Settable properties
Learned properties (frequencies, decays, amplitudes) can now be setted. This
allows post-fit manipulations, e.g. pitch-shift
### Improvements
Now forcing correct package version in notebooks. Also using quiet mode instead
of clearing output
1 change: 1 addition & 0 deletions docs/source/changelog.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
Changelog
=========

.. mdinclude:: ../../changelog/v1_4_0.md
.. mdinclude:: ../../changelog/v1_3_0.md
.. mdinclude:: ../../changelog/v1_2_3.md
.. mdinclude:: ../../changelog/v1_2_2.md
Expand Down
41 changes: 37 additions & 4 deletions notebooks/SAMPLE.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,8 @@
"metadata": {},
"outputs": [],
"source": [
"# Install requirements\n",
"from IPython.display import clear_output\n",
"import sys\n",
"!$sys.executable -m pip install lim-sample[notebooks,plots]==1.3.0\n",
"clear_output()"
"!$sys.executable -m pip install -qU lim-sample[notebooks,plots]==1.4.0"
]
},
{
Expand Down Expand Up @@ -331,6 +328,42 @@
"resize(12, 12)\n",
"play(x_dual, rate=fs)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Manipulate\n",
"We can also manipulate the estimated modal parameters to generate a different sound!\n",
"\n",
"As an example we'll tune up the pitches, power-transform the decays and level the amplitudes"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import copy\n",
"sample_mod = copy.deepcopy(sample)\n",
"\n",
"semitones = 1 #@param {type:\"slider\", min:-12, max:12, step:1}\n",
"gamma = 3.14 #@param {type:\"slider\", min:0.01, max:4, step:0.01}\n",
"\n",
"sample_mod.freqs_ *= 2**(semitones/12)\n",
"sample_mod.decays_ **= gamma\n",
"sample_mod.amps_ = np.full(\n",
" sample.amps_.size,\n",
" 1/sample.amps_.size\n",
")\n",
"\n",
"x_mod = sample_mod.predict(np.arange(x.size) / fs)\n",
"waveplot(x_mod, sr=fs, alpha=.5, zorder=100)\n",
"plt.grid()\n",
"resize()\n",
"play(x_mod, rate=fs)"
]
}
],
"metadata": {
Expand Down
4 changes: 1 addition & 3 deletions notebooks/SDT.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,8 @@
"metadata": {},
"outputs": [],
"source": [
"from IPython.display import clear_output\n",
"import sys\n",
"!$sys.executable -m pip install lim-sample[notebooks,plots]==1.3.0\n",
"clear_output()"
"!$sys.executable -m pip install -qU lim-sample[notebooks,plots]==1.4.0"
]
},
{
Expand Down
2 changes: 1 addition & 1 deletion sample/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
from sample.sample import SAMPLE


__version__ = "1.3.0"
__version__ = "1.4.0"


@cli.main(__name__)
Expand Down
19 changes: 18 additions & 1 deletion sample/sample.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import numpy as np
import functools
import copy
from typing import Callable


class SAMPLE(base.RegressorMixin, base.BaseEstimator):
Expand All @@ -19,6 +20,8 @@ class SAMPLE(base.RegressorMixin, base.BaseEstimator):
coefficient of :data:`regressor`
regressor_q (str): Attribute name for the estimated intercept
coefficient of :data:`regressor`
freq_reduce (callable): Callable function for reducing the frequency track
into a single frequency. Defaults to :func:`numpy.mean`
**kwargs: Keyword arguments, will be set as parameters of submodels. For a
complete list of all parameter names and default values, please, run
:data:`SAMPLE().get_params()`. For an explanation of the parameters,
Expand All @@ -29,12 +32,14 @@ def __init__(
regressor=HingeRegression(),
regressor_k: str = "k_",
regressor_q: str = "q_",
freq_reduce: Callable[[np.ndarray], float] = np.mean,
**kwargs,
):
self.sinusoidal_model = sinusoidal_model
self.regressor = regressor
self.regressor_k = regressor_k
self.regressor_q = regressor_q
self.freq_reduce = freq_reduce
self.set_params(**kwargs)

@property
Expand Down Expand Up @@ -68,7 +73,7 @@ def fit(self, x: np.ndarray, y=None, **kwargs):
self.param_matrix_ = np.zeros((3, len(tracks)))
for i, t in enumerate(tracks):
notnans = np.logical_not(np.isnan(t["mag"]))
self.param_matrix_[0, i] = np.mean(t["freq"][notnans])
self.param_matrix_[0, i] = self.freq_reduce(t["freq"][notnans])
x_ = (t["start_frame"] + np.arange(t["mag"].size)[notnans]) * \
self.sinusoidal_model.h / self.sinusoidal_model.fs
y_ = t["mag"][notnans]
Expand All @@ -86,16 +91,28 @@ def freqs_(self) -> np.ndarray:
"""Learned modal frequencies"""
return self.param_matrix_[0, :]

@freqs_.setter
def freqs_(self, f: np.ndarray):
self.param_matrix_[0, :] = f

@property
def decays_(self) -> np.ndarray:
"""Learned modal decays"""
return self.param_matrix_[1, :]

@decays_.setter
def decays_(self, d: np.ndarray):
self.param_matrix_[1, :] = d

@property
def amps_(self) -> np.ndarray:
"""Learned modal amplitudes"""
return self.param_matrix_[2, :]

@amps_.setter
def amps_(self, a: np.ndarray):
self.param_matrix_[2, :] = a

@property
def energies_(self) -> np.ndarray:
"""Learned modal energies"""
Expand Down
33 changes: 33 additions & 0 deletions tests/test_sample.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,39 @@ def test_strip_reverse(self):
with self.assert_doesnt_raise():
s.fit(self.x)

def test_freqs_modification(self):
"""Test that frequencies can be effectively manipulated post-fit"""
s = copy.deepcopy(self.sample)
s.fit(self.x)
t = copy.deepcopy(s)
k = 1.2
t.freqs_ *= k
for i, (f_s, f_t) in enumerate(zip(s.freqs_, t.freqs_)):
with self.subTest(partial=i):
self.assertEqual(f_s * k, f_t)

def test_decays_modification(self):
"""Test that decays can be effectively manipulated post-fit"""
s = copy.deepcopy(self.sample)
s.fit(self.x)
t = copy.deepcopy(s)
k = 1.2
t.decays_ *= k
for i, (d_s, d_t) in enumerate(zip(s.decays_, t.decays_)):
with self.subTest(partial=i):
self.assertEqual(d_s * k, d_t)

def test_amps_modification(self):
"""Test that amplitudes can be effectively manipulated post-fit"""
s = copy.deepcopy(self.sample)
s.fit(self.x)
t = copy.deepcopy(s)
k = 1.2
t.amps_ *= k
for i, (a_s, a_t) in enumerate(zip(s.amps_, t.amps_)):
with self.subTest(partial=i):
self.assertEqual(a_s * k, a_t)

def test_plot_2d(self):
"""Test 2D plot"""
s = copy.deepcopy(self.sample).fit(self.x)
Expand Down

0 comments on commit c6f8a1f

Please sign in to comment.