Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/more terms #13

Merged
merged 8 commits into from
Oct 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions src/soundevent/data/datasets.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

class Dataset(RecordingSet):
name: str

description: Optional[str] = None

@classmethod
Expand Down
2 changes: 1 addition & 1 deletion src/soundevent/data/features.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,8 @@ def handle_deprecated_name(cls, values):

def find_feature(
features: Sequence[Feature],
term: Optional[Term] = None,
label: Optional[str] = None,
term: Optional[Term] = None,
default: Optional[Feature] = None,
) -> Optional[Feature]:
"""Find a feature by its name.
Expand Down
10 changes: 4 additions & 6 deletions src/soundevent/data/geometries.py
Original file line number Diff line number Diff line change
Expand Up @@ -397,7 +397,7 @@ def _is_ordered_by_time(cls, v: List[List[float]]) -> List[List[float]]:
start_time = v[0][0]
end_time = v[-1][0]
if start_time > end_time:
raise ValueError("The line must be ordered by time.")
return v[::-1]
return v


Expand Down Expand Up @@ -549,14 +549,12 @@ def _validate_coordinates(cls, v: List[float]) -> List[float]:
)

if start_time > end_time:
raise ValueError("The start time must be before the end time.")
start_time, end_time = end_time, start_time

if low_freq > high_freq:
raise ValueError(
"The start frequency must be before the end frequency."
)
low_freq, high_freq = high_freq, low_freq

return v
return [start_time, low_freq, end_time, high_freq]


class MultiPoint(BaseGeometry):
Expand Down
278 changes: 195 additions & 83 deletions src/soundevent/data/recordings.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
from typing import List, Optional, Union
from uuid import UUID, uuid4

from pydantic import BaseModel, Field
from pydantic import BaseModel, ConfigDict, Field

from soundevent.data.features import Feature
from soundevent.data.notes import Note
Expand All @@ -73,93 +73,205 @@


class Recording(BaseModel):
"""Recording Class.

Representing an audio recording in bioacoustic research, recordings embody
single files in their raw, unaltered state, typically as generated by
recording devices. They serve as the foundational material upon which
bioacoustic research is conducted. Each recording is characterized by a
unique identifier, file path, duration, number of channels, sample rate,
time expansion factor (if applicable), hash, recording date, time,
geographic coordinates, associated tags, features, and notes

Attributes
----------
uuid
A unique identifier for the recording.
path
The file path to the audio recording.
duration
The duration of the audio file in seconds. This duration is adjusted by
the time expansion factor if the audio file is time expanded, providing
the real duration of the recorded audio.
channels
The number of channels in the audio file.
samplerate
The sample rate of the audio file in Hz. Similar to duration, the
sample rate is adjusted by the time expansion factor if the audio file
is time expanded, representing the real sample rate of the recorded
audio.
time_expansion
The time expansion factor of the audio file. Default is 1.0, indicating
no time expansion.
hash
The md5 hash of the audio file. Default is None.
date
The date on which the recording was made. Default is None.
time
The time at which the recording was made. Default is None.
latitude
The latitude coordinate of the site of recording. Default is None.
longitude
The longitude coordinate of the site of recording. Default is None.
tags
A list of tags associated with the recording. Default is an empty list.
features
A list of features associated with the recording. Default is an empty
list.
notes : List[Note]
A list of notes associated with the recording. Default is an empty
list.
"""Represents an audio recording in bioacoustic research.

This class models raw, unaltered audio files as captured by recording
devices. Recordings are fundamental to bioacoustic research and are
identified by various metadata, including:

* Unique identifier
* File path
* Duration
* Number of channels
* Sample rate
* Time expansion factor
* Hash
* Geographic coordinates
* Tags, features, and notes

Notes
-----
When dealing with time-expanded recordings, adjustments are made to both
the duration and sample rate based on the time expansion factor. As a
result, the duration and sample rate stored in the Recording object may
deviate from the values derived from the file metadata.

A time-expanded recording is one that has been either slowed down or sped
up, typically to facilitate the playback and analysis of audio data. In
these cases, although the audio was originally captured at a specific
sample rate, the resulting audio file exhibits a different sample rate due
to the time expansion process. The time expansion factor represents the
ratio of the original sample rate to the sample rate of the time-expanded
recording.

Since the actual sample rate used to capture the audio differs from the
stored sample rate in the audio file, we have chosen to store the true
sample rate in the Recording object. This ensures that the Recording object
accurately reflects the sample rate at which the audio was originally
captured.
For time-expanded audio (slowed down or sped up), the `duration` and
`sample_rate` reflect the **original recording values**, not the modified
values in the file. This ensures accuracy in representing the audio's true
capture conditions.
"""

