diff --git a/.github/workflows/docs.yaml b/.github/workflows/docs.yaml index 08e8e1f3..ecee7d6f 100644 --- a/.github/workflows/docs.yaml +++ b/.github/workflows/docs.yaml @@ -30,15 +30,34 @@ jobs: - uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - - name: Install dependencies + - name: Install ffmpeg (Ubuntu) + if: startsWith(matrix.os, 'ubuntu') + run: sudo apt-get update && sudo apt-get install -y ffmpeg + - name: Install ffmpeg (macOS) + if: startsWith(matrix.os, 'macos') + run: brew install ffmpeg + - name: Install ffmpeg (Windows) + if: startsWith(matrix.os, 'windows') + run: choco install ffmpeg + - name: Install pipx and ensure it's up to date + run: | + python -m pip install --upgrade pipx + pipx ensurepath + shell: bash + - name: Install poetry + run: pipx install poetry==1.7.1 + shell: bash + - name: Install dependencies with Poetry run: | - python -m pip install poetry==1.7.1 poetry run pip install iso-639 poetry install --with dev,docs shell: bash - name: Build docs + env: + HF_TOKEN: ${{ secrets.HF_TOKEN }} run: | - APP_MODULE_NAME=$(ls src -U | head -1) + APP_MODULE_NAME=$(ls -1 src | sort | head -1) + echo "APP_MODULE_NAME: $APP_MODULE_NAME" poetry run pdoc src/"$APP_MODULE_NAME" -o docs -t docs_style/pdoc-theme --docformat google touch docs/.nojekyll shell: bash diff --git a/.gitignore b/.gitignore index cdf50e29..4ddeae03 100644 --- a/.gitignore +++ b/.gitignore @@ -76,7 +76,7 @@ instance/ .scrapy # Sphinx documentation -docs/_build/ +# docs/_build/ # PyBuilder .pybuilder/ @@ -167,6 +167,8 @@ cython_debug/ .idea/ data/ +# pdoc documentation +docs/ # Speechbrain models pretrained_models diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 6c4ae8d9..b5880847 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -57,9 +57,9 @@ repos: rev: v2.3.0 hooks: - id: codespell + args: [--skip=*.ipynb] additional_dependencies: - tomli - - repo: https://github.com/hija/clean-dotenv rev: v0.0.7 hooks: diff --git a/audio_48khz_mono_16bits.wav b/audio_48khz_mono_16bits.wav new file mode 120000 index 00000000..6f4d4163 --- /dev/null +++ b/audio_48khz_mono_16bits.wav @@ -0,0 +1 @@ +/Users/isaacbevers/sensein/senselab-wrapper/senselab/src/tests/data_for_testing/audio_48khz_mono_16bits.wav \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index 1e9a6748..173100a9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -150,7 +150,8 @@ pattern = "default-unprefixed" [tool.codespell] skip = [ "poetry.lock", - "docs_style/pdoc-theme/syntax-highlighting.css" + "docs_style/pdoc-theme/syntax-highlighting.css", + "*.ipynb" ] ignore-words-list = ["senselab", "nd", "astroid", "wil", "SER"] diff --git a/src/senselab/audio/tasks/preprocessing/preprocessing.py b/src/senselab/audio/tasks/preprocessing/preprocessing.py index 3e928569..1ba5404b 100644 --- a/src/senselab/audio/tasks/preprocessing/preprocessing.py +++ b/src/senselab/audio/tasks/preprocessing/preprocessing.py @@ -1,34 +1,49 @@ """This module implements some utilities for the preprocessing task.""" -from typing import List, Tuple +from typing import List, Optional, Tuple import pydra -import torchaudio.functional as F +import torch +from scipy import signal +from speechbrain.augment.time_domain import Resample from senselab.audio.data_structures.audio import Audio -def resample_audios(audios: List[Audio], resample_rate: int, rolloff: float = 0.99) -> List[Audio]: - """Resamples all Audios to a given sampling rate. - - Takes a list of audios and resamples each into the new sampling rate. Notably does not assume any - specific structure of the audios (can vary in stereo vs. mono as well as their original sampling rate) +def resample_audios( + audios: List[Audio], + resample_rate: int, + lowcut: Optional[float] = None, + order: int = 4, +) -> List[Audio]: + """Resamples a list of audio signals to a given sampling rate. Args: - audios: List of Audios to resample - resample_rate: Rate at which to resample the Audio - rolloff: The roll-off frequency of the filter, as a fraction of the Nyquist. - Lower values reduce anti-aliasing, but also reduce some of the highest frequencies + audios (List[Audio]): List of audio objects to resample. + resample_rate (int): Target sampling rate. + lowcut (float, optional): Low cut frequency for IIR filter. + order (int, optional): Order of the IIR filter. Defaults to 4. Returns: - List of Audios that have all been resampled to the given resampling rate + List[Audio]: Resampled audio objects. """ resampled_audios = [] for audio in audios: - resampled = F.resample(audio.waveform, audio.sampling_rate, resample_rate, rolloff=rolloff) + if lowcut is None: + lowcut = resample_rate / 2 - 100 + sos = signal.butter(order, lowcut, btype="low", output="sos", fs=resample_rate) + + channels = [] + for channel in audio.waveform: + filtered_channel = torch.from_numpy(signal.sosfiltfilt(sos, channel.numpy()).copy()).float() + resampler = Resample(orig_freq=audio.sampling_rate, new_freq=resample_rate) + resampled_channel = resampler(filtered_channel.unsqueeze(0)).squeeze(0) + channels.append(resampled_channel) + + resampled_waveform = torch.stack(channels) resampled_audios.append( Audio( - waveform=resampled, + waveform=resampled_waveform, sampling_rate=resample_rate, metadata=audio.metadata.copy(), orig_path_or_id=audio.orig_path_or_id, diff --git a/src/senselab/audio/tasks/speaker_verification/__init__.py b/src/senselab/audio/tasks/speaker_verification/__init__.py new file mode 100644 index 00000000..941cfc0b --- /dev/null +++ b/src/senselab/audio/tasks/speaker_verification/__init__.py @@ -0,0 +1 @@ +"""Verifies whether two audio segments belong to the same speaker.""" diff --git a/src/senselab/audio/tasks/speaker_verification/speaker_verification.py b/src/senselab/audio/tasks/speaker_verification/speaker_verification.py new file mode 100644 index 00000000..5f739ff8 --- /dev/null +++ b/src/senselab/audio/tasks/speaker_verification/speaker_verification.py @@ -0,0 +1,61 @@ +"""Audio Processing and Speaker Verification Module. + +This module provides functions for resampling audio using an IIR filter and +verifying if two audio samples or files are from the same speaker using a +specified model. +""" + +from typing import List, Optional, Tuple + +from torch.nn.functional import cosine_similarity + +from senselab.audio.data_structures.audio import Audio +from senselab.audio.tasks.speaker_embeddings.speechbrain import SpeechBrainEmbeddings +from senselab.utils.data_structures.device import DeviceType, _select_device_and_dtype +from senselab.utils.data_structures.model import SpeechBrainModel + +TRAINING_SAMPLE_RATE = 16000 # spkrec-ecapa-voxceleb trained on 16kHz audio + + +def verify_speaker( + audios: List[Tuple[Audio, Audio]], + model: SpeechBrainModel = SpeechBrainModel(path_or_uri="speechbrain/spkrec-ecapa-voxceleb", revision="main"), + device: Optional[DeviceType] = None, + threshold: float = 0.25, +) -> List[Tuple[float, bool]]: + """Verifies if two audio samples are from the same speaker. + + Args: + audios (List[Tuple[Audio, Audio]]): A list of tuples, where each tuple contains + two audio samples to be compared. + model (SpeechBrainModel, optional): The model for speaker verification. + device (DeviceType, optional): The device to run the model on. Defaults to CPU. + threshold (float, optional): The threshold to determine same speaker. + + Returns: + List[Tuple[float, bool]]: A list of tuples containing the verification score and + the prediction for each pair of audio samples. The + verification score is a float indicating the similarity + between the two samples, and the prediction is a boolean + indicating if the two samples are from the same speaker. + """ + device = _select_device_and_dtype(compatible_devices=[DeviceType.CPU, DeviceType.CUDA])[0] + + scores_and_predictions = [] + for audio1, audio2 in audios: + if audio1.sampling_rate != TRAINING_SAMPLE_RATE: + raise ValueError(f"{model.path_or_uri} trained on {TRAINING_SAMPLE_RATE} \ + sample audio, but audio1 has sample rate {audio1.sampling_rate}.") + if audio2.sampling_rate != TRAINING_SAMPLE_RATE: + raise ValueError(f"{model.path_or_uri} trained on {TRAINING_SAMPLE_RATE} \ + sample audio, but audio2 has sample rate {audio2.sampling_rate}.") + + embeddings = SpeechBrainEmbeddings.extract_speechbrain_speaker_embeddings_from_audios( + audios=[audio1, audio2], model=model, device=device + ) + embedding1, embedding2 = embeddings + similarity = cosine_similarity(embedding1.unsqueeze(0), embedding2.unsqueeze(0)) + score = similarity.mean().item() + prediction = score > threshold + scores_and_predictions.append((score, prediction)) + return scores_and_predictions diff --git a/src/senselab/audio/tasks/speech_enhancement/speechbrain.py b/src/senselab/audio/tasks/speech_enhancement/speechbrain.py index 47ad362a..fea33dc2 100644 --- a/src/senselab/audio/tasks/speech_enhancement/speechbrain.py +++ b/src/senselab/audio/tasks/speech_enhancement/speechbrain.py @@ -1,4 +1,5 @@ """This module provides the Speechbrain interface for speech enhancement.""" + from typing import Dict, List, Optional import torch @@ -35,10 +36,7 @@ def _get_speechbrain_model( ) key = f"{model.path_or_uri}-{model.revision}-{device.value}" if key not in cls._models: - cls._models[key] = separator.from_hparams( - source=model.path_or_uri, - run_opts={"device": device.value} - ) + cls._models[key] = separator.from_hparams(source=model.path_or_uri, run_opts={"device": device.value}) return cls._models[key] @classmethod @@ -46,8 +44,8 @@ def enhance_audios_with_speechbrain( cls, audios: List[Audio], model: SpeechBrainModel = SpeechBrainModel( - path_or_uri="speechbrain/sepformer-wham16k-enhancement", - revision="main"), + path_or_uri="speechbrain/sepformer-wham16k-enhancement", revision="main" + ), device: Optional[DeviceType] = None, ) -> List[Audio]: """Enhances all audio samples in the dataset. @@ -59,7 +57,7 @@ def enhance_audios_with_speechbrain( Returns: List[Audio]: The list of enhanced audio objects. - + Todo: - Optimizing the computation by working in batches - Double-checking the input size of enhancer.encode_batch @@ -70,13 +68,13 @@ def enhance_audios_with_speechbrain( # Check that all audio objects have the correct sampling rate for audio in audios: if audio.waveform.shape[0] != 1: - raise ValueError( - f"Audio waveform must be mono (1 channel), but got {audio.waveform.shape[0]} channels" - ) + raise ValueError(f"Audio waveform must be mono (1 channel), but got {audio.waveform.shape[0]} channels") if audio.sampling_rate != expected_sample_rate: raise ValueError( - "Audio sampling rate " + str(audio.sampling_rate) + - " does not match expected " + str(expected_sample_rate) + "Audio sampling rate " + + str(audio.sampling_rate) + + " does not match expected " + + str(expected_sample_rate) ) # Stack audio waveforms for batch processing @@ -87,6 +85,6 @@ def enhance_audios_with_speechbrain( # Update the original audio objects with the enhanced waveforms for audio, enhanced_waveform in zip(audios, enhanced_waveforms): - audio.waveform = enhanced_waveform + audio.waveform = enhanced_waveform.reshape(1, -1) return audios diff --git a/src/tests/audio/tasks/speaker_verification_test.py b/src/tests/audio/tasks/speaker_verification_test.py new file mode 100644 index 00000000..f42ccd38 --- /dev/null +++ b/src/tests/audio/tasks/speaker_verification_test.py @@ -0,0 +1,40 @@ +"""Test Module for Audio Processing and Speaker Verification. + +This module contains minimal tests to ensure the audio processing and speaker verification functions do not fail. + +Tests: + - test_resample_iir: Tests the resample_iir function. + - test_verify_speaker: Tests the verify_speaker function. + - test_verify_speaker_from_files: Tests the verify_speaker_from_files function. +""" + +import os + +import pytest + +from senselab.audio.data_structures.audio import Audio +from senselab.audio.tasks.preprocessing.preprocessing import resample_audios +from senselab.audio.tasks.speaker_verification.speaker_verification import ( + verify_speaker, +) + +if os.getenv("GITHUB_ACTIONS") != "true": + + @pytest.mark.large_model + def test_verify_speaker(mono_audio_sample: Audio) -> None: + """Tests the verify_speaker function to ensure it does not fail. + + Args: + mono_audio_sample (Audio): The mono audio sample to use for testing. + + Returns: + None + """ + mono_audio_sample = resample_audios([mono_audio_sample], 16000)[0] + assert mono_audio_sample.sampling_rate == 16000 + mono_audio_samples = [(mono_audio_sample, mono_audio_sample)] * 3 + scores_and_predictions = verify_speaker(mono_audio_samples) + assert scores_and_predictions + assert len(scores_and_predictions[0]) == 2 + assert isinstance(scores_and_predictions[0][0], float) + assert isinstance(scores_and_predictions[0][1], bool) diff --git a/tutorials/getting_started.ipynb b/tutorials/getting_started.ipynb new file mode 100644 index 00000000..f7216ad5 --- /dev/null +++ b/tutorials/getting_started.ipynb @@ -0,0 +1,525 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Getting Started with ```senselab```\n", + "\n", + "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/sensein/senselab/blob/main/tutorials/getting_started.ipynb)\n", + "\n", + "\n", + "Welcome to the `senselab` quick start tutorial! \n", + "\n", + "This guide will showcase some of the key functionalities offered by `senselab`. We'll cover how to read, preprocess, analyze, and manipulate audio data. For more details, please check the documentation and task-specific tutorials. \n", + "\n", + "Note that the package evolves continuously, so if you find that this tutorial breaks at some point, please let us know by opening an issue. \n", + "\n", + "Let's get started!" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Installation" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "vscode": { + "languageId": "shellscript" + } + }, + "outputs": [], + "source": [ + "pip install senselab" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Reading audio clips from disk:\n", + "Need to read some audio files from disk? **EASY!**" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "from senselab.audio.data_structures.audio import Audio\n", + "\n", + "MONO_AUDIO_PATH = \"../src/tests/data_for_testing/audio_48khz_mono_16bits.wav\"\n", + "STEREO_AUDIO_PATH = \"../src/tests/data_for_testing/audio_48khz_stereo_16bits.wav\"\n", + "\n", + "audio1 = Audio.from_filepath(MONO_AUDIO_PATH)\n", + "audio2 = Audio.from_filepath(STEREO_AUDIO_PATH)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Downmixing audio clips to mono\n", + "Want to downmix your audio to mono? It has neve been that **EASY!**! Here\u2019s how:" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The original audio has 2 channels.\n", + "The downmixed audio has 1 channels.\n" + ] + } + ], + "source": [ + "from senselab.audio.tasks.preprocessing.preprocessing import downmix_audios_to_mono\n", + "\n", + "print(\"The original audio has {} channels.\".format(audio2.waveform.shape[0]))\n", + "audio2 = downmix_audios_to_mono([audio2])[0]\n", + "print(\"The downmixed audio has {} channels.\".format(audio2.waveform.shape[0]))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Resampling audio clips to 16000 Hz\n", + "Need to resample your audio to 16000 Hz? **EASY!**\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The original audio has a sampling rate of 48000 Hz.\n", + "The resampled audio has a sampling rate of 16000 Hz.\n" + ] + } + ], + "source": [ + "from senselab.audio.tasks.preprocessing.preprocessing import resample_audios\n", + "\n", + "print(\"The original audio has a sampling rate of {} Hz.\".format(audio1.sampling_rate))\n", + "[audio1, audio2] = resample_audios([audio1, audio2], resample_rate=16000)\n", + "print(\"The resampled audio has a sampling rate of {} Hz.\".format(audio1.sampling_rate))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Playing and plotting audio\n", + "Want to play or plot your audio? **EASY!**! Here is how:" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + " \n", + " " + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "from senselab.audio.tasks.plotting.plotting import play_audio\n", + "play_audio(audio1)" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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3njjDaSlpelc5uXLl6N+/fpwdnaGv78/XnzxxYr+GoiIiGwGg34iIiKqsPXr18PX1xdnzpzBhAkT8P7772P48OHo3Lkzzp8/j/DwcLzxxhvIzc0FAKSnp6N3795o1aoVzp07h7179yI5ORkvvfSSTsc9d+4cPvzwQ8ybNw83b97E3r170b17d2N8RCIiIqvE7v1ERERUYaGhoZgxYwYAYPr06Vi8eDF8fX0xZswYAMCsWbOwYsUKXLp0CR07dsRPP/2EVq1aYeHChfJ9rF27FkFBQbh16xYaNGig1XHv378PNzc3DBw4EB4eHqhduzZatWpl+A9IRERkpdjST0RERBXWokUL+f/t7Ozg4+OD5s2by5f5+/sDAFJSUgAAFy9exKFDh+Q5Atzd3dGoUSMAwJ07d7Q+bp8+fVC7dm2EhITgjTfewJ9//invTUBEREQM+omIiMgAHBwcFF4LBAKFZbJZAcRiMQAgOzsbgwYNQkxMjMLP7du3deqe7+HhgfPnz2PDhg2oXr06Zs2ahdDQUKSnp1f8QxEREdkAdu8nIiIik2vdujW2bNmC4OBg2NtX7HHE3t4eYWFhCAsLw+zZs+Ht7Y2DBw9i6NChBiotERGR9WJLPxEREZncuHHj8OTJE7zyyis4e/Ys7ty5g//++w+jR49GUVGR1vv5999/8cMPPyAmJgb37t3Db7/9BrFYjIYNGxqx9ERERNaDQT8RERGZXGBgIE6cOIGioiKEh4ejefPmmDRpEry9vSEUav944u3tja1bt6J3795o3LgxVq5ciQ0bNqBp06ZGLD0REZH1EEgkEom5C0FERESkya+//opJkybpNV5fIBBg27ZtGDJkiMHLRUREZMnY0k9ERERWIyMjA+7u7vj000+12v69996Du7u7kUtFRERkudjST0RERFYhKysLycnJAKTd+n19fTW+JyUlBZmZmQCA6tWrw83NzahlJCIisjQM+omIiIiIiIhsFLv3ExEREREREdkoBv1ERERERERENopBPxEREREREZGNYtBPREREREREZKMY9BMRERERERHZKAb9RERERERERDaKQT8RERERERGRjWLQT0RERERERGSjGPQTERERERER2aj/AzOcZjFeCSU1AAAAAElFTkSuQmCC", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "from senselab.audio.tasks.plotting.plotting import plot_waveform\n", + "plot_waveform(audio1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Voice Activity Detection\n", + "Want to detect when someone is speaking? **EASY!**" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Voice activity detection results: [[ScriptLine(text=None, speaker='VOICE', start=0.03096875, end=3.1359687500000004, chunks=None), ScriptLine(text=None, speaker='VOICE', start=3.3553437500000003, end=3.6253437500000003, chunks=None), ScriptLine(text=None, speaker='VOICE', start=3.6253437500000003, end=3.94596875, chunks=None), ScriptLine(text=None, speaker='VOICE', start=3.94596875, end=4.87409375, chunks=None)], [ScriptLine(text=None, speaker='VOICE', start=0.03096875, end=3.0515937500000003, chunks=None), ScriptLine(text=None, speaker='VOICE', start=3.3215937500000003, end=4.890968750000001, chunks=None)]]\n" + ] + } + ], + "source": [ + "from senselab.audio.tasks.voice_activity_detection.api import detect_human_voice_activity_in_audios\n", + "from senselab.utils.data_structures.model import PyannoteAudioModel\n", + "\n", + "pyannote_model = PyannoteAudioModel(path_or_uri=\"pyannote/speaker-diarization-3.1\", revision=\"main\")\n", + "voice_activity_results = detect_human_voice_activity_in_audios(audios=[audio1, audio2], model=pyannote_model)\n", + "print(\"Voice activity detection results: {}\".format(voice_activity_results))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Speaker Diarization\n", + "Wondering who is speaking and when? **EASY!**" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Diarization results: [[ScriptLine(text=None, speaker='SPEAKER_00', start=0.03096875, end=3.1359687500000004, chunks=None), ScriptLine(text=None, speaker='SPEAKER_00', start=3.3553437500000003, end=3.6253437500000003, chunks=None), ScriptLine(text=None, speaker='SPEAKER_01', start=3.6253437500000003, end=3.94596875, chunks=None), ScriptLine(text=None, speaker='SPEAKER_00', start=3.94596875, end=4.87409375, chunks=None)], [ScriptLine(text=None, speaker='SPEAKER_00', start=0.03096875, end=3.0515937500000003, chunks=None), ScriptLine(text=None, speaker='SPEAKER_01', start=3.3215937500000003, end=4.890968750000001, chunks=None)]]\n" + ] + } + ], + "source": [ + "from senselab.audio.tasks.speaker_diarization.api import diarize_audios\n", + "\n", + "pyannote_model = PyannoteAudioModel(path_or_uri=\"pyannote/speaker-diarization-3.1\", revision=\"main\")\n", + "diarization_results = diarize_audios(audios=[audio1, audio2], model=pyannote_model)\n", + "\n", + "print(\"Diarization results: {}\".format(diarization_results))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Automatic Speech Recognition\n", + "Want to convert speech to text? **EASY!**! Use this:\n" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Special tokens have been added in the vocabulary, make sure the associated word embeddings are fine-tuned or trained.\n", + "Due to a bug fix in https://github.com/huggingface/transformers/pull/28687 transcription using a multilingual Whisper will default to language detection followed by transcription instead of translation to English.This might be a breaking change for your use case. If you want to instead always translate your audio to English, make sure to pass `language='en'`.\n", + "The attention mask is not set and cannot be inferred from input because pad token is same as eos token.As a consequence, you may observe unexpected behavior. Please pass your input's `attention_mask` to obtain reliable results.\n", + "WhisperModel is using WhisperSdpaAttention, but `torch.nn.functional.scaled_dot_product_attention` does not support `output_attentions=True` or `layer_head_mask` not None. Falling back to the manual attention implementation, but specifying the manual implementation will be required from Transformers version v5.0.0 onwards. This warning can be removed using the argument `attn_implementation=\"eager\"` when loading the model.\n", + "Whisper did not predict an ending timestamp, which can happen if audio is cut off in the middle of a word. Also make sure WhisperTimeStampLogitsProcessor was used during generation.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Transcripts: [ScriptLine(text='This is beautiful. This is Johnny. Kenny. Enjoy. We just wanted to take a minute to thank you.', speaker=None, start=0.0, end=4.9, chunks=[ScriptLine(text='This', speaker=None, start=0.0, end=0.3, chunks=None), ScriptLine(text='is', speaker=None, start=0.3, end=0.5, chunks=None), ScriptLine(text='beautiful.', speaker=None, start=0.5, end=1.04, chunks=None), ScriptLine(text='This', speaker=None, start=1.04, end=1.28, chunks=None), ScriptLine(text='is', speaker=None, start=1.28, end=1.4, chunks=None), ScriptLine(text='Johnny.', speaker=None, start=1.4, end=1.9, chunks=None), ScriptLine(text='Kenny.', speaker=None, start=1.9, end=2.5, chunks=None), ScriptLine(text='Enjoy.', speaker=None, start=2.5, end=3.48, chunks=None), ScriptLine(text='We', speaker=None, start=3.48, end=3.58, chunks=None), ScriptLine(text='just', speaker=None, start=3.58, end=3.74, chunks=None), ScriptLine(text='wanted', speaker=None, start=3.74, end=3.9, chunks=None), ScriptLine(text='to', speaker=None, start=3.9, end=4.06, chunks=None), ScriptLine(text='take', speaker=None, start=4.06, end=4.24, chunks=None), ScriptLine(text='a', speaker=None, start=4.24, end=4.38, chunks=None), ScriptLine(text='minute', speaker=None, start=4.38, end=4.48, chunks=None), ScriptLine(text='to', speaker=None, start=4.48, end=4.66, chunks=None), ScriptLine(text='thank', speaker=None, start=4.66, end=4.9, chunks=None), ScriptLine(text='you.', speaker=None, start=4.9, end=4.9, chunks=None)]), ScriptLine(text='This is Peter. This is Johnny. Kenny. And Joe. We just wanted to take a minute to thank you.', speaker=None, start=0.08, end=4.88, chunks=[ScriptLine(text='This', speaker=None, start=0.08, end=0.3, chunks=None), ScriptLine(text='is', speaker=None, start=0.3, end=0.48, chunks=None), ScriptLine(text='Peter.', speaker=None, start=0.48, end=1.1, chunks=None), ScriptLine(text='This', speaker=None, start=1.1, end=1.18, chunks=None), ScriptLine(text='is', speaker=None, start=1.18, end=1.4, chunks=None), ScriptLine(text='Johnny.', speaker=None, start=1.4, end=2.24, chunks=None), ScriptLine(text='Kenny.', speaker=None, start=2.24, end=2.44, chunks=None), ScriptLine(text='And', speaker=None, start=2.44, end=2.6, chunks=None), ScriptLine(text='Joe.', speaker=None, start=2.6, end=3.5, chunks=None), ScriptLine(text='We', speaker=None, start=3.5, end=3.52, chunks=None), ScriptLine(text='just', speaker=None, start=3.52, end=3.78, chunks=None), ScriptLine(text='wanted', speaker=None, start=3.78, end=3.9, chunks=None), ScriptLine(text='to', speaker=None, start=3.9, end=4.04, chunks=None), ScriptLine(text='take', speaker=None, start=4.04, end=4.24, chunks=None), ScriptLine(text='a', speaker=None, start=4.24, end=4.38, chunks=None), ScriptLine(text='minute', speaker=None, start=4.38, end=4.48, chunks=None), ScriptLine(text='to', speaker=None, start=4.48, end=4.68, chunks=None), ScriptLine(text='thank', speaker=None, start=4.68, end=4.88, chunks=None), ScriptLine(text='you.', speaker=None, start=4.88, end=5.14, chunks=None)])]\n" + ] + } + ], + "source": [ + "from senselab.audio.tasks.speech_to_text.api import transcribe_audios\n", + "from senselab.utils.data_structures.model import HFModel\n", + "\n", + "hf_model = HFModel(path_or_uri=\"openai/whisper-tiny\", revision=\"main\")\n", + "transcripts = transcribe_audios(audios=[audio1, audio2], model=hf_model)\n", + "\n", + "print(\"Transcripts: {}\".format(transcripts))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Speaker Embeddings\n", + "Need to get unique speaker signatures? **EASY!** Here\u2019s how:" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Speaker embeddings: [tensor([ 13.3957, 26.2355, 37.4537, -2.8282, 8.9507, -29.2735, 7.2133,\n", + " 45.1035, -15.5556, -1.7310, 21.6599, -20.0387, 3.2208, 8.7215,\n", + " -10.7560, 22.5969, 29.0999, -11.3117, -7.1902, 1.2383, -1.0127,\n", + " -2.9714, -9.1717, 2.9307, 14.5644, 22.5480, 32.8797, -8.2324,\n", + " -45.2855, -44.8601, -0.4651, 3.9789, 23.8119, 1.7783, -5.7042,\n", + " -15.5208, 19.8033, -24.0270, 5.0979, -3.6242, -13.6030, 39.9842,\n", + " 13.3587, -3.6292, -7.7488, 15.8596, -11.6165, -11.8744, 6.2166,\n", + " -3.0217, -21.2551, 0.7295, 19.4582, 29.5501, -5.4905, -18.5775,\n", + " -16.1116, -33.7832, -3.8432, 17.6366, -2.1034, 9.4590, -27.4943,\n", + " 0.6271, 28.4789, -10.5076, -11.0000, -6.1025, -16.5245, -10.9806,\n", + " 1.6901, 17.1203, 1.9592, -28.5540, 24.3082, 10.7635, -0.8738,\n", + " -17.3388, -8.4655, 15.3403, 22.4938, -6.3000, 4.0899, 9.6344,\n", + " -1.6355, 22.7877, 11.6864, 28.3855, -8.9496, 31.4788, -38.0877,\n", + " 9.4627, 27.5120, -9.9188, -31.4496, 15.4476, 2.0600, -4.8030,\n", + " -21.5671, 5.3270, 30.7293, -4.6995, 4.1002, -7.2646, 2.5260,\n", + " -10.8024, 1.5449, -5.9423, 8.8494, -6.3957, 10.0073, -25.6943,\n", + " 17.2914, 25.6856, 20.1078, -8.2351, -20.7194, 9.9062, -8.8984,\n", + " 5.9353, -27.8755, -7.2793, -21.9900, -2.7173, -17.6591, 20.7600,\n", + " -13.0104, -18.6974, -6.9513, 17.8341, -23.1684, -4.7947, -14.2303,\n", + " 1.2443, -9.7829, -3.3088, -20.0398, -12.6467, -6.2099, 2.0532,\n", + " 12.2837, 15.2998, -9.5024, -8.2001, 8.7692, 3.6774, 11.5215,\n", + " -1.4098, 0.6301, 1.7540, 11.4052, -6.6771, -8.7574, 35.5005,\n", + " -4.3977, -0.5316, -22.3267, 15.5236, -17.2237, 5.5499, 11.2341,\n", + " 16.1329, -9.3619, -13.6780, 1.3820, 15.5668, -0.2123, 8.9507,\n", + " 7.4602, -12.7370, 10.6937, -11.4908, 12.6570, -24.1560, 1.6060,\n", + " -18.6128, -4.3532, 12.1146, 13.4223, 16.2724, -14.1925, 28.3128,\n", + " 28.5381, -7.4341, -28.3595, -0.2795, 4.3653, -6.5646, -25.4785,\n", + " -11.7617, 19.1149, -15.8362]), tensor([ 13.3957, 26.2355, 37.4537, -2.8282, 8.9507, -29.2735, 7.2133,\n", + " 45.1035, -15.5556, -1.7310, 21.6599, -20.0387, 3.2208, 8.7215,\n", + " -10.7560, 22.5969, 29.0999, -11.3117, -7.1902, 1.2383, -1.0127,\n", + " -2.9714, -9.1717, 2.9307, 14.5644, 22.5480, 32.8797, -8.2324,\n", + " -45.2855, -44.8601, -0.4651, 3.9789, 23.8119, 1.7783, -5.7042,\n", + " -15.5208, 19.8033, -24.0270, 5.0979, -3.6242, -13.6030, 39.9842,\n", + " 13.3587, -3.6292, -7.7488, 15.8596, -11.6165, -11.8744, 6.2166,\n", + " -3.0217, -21.2551, 0.7295, 19.4582, 29.5501, -5.4905, -18.5775,\n", + " -16.1116, -33.7832, -3.8432, 17.6366, -2.1034, 9.4590, -27.4943,\n", + " 0.6271, 28.4789, -10.5076, -11.0000, -6.1025, -16.5245, -10.9806,\n", + " 1.6901, 17.1203, 1.9592, -28.5540, 24.3082, 10.7635, -0.8738,\n", + " -17.3388, -8.4655, 15.3403, 22.4938, -6.3000, 4.0899, 9.6344,\n", + " -1.6355, 22.7877, 11.6864, 28.3855, -8.9496, 31.4788, -38.0877,\n", + " 9.4627, 27.5120, -9.9188, -31.4496, 15.4476, 2.0600, -4.8030,\n", + " -21.5671, 5.3270, 30.7293, -4.6995, 4.1002, -7.2646, 2.5260,\n", + " -10.8024, 1.5449, -5.9423, 8.8494, -6.3957, 10.0073, -25.6943,\n", + " 17.2914, 25.6856, 20.1078, -8.2351, -20.7194, 9.9062, -8.8984,\n", + " 5.9353, -27.8755, -7.2793, -21.9900, -2.7173, -17.6591, 20.7600,\n", + " -13.0104, -18.6974, -6.9513, 17.8341, -23.1684, -4.7947, -14.2303,\n", + " 1.2443, -9.7829, -3.3088, -20.0398, -12.6467, -6.2099, 2.0532,\n", + " 12.2837, 15.2998, -9.5024, -8.2001, 8.7692, 3.6774, 11.5215,\n", + " -1.4098, 0.6301, 1.7540, 11.4052, -6.6771, -8.7574, 35.5005,\n", + " -4.3977, -0.5316, -22.3267, 15.5236, -17.2237, 5.5499, 11.2341,\n", + " 16.1329, -9.3619, -13.6780, 1.3820, 15.5668, -0.2123, 8.9507,\n", + " 7.4602, -12.7370, 10.6937, -11.4908, 12.6570, -24.1560, 1.6060,\n", + " -18.6128, -4.3532, 12.1146, 13.4223, 16.2724, -14.1925, 28.3128,\n", + " 28.5381, -7.4341, -28.3595, -0.2795, 4.3653, -6.5646, -25.4785,\n", + " -11.7617, 19.1149, -15.8362])]\n" + ] + } + ], + "source": [ + "from senselab.audio.tasks.speaker_embeddings.api import extract_speaker_embeddings_from_audios\n", + "from senselab.utils.data_structures.model import SpeechBrainModel\n", + "\n", + "ecapa_model = SpeechBrainModel(path_or_uri=\"speechbrain/spkrec-ecapa-voxceleb\", revision=\"main\")\n", + "embeddings = extract_speaker_embeddings_from_audios(audios=[audio1, audio1], model=ecapa_model)\n", + "\n", + "print(\"Speaker embeddings: {}\".format(embeddings))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Speech Emotion Recognition\n", + "Want to know the emotions in the speech? **EASY!**" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Some weights of the model checkpoint at ehcalabres/wav2vec2-lg-xlsr-en-speech-emotion-recognition were not used when initializing Wav2Vec2ForSequenceClassification: ['classifier.dense.bias', 'classifier.dense.weight', 'classifier.output.bias', 'classifier.output.weight', 'wav2vec2.encoder.pos_conv_embed.conv.weight_g', 'wav2vec2.encoder.pos_conv_embed.conv.weight_v']\n", + "- This IS expected if you are initializing Wav2Vec2ForSequenceClassification from the checkpoint of a model trained on another task or with another architecture (e.g. initializing a BertForSequenceClassification model from a BertForPreTraining model).\n", + "- This IS NOT expected if you are initializing Wav2Vec2ForSequenceClassification from the checkpoint of a model that you expect to be exactly identical (initializing a BertForSequenceClassification model from a BertForSequenceClassification model).\n", + "Some weights of Wav2Vec2ForSequenceClassification were not initialized from the model checkpoint at ehcalabres/wav2vec2-lg-xlsr-en-speech-emotion-recognition and are newly initialized: ['classifier.bias', 'classifier.weight', 'projector.bias', 'projector.weight', 'wav2vec2.encoder.pos_conv_embed.conv.parametrizations.weight.original0', 'wav2vec2.encoder.pos_conv_embed.conv.parametrizations.weight.original1']\n", + "You should probably TRAIN this model on a down-stream task to be able to use it for predictions and inference.\n", + "Hardware accelerator e.g. GPU is available in the environment, but no `device` argument is passed to the `Pipeline` object. Model will be on CPU.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Emotion results: [('neutral', {'neutral': 0.14024856686592102, 'angry': 0.1284991055727005, 'calm': 0.12721076607704163, 'happy': 0.12397731840610504, 'disgust': 0.12309260666370392}), ('neutral', {'neutral': 0.1407526433467865, 'angry': 0.1282917857170105, 'calm': 0.12782087922096252, 'disgust': 0.12420850247144699, 'happy': 0.12152237445116043})]\n" + ] + } + ], + "source": [ + "from senselab.audio.tasks.classification.speech_emotion_recognition import speech_emotion_recognition_with_hf_models\n", + "\n", + "emotion_model = HFModel(path_or_uri=\"ehcalabres/wav2vec2-lg-xlsr-en-speech-emotion-recognition\")\n", + "emotion_results = speech_emotion_recognition_with_hf_models([audio1, audio2], emotion_model)\n", + "\n", + "print(\"Emotion results: {}\".format(emotion_results))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Audio Augmentation\n", + "Need to augment your audio data? **EASY!**! Here\u2019s how:" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Augmented audio: waveform=tensor([[1.0264e-04, 7.8498e-05, 1.1372e-04, ..., -0.0000e+00, -0.0000e+00,\n", + " -0.0000e+00]]) sampling_rate=16000 orig_path_or_id='../src/tests/data_for_testing/audio_48khz_mono_16bits.wav' metadata={}\n" + ] + } + ], + "source": [ + "from torch_audiomentations import Compose, PolarityInversion\n", + "from senselab.audio.tasks.data_augmentation.data_augmentation import augment_audios\n", + "\n", + "apply_augmentation = Compose(transforms=[PolarityInversion(p=1, output_type=\"dict\")], output_type=\"dict\")\n", + "[augmented_audio1, augmented_audio2] = augment_audios([audio1, audio2], apply_augmentation)\n", + "\n", + "print(\"Augmented audio: {}\".format(augmented_audio1))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Feature Extraction\n", + "Want to extract some OPENSMILE features from audio? **EASY!**\n" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "OpenSMILE features: [{'F0semitoneFrom27.5Hz_sma3nz_amean': 0.0, 'F0semitoneFrom27.5Hz_sma3nz_stddevNorm': 0.0, 'F0semitoneFrom27.5Hz_sma3nz_percentile20.0': 0.0, 'F0semitoneFrom27.5Hz_sma3nz_percentile50.0': 0.0, 'F0semitoneFrom27.5Hz_sma3nz_percentile80.0': 0.0, 'F0semitoneFrom27.5Hz_sma3nz_pctlrange0-2': 0.0, 'F0semitoneFrom27.5Hz_sma3nz_meanRisingSlope': 0.0, 'F0semitoneFrom27.5Hz_sma3nz_stddevRisingSlope': 0.0, 'F0semitoneFrom27.5Hz_sma3nz_meanFallingSlope': 0.0, 'F0semitoneFrom27.5Hz_sma3nz_stddevFallingSlope': 0.0, 'loudness_sma3_amean': 4.665394306182861, 'loudness_sma3_stddevNorm': 0.5007734298706055, 'loudness_sma3_percentile20.0': 1.9130202531814575, 'loudness_sma3_percentile50.0': 5.763050079345703, 'loudness_sma3_percentile80.0': 6.902288436889648, 'loudness_sma3_pctlrange0-2': 4.9892683029174805, 'loudness_sma3_meanRisingSlope': 48.17048645019531, 'loudness_sma3_stddevRisingSlope': 29.044353485107422, 'loudness_sma3_meanFallingSlope': 34.63795471191406, 'loudness_sma3_stddevFallingSlope': 30.348445892333984, 'spectralFlux_sma3_amean': 3.0373308658599854, 'spectralFlux_sma3_stddevNorm': 0.5504347085952759, 'mfcc1_sma3_amean': -7.3260178565979, 'mfcc1_sma3_stddevNorm': -1.2529454231262207, 'mfcc2_sma3_amean': 1.0084701776504517, 'mfcc2_sma3_stddevNorm': 8.086338996887207, 'mfcc3_sma3_amean': 1.6081973314285278, 'mfcc3_sma3_stddevNorm': 4.823134899139404, 'mfcc4_sma3_amean': 0.7950991988182068, 'mfcc4_sma3_stddevNorm': 6.340704917907715, 'jitterLocal_sma3nz_amean': 0.0, 'jitterLocal_sma3nz_stddevNorm': 0.0, 'shimmerLocaldB_sma3nz_amean': 0.0, 'shimmerLocaldB_sma3nz_stddevNorm': 0.0, 'HNRdBACF_sma3nz_amean': 0.0, 'HNRdBACF_sma3nz_stddevNorm': 0.0, 'logRelF0-H1-H2_sma3nz_amean': 0.0, 'logRelF0-H1-H2_sma3nz_stddevNorm': 0.0, 'logRelF0-H1-A3_sma3nz_amean': 0.0, 'logRelF0-H1-A3_sma3nz_stddevNorm': 0.0, 'F1frequency_sma3nz_amean': 0.0, 'F1frequency_sma3nz_stddevNorm': 0.0, 'F1bandwidth_sma3nz_amean': 0.0, 'F1bandwidth_sma3nz_stddevNorm': 0.0, 'F1amplitudeLogRelF0_sma3nz_amean': -201.0, 'F1amplitudeLogRelF0_sma3nz_stddevNorm': 0.0, 'F2frequency_sma3nz_amean': 0.0, 'F2frequency_sma3nz_stddevNorm': 0.0, 'F2bandwidth_sma3nz_amean': 0.0, 'F2bandwidth_sma3nz_stddevNorm': 0.0, 'F2amplitudeLogRelF0_sma3nz_amean': -201.0, 'F2amplitudeLogRelF0_sma3nz_stddevNorm': 0.0, 'F3frequency_sma3nz_amean': 0.0, 'F3frequency_sma3nz_stddevNorm': 0.0, 'F3bandwidth_sma3nz_amean': 0.0, 'F3bandwidth_sma3nz_stddevNorm': 0.0, 'F3amplitudeLogRelF0_sma3nz_amean': -201.0, 'F3amplitudeLogRelF0_sma3nz_stddevNorm': 0.0, 'alphaRatioV_sma3nz_amean': 0.0, 'alphaRatioV_sma3nz_stddevNorm': 0.0, 'hammarbergIndexV_sma3nz_amean': 0.0, 'hammarbergIndexV_sma3nz_stddevNorm': 0.0, 'slopeV0-500_sma3nz_amean': 0.0, 'slopeV0-500_sma3nz_stddevNorm': 0.0, 'slopeV500-1500_sma3nz_amean': 0.0, 'slopeV500-1500_sma3nz_stddevNorm': 0.0, 'spectralFluxV_sma3nz_amean': 0.0, 'spectralFluxV_sma3nz_stddevNorm': 0.0, 'mfcc1V_sma3nz_amean': 0.0, 'mfcc1V_sma3nz_stddevNorm': 0.0, 'mfcc2V_sma3nz_amean': 0.0, 'mfcc2V_sma3nz_stddevNorm': 0.0, 'mfcc3V_sma3nz_amean': 0.0, 'mfcc3V_sma3nz_stddevNorm': 0.0, 'mfcc4V_sma3nz_amean': 0.0, 'mfcc4V_sma3nz_stddevNorm': 0.0, 'alphaRatioUV_sma3nz_amean': 3.881474018096924, 'hammarbergIndexUV_sma3nz_amean': 3.0704212188720703, 'slopeUV0-500_sma3nz_amean': -0.011536612175405025, 'slopeUV500-1500_sma3nz_amean': -0.004415606148540974, 'spectralFluxUV_sma3nz_amean': 3.0689496994018555, 'loudnessPeaksPerSec': 5.091650009155273, 'VoicedSegmentsPerSec': 0.0, 'MeanVoicedSegmentLengthSec': 0.0, 'StddevVoicedSegmentLengthSec': 0.0, 'MeanUnvoicedSegmentLength': 4.849999904632568, 'StddevUnvoicedSegmentLength': 0.0, 'equivalentSoundLevel_dBp': -7.12342643737793}, {'F0semitoneFrom27.5Hz_sma3nz_amean': 25.710796356201172, 'F0semitoneFrom27.5Hz_sma3nz_stddevNorm': 0.1605353206396103, 'F0semitoneFrom27.5Hz_sma3nz_percentile20.0': 21.095951080322266, 'F0semitoneFrom27.5Hz_sma3nz_percentile50.0': 25.9762020111084, 'F0semitoneFrom27.5Hz_sma3nz_percentile80.0': 29.512413024902344, 'F0semitoneFrom27.5Hz_sma3nz_pctlrange0-2': 8.416461944580078, 'F0semitoneFrom27.5Hz_sma3nz_meanRisingSlope': 82.34796905517578, 'F0semitoneFrom27.5Hz_sma3nz_stddevRisingSlope': 99.20043182373047, 'F0semitoneFrom27.5Hz_sma3nz_meanFallingSlope': 22.002275466918945, 'F0semitoneFrom27.5Hz_sma3nz_stddevFallingSlope': 9.043970108032227, 'loudness_sma3_amean': 0.8608756065368652, 'loudness_sma3_stddevNorm': 0.43875232338905334, 'loudness_sma3_percentile20.0': 0.5877408981323242, 'loudness_sma3_percentile50.0': 0.8352401852607727, 'loudness_sma3_percentile80.0': 1.1747918128967285, 'loudness_sma3_pctlrange0-2': 0.5870509147644043, 'loudness_sma3_meanRisingSlope': 10.285205841064453, 'loudness_sma3_stddevRisingSlope': 7.544795513153076, 'loudness_sma3_meanFallingSlope': 7.612530708312988, 'loudness_sma3_stddevFallingSlope': 4.159041404724121, 'spectralFlux_sma3_amean': 0.3213598430156708, 'spectralFlux_sma3_stddevNorm': 0.6921582221984863, 'mfcc1_sma3_amean': 10.274803161621094, 'mfcc1_sma3_stddevNorm': 1.1581648588180542, 'mfcc2_sma3_amean': 4.262022018432617, 'mfcc2_sma3_stddevNorm': 2.0523014068603516, 'mfcc3_sma3_amean': 7.624594211578369, 'mfcc3_sma3_stddevNorm': 1.4570356607437134, 'mfcc4_sma3_amean': 3.667618751525879, 'mfcc4_sma3_stddevNorm': 2.69022274017334, 'jitterLocal_sma3nz_amean': 0.019597545266151428, 'jitterLocal_sma3nz_stddevNorm': 0.9063855409622192, 'shimmerLocaldB_sma3nz_amean': 1.264746069908142, 'shimmerLocaldB_sma3nz_stddevNorm': 0.4629262685775757, 'HNRdBACF_sma3nz_amean': 3.6400070190429688, 'HNRdBACF_sma3nz_stddevNorm': 0.5911335945129395, 'logRelF0-H1-H2_sma3nz_amean': 1.2158769369125366, 'logRelF0-H1-H2_sma3nz_stddevNorm': 3.8838469982147217, 'logRelF0-H1-A3_sma3nz_amean': 18.83077621459961, 'logRelF0-H1-A3_sma3nz_stddevNorm': 0.3087078630924225, 'F1frequency_sma3nz_amean': 665.1737670898438, 'F1frequency_sma3nz_stddevNorm': 0.4195936620235443, 'F1bandwidth_sma3nz_amean': 1300.4451904296875, 'F1bandwidth_sma3nz_stddevNorm': 0.16353538632392883, 'F1amplitudeLogRelF0_sma3nz_amean': -132.1533660888672, 'F1amplitudeLogRelF0_sma3nz_stddevNorm': -0.6691396832466125, 'F2frequency_sma3nz_amean': 1657.174560546875, 'F2frequency_sma3nz_stddevNorm': 0.17014622688293457, 'F2bandwidth_sma3nz_amean': 1105.97900390625, 'F2bandwidth_sma3nz_stddevNorm': 0.24582387506961823, 'F2amplitudeLogRelF0_sma3nz_amean': -132.76707458496094, 'F2amplitudeLogRelF0_sma3nz_stddevNorm': -0.6468541026115417, 'F3frequency_sma3nz_amean': 2601.5419921875, 'F3frequency_sma3nz_stddevNorm': 0.11460811644792557, 'F3bandwidth_sma3nz_amean': 1091.6160888671875, 'F3bandwidth_sma3nz_stddevNorm': 0.37865355610847473, 'F3amplitudeLogRelF0_sma3nz_amean': -134.5210723876953, 'F3amplitudeLogRelF0_sma3nz_stddevNorm': -0.6203084588050842, 'alphaRatioV_sma3nz_amean': -8.626544952392578, 'alphaRatioV_sma3nz_stddevNorm': -0.4953792989253998, 'hammarbergIndexV_sma3nz_amean': 16.796852111816406, 'hammarbergIndexV_sma3nz_stddevNorm': 0.3567315638065338, 'slopeV0-500_sma3nz_amean': 0.021949267014861107, 'slopeV0-500_sma3nz_stddevNorm': 1.0097254514694214, 'slopeV500-1500_sma3nz_amean': -0.008139749057590961, 'slopeV500-1500_sma3nz_stddevNorm': -1.6243412494659424, 'spectralFluxV_sma3nz_amean': 0.4831695556640625, 'spectralFluxV_sma3nz_stddevNorm': 0.48576220870018005, 'mfcc1V_sma3nz_amean': 20.25444793701172, 'mfcc1V_sma3nz_stddevNorm': 0.44413772225379944, 'mfcc2V_sma3nz_amean': 3.6194145679473877, 'mfcc2V_sma3nz_stddevNorm': 2.17659068107605, 'mfcc3V_sma3nz_amean': 7.736477375030518, 'mfcc3V_sma3nz_stddevNorm': 1.8631006479263306, 'mfcc4V_sma3nz_amean': 4.605042934417725, 'mfcc4V_sma3nz_stddevNorm': 2.8646581172943115, 'alphaRatioUV_sma3nz_amean': -2.5990116596221924, 'hammarbergIndexUV_sma3nz_amean': 8.86290168762207, 'slopeUV0-500_sma3nz_amean': 0.002166706370189786, 'slopeUV500-1500_sma3nz_amean': 0.00673573836684227, 'spectralFluxUV_sma3nz_amean': 0.24703539907932281, 'loudnessPeaksPerSec': 3.8834950923919678, 'VoicedSegmentsPerSec': 2.745098114013672, 'MeanVoicedSegmentLengthSec': 0.12214285880327225, 'StddevVoicedSegmentLengthSec': 0.09025190770626068, 'MeanUnvoicedSegmentLength': 0.20666664838790894, 'StddevUnvoicedSegmentLength': 0.17666037380695343, 'equivalentSoundLevel_dBp': -24.297258377075195}]\n" + ] + } + ], + "source": [ + "from senselab.audio.tasks.features_extraction.opensmile import extract_opensmile_features_from_audios\n", + "\n", + "features = extract_opensmile_features_from_audios([audio1, audio2])\n", + "\n", + "print(\"OpenSMILE features: {}\".format(features))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Speech Enhancement\n", + "Need to clean up your audio? **EASY!** Here\u2019s how:" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Enhanced audios: [Audio(waveform=tensor([[0.0026, 0.0027, 0.0041, ..., 0.0000, 0.0000, 0.0000]]), sampling_rate=16000, orig_path_or_id='../src/tests/data_for_testing/audio_48khz_mono_16bits.wav', metadata={}), Audio(waveform=tensor([[0.0026, 0.0027, 0.0041, ..., 0.0000, 0.0000, 0.0000]]), sampling_rate=16000, orig_path_or_id='../src/tests/data_for_testing/audio_48khz_mono_16bits.wav', metadata={})]\n" + ] + } + ], + "source": [ + "from senselab.audio.tasks.speech_enhancement.api import enhance_audios\n", + "from senselab.utils.data_structures.model import SpeechBrainModel\n", + "\n", + "speechbrain_model = SpeechBrainModel(path_or_uri=\"speechbrain/sepformer-wham16k-enhancement\", revision=\"main\")\n", + "enhanced_audios = enhance_audios(audios=[audio1, audio1], model=speechbrain_model)\n", + "\n", + "print(\"Enhanced audios: {}\".format(enhanced_audios))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "senselab-UNCffeRf-py3.10", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.10" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +}