Skip to content

Commit

Permalink
Merge pull request #15 from descriptinc/ps/discourse
Browse files Browse the repository at this point in the history
Discourse upload, widget improvements, bug fixes.
  • Loading branch information
pseeth authored Feb 4, 2022
2 parents ef6ed08 + 906de0b commit ae66a24
Show file tree
Hide file tree
Showing 16 changed files with 229 additions and 53 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ jobs:
- uses: actions/checkout@v2
# Run isort + black formatter
- name: Python Code Formatter
uses: tdeboissiere/python-format-action@master
uses: descriptinc/python-format-action@master

build:
runs-on: ubuntu-latest
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -130,3 +130,4 @@ dmypy.json
profile_speed.py.lprof

scratch/
*.ipynb
4 changes: 2 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ repos:
hooks:
- id: reorder-python-imports
- repo: https://github.com/psf/black
rev: 21.4b2
rev: 22.1.0
hooks:
- id: black
language_version: python3
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v3.4.0
rev: v4.0.1
hooks:
- id: end-of-file-fixer
- id: trailing-whitespace
2 changes: 1 addition & 1 deletion audiotools/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
__version__ = "0.1.4"
__version__ = "0.1.5"
from .core import AudioSignal, STFTParams, Meter, util
from . import metrics
62 changes: 61 additions & 1 deletion audiotools/core/display.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,30 @@
import json
import os
import shlex
import subprocess
import tempfile

import matplotlib.pyplot as plt
import numpy as np
from matplotlib.gridspec import GridSpec


class DisplayMixin:
def specshow(self, batch_idx=0, x_axis="time", y_axis="linear", **kwargs):
import librosa
import librosa.display

# Always re-compute the STFT data before showing it, in case
# it changed.
self.stft_data = None

log_mag = librosa.amplitude_to_db(self.magnitude.cpu().numpy(), ref=np.max)
librosa.display.specshow(
log_mag[batch_idx].mean(axis=0),
x_axis=x_axis,
y_axis=y_axis,
sr=self.sample_rate,
**kwargs
**kwargs,
)

def waveplot(self, batch_idx=0, x_axis="time", **kwargs):
Expand All @@ -24,3 +36,51 @@ def waveplot(self, batch_idx=0, x_axis="time", **kwargs):
librosa.display.waveplot(
audio_data, x_axis=x_axis, sr=self.sample_rate, **kwargs
)

def wavespec(self, batch_idx=0, x_axis="time", **kwargs):
gs = GridSpec(6, 1)
plt.subplot(gs[0, :])
self.waveplot(batch_idx=batch_idx, x_axis=x_axis)
plt.subplot(gs[1:, :])
self.specshow(batch_idx=batch_idx, x_axis=x_axis, **kwargs)

def upload_to_discourse(
self,
label=None,
api_username=None,
api_key=None,
batch_idx=0,
discourse_server=None,
ext=".wav",
): # pragma: no cover
if api_username is None:
api_username = os.environ.get("DISCOURSE_API_USERNAME", None)
if api_key is None:
api_key = os.environ.get("DISCOURSE_API_KEY", None)
if discourse_server is None:
discourse_server = os.environ.get("DISCOURSE_SERVER", None)

if discourse_server is None or api_key is None or api_username is None:
raise RuntimeError(
"DISCOURSE_API_KEY, DISCOURSE_SERVER, DISCOURSE_API_USERNAME must be set in your environment!"
)

with tempfile.NamedTemporaryFile(suffix=ext) as f:
self.write(f.name, batch_idx=batch_idx)

command = (
f"curl -s -X POST {discourse_server}/uploads.json "
f"-H 'content-type: multipart/form-data;' "
f"-H 'Api-Key: {api_key}' "
f"-H 'Api-Username: {api_username}' "
f"-F 'type=composer' "
f"-F 'files[]=@{f.name}' "
)
info = json.loads(subprocess.check_output(shlex.split(command)))

label = self.path_to_input_file if label is None else label
if label is None:
label = "unknown"

formatted = f"![{label}|audio]({info['short_path']})"
return formatted, info
5 changes: 4 additions & 1 deletion audiotools/core/dsp.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,10 @@ def low_pass(self, cutoffs, zeros=51):
cutoffs = util.ensure_tensor(cutoffs, 2, self.batch_size)
cutoffs = cutoffs / self.sample_rate
filtered = torch.empty_like(self.audio_data)

for i, cutoff in enumerate(cutoffs):
filtered[i] = julius.lowpass_filter(self.audio_data[i], cutoff, zeros=zeros)
lp_filter = julius.LowPassFilter(cutoff, zeros=zeros).to(self.device)
filtered[i] = lp_filter(self.audio_data[i])

self.audio_data = filtered
return self
14 changes: 7 additions & 7 deletions audiotools/core/effects.py
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ def equalizer(self, db):
else:
db = db.unsqueeze(0)

weights = (10 ** db).to(self.device).float()
weights = (10**db).to(self.device).float()
fbank = fbank * weights[:, None, None, :]
eq_audio_data = fbank.sum(-1)
self.audio_data = eq_audio_data
Expand Down Expand Up @@ -252,8 +252,8 @@ def decompose_ir(self):

def measure_drr(self):
early_response, late_field, _ = self.decompose_ir()
num = (early_response ** 2).sum(dim=-1)
den = (late_field ** 2).sum(dim=-1)
num = (early_response**2).sum(dim=-1)
den = (late_field**2).sum(dim=-1)
drr = 10 * torch.log10(num / den)
return drr

Expand All @@ -263,17 +263,17 @@ def solve_alpha(early_response, late_field, wd, target_drr):
# ----------
# Apply the good ol' quadratic formula.

wd_sq = wd ** 2
wd_sq = wd**2
wd_sq_1 = (1 - wd) ** 2
e_sq = early_response ** 2
l_sq = late_field ** 2
e_sq = early_response**2
l_sq = late_field**2
a = (wd_sq * e_sq).sum(dim=-1)
b = (2 * (1 - wd) * wd * e_sq).sum(dim=-1)
c = (wd_sq_1 * e_sq).sum(dim=-1) - torch.pow(10, target_drr / 10) * l_sq.sum(
dim=-1
)

expr = ((b ** 2) - 4 * a * c).sqrt()
expr = ((b**2) - 4 * a * c).sqrt()
alpha = torch.maximum(
(-b - expr) / (2 * a),
(-b + expr) / (2 * a),
Expand Down
12 changes: 9 additions & 3 deletions audiotools/core/ffmpeg.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import subprocess
import tempfile

import ffmpy
import numpy as np
import torch

Expand Down Expand Up @@ -79,10 +80,15 @@ def ffmpeg_resample(self, sample_rate, quiet=True):
@classmethod
def load_from_file_with_ffmpeg(cls, audio_path, quiet=True, **kwargs):
with tempfile.NamedTemporaryFile(suffix=".wav") as f:
command = f"ffmpeg -i '{audio_path}' {f.name} -y"
global_options = "-y"
if quiet:
command += " -hide_banner -loglevel error"
global_options += " -loglevel error"

subprocess.check_call(shlex.split(command))
ff = ffmpy.FFmpeg(
inputs={audio_path: None},
outputs={f.name: None},
global_options=global_options,
)
ff.run()
signal = cls(f.name, **kwargs)
return signal
Loading

0 comments on commit ae66a24

Please sign in to comment.