uuid: UUID = Field(default_factory=uuid4, repr=False)
path: Path
duration: float
channels: int
samplerate: int
time_expansion: float = 1.0
hash: Optional[str] = Field(default=None, repr=False)
date: Optional[datetime.date] = Field(default=None, repr=False)
time: Optional[datetime.time] = Field(default=None, repr=False)
latitude: Optional[float] = Field(default=None, repr=False)
longitude: Optional[float] = Field(default=None, repr=False)
tags: List[Tag] = Field(default_factory=list, repr=False)
features: List[Feature] = Field(default_factory=list, repr=False)
notes: List[Note] = Field(default_factory=list, repr=False)
owners: List[User] = Field(default_factory=list, repr=False)
rights: Optional[str] = None
model_config = ConfigDict(extra="allow")

uuid: UUID = Field(
default_factory=uuid4,
serialization_alias="dcterms:identifier",
title="Identifier",
description="An unambiguous reference to the resource within a given context.",
repr=False,
json_schema_extra={
"$id": "http://purl.org/dc/terms/identifier",
},
)
"""A unique identifier for the recording."""

path: Path = Field(
title="Path",
description="The path to the audio file.",
repr=True,
)
"""The file path to the audio recording."""

duration: float = Field(
title="Duration",
serialization_alias="ac:mediaDuration",
description="The duration of the audio file in seconds.",
repr=False,
json_schema_extra={
"$id": "http://rs.tdwg.org/ac/terms/mediaDuration",
},
)
"""The duration of the audio file in seconds.

This duration is adjusted by the time expansion factor if the audio file is
time expanded, providing the real duration of the recorded audio.
"""

channels: int = Field(
title="Channels",
serialization_alias="mo:channels",
description="The number of channels in the audio file.",
repr=False,
json_schema_extra={"$id": "http://purl.org/ontology/mo/channels"},
)
"""The number of channels in the audio file."""

samplerate: int = Field(
title="Sample Rate",
serialization_alias="mo:sample_rate",
description="The sample rate of the audio file in Hz.",
repr=False,
json_schema_extra={"$id": "http://purl.org/ontology/mo/sample_rate"},
)
"""The sample rate of the audio file in Hz.

Similar to duration, the sample rate is adjusted by the time expansion
factor if the audio file is time expanded, representing the real sample
rate of the recorded audio.
"""

time_expansion: float = Field(
default=1.0,
serialization_alias="ac:mediaSpeed",
title="Media Speed",
description="The decimal fraction representing the natural speed over the encoded speed.",
repr=False,
json_schema_extra={"$id": "http://rs.tdwg.org/ac/terms/mediaSpeed"},
)
"""The time expansion factor of the audio file.

Default is 1.0, indicating no time expansion.
"""

hash: Optional[str] = Field(
default=None,
serialization_alias="ac:hashValue",
title="Hash",
description="The value computed by a hash function applied to the media that will be delivered at the access point.",
repr=False,
json_schema_extra={"$id": "http://rs.tdwg.org/ac/terms/hashValue"},
)
"""The md5 hash of the audio file.

Default is None.
"""

date: Optional[datetime.date] = Field(
default=None,
repr=False,
deprecated=False,
)
"""The date on which the recording was made.

Default is None.
"""

