[M] Move non-api scripts to experiment\
This commit is contained in:
@@ -0,0 +1,212 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import io
|
||||
import os
|
||||
import subprocess
|
||||
import tempfile
|
||||
import time
|
||||
import warnings
|
||||
from subprocess import Popen, PIPE
|
||||
from typing import NamedTuple, Callable
|
||||
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
import scipy.io.wavfile
|
||||
from PIL import Image
|
||||
from inaSpeechSegmenter import *
|
||||
from inaSpeechSegmenter.segmenter import featGenerator
|
||||
from matplotlib.figure import Figure, Axes
|
||||
|
||||
|
||||
class ResultFrame(NamedTuple):
|
||||
gender: str
|
||||
start: float
|
||||
end: float
|
||||
|
||||
|
||||
class Result(NamedTuple):
|
||||
frames: list[ResultFrame]
|
||||
file: str
|
||||
|
||||
|
||||
class BatchResults(NamedTuple):
|
||||
results: list[Result]
|
||||
time_full: float
|
||||
time_avg: float
|
||||
successes: int
|
||||
messages: list[tuple[str, int]]
|
||||
|
||||
|
||||
def process(self: Segmenter, inp: list[str], tmpdir=None, verbose=False, skip_if_exist=False,
|
||||
nbtry=1, try_delay=2.) -> BatchResults:
|
||||
t_batch_start = time.time()
|
||||
|
||||
results: list[Result] = []
|
||||
lmsg = []
|
||||
fg = featGenerator(inp.copy(), inp.copy(), tmpdir, self.ffmpeg, skip_if_exist, nbtry, try_delay)
|
||||
i = 0
|
||||
for feats, msg in fg:
|
||||
lmsg += msg
|
||||
i += len(msg)
|
||||
if verbose:
|
||||
print('%d/%d' % (i, len(inp)), msg)
|
||||
if feats is None:
|
||||
break
|
||||
mspec, loge, diff_len = feats
|
||||
lseg = self.segment_feats(mspec, loge, diff_len, 0)
|
||||
results.append(Result([ResultFrame(*s) for s in lseg], inp[len(lmsg) - 1]))
|
||||
|
||||
t_batch_dur = time.time() - t_batch_start
|
||||
nb_processed = len([e for e in lmsg if e[1] == 0])
|
||||
avg = t_batch_dur / nb_processed if nb_processed else -1
|
||||
return BatchResults(results, t_batch_dur, avg, nb_processed, lmsg)
|
||||
|
||||
|
||||
def to_wav(file: str, callback: Callable, start_sec: float = 0, stop_sec: float = 0):
|
||||
"""
|
||||
Convert media to temp wav 16k file and return features
|
||||
"""
|
||||
base, _ = os.path.splitext(os.path.basename(file))
|
||||
|
||||
with tempfile.TemporaryDirectory() as tmpdir_name:
|
||||
# build ffmpeg command line
|
||||
tmp_wav = tmpdir_name + '/' + base + '.wav'
|
||||
args = ['ffmpeg', '-y', '-i', file, '-ar', '16000', '-ac', '1']
|
||||
|
||||
if start_sec != 0:
|
||||
args += ['-ss', '%f' % start_sec]
|
||||
if stop_sec != 0:
|
||||
args += ['-to', '%f' % stop_sec]
|
||||
|
||||
args += [tmp_wav]
|
||||
|
||||
# launch ffmpeg
|
||||
p = Popen(args, stdout=PIPE, stderr=PIPE)
|
||||
output, error = p.communicate()
|
||||
assert p.returncode == 0, error
|
||||
|
||||
return callback(tmp_wav)
|
||||
|
||||
|
||||
def show_image_buffer(buf):
|
||||
im = Image.open(buf)
|
||||
im.show()
|
||||
buf.close()
|
||||
|
||||
|
||||
def draw_result(file: str, result: Result):
|
||||
"""
|
||||
Draw segmentation result
|
||||
|
||||
:param file: Audio file
|
||||
:param result: Segmentation result
|
||||
:return: Result image in bytes (please close it after use)
|
||||
"""
|
||||
def wav_callback(wavfile: str):
|
||||
sample_rate, audio = scipy.io.wavfile.read(wavfile)
|
||||
_time = np.linspace(0, len(audio) / sample_rate, num=len(audio))
|
||||
|
||||
fig: Figure = plt.gcf()
|
||||
ax: Axes = plt.gca()
|
||||
|
||||
# Plot audio
|
||||
plt.plot(_time, audio, color='white')
|
||||
|
||||
# Set size
|
||||
# fig.set_dpi(400)
|
||||
fig.set_size_inches(18, 6)
|
||||
|
||||
# Cutoff frequency so that the plot looks centered
|
||||
cutoff = min(abs(min(audio)), abs(max(audio)))
|
||||
ax.set_ylim([-cutoff, cutoff])
|
||||
ax.set_xlim([result.frames[0].start, result.frames[-1].end])
|
||||
|
||||
# Draw segmentation areas
|
||||
colors = {'female': '#F5A9B8', 'male': '#5BCEFA', 'default': 'gray'}
|
||||
for r in result.frames:
|
||||
color = colors[r.gender] if r.gender in colors else colors['default']
|
||||
ax.axvspan(r.start, r.end - 0.01, alpha=.5, color=color)
|
||||
|
||||
# Savefig to bytes
|
||||
buf = io.BytesIO()
|
||||
plt.axis('off')
|
||||
plt.savefig(buf, bbox_inches='tight', pad_inches=0, transparent=False)
|
||||
buf.seek(0)
|
||||
plt.clf()
|
||||
plt.close()
|
||||
return buf
|
||||
|
||||
return to_wav(file, wav_callback)
|
||||
|
||||
|
||||
def get_result_percentages(result: Result) -> tuple[float, float, float, float]:
|
||||
"""
|
||||
Get percentages
|
||||
|
||||
:param result: Result
|
||||
:return: %female, %male, %other, %female-vs-female+male
|
||||
"""
|
||||
# Count total and categorical durations
|
||||
total_dur = 0
|
||||
durations: dict[str, int] = {f.gender: 0 for f in result.frames}
|
||||
for f in result.frames:
|
||||
dur = f.end - f.start
|
||||
durations[f.gender] += dur
|
||||
total_dur += dur
|
||||
|
||||
# Convert durations to ratios
|
||||
for d in durations:
|
||||
durations[d] /= total_dur
|
||||
|
||||
# Return results
|
||||
f = durations.get('female', 0)
|
||||
m = durations.get('male', 0)
|
||||
|
||||
fm_total = f + m
|
||||
pf = 0 if fm_total == 0 else f / fm_total
|
||||
|
||||
return f, m, 1 - f - m, pf
|
||||
|
||||
|
||||
def test():
|
||||
# results: BatchResults = BatchResults(
|
||||
# [Result([ResultFrame('female', 0.0, 10.48), ResultFrame('male', 10.48, 12.780000000000001)],
|
||||
# '../test.csv')],
|
||||
# 1.7032792568206787, 1.7032792568206787, 1,
|
||||
# [('../test.csv', 0)])
|
||||
|
||||
warnings.filterwarnings("ignore")
|
||||
seg = Segmenter()
|
||||
audio_file = '../test.flac'
|
||||
|
||||
# Warmup run
|
||||
results = process(seg, [audio_file])
|
||||
print(results)
|
||||
|
||||
# # Actual run
|
||||
# results = process(seg, ['../test.flac'])
|
||||
# print(results)
|
||||
|
||||
# Benchmark
|
||||
iterations = 60
|
||||
total_time = 0
|
||||
audio_len = float(subprocess.getoutput(f'ffprobe -i {audio_file} -show_entries format=duration -v quiet -of csv="p=0"'))
|
||||
print(f'Audio length: {audio_len}')
|
||||
|
||||
for i in range(iterations):
|
||||
results = process(seg, [audio_file])
|
||||
total_time += results.time_full
|
||||
|
||||
time_per_second = total_time / iterations / audio_len
|
||||
print(f'Benchmark result: {total_time}s / {iterations} iterations = {time_per_second} seconds of processing per second in audio')
|
||||
print(f'Score: {1 / time_per_second}')
|
||||
|
||||
# Draw results
|
||||
# with draw_result(audio_file, results.results[0]) as buf:
|
||||
# show_image_buffer(buf)
|
||||
# print(get_result_percentages(results.results[0]))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test()
|
||||
pass
|
||||
Reference in New Issue
Block a user