-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
95ab22b
commit b14435a
Showing
17 changed files
with
191 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,5 +7,9 @@ tmp/ | |
*.egg | ||
build | ||
htmlcov | ||
*.egg-info/ | ||
|
||
/.venv/ | ||
/dist/ | ||
/build/ | ||
/*.so |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
[settings] | ||
multi_line_output=3 | ||
include_trailing_comma=True | ||
force_grid_wrap=0 | ||
use_parentheses=True | ||
line_length=88 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,16 @@ | ||
# pyspeex-noise | ||
|
||
Noise suppression using speex. | ||
Noise suppression and automatic gain control using speex. | ||
|
||
``` python | ||
from pyspeex_noise import AudioProcessor | ||
|
||
auto_gain = 4000 | ||
noise_suppression = -30 | ||
audio_processor = AudioProcessor(auto_gain, noise_suppression) | ||
|
||
# Process 10ms chunks of 16-bit mono PCM @16Khz | ||
while audio := get_10ms_of_audio(): | ||
assert len(audio) == 160 * 2 # 160 samples | ||
clean_audio = audio_processor.Process10ms(audio).audio | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
[mypy] | ||
ignore_missing_imports = true | ||
|
||
[mypy-setuptools.*] | ||
ignore_missing_imports = True |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
[MESSAGES CONTROL] | ||
disable= | ||
format, | ||
abstract-method, | ||
cyclic-import, | ||
duplicate-code, | ||
global-statement, | ||
import-outside-toplevel, | ||
inconsistent-return-statements, | ||
locally-disabled, | ||
not-context-manager, | ||
too-few-public-methods, | ||
too-many-arguments, | ||
too-many-branches, | ||
too-many-instance-attributes, | ||
too-many-lines, | ||
too-many-locals, | ||
too-many-public-methods, | ||
too-many-return-statements, | ||
too-many-statements, | ||
too-many-boolean-expressions, | ||
unnecessary-pass, | ||
unused-argument, | ||
broad-except, | ||
too-many-nested-blocks, | ||
invalid-name, | ||
unused-import, | ||
fixme, | ||
useless-super-delegation, | ||
missing-module-docstring, | ||
missing-class-docstring, | ||
missing-function-docstring, | ||
import-error, | ||
consider-using-with | ||
|
||
[FORMAT] | ||
expected-line-ending-format=LF |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,4 @@ | ||
from speex_noise_cpp import AudioProcessor | ||
"""Noise suppression and auto gain with speex.""" | ||
from speex_noise_cpp import AudioProcessor # pylint: disable=E0611 | ||
|
||
__all__ = ["AudioProcessor"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,8 @@ | ||
pytest | ||
black==22.12.0 | ||
flake8==6.0.0 | ||
isort==5.11.3 | ||
mypy==0.991 | ||
pylint==2.15.9 | ||
pytest==8.2.2 | ||
pybind11 | ||
build |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
#!/usr/bin/env python3 | ||
import subprocess | ||
import venv | ||
from pathlib import Path | ||
|
||
_DIR = Path(__file__).parent | ||
_PROGRAM_DIR = _DIR.parent | ||
_VENV_DIR = _PROGRAM_DIR / ".venv" | ||
_MODULE_DIR = _PROGRAM_DIR / "pyspeex_noise" | ||
_TESTS_DIR = _PROGRAM_DIR / "tests" | ||
|
||
_FORMAT_DIRS = [_MODULE_DIR, _TESTS_DIR] | ||
|
||
context = venv.EnvBuilder().ensure_directories(_VENV_DIR) | ||
subprocess.check_call([context.env_exe, "-m", "black"] + _FORMAT_DIRS) | ||
subprocess.check_call([context.env_exe, "-m", "isort"] + _FORMAT_DIRS) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
#!/usr/bin/env python3 | ||
import subprocess | ||
import venv | ||
from pathlib import Path | ||
|
||
_DIR = Path(__file__).parent | ||
_PROGRAM_DIR = _DIR.parent | ||
_VENV_DIR = _PROGRAM_DIR / ".venv" | ||
_MODULE_DIR = _PROGRAM_DIR / "pyspeex_noise" | ||
_TESTS_DIR = _PROGRAM_DIR / "tests" | ||
|
||
_LINT_DIRS = [_MODULE_DIR, _TESTS_DIR] | ||
|
||
context = venv.EnvBuilder().ensure_directories(_VENV_DIR) | ||
subprocess.check_call([context.env_exe, "-m", "black"] + _LINT_DIRS + ["--check"]) | ||
subprocess.check_call([context.env_exe, "-m", "isort"] + _LINT_DIRS + ["--check"]) | ||
subprocess.check_call([context.env_exe, "-m", "flake8"] + _LINT_DIRS) | ||
subprocess.check_call([context.env_exe, "-m", "pylint"] + _LINT_DIRS) | ||
subprocess.check_call([context.env_exe, "-m", "mypy"] + _LINT_DIRS) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
#!/usr/bin/env python3 | ||
import subprocess | ||
import venv | ||
from pathlib import Path | ||
|
||
_DIR = Path(__file__).parent | ||
_PROGRAM_DIR = _DIR.parent | ||
_VENV_DIR = _PROGRAM_DIR / ".venv" | ||
|
||
context = venv.EnvBuilder().ensure_directories(_VENV_DIR) | ||
subprocess.check_call([context.env_exe, "-m", "build", "--sdist", "--wheel"]) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
[flake8] | ||
# To work with Black | ||
max-line-length = 88 | ||
# E501: line too long | ||
# W503: Line break occurred before a binary operator | ||
# E203: Whitespace before ':' | ||
# D202 No blank lines allowed after function docstring | ||
# W504 line break after binary operator | ||
ignore = | ||
E501, | ||
W503, | ||
E203, | ||
D202, | ||
W504 | ||
|
||
[isort] | ||
multi_line_output = 3 | ||
include_trailing_comma=True | ||
force_grid_wrap=0 | ||
use_parentheses=True | ||
line_length=88 | ||
indent = " " |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,53 @@ | ||
import array | ||
import math | ||
import statistics | ||
import wave | ||
from pathlib import Path | ||
|
||
from pyspeex_noise import AudioProcessor | ||
|
||
_DIR = Path(__file__).parent | ||
|
||
SAMPLES_10MS = 160 | ||
BYTES_10MS = SAMPLES_10MS * 2 | ||
|
||
|
||
def _get_energy(chunk: bytes): | ||
"""RMS""" | ||
chunk_array = array.array("h", chunk) | ||
energy = -math.sqrt(sum(x**2 for x in chunk_array) / len(chunk_array)) | ||
debiased_energy = math.sqrt( | ||
sum((x + energy) ** 2 for x in chunk_array) / len(chunk_array) | ||
) | ||
|
||
return debiased_energy | ||
|
||
|
||
def test_audio_processor(): | ||
def test_no_processing(): | ||
"""Test that audio is not changed if no auto gain or noise suppression is applied.""" | ||
audio_processor = AudioProcessor(0, 0) | ||
data_in = bytes(320) | ||
result = audio_processor.Process10ms(data_in) | ||
assert result.audio == data_in | ||
|
||
|
||
def test_noise_suppression(): | ||
"""Test default settings on a noisy file.""" | ||
audio_processor = AudioProcessor(4000, -30) | ||
noisy_energy = [] | ||
clean_energy = [] | ||
|
||
with wave.open(str(_DIR / "noise.wav"), "rb") as wav_file: | ||
assert wav_file.getframerate() == 16000 | ||
assert wav_file.getsampwidth() == 2 | ||
assert wav_file.getnchannels() == 1 | ||
|
||
chunk = wav_file.readframes(SAMPLES_10MS) | ||
while len(chunk) == BYTES_10MS: | ||
clean_chunk = audio_processor.Process10ms(chunk).audio | ||
noisy_energy.append(_get_energy(chunk)) | ||
clean_energy.append(_get_energy(clean_chunk)) | ||
chunk = wav_file.readframes(SAMPLES_10MS) | ||
|
||
# A lot less energy | ||
assert (statistics.mean(noisy_energy) / statistics.mean(clean_energy)) > 30 |