import os
import webrtcvad
import wave
import collections
import contextlib
import sys
from glob import glob
import librosa
import matplotlib.pyplot as plt

def load_dataset(directory: str):
    sr = None
    X, labels, files = [], [], []
    for f in glob(directory + "/*.wav"):
        filename = os.path.basename(f)
        y = [int(label) for label in filename[:-4].split("_")]
        x, sr = librosa.load(f)
        X.append(x)
        labels.append(y)
        files.append(f)  # Изменено на f, чтобы сохранить полный путь к файлу

    return X, labels, sr, files

def read_wave(path):
    x, sr = librosa.load(path, sr=None)
    if sr not in (16000, 32000, 48000):
        x = librosa.resample(x, orig_sr=sr, target_sr=16000)
        sr = 16000
    pcm_data = x.astype('int16').tobytes()
    return pcm_data, sr

def frame_generator(frame_duration_ms, audio, sample_rate):
    n = int(sample_rate * (frame_duration_ms / 1000.0) * 2)
    offset = 0
    timestamp = 0.0
    duration = (1.0 / sample_rate) * n
    while offset + n < len(audio):
        yield audio[offset:offset + n], timestamp, duration
        timestamp += duration
        offset += n

def vad_collector(sample_rate, frame_duration_ms, padding_duration_ms, vad, frames):
    num_padding_frames = int(padding_duration_ms / frame_duration_ms)
    ring_buffer = collections.deque(maxlen=num_padding_frames)
    triggered = False

    voiced_frames = []
    for frame, timestamp, duration in frames:
        is_speech = vad.is_speech(frame, sample_rate)

        if not triggered:
            ring_buffer.append((frame, is_speech))
            num_voiced = len([f for f, speech in ring_buffer if speech])
            if num_voiced > 0.9 * ring_buffer.maxlen:
                triggered = True
                for f, s in ring_buffer:
                    voiced_frames.append(f)
                ring_buffer.clear()
        else:
            voiced_frames.append(frame)
            ring_buffer.append((frame, is_speech))
            num_unvoiced = len([f for f, speech in ring_buffer if not speech])
            if num_unvoiced > 0.9 * ring_buffer.maxlen:
                triggered = False
                yield b''.join([f.bytes for f in voiced_frames])
                ring_buffer.clear()
                voiced_frames = []
    if voiced_frames:
        yield b''.join([fbytes for f in voiced_frames])

def run_vad(audio_path):
    audio, sample_rate = read_wave(audio_path)
    vad = webrtcvad.Vad(3)
    frames = frame_generator(30, audio, sample_rate)
    frames = list(frames)
    segments = vad_collector(sample_rate, 30, 300, vad, frames)
    speech_segments = []
    for i, segment in enumerate(segments):
        path = 'chunk-%002d.wav' % (i,)
        with open(path, 'wb') as f:
            f.write(segment)
        speech_segments.append(path)
    return speech_segments

def plot_vad(X, sr, speech_segments):
    plt.figure(figsize=(12, 4))
    plt.plot(X, label='Signal')
    timestamps = []

    for segment in speech_segments:
        segment_data, _ = librosa.load(segment, sr=sr)
        timestamp = librosa.samples_to_time(list(X).index(segment_data[0]), sr=sr)
        timestamps.append(timestamp)

    speech_starts = timestamps
    speech_ends = timestamps[1:] + [librosa.samples_to_time(len(X), sr=sr)]

    for segment_start, segment_end in zip(speech_starts, speech_ends):
        plt.axvspan(segment_start, segment_end, color='red', alpha=0.5)

    plt.xlabel('Time (s)')
    plt.ylabel('Amplitude')
    plt.legend(loc='best')
    plt.title('Voice Activity Detection')
    plt.show()

# Замените 'path/to/your/directory' на локальный путь к вашей директории с аудиофайлами
directory = '/content/drive/MyDrive/School21/day09/datasets/audio_yes_no/waves_yesno 2'
X, labels, sr, files = load_dataset(directory)

for i, audio_path in enumerate(files):
    speech_segments = run_vad(audio_path)
    plot_vad(X[i], sr, speech_segments)