Source code for metamoth.metadata
"""Module with AM Metadata structure for different firmware versions.
This module contains the AMMetadata class and its subclasses for different
firmware versions.
"""
# pylint: disable=too-many-instance-attributes
from dataclasses import dataclass
from datetime import datetime as dt
from datetime import timezone as tz
from typing import Optional
from metamoth.enums import FilterType, GainSetting, RecordingState
from metamoth.mediainfo import MediaInfo
__all__ = [
"CommentMetadata",
"CommentMetadataV1",
"CommentMetadataV2",
"CommentMetadataV3",
"CommentMetadataV4",
"CommentMetadataV5",
"CommentMetadataV6",
"AMMetadata",
"FrequencyFilter",
"AmplitudeThreshold",
"FrequencyTrigger",
"ExtraMetadata",
"assemble_metadata",
]
[docs]@dataclass
class FrequencyFilter:
"""Frequency filter applied to the recording."""
type: FilterType
"""Filter type applied to the recording."""
higher_frequency_hz: Optional[int]
"""Higher filter frequency in Hz. None if no upper filter is applied."""
lower_frequency_hz: Optional[int]
"""Lower filter frequency in Hz. None if no lower filter is applied."""
[docs]@dataclass
class AmplitudeThreshold:
"""Amplitude threshold applied to the recording."""
enabled: bool
"""True if the amplitude threshold is enabled."""
threshold: int
"""Amplitude threshold."""
[docs]@dataclass
class FrequencyTrigger:
"""Frequency trigger metadata."""
enabled: bool
"""True if frequency trigger is enabled."""
centre_frequency_hz: int
"""Centre frequency in Hz."""
window_length_shift: int
"""Window length shift in samples."""
[docs]@dataclass
class CommentMetadata:
"""Base class for AudioMoth metadata stored in comment."""
audiomoth_id: str
"""AudioMoth ID. This is the serial number of the AudioMoth."""
datetime: dt
"""Datetime of the recording."""
timezone: tz
"""Timezone of the recording."""
gain: GainSetting
"""Gain setting of the AudioMoth."""
comment: str
"""Full comment string."""
low_battery: bool
"""True if the battery is low."""
battery_state_v: float
"""Battery state in volts."""
[docs]@dataclass
class CommentMetadataV1(CommentMetadata):
"""AudioMoth recording metadata in comment string.
Valid for versions 1.0, 1.0.1, 1.1.0, 1.2.0,
Timezone is always UTC for versions 1.0 and 1.0.1. For versions 1.1.0 and
1.2.0, the an UTC hour offset can be set in the AudioMoth settings.
"""
[docs]@dataclass
class CommentMetadataV2(CommentMetadata):
"""AudioMoth recording metadata in comment string.
Valid for versions 1.2.1, 1.2.2, 1.3.0
"""
recording_state: RecordingState
"""Recording state of the AudioMoth."""
[docs]@dataclass
class CommentMetadataV3(CommentMetadata):
"""AudioMoth recording metadata in comment string.
Valid for versions 1.4.0, 1.4.1, 1.4.2, 1.4.3, 1.4.4
"""
recording_state: RecordingState
"""Recording state of the AudioMoth."""
temperature_c: float
"""Temperature in degrees Celsius."""
amplitude_threshold: AmplitudeThreshold
"""Amplitude threshold applied to the recording."""
frequency_filter: FrequencyFilter
"""Frequency filter applied to the recording."""
[docs]@dataclass
class CommentMetadataV4(CommentMetadata):
"""AudioMoth recording metadata in comment string.
Valid for version 1.5.0
"""
recording_state: RecordingState
"""Recording state of the AudioMoth."""
temperature_c: float
"""Temperature in degrees Celsius."""
amplitude_threshold: AmplitudeThreshold
"""Amplitude threshold applied to the recording."""
frequency_filter: FrequencyFilter
"""Frequency filter applied to the recording."""
deployment_id: Optional[int]
"""Deployment ID of the AudioMoth."""
external_microphone: bool
"""True if an external microphone is connected to the AudioMoth."""
[docs]@dataclass
class CommentMetadataV5(CommentMetadata):
"""AudioMoth recording metadata in comment string.
Valid for versions 1.6.0, 1.7.0 and 1.7.1
"""
recording_state: RecordingState
"""Recording state of the AudioMoth."""
temperature_c: float
"""Temperature in degrees Celsius."""
amplitude_threshold: AmplitudeThreshold
"""Amplitude threshold applied to the recording."""
frequency_filter: FrequencyFilter
"""Frequency filter applied to the recording."""
deployment_id: Optional[str]
"""Deployment ID of the AudioMoth."""
external_microphone: bool
"""True if an external microphone is connected to the AudioMoth."""
minimum_trigger_duration_s: int
"""Minimum trigger duration in seconds."""
[docs]@dataclass
class CommentMetadataV6(CommentMetadata):
"""AudioMoth recording metadata in comment string.
Valid for versions 1.8.0 and 1.8.1
"""
recording_state: Optional[RecordingState] = RecordingState.RECORDING_OKAY
"""Recording state of the AudioMoth."""
temperature_c: Optional[float] = None
"""Temperature in degrees Celsius."""
amplitude_threshold: Optional[AmplitudeThreshold] = None
"""Amplitude threshold applied to the recording."""
frequency_filter: Optional[FrequencyFilter] = None
"""Frequency filter applied to the recording."""
deployment_id: Optional[int] = None
"""Deployment ID of the AudioMoth."""
external_microphone: bool = False
"""True if an external microphone is connected to the AudioMoth."""
minimum_trigger_duration_s: Optional[int] = None
"""Minimum trigger duration in seconds."""
frequency_trigger: Optional[FrequencyTrigger] = None
"""Frequency trigger metadata."""
[docs]@dataclass
class ExtraMetadata:
"""Extra metadata."""
path: str
"""Path to the recording."""
firmware_version: str
"""Firmware version of the AudioMoth."""
[docs]@dataclass
class AMMetadata(CommentMetadataV6, MediaInfo, ExtraMetadata):
"""AudioMoth recording metadata."""
[docs]def assemble_metadata(
path: str,
media_info: MediaInfo,
comment_metadata: dict,
artist: Optional[str],
) -> AMMetadata:
"""Assemble the metadata for the recording.
Parameters
----------
media_info : dict
Media information dictionary.
metadata : dict
Metadata dictionary.
artist : str
Artist string. Can be None.
Returns
-------
metadata : AMMetadataV6
Metadata object.
"""
if comment_metadata["audiomoth_id"] is None:
if artist is None:
raise ValueError("No AudioMoth ID found in comment or artist.")
comment_metadata["audiomoth_id"] = artist
return AMMetadata(
path=path,
samplerate_hz=media_info.samplerate_hz,
duration_s=media_info.duration_s,
samples=media_info.samples,
channels=media_info.channels,
**comment_metadata,
)