Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
6473cb0
move multichannel_audio_file patch to specific fixture
Gautzilla Jul 22, 2026
6121a43
add MockedAudioFile class for tests
Gautzilla Jul 22, 2026
c9ff8e7
add tests for MockedAudioFile class
Gautzilla Jul 22, 2026
e6881e6
add AudioData.channels property
Gautzilla Jul 22, 2026
1449739
override stream in MockedAudioFile
Gautzilla Jul 22, 2026
ded6d86
add test for chanel-based filtered get_value()
Gautzilla Jul 22, 2026
e7f430d
target AudioData.channels in AudioData.get_value() method
Gautzilla Jul 22, 2026
df24c14
remove redundant if statement
Gautzilla Jul 22, 2026
421e714
add default SpectroData channel test
Gautzilla Jul 22, 2026
0b28660
add test for SpectroData.audio_channel
Gautzilla Jul 22, 2026
24f513c
add SpectroData.audio_channel property
Gautzilla Jul 23, 2026
fbf0c53
SpectroData.audio_channel refers to the channel in the file
Gautzilla Jul 23, 2026
5c55eb7
add channels parameter docstring
Gautzilla Jul 23, 2026
0a07d1a
add channels to AudioData dict
Gautzilla Jul 23, 2026
2da2a14
fix MockedAudioFile import
Gautzilla Jul 23, 2026
a41f25c
refix MockedAudioFile import
Gautzilla Jul 23, 2026
3ffdf8e
add test for SpectroData channel serialization
Gautzilla Jul 23, 2026
9cd919d
add audio_channels property in SpectroData dict
Gautzilla Jul 23, 2026
f9bcb81
store normalization values per channel
Gautzilla Jul 23, 2026
ae46385
use chanel-based normalization in default values
Gautzilla Jul 23, 2026
15c8fab
add normalization_values serialization test
Gautzilla Jul 23, 2026
7ffb8fb
adapt default axes to multichannel audio files
Gautzilla Jul 24, 2026
5b07cb7
adapt get_default_axes to 2D plots
Gautzilla Jul 24, 2026
2f0a7e1
Merge branch 'main' into multichannel-files
Gautzilla Jul 27, 2026
eaa0e99
remove test placeholder
Gautzilla Jul 27, 2026
58e4922
add multichannel AudioData default plot() axes test
Gautzilla Jul 27, 2026
c4910c4
Merge branch 'main' into multichannel-files
Gautzilla Jul 29, 2026
2afdfc4
add multichannel page in usage doc section
Gautzilla Jul 29, 2026
5d27519
add multichannel example notebook
Gautzilla Jul 29, 2026
f4dbdfe
Merge branch 'main' into multichannel-files
Gautzilla Jul 30, 2026
96f690d
adapt mocked method signature with updated kwargs one
Gautzilla Jul 30, 2026
478824d
replace messy kwargs with args
Gautzilla Jul 30, 2026
1f71baa
Merge branch 'main' into multichannel-files
Gautzilla Jul 30, 2026
a80a933
store both args and kwargs in plot(Ã) mock
Gautzilla Jul 30, 2026
fb3c9ba
fix sds name in notebook
Gautzilla Jul 30, 2026
744a60c
add multichannel entry in examples toctree
Gautzilla Jul 30, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file not shown.
276 changes: 276 additions & 0 deletions docs/source/example_multichannel.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,276 @@
{
"cells": [
{
"cell_type": "code",
"id": "initial_id",
"metadata": {
"collapsed": true,
"tags": [
"remove-cell"
]
},
"source": [
"# Executing this cell will:\n",
"\n",
"# Disable all TQDM outputs in stdout.\n",
"import os\n",
"\n",
"os.environ[\"DISABLE_TQDM\"] = \"True\"\n",
"\n",
"# Setup the python logger for the Public API\n",
"from osekit import setup_logging\n",
"\n",
"setup_logging() # Overwrites the default logger to"
],
"outputs": [],
"execution_count": null
},
{
"cell_type": "markdown",
"id": "8c395a2079d86493",
"metadata": {},
"source": [
"# Working with multichannel audio files [^download]\n",
"\n",
"[^download]: This notebook can be downloaded as **{nb-download}`example_multichannel.ipynb`**."
]
},
{
"cell_type": "markdown",
"id": "90049102bdc38599",
"metadata": {},
"source": [
"# Basics: Core API\n",
"\n",
"## Parsing a multichannel file\n",
"\n",
"The `AudioFile.channels` property indicates the number of channels that a given `AudioFile` has.\n",
"\n",
"The `AudioData.channels` property is a **list of ints** that represents the targeted channels of the file:"
]
},
{
"cell_type": "code",
"id": "c1f1dcd7e3e90141",
"metadata": {},
"source": [
"from pathlib import Path\n",
"from osekit.core.audio_file import AudioFile\n",
"from osekit.core.audio_data import AudioData\n",
"\n",
"af = AudioFile(\n",
" path=Path(\"_static/sample_audio/multichannel/multichannel_220925_223450.wav\"),\n",
" strptime_format=r\"%y%m%d_%H%M%S\",\n",
")\n",
"\n",
"print(f\"The audio file has {af.channels} channels.\")\n",
"\n",
"ad: AudioData = AudioData.from_files([af])\n",
"\n",
"print(f\"By default, all channels are targeted: {ad.channels}.\")"
],
"outputs": [],
"execution_count": null
},
{
"cell_type": "markdown",
"id": "fd8e3d095a534d5",
"metadata": {},
"source": [
"## Targeting specific channel(s)\n",
"\n",
"`AudioData.channels` can be set to target specific channel(s):"
]
},
{
"cell_type": "code",
"id": "ea1c469c76a14fe3",
"metadata": {},
"source": [
"import matplotlib.pyplot as plt\n",
"\n",
"ad.channels = [0, 2] # Removing channel 1 from targeted channels\n",
"ad.plot()\n",
"plt.show()"
],
"outputs": [],
"execution_count": null
},
{
"cell_type": "markdown",
"id": "1b00f1600c66e3c6",
"metadata": {},
"source": [
"## Computing the spectrum of a specific channel\n",
"\n",
"`SpectroData` target **a specific** channel of a file:"
]
},
{
"cell_type": "code",
"id": "87f3839389f684c3",
"metadata": {},
"source": [
"from osekit.core.spectro_data import SpectroData\n",
"from scipy.signal import ShortTimeFFT, windows\n",
"\n",
"sd = SpectroData.from_audio_data(\n",
" data=ad,\n",
" fft=ShortTimeFFT(win=windows.hamming(1024), hop=128, fs=ad.sample_rate),\n",
")\n",
"\n",
"sd.audio_channel = 2 # Targets the third channel of the file (which is the second channel of the AudioData)\n",
"sd.plot()\n",
"plt.show()"
],
"outputs": [],
"execution_count": null
},
{
"cell_type": "markdown",
"id": "8bfbe3f450ad73cd",
"metadata": {},
"source": "# Public API"
},
{
"cell_type": "markdown",
"id": "e2d5321198880205",
"metadata": {},
"source": [
"## Build the Project\n",
"\n",
"First, we have to build the project from the raw audio files:"
]
},
{
"cell_type": "code",
"id": "3ab3cb447c59a857",
"metadata": {},
"source": [
"from pathlib import Path\n",
"from osekit.public.project import Project\n",
"\n",
"folder = Path(r\"_static/sample_audio/multichannel\")\n",
"strptime_format = r\"%y%m%d_%H%M%S\"\n",
"\n",
"project = Project(\n",
" folder=folder,\n",
" strptime_format=strptime_format,\n",
")\n",
"\n",
"project.build()"
],
"outputs": [],
"execution_count": null
},
{
"cell_type": "markdown",
"id": "2f5510c9c396ee2f",
"metadata": {},
"source": [
"## Declare the Transform\n",
"\n",
"Then we **declare** a `Transform` which would work on the audio (e.g. export spectrograms):"
]
},
{
"cell_type": "code",
"id": "d993991e8c23a2c0",
"metadata": {},
"source": [
"from osekit.public.transform import Transform, OutputType\n",
"from scipy.signal import ShortTimeFFT\n",
"from scipy.signal.windows import hamming\n",
"\n",
"transform = Transform(\n",
" output_type=OutputType.SPECTROGRAM,\n",
" fft=ShortTimeFFT(win=hamming(1024), hop=128, fs=project.origin_dataset.sample_rate),\n",
" name=\"one_spectrogram_per_channel\",\n",
")"
],
"outputs": [],
"execution_count": null
},
{
"cell_type": "markdown",
"id": "7f58320386d3dc14",
"metadata": {},
"source": "Now, we will use some **Core API** on top of the **Public API** to get one spectrogram per channel:"
},
{
"cell_type": "code",
"id": "c6b54cf5f1ecb44b",
"metadata": {},
"source": [
"import copy\n",
"\n",
"# We get the transform SpectroData(s) -- here there is only one\n",
"sds = project.prepare_spectro(transform=transform)\n",
"\n",
"# We'll create one spectro data per channel:\n",
"sds_channels = []\n",
"for sd in sds.data:\n",
" for channel in (0, 2): # Targeting the specific channels here\n",
" sd_copy = copy.copy(sd)\n",
" sd_copy.audio_channel = channel\n",
" sd_copy.name += \"_channel_\" + str(channel)\n",
" sds_channels.append(sd_copy)\n",
"\n",
"# We'll then set the sds data as sd_channels:\n",
"sds.data = sds_channels\n",
"\n",
"# Let's check everything's ok:\n",
"for sd in sds.data:\n",
" print(f\"Spectrogram for channel {sd.audio_channel}\")"
],
"outputs": [],
"execution_count": null
},
{
"cell_type": "markdown",
"id": "a119e3339b02e775",
"metadata": {},
"source": "We should now be able to run the transform on the edited `SpectroDataset`:"
},
{
"cell_type": "code",
"id": "1948b260fcaf03ab",
"metadata": {},
"source": "project.run(transform=transform, spectro_dataset=sds)",
"outputs": [],
"execution_count": null
},
{
"cell_type": "code",
"id": "449dc442b4a5df75",
"metadata": {},
"source": [
"# Reset the project to get all files back to place.\n",
"project.reset()"
],
"outputs": [],
"execution_count": null
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 2
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython2",
"version": "2.7.6"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
8 changes: 8 additions & 0 deletions docs/source/examples.rst
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,17 @@ In the ``docs/source/_static/sample_audio/timestamped`` folder, files are just n

===========

.. topic:: :doc:`Work with multichannel audio files <example_multichannel>`

Work on multichannel audio, compute spectrums from specific channels...

===========

.. topic:: :doc:`Use APLOSE results <example_aplose_result>`

Parse `APLOSE <https://osmose.ifremer.fr/doc/>`_ results csv files in OSEkit, and use the detections to filter the audio or spectrograms from the project.


.. toctree ::
:hidden:

Expand All @@ -70,4 +77,5 @@ In the ``docs/source/_static/sample_audio/timestamped`` folder, files are just n
example_multiple_spectrograms
example_multiple_spectrograms_id
example_ltas
example_multichannel
example_aplose_result
46 changes: 46 additions & 0 deletions docs/source/multichannel.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
.. _multichannel:

Working with multichannel audio files
-------------------------------------

The audio classes in **OSEkit** allow multichannel audio handling, e.g. the :meth:`osekit.core.audio_data.AudioData.get_value` method returns a ``samples x channels`` matrix.

The :attr:`osekit.core.audio_file.AudioFile.channels` property depicts the number of channels of a given ``AudioFile``:

.. code-block:: python

from pathlib import Path
from osekit.core.audio_file import AudioFile

af = AudioFile(...)
print(af.channels)

>>> 3

The :attr:`osekit.core.audio_data.AudioData.channels` property relates to the list of channels concerned by this audio data:

.. code-block:: python

from osekit.core.audio_data import AudioData

ad = AudioData.from_files(files=[af])
ad.channels = [0,2] # We want to keep only channels 0 and 2
print(ad.get_value().shape[1])

>>> 2 # One value array per channel

Finally, a ``SpectroData`` that has a linked ``AudioData`` targets a **specific channel** of this ``AudioData``:

.. code-block:: python

from osekit.core.spectro_data import SpectroData
from scipy.signal import ShortTimeFFT

sd = SpectroData.from_audio_data(data=ad, ...)
sd.audio_channel = 2 # The spectrum will be computed on the channel 2 of the file

.. important::

The :attr:`osekit.core.spectro_data.SpectroData.audio_channel` value refers to the index of the channel of the **file**.

If, as in the example above, the ``AudioFile`` has 3 channels ``[0,1,2]``, the ``AudioData`` targets channels ``[0,2]`` and the ``SpectroData`` targets the channel ``2``, the spectrum will be computed on the **third channel** of the file (with index ``2``).
1 change: 1 addition & 0 deletions docs/source/usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,4 @@ The package combines two APIs:
multiprocessing
jobs
aplose
multichannel
Loading