time: Optional[datetime.time] = Field(
default=None,
repr=False,
deprecated=False,
)
"""The time at which the recording was made.

Default is None.
"""

latitude: Optional[float] = Field(
default=None,
serialization_alias="dwc:decimalLatitude",
title="Decimal Latitude",
description="The geographic latitude (in decimal degrees, using the spatial reference system given in dwc:geodeticDatum) of the geographic center of a dcterms:Location. Positive values are north of the Equator, negative values are south of it. Legal values lie between -90 and 90, inclusive.",
repr=False,
json_schema_extra={
"$id": "http://rs.tdwg.org/dwc/terms/decimalLatitude"
},
)
"""The latitude coordinate of the site of recording.

Default is None.
"""

longitude: Optional[float] = Field(
default=None,
serialization_alias="dwc:decimalLongitude",
title="Decimal Longitude",
description="The geographic longitude (in decimal degrees, using the spatial reference system given in dwc:geodeticDatum) of the geographic center of a dcterms:Location. Positive values are east of the Greenwich Meridian, negative values are west of it. Legal values lie between -180 and 180, inclusive.",
repr=False,
json_schema_extra={
"$id": "http://rs.tdwg.org/dwc/terms/decimalLongitude"
},
)

license: Optional[str] = Field(
default=None,
serialization_alias="dcterms:license",
title="License",
description="A legal document giving official permission to do something with the resource.",
repr=False,
json_schema_extra={"$id": "http://purl.org/dc/terms/license"},
)

owners: List[User] = Field(
default_factory=list,
serialization_alias="xmpRights:Owner",
title="Copyright Owner",
description="A list of legal owners of the resource.",
repr=False,
json_schema_extra={"$id": "http://ns.adobe.com/xap/1.0/rights/Owner"},
)

rights: Optional[str] = Field(
default=None,
serialization_alias="dcterms:rights",
title="Copyright Statement",
description="Information about rights held in and over the resource.",
repr=False,
json_schema_extra={"$id": "http://purl.org/dc/terms/rights"},
)

tags: List[Tag] = Field(
default_factory=list,
repr=False,
)
"""A list of tags associated with the recording."""

features: List[Feature] = Field(
default_factory=list,
repr=False,
)
"""A list of features associated with the recording."""

notes: List[Note] = Field(
default_factory=list,
repr=False,
)
"""A list of notes associated with the recording."""

@classmethod
def from_file(
Expand Down
4 changes: 2 additions & 2 deletions src/soundevent/data/sequences.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,9 @@ class Sequence(BaseModel):

Attributes
----------
id
uuid
A unique identifier for the sequence.
sound_event
sound_events
A list of sound events within the sequence.
features
A list of features associated with the sequence, offering quantitative
Expand Down
10 changes: 4 additions & 6 deletions src/soundevent/data/tags.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
from collections.abc import Sequence
from typing import Optional

from pydantic import BaseModel, ConfigDict, Field, model_validator
from pydantic import BaseModel, Field, model_validator

from soundevent.data.compat import key_from_term, term_from_key
from soundevent.data.terms import Term
Expand All @@ -51,12 +51,10 @@ class Tag(BaseModel):
The `key` attribute is deprecated. Use `term` instead.
"""

model_config = ConfigDict(extra="allow")

term: Term = Field(
title="Term",
description="The standardised term associated with the tag.",
repr=False,
repr=True,
)

value: str = Field(
Expand Down Expand Up @@ -86,7 +84,7 @@ def handle_deprecated_key(cls, values):
warnings.warn(
"The 'key' field is deprecated. Please use 'term' instead.",
DeprecationWarning,
stacklevel=1,
stacklevel=2,
)

if "term" not in values:
Expand All @@ -98,8 +96,8 @@ def handle_deprecated_key(cls, values):

def find_tag(
tags: Sequence[Tag],
term: Optional[Term] = None,
label: Optional[str] = None,
term: Optional[Term] = None,
default: Optional[Tag] = None,
) -> Optional[Tag]:
"""Find a tag by its key.
Expand Down
Loading
Loading