2

I am trying to use aubio and python for a school project, here's the goal : detect when someone emit two sounds, each with a length of 2s, and with an interval between them of max 3s. The second one need to be higher than the first one. When these conditions are met, the program send a Wake-On-Lan package (not implemented in current code).

import alsaaudio
import numpy as np
import aubio
import time
import threading



class Audio_watcher:
    # constants
    samplerate = 44100
    win_s = 2048
    hop_s = win_s // 2
    framesize = hop_s
    nb_samples = 20
    tone_duration = 2.0
    per_sampling = tone_duration / nb_samples
    tone_max_interval = 3.0
    tone_diff_ratio = 2


    def __init__(self):
        self.last_frequencies = np.zeros(Audio_watcher.nb_samples)
        self.last_energies = np.zeros(Audio_watcher.nb_samples)
        self.detected_tone = 0

        # set up audio input
        recorder = alsaaudio.PCM(type=alsaaudio.PCM_CAPTURE)
        recorder.setperiodsize(Audio_watcher.framesize)
        recorder.setrate(Audio_watcher.samplerate)
        recorder.setformat(alsaaudio.PCM_FORMAT_FLOAT_LE)
        recorder.setchannels(1)
        self.recorder = recorder

        pitcher = aubio.pitch("default", Audio_watcher.win_s, Audio_watcher.hop_s, Audio_watcher.samplerate)
        pitcher.set_unit("Hz")
        pitcher.set_silence(-40)
        self.pitcher = pitcher
        # A filter
        f = aubio.digital_filter(7)
        f.set_a_weighting(Audio_watcher.samplerate)
        self.f = f


    def get_audio(self):
        # read and convert data from audio input
        _, data = self.recorder.read()
        samples = np.fromstring(data, dtype=aubio.float_type)
        filtered_samples = self.f(samples)
        print(filtered_samples)

        # pitch and energy of current frame
        freq = self.pitcher(filtered_samples)[0]
        print(freq)
        self.last_frequencies = np.roll(self.last_frequencies, 1)
        self.last_frequencies[0] = freq
        self.last_energies = np.roll(self.last_energies, 1)
        self.last_energies[0] = np.sum(filtered_samples**2)/len(filtered_samples)

        threading.Timer(Audio_watcher.per_sampling, self.get_audio).start()


    def reset_detected_tone():
        self.detected_tone = 0


    def detect_tone(self):
        std_last = np.std(self.last_frequencies)
        if std_last <= 200 and std_last > 0:
            mean_freq = np.mean(self.last_frequencies)
            if self.detected_tone == 0:
                self.detected_tone = mean_freq
                threading.Timer(Audio_watcher.tone_max_interval, self.reset_detected_tone).start()
            elif mean_freq > Audio_watcher.tone_diff_ratio * self.detected_tone:
                print('wol')

        threading.Timer(Audio_watcher.tone_duration, self.detect_tone).start()



aw = Audio_watcher()
aw.get_audio()
aw.detect_tone()

However with this code I get a great delay between the sounds and their detection, I think it has to do with the recorder being called only one time every 0.1s, but I can't find how to give correct parameters to aubio.
Does anyone knows how to configure the constants so it works ?
Thanks a lot !

EStt
  • 41
  • 6

1 Answers1

1

Found out what was causing this error, I needed to put the code that sets up the audio input in the get_audio function so it renewed everytime

EStt
  • 41
  • 6