HearingTest.py 2.63 KB
Newer Older
1
import time
2
import numpy as np
3
import random
4
from SoundLibrary import SoundLibrary
Ed Rogers's avatar
Ed Rogers committed
5
6
from typing import List
# from HearingTestGUI import HearingMplCanvas
Ed Rogers's avatar
Ed Rogers committed
7

8
9
10
11
class SoundRecord:
    def __init__(self, freq, volume, time):
        self.freq = freq
        self.volume = volume
Ed Rogers's avatar
Ed Rogers committed
12
13
        self.time = time
        self.heard = None
14
15


16
class HearingTest:
Ed Rogers's avatar
Ed Rogers committed
17
    upper_lim = 1
Ed Rogers's avatar
Ed Rogers committed
18
19
    lower_lim = 0
    n_blocks = 20
20
    max_response_time = 1  # in seconds
Ed Rogers's avatar
Ed Rogers committed
21
22
23

    @staticmethod
    def get_block_size():
24
        return (HearingTest.upper_lim - HearingTest.lower_lim) / HearingTest.n_blocks
25

Ed Rogers's avatar
Ed Rogers committed
26
    def __init__(self, library: SoundLibrary, canvas):
27
        self.library = library
28
29
        self.lower_bounds = np.full_like(self.freqs, fill_value=self.lower_lim, dtype=float)
        self.upper_bounds = np.full_like(self.freqs, fill_value=self.upper_lim, dtype=float)
30
31
        self.false_presses = 0
        self.sounds = []
Ed Rogers's avatar
Ed Rogers committed
32
        self.canvas = canvas
33
34

    @property
35
    def freqs(self):
36
37
        return self.library.freqs

Ed Rogers's avatar
Ed Rogers committed
38
    def handle_key_press(self, _time):
39
40
41
42
43
        sound = self.sounds[-1]
        if not sound.heard and (_time - sound.time <= self.max_response_time):
            sound.heard = True
            if self.lower_bounds[self.freqs == sound.freq] < sound.volume:
                self.set_lower_bound(sound.freq, sound.volume)
Ed Rogers's avatar
Ed Rogers committed
44
45
46
        else:
            self.false_presses += 1
        self.check_for_not_heard(_time)
47
48
49
50
51
        return

    def play_next_sound(self):
        # TODO select tone based on results
        volume = random.random()
52
        freq = random.choice(self.freqs)
53
        self.library.play(freq, volume)
Ed Rogers's avatar
Ed Rogers committed
54
        played_time = time.time()
55

56
        next_sleep_time = random.uniform(self.max_response_time*1.2, self.max_response_time*3)
57

58
        self.sounds.append(SoundRecord(freq, volume, played_time))
59
        test_finished = False
60

Ed Rogers's avatar
Ed Rogers committed
61
        self.check_for_not_heard(played_time)
62
        return test_finished, freq, volume, played_time, next_sleep_time
Ed Rogers's avatar
Ed Rogers committed
63
64
65
66

    def check_for_not_heard(self, event_time):
        for sound in reversed(self.sounds):
            delay = event_time - sound.time
67
            # print(delay)
Ed Rogers's avatar
Ed Rogers committed
68
69
70
71
            if sound.heard is not None:
                break
            elif delay > self.max_response_time:
                sound.heard = False
72
73
                if self.upper_bounds[self.freqs == sound.freq] > sound.volume:
                    self.set_upper_bound(sound.freq, sound.volume)
Ed Rogers's avatar
Ed Rogers committed
74

75
76
    def set_lower_bound(self, freq, volume):
        self.lower_bounds[self.freqs == freq] = volume
Ed Rogers's avatar
Ed Rogers committed
77
78
        self.canvas.update_result(self)

79
80
    def set_upper_bound(self, freq, volume):
        self.upper_bounds[self.freqs == freq] = volume
Ed Rogers's avatar
Ed Rogers committed
81
        self.canvas.update_result(self)