Skip to content

Commit

Permalink
Analyse tracks (#15)
Browse files Browse the repository at this point in the history
* load values from metadata and allow for slightly longer last cacophony index bin

* add support for new audio models

* add chirps

* adjust chirps and track generation

* reduce min track length

* analyse tracks

---------

Co-authored-by: gferraro <[email protected]>
  • Loading branch information
gferraro and gferraro authored Apr 16, 2024
1 parent 1383654 commit c0a7343
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 22 deletions.
63 changes: 44 additions & 19 deletions Melt/chain.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@
from identify_morepork import identify_morepork
from identify_tracks import classify, get_max_chirps
import math

from pathlib import Path
import argparse
import json

NON_BIRD = ["human", "noise"]

Expand Down Expand Up @@ -99,38 +100,45 @@ def filter_tracks(tracks):
return filtered


def species_identify(file_name, morepork_model, bird_models):
def species_identify(file_name, morepork_model, bird_models,analyse_tracks):
labels = []
result = {}
if morepork_model is not None:
meta_file = Path(file_name).with_suffix(".txt")
meta_data = None
if meta_file.exists():
with meta_file.open("r") as f:
meta_data = json.load(f)
if morepork_model is not None and not analyse_tracks:
morepork_ids = identify_morepork(file_name, morepork_model)
labels.extend(morepork_ids)
if bird_models is not None:
bird_ids, length, chirps, signals = classify(file_name, bird_models)
bird_ids, length, chirps, signals = classify(file_name, bird_models,analyse_tracks,meta_data)
labels.extend(bird_ids)
cacophony_index, version = calc_cacophony_index(filter_tracks(bird_ids), length)
max_chirps = get_max_chirps(length)
version = "2.0"
chirp_index = 0 if max_chirps == 0 else round(100 * chirps / max_chirps)

result["cacophony_index"] = cacophony_index
result["cacophony_index_version"] = version
result["chirps"] = {
"chirps": chirps,
"max_chirps": max_chirps,
"chirp_index": chirp_index,
"signals": [s.to_array() for s in signals],
}
if not analyse_tracks:
max_chirps = get_max_chirps(length)
version = "2.0"
chirp_index = 0 if max_chirps == 0 else round(100 * chirps / max_chirps)

result["cacophony_index"] = cacophony_index
result["cacophony_index_version"] = version
result["chirps"] = {
"chirps": chirps,
"max_chirps": max_chirps,
"chirp_index": chirp_index,
"signals": [s.to_array() for s in signals],
}

result["species_identify"] = labels
result["species_identify_version"] = "2021-02-01"
return result


def examine(file_name, morepork_model, bird_model):
def examine(file_name, morepork_model, bird_model,analyse_tracks=False):
import cacophony_index

summary = cacophony_index.calculate(file_name)
summary.update(species_identify(file_name, morepork_model, bird_model))
summary.update(species_identify(file_name, morepork_model, bird_model,analyse_tracks))
return summary


Expand Down Expand Up @@ -163,13 +171,30 @@ def parse_args():

parser.add_argument("file", help="Audio file to run on")

parser.add_argument(
"--analyse-tracks",
type=str2bool,
default=False,
help="Classify human made tracks marked with classify flag, in metadata file",
)

args = parser.parse_args()
if args.bird_model is None or len(args.bird_model) == 0:
args.bird_model = ["/models/bird-model"]

return args


def str2bool(v):
if isinstance(v, bool):
return v
if v.lower() in ("yes", "true", "t", "y", "1"):
return True
elif v.lower() in ("no", "false", "f", "n", "0"):
return False
else:
raise argparse.ArgumentTypeError("Boolean value expected.")

def main():
args = parse_args()

Expand All @@ -182,7 +207,7 @@ def main():

summary = cacophony_index.calculate(args.file)
else:
summary = examine(args.file, args.morepork_model, args.bird_model)
summary = examine(args.file, args.morepork_model, args.bird_model, analyse_tracks = args.analyse_tracks )

t1 = time.time()

Expand Down
26 changes: 23 additions & 3 deletions Melt/identify_tracks.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
DEFAULT_BIRDS = ["bird"]
DEFAULT_BIRDS.extend(DEFAULT_SPECIES)
SIGNAL_WIDTH = 0.25
MAX_FRQUENCY = 48000 / 2


# roughly the max possible chirps
Expand Down Expand Up @@ -319,14 +320,30 @@ def get_end(frames, sr):
return file_length


def classify(file, models):
def classify(file, models,analyse_tracks,meta_data = None):
frames, sr = load_recording(file)
length = get_end(frames, sr)
signals = signal_noise(frames[: int(sr * length)], sr, 281)
# want to use signals for chrips
tracks = [s.copy() for s in signals]

if analyse_tracks:
if meta_data is None:
return
meta_tracks = [t for t in meta_data["Tracks"] if t.get("classify")]
tracks = []
for t in meta_tracks:
pos = t["data"]["positions"][0]
freq_start = pos["y"] * MAX_FRQUENCY
freq_end = pos["height"]*MAX_FRQUENCY + freq_start

# add to signals also???
signal = Signal(t["data"]["start_s"], t["data"]["end_s"], freq_start,freq_end)
signal.track_id = t["id"]
tracks.append(signal)
else:
tracks = [s.copy() for s in signals]

tracks = get_tracks_from_signals(tracks, length)
tracks = get_tracks_from_signals(tracks, length)
mel_data = None

for model_file in models:
Expand Down Expand Up @@ -650,6 +667,7 @@ def __init__(self, start, end, freq_start, freq_end):
self.mel_freq_start = mel_freq(freq_start)
self.mel_freq_end = mel_freq(freq_end)
self.predictions = []
self.track_id = None
# self.model = None
# self.labels = None
# self.confidences = None
Expand Down Expand Up @@ -737,6 +755,8 @@ def get_meta(self):
meta["freq_start"] = self.freq_start
meta["freq_end"] = self.freq_end
meta["predictions"] = [r.get_meta() for r in self.predictions]
if self.track_id is not None:
meta["track_id"] = self.track_id
return meta


Expand Down

0 comments on commit c0a7343

Please sign in to comment.