Skip to content

Commit

Permalink
Modernize infrastructure
Browse files Browse the repository at this point in the history
  • Loading branch information
mmcauliffe committed Aug 27, 2024
1 parent 5f8876b commit 6ad81b3
Show file tree
Hide file tree
Showing 17 changed files with 219 additions and 31 deletions.
47 changes: 47 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
name: CI
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
# Allow rebuilds via API.
repository_dispatch:
types: rebuild

concurrency:
group: run_tests-${{ github.ref }}
cancel-in-progress: true

jobs:
test:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@main
with:
fetch-depth: 0

- name: Install Conda environment with Micromamba
uses: mamba-org/setup-micromamba@v1
with:
environment-file: environment.yml
environment-name: mfa
create-args: >-
python=3.9
cache-environment: true

- name: Download and set up Praat
run: |
wget https://www.fon.hum.uva.nl/praat/praat6417_linux-intel64-barren.tar.gz -O praat.tar.gz
tar -xvzf praat.tar.gz
echo "praat=$(pwd)/praat_barren" >> $GITHUB_ENV
- name: Run tests
shell: bash -l {0}
run: pytest -x ./tests

- name: "Upload coverage to Codecov"
uses: "codecov/codecov-action@v3"
with:
file: ./coverage.xml
fail_ci_if_error: false
40 changes: 40 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
name: Publish Python distributions to PyPI

on:
release:
types: [published]

jobs:
build-n-publish:
name: Build and publish to PyPI
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@main
with:
fetch-depth: 0
- name: Set up Python 3.10
uses: actions/setup-python@v3
with:
python-version: "3.10"

- name: Install pypa/build
run: >-
python -m
pip install
build
--user
- name: Build a binary wheel and a source tarball
run: >-
python -m
build
--sdist
--wheel
--outdir dist/
.
- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
user: __token__
password: ${{ secrets.PYPI_API_TOKEN }}
12 changes: 12 additions & 0 deletions .readthedocs.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
version: 2

build:
os: "ubuntu-20.04"
tools:
python: "mambaforge-4.10"

sphinx:
configuration: docs/source/conf.py

conda:
environment: rtd_environment.yml
10 changes: 5 additions & 5 deletions conch/analysis/amplitude_envelopes/amplitude_envelopes.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import numpy as np
import librosa

from scipy.signal import filtfilt, butter, hilbert

from librosa import resample
from scipy.signal import resample

from ..helper import preemphasize
from ..functions import BaseAnalysisFunction
Expand Down Expand Up @@ -62,9 +60,11 @@ def generate_amplitude_envelopes(signal, sr, num_bands, min_frequency, max_frequ
for i in range(num_bands):
b, a = butter(2, (band_mins[i] / (sr / 2), band_maxes[i] / (sr / 2)), btype='bandpass')
env = filtfilt(b, a, proc)
env = abs(hilbert(env))
env = np.abs(hilbert(env))
if mode == 'downsample':
env = resample(env, sr, 120)
env = resample(
env, int(env.shape[0] * 120 / sr)
)
envs.append(env)
envs = np.array(envs).T
if mode == 'downsample':
Expand Down
8 changes: 5 additions & 3 deletions conch/analysis/formants/lpc.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import librosa
import numpy as np
import scipy as sp
from scipy.signal import lfilter

from scipy.fftpack import fft, ifft
from scipy.signal.windows import gaussian
from scipy.signal import resample

from ..helper import nextpow2
from ..functions import BaseAnalysisFunction
Expand Down Expand Up @@ -216,7 +216,9 @@ def lpc_formants(signal, sr, num_formants, max_freq, time_step,
alpha = np.exp(-2 * np.pi * 50 * (1 / new_sr))
proc = lfilter([1., -alpha], 1, signal)
if sr > new_sr:
proc = librosa.resample(proc, sr, new_sr)
proc = resample(
proc, int(proc.shape[0] * new_sr / sr)
)
nperseg = int(win_len * new_sr)
nperstep = int(time_step * new_sr)
if window_shape == 'gaussian':
Expand All @@ -237,7 +239,7 @@ def lpc_formants(signal, sr, num_formants, max_freq, time_step,
continue
if f > max_freq - 50:
continue
formants.append((np.asscalar(f), np.asscalar(bw[j])))
formants.append((float(f), float(bw[j])))
missing = num_formants - len(formants)
if missing:
formants += [(None, None)] * missing
Expand Down
15 changes: 15 additions & 0 deletions environment.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
channels:
- conda-forge
dependencies:
- python>=3.8
- numpy
- librosa
- pysoundfile
- scipy
- praatio
- pytest
- reaper
- pip:
- build
- twine
- pyraat
5 changes: 0 additions & 5 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,3 @@ scipy
pyraat
praatio
librosa
pytest
sphinx>=1.3b3
numpydoc
future
textgrid
19 changes: 19 additions & 0 deletions rtd_environment.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
channels:
- conda-forge
dependencies:
- python>=3.8
- numpy
- librosa
- pysoundfile
- scipy
- praatio
- sphinx
- numpydoc
- sphinx-design
- sphinx-click
- sphinx-intl
- pydata-sphinx-theme
- myst-parser
- mock
- pip:
- pyraat
6 changes: 2 additions & 4 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,22 +108,20 @@ def autovot_correct_times():

@pytest.fixture(scope='session')
def praatpath():
if os.environ.get('TRAVIS'):
if os.environ.get('GITHUB_ACTIONS'):
return os.path.join(os.environ.get('HOME'), 'tools', 'praat')
return 'praat'


@pytest.fixture(scope='session')
def reaperpath():
if os.environ.get('TRAVIS'):
return os.path.join(os.environ.get('HOME'), 'tools', 'reaper')
return 'reaper'


@pytest.fixture(scope='session')
def reaper_func(reaperpath):
from conch.analysis.pitch.reaper import ReaperPitchTrackFunction
return ReaperPitchTrackFunction(reaper_path=reaperpath)
return ReaperPitchTrackFunction()


@pytest.fixture(scope='session')
Expand Down
6 changes: 4 additions & 2 deletions tests/test_analysis_autovot.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
from conch.analysis.autovot import AutoVOTAnalysisFunction
import librosa
from statistics import mean
import wave
import pytest
import shutil
from conch.analysis.segments import SegmentMapping
from conch import analyze_segments


def test_autovot(acoustic_corpus_path, autovot_markings, classifier_path, autovot_correct_times):
autovot_path = shutil.which("VotDecode")
if autovot_path is None:
pytest.skip("No AutoVOT")
mapping = SegmentMapping()
with wave.open(acoustic_corpus_path, 'r') as f:
length = f.getnframes() / float(f.getframerate())
Expand Down
14 changes: 13 additions & 1 deletion tests/test_analysis_formants_praat.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@
PraatSegmentFormantPointFunction, PraatSegmentFormantTrackFunction
import librosa
import pytest

import shutil
from conch.exceptions import FunctionMismatch

from conch.analysis.segments import FileSegment, SignalSegment, SegmentMapping


def test_formant_track_praat(praatpath, base_filenames):
praat_path = shutil.which("praat")
if praat_path is None:
pytest.skip("No Praat")
for f in base_filenames:
wavpath = f + '.wav'
func = PraatFormantTrackFunction(praat_path=praatpath, time_step=0.01,
Expand All @@ -24,6 +27,9 @@ def test_formant_track_praat(praatpath, base_filenames):


def test_formant_point_praat(praatpath, base_filenames):
praat_path = shutil.which("praat")
if praat_path is None:
pytest.skip("No Praat")
for f in base_filenames:
wavpath = f + '.wav'
func = PraatFormantPointFunction(praat_path=praatpath, time_step=0.01,
Expand All @@ -39,6 +45,9 @@ def test_formant_point_praat(praatpath, base_filenames):


def test_segment_formant_track_praat(praatpath, acoustic_corpus_path):
praat_path = shutil.which("praat")
if praat_path is None:
pytest.skip("No Praat")
func = PraatSegmentFormantTrackFunction(praat_path=praatpath, time_step=0.01,
window_length=0.025, num_formants=5, max_frequency=5500)
segment = FileSegment(acoustic_corpus_path, 2.142, 2.245, 0, padding=0.1)
Expand All @@ -55,6 +64,9 @@ def test_segment_formant_track_praat(praatpath, acoustic_corpus_path):


def test_segment_formant_point_praat(praatpath, acoustic_corpus_path):
praat_path = shutil.which("praat")
if praat_path is None:
pytest.skip("No Praat")
func = PraatSegmentFormantPointFunction(praat_path=praatpath, time_step=0.01,
window_length=0.025, num_formants=5, max_frequency=5500, point_percent=0.33)

Expand Down
7 changes: 7 additions & 0 deletions tests/test_analysis_intensity_praat.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
from conch.analysis.intensity.praat import PraatIntensityTrackFunction, PraatSegmentIntensityTrackFunction
import librosa
import pytest
import shutil

from conch.analysis.segments import FileSegment, SignalSegment
from conch.exceptions import FunctionMismatch


def test_intensity_praat(praatpath, base_filenames):
praat_path = shutil.which("praat")
if praat_path is None:
pytest.skip("No Praat")
for f in base_filenames:
wavpath = f + '.wav'
func = PraatIntensityTrackFunction(praat_path=praatpath, time_step=0.01)
Expand All @@ -22,6 +26,9 @@ def test_intensity_praat(praatpath, base_filenames):


def test_segment_pitch_track_praat(praatpath, base_filenames):
praat_path = shutil.which("praat")
if praat_path is None:
pytest.skip("No Praat")
for f in base_filenames:
if f != 'acoustic_corpus':
continue
Expand Down
5 changes: 5 additions & 0 deletions tests/test_analysis_mfcc_praat.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
from conch.analysis.mfcc.praat import PraatMfccFunction
import librosa
import shutil
import pytest

from conch.analysis.segments import FileSegment, SignalSegment


def test_mfcc_praat(praatpath, base_filenames):
praat_path = shutil.which("praat")
if praat_path is None:
pytest.skip("No Praat")
for f in base_filenames:
wavpath = f + '.wav'
func = PraatMfccFunction(praat_path=praatpath, window_length=0.025, time_step=0.01, max_frequency=7800,
Expand Down
11 changes: 10 additions & 1 deletion tests/test_analysis_pitch_praat.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
from conch.analysis.pitch.praat import PraatPitchTrackFunction, PraatSegmentPitchTrackFunction
import librosa
from statistics import mean
from scipy.io import wavfile
import pytest
import shutil
from conch.analysis.segments import FileSegment, SignalSegment
from conch.exceptions import FunctionMismatch


def test_pitch_praat(praatpath, base_filenames):
praat_path = shutil.which("praat")
if praat_path is None:
pytest.skip("No Praat")
for f in base_filenames:
wavpath = f + '.wav'
func = PraatPitchTrackFunction(praat_path=praatpath, time_step=0.01,
Expand All @@ -22,6 +25,9 @@ def test_pitch_praat(praatpath, base_filenames):
# assert pitch == pitch2

def test_pitch_pulses_praat(praatpath, noise_path, y_path):
praat_path = shutil.which("praat")
if praat_path is None:
pytest.skip("No Praat")
func = PraatPitchTrackFunction(praat_path=praatpath, time_step=0.01, min_pitch=75, max_pitch=600,
with_pulses=True)
pitch, pulses = func(noise_path)
Expand All @@ -43,6 +49,9 @@ def test_pitch_pulses_praat(praatpath, noise_path, y_path):


def test_segment_pitch_track_praat(praatpath, acoustic_corpus_path):
praat_path = shutil.which("praat")
if praat_path is None:
pytest.skip("No Praat")
func = PraatSegmentPitchTrackFunction(praat_path=praatpath, time_step=0.01, min_pitch=75, max_pitch=600)
segment = FileSegment(acoustic_corpus_path, 2.142, 2.245, 0, padding=0.1)
pitch = func(segment)
Expand Down
Loading

0 comments on commit 6ad81b3

Please sign in to comment.