Checked over click playing logic
This commit is contained in:
+4
-19
@@ -65,43 +65,28 @@ class ClickTestThread(BaseThread):
|
||||
'''
|
||||
self.waitForPageLoad()
|
||||
self.socketio.emit('test_ready', namespace='/main')
|
||||
for self.trial_ind in range(self.nTrials):
|
||||
for self.trial_ind in range(self.trial_ind, self.nTrials):
|
||||
self.displayInstructions()
|
||||
self.waitForPartReady()
|
||||
if self._stopevent.isSet() or self.finishTest:
|
||||
break
|
||||
# Play concatenated matrix sentences at set SNR
|
||||
self.playStimulus(self.wav_file)
|
||||
self.playStimulusWav(self.wav_file)
|
||||
self.saveState(out=self.backupFilepath)
|
||||
if not self._stopevent.isSet():
|
||||
self.unsetPageLoaded()
|
||||
self.socketio.emit('processing-complete', namespace='/main')
|
||||
self.waitForFinalise()
|
||||
|
||||
|
||||
def displayInstructions(self):
|
||||
self.socketio.emit('display_instructions', namespace='/main')
|
||||
|
||||
|
||||
def playStimulus(self, wav_file, replay=False):
|
||||
self.newResp = False
|
||||
self.socketio.emit("stim_playing", namespace="/main")
|
||||
# if not replay:
|
||||
# self.y = self.generateTrial(self.snr)
|
||||
# Play audio
|
||||
# sd.play(self.y, self.fs, blocking=True)
|
||||
if not self.dev_mode:
|
||||
self.play_wav(wav_file, 'finish_test')
|
||||
else:
|
||||
self.play_wav('./test.wav', 'finish_test')
|
||||
|
||||
self.socketio.emit("stim_done", namespace="/main")
|
||||
|
||||
|
||||
def loadStimulus(self):
|
||||
'''
|
||||
'''
|
||||
#audio, fs, enc, fmt = sndio.read(wav, return_format=True)
|
||||
|
||||
pass
|
||||
|
||||
def saveState(self, out="test_state.pkl"):
|
||||
saveDict = {k:self.__dict__[k] for k in self.toSave}
|
||||
|
||||
@@ -14,12 +14,12 @@ server_lock = Lock()
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
log = logging.getLogger('werkzeug')
|
||||
log.setLevel(logging.ERROR)
|
||||
log = logging.getLogger('engineio')
|
||||
log.setLevel(logging.ERROR)
|
||||
log = logging.getLogger('socketio')
|
||||
log.setLevel(logging.ERROR)
|
||||
# log = logging.getLogger('werkzeug')
|
||||
# log.setLevel(logging.ERROR)
|
||||
# log = logging.getLogger('engineio')
|
||||
# log.setLevel(logging.ERROR)
|
||||
# log = logging.getLogger('socketio')
|
||||
# log.setLevel(logging.ERROR)
|
||||
|
||||
|
||||
def url_ok(url, port):
|
||||
|
||||
+30
-28
@@ -92,7 +92,7 @@ class MatTestThread(BaseThread):
|
||||
self.srt_50 = None
|
||||
self.s_50 = None
|
||||
|
||||
self.wordsCorrect = np.full((90, 5), False, dtype=bool)
|
||||
self.wordsCorrect = np.full((180, 5), False, dtype=bool)
|
||||
self.trialN = 0
|
||||
|
||||
self.availableSentenceInds = []
|
||||
@@ -111,13 +111,14 @@ class MatTestThread(BaseThread):
|
||||
'wordsCorrect', 'trialN', 'test_name', 'backupFilepath',
|
||||
'currentWords', 'nCorrect', 'availableSentenceInds',
|
||||
'lists', 'listsRMS', 'listsString']
|
||||
self.toFinalise = ['snrTrack', 'trackOrder', 'trialN', 'wordsCorrect',
|
||||
self.toFinalise = ['trackSNR', 'trackOrder', 'trialN', 'wordsCorrect',
|
||||
'presentedWords', 'responses', 'srt_50', 's_50']
|
||||
|
||||
# Attach messages from gui to class methods
|
||||
self.socketio.on_event('submit_response', self.submitMatResponse, namespace='/main')
|
||||
self.socketio.on_event('page_loaded', self.setPageLoaded, namespace='/main')
|
||||
self.socketio.on_event('repeat_stimulus', self.playStimulusSocketHandle, namespace='/main')
|
||||
self.socketio.on_event('finalise_results', self.finaliseResults, namespace='/main')
|
||||
|
||||
self.loadNoise(noiseFilepath, noiseRMSFilepath)
|
||||
|
||||
@@ -132,7 +133,7 @@ class MatTestThread(BaseThread):
|
||||
dpi = 300
|
||||
|
||||
maxTrialN = np.max([x.trialN for x in self.adaptiveTracks])
|
||||
plt.xlim([-1, maxTrialN])
|
||||
plt.xlim([-1, maxTrialN+1])
|
||||
plt.savefig(self.img, format='png', figsize=(800/dpi, 800/dpi), dpi=dpi)
|
||||
self.img.seek(0)
|
||||
plot_url = base64.b64encode(self.img.getvalue()).decode()
|
||||
@@ -148,7 +149,7 @@ class MatTestThread(BaseThread):
|
||||
|
||||
self.displayInstructions()
|
||||
self.waitForPartReady()
|
||||
while not self.finishTest and not self._stopevent.isSet() and len(self.availableSentenceInds):
|
||||
while not self.finishTest and not self._stopevent.isSet() and len(self.availableSentenceInds) and len(self.trackOrder):
|
||||
# Plot SNR of current trial to the clinician screen
|
||||
for at in self.adaptiveTracks:
|
||||
at.plotSNR()
|
||||
@@ -176,6 +177,7 @@ class MatTestThread(BaseThread):
|
||||
self.checkSentencesAvailable()
|
||||
self.saveState(out=self.backupFilepath)
|
||||
self.trialN += 1
|
||||
self.adaptiveTracks[self.adTrInd].incrementTrialN()
|
||||
self.saveState(out=self.backupFilepath)
|
||||
if not self._stopevent.isSet():
|
||||
self.unsetPageLoaded()
|
||||
@@ -189,21 +191,6 @@ class MatTestThread(BaseThread):
|
||||
self.waitForFinalise()
|
||||
|
||||
|
||||
def finaliseResults(self):
|
||||
saveDict = {k:self.__dict__[k] for k in self.toFinalise}
|
||||
if self.participant:
|
||||
self.participant[self.test_name].update(saveDict)
|
||||
self.participant.save(self.test_name)
|
||||
backup_path = os.path.join(self.participant.data_paths[self.test_name],
|
||||
'finalised_backup.pkl')
|
||||
copy2(self.backupFilepath, backup_path)
|
||||
else:
|
||||
copy2(self.backupFilepath, './finalised_backup.pkl')
|
||||
with open('./{}_results.pkl'.format(self.test_name), 'wb') as f:
|
||||
dill.dump(saveDict, f)
|
||||
self.finalised = True
|
||||
|
||||
|
||||
|
||||
@staticmethod
|
||||
def logisticFunction(L, L_50, s_50):
|
||||
@@ -246,9 +233,8 @@ class MatTestThread(BaseThread):
|
||||
def fitLogistic(self):
|
||||
'''
|
||||
'''
|
||||
self.wordsCorrect = [x.getWordsCorrect() for x in self.adaptiveTracks]
|
||||
self.trackSNR = [x.getSNRTrack() for x in self.adaptiveTracks]
|
||||
set_trace()
|
||||
self.wordsCorrect = np.concatenate([x.getWordsCorrect() for x in self.adaptiveTracks])
|
||||
self.trackSNR = np.concatenate([x.getSNRTrack() for x in self.adaptiveTracks])
|
||||
res = minimize(self.logisticFuncLiklihood, np.array([np.mean(self.trackSNR),1.0]))
|
||||
percent_correct = (np.sum(self.wordsCorrect, axis=1)/self.wordsCorrect.shape[1])*100.
|
||||
sortedSNRind = np.argsort(-self.trackSNR)
|
||||
@@ -412,6 +398,21 @@ class MatTestThread(BaseThread):
|
||||
with open(out, 'wb') as f:
|
||||
dill.dump(saveDict, f)
|
||||
|
||||
|
||||
def finaliseResults(self):
|
||||
saveDict = {k:self.__dict__[k] for k in self.toFinalise}
|
||||
saveDict['adaptiveTracks'] = []
|
||||
for ind, _ in enumerate(self.adaptiveTracks):
|
||||
atDict = self.adaptiveTracks[ind].createSaveDict()
|
||||
saveDict['adaptiveTracks'].append(atDict)
|
||||
self.participant[self.test_name].update(saveDict)
|
||||
self.participant.save(self.test_name)
|
||||
backup_path = os.path.join(self.participant.data_paths[self.test_name],
|
||||
'finalised_backup.pkl')
|
||||
copy2(self.backupFilepath, backup_path)
|
||||
set_trace()
|
||||
self.finalised = True
|
||||
|
||||
class AdaptiveTrack():
|
||||
'''
|
||||
'''
|
||||
@@ -421,13 +422,13 @@ class AdaptiveTrack():
|
||||
self.snr = 0.0
|
||||
self.direction = 0
|
||||
# Record SNRs presented with each trial of the adaptive track
|
||||
self.snrTrack = np.empty(90)
|
||||
self.snrTrack = np.empty(180)
|
||||
self.snrTrack[:] = np.nan
|
||||
self.snrTrack[0] = 0.0
|
||||
# Count number of presented trials
|
||||
self.trialN = 0
|
||||
self.reduction_coef = np.load(red_coef)*np.load(cal_coef)
|
||||
self.wordsCorrect = np.full((90, 5), False, dtype=bool)
|
||||
self.wordsCorrect = np.full((180, 5), False, dtype=bool)
|
||||
|
||||
# Adaptive track parameters
|
||||
self.slope = 0.15
|
||||
@@ -454,6 +455,9 @@ class AdaptiveTrack():
|
||||
def processResponse(resp):
|
||||
pass
|
||||
|
||||
def incrementTrialN(self):
|
||||
self.trialN += 1
|
||||
|
||||
|
||||
def generateTrial(self, x, x_rms):
|
||||
# Convert desired SNR to dB FS
|
||||
@@ -489,16 +493,14 @@ class AdaptiveTrack():
|
||||
self.i += 1
|
||||
self.direction = currentDirection
|
||||
self.snrTrack[self.trialN] = self.snr
|
||||
self.trialN += 1
|
||||
print("Track {0} trial N: {1}".format(self.target, self.trialN))
|
||||
|
||||
|
||||
def plotSNR(self):
|
||||
'''
|
||||
'''
|
||||
plt.plot(self.snrTrack, 'o-')
|
||||
plt.ylim([20.0, -20.0])
|
||||
plt.xticks(np.arange(90))
|
||||
plt.ylim([20.0, -30.0])
|
||||
plt.xticks(np.arange(180))
|
||||
plt.xlabel("Trial N")
|
||||
plt.ylabel("SNR (dB)")
|
||||
plt.title("Adaptive track")
|
||||
|
||||
@@ -262,3 +262,14 @@ Calibration routing
|
||||
@server.route('/calibrate')
|
||||
def calibrate():
|
||||
return render_template("calibrate.html")
|
||||
|
||||
'''
|
||||
Basic audiology test routing
|
||||
'''
|
||||
@server.route('/pta_test')
|
||||
def pta():
|
||||
return render_template("pta.html")
|
||||
|
||||
@server.route('/tympanometry')
|
||||
def typms():
|
||||
return render_template("tympanometry.html")
|
||||
|
||||
@@ -15,6 +15,8 @@ $(document).ready(function(){
|
||||
|
||||
$('#mat-save').click(function(event) {
|
||||
socket.emit("finalise_results")
|
||||
});
|
||||
socket.on('test_finished', function(msg) {
|
||||
window.location.href = '/home';
|
||||
});
|
||||
});
|
||||
|
||||
@@ -62,11 +62,11 @@
|
||||
waitingDialog.hide();
|
||||
});
|
||||
|
||||
socket.on('stim_playing', function(msg) {
|
||||
socket.on('click_test_stim_playing', function(msg) {
|
||||
on()
|
||||
});
|
||||
|
||||
socket.on('stim_done', function(msg) {
|
||||
socket.on('click_test_stim_done', function(msg) {
|
||||
off()
|
||||
});
|
||||
|
||||
|
||||
@@ -15,6 +15,8 @@ $(document).ready(function(){
|
||||
|
||||
$('#mat-save').click(function(event) {
|
||||
socket.emit("finalise_results")
|
||||
});
|
||||
socket.on('test_finished', function(msg) {
|
||||
window.location.href = '/home';
|
||||
});
|
||||
});
|
||||
|
||||
@@ -42,6 +42,8 @@ $(document).ready(function(){
|
||||
|
||||
$('#mat-save').click(function(event) {
|
||||
socket.emit("finalise_results")
|
||||
});
|
||||
socket.on('test_finished', function(msg) {
|
||||
window.location.href = '/home';
|
||||
});
|
||||
|
||||
|
||||
@@ -64,15 +64,23 @@
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="d-flex justify-content-center mt-2" role="group">
|
||||
<button type="button" id="mat-save" class="btn btn-primary mx-3">Save and finish test</button>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
$(document).ready(function(){
|
||||
// Initialise socketio with a namespace called "main"
|
||||
var socket = io.connect(location.protocol + '//' + document.domain + ':' + location.port + '/main');
|
||||
socket.on('test_resp', function(msg) {
|
||||
console.log("Yup");
|
||||
$(`#Q1 > .T${parseInt(msg['trial_ind'])+1} > button`).attr("data-original-title", msg['ans']).tooltip('show');
|
||||
});
|
||||
$('#mat-save').click(function(event) {
|
||||
socket.emit("finalise_results")
|
||||
});
|
||||
socket.on('test_finished', function(msg) {
|
||||
window.location.href = '/home';
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
@@ -114,6 +114,8 @@ $(document).ready(function(){
|
||||
|
||||
$('#mat-save').click(function(event) {
|
||||
socket.emit("finalise_results")
|
||||
});
|
||||
socket.on('test_finished', function(msg) {
|
||||
window.location.href = '/home';
|
||||
});
|
||||
|
||||
|
||||
@@ -42,7 +42,6 @@
|
||||
margin-right: auto;
|
||||
height:100%;
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
|
||||
|
||||
@@ -32,6 +32,8 @@ $(document).ready(function(){
|
||||
$('#mat-save').click(function(event) {
|
||||
socket.emit("finalise_results")
|
||||
finalised=1;
|
||||
});
|
||||
socket.on('test_finished', function(msg) {
|
||||
window.location.href = '/home';
|
||||
});
|
||||
|
||||
|
||||
@@ -6,10 +6,11 @@
|
||||
<div class="card-body">
|
||||
<h2>Instructions</h2>
|
||||
<p>
|
||||
In this test, you will be presented with repeated "da"
|
||||
utterances. Simply listen to the stimulus, you do not need to
|
||||
respond.
|
||||
</p>
|
||||
In this test, you will be presented with sentences spoken in
|
||||
background noise. Use the grid to select the word you hear from
|
||||
each column. If you can't hear a word, take a guess. When you
|
||||
have made your selection, press submit to continue to the next
|
||||
sentence.</p>
|
||||
<button type="button" href="#" id="instr_continue" class="Btn Btn-primary">Continue</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<div class="form-group">
|
||||
<label for="listN">Number of lists:</label>
|
||||
<br>
|
||||
<input id="listN" name="listN" type="number" value="3" max="18" min="1" style="width:85%">
|
||||
<input id="listN" name="listN" type="number" value="5" max="18" min="1" style="width:85%">
|
||||
</div>
|
||||
<div class="form-group d-flex justify-content-center">
|
||||
<button type="button" id="submit" class="btn btn-primary mx-3">Start new test</button>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<html>
|
||||
<link rel="stylesheet" media="screen" href = "{{ url_for('static', filename='bootstrap.min.css') }}">
|
||||
<link rel=stylesheet type=text/css href="{{ url_for('static', filename='style.css') }}">
|
||||
<meta name="viewport" content = "width=device-width, initial-scale=1.0">
|
||||
<head>
|
||||
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
|
||||
|
||||
+9
-7
@@ -78,7 +78,7 @@ class BaseThread(Thread):
|
||||
self.dev_mode = False
|
||||
|
||||
|
||||
def play_wav(self, wav_file, stop_string):
|
||||
def play_wav(self, wav_file, stop_string='stop_audio'):
|
||||
self.wavThread = WavPlayer(wav_file, socketio=socketio, stop_string=stop_string)
|
||||
self.wavThread.run()
|
||||
|
||||
@@ -153,8 +153,11 @@ class BaseThread(Thread):
|
||||
Wait for results to be finalised by socketio handler
|
||||
'''
|
||||
while not self.finalised and not self._stopevent.isSet() and not self.finishTest:
|
||||
print(self.finishTest)
|
||||
print("self.finalised {}".format(self.finalised))
|
||||
print("self.finishTest {}".format(self.finishTest))
|
||||
print("self._stopevent {}".format(self._stopevent))
|
||||
self._stopevent.wait(0.2)
|
||||
self.socketio.emit("test_finished", namespace='/main')
|
||||
return
|
||||
|
||||
|
||||
@@ -175,11 +178,11 @@ class BaseThread(Thread):
|
||||
self.newResp = False
|
||||
self.socketio.emit("{}_stim_playing".format(self.test_name), namespace="/main")
|
||||
if not self.dev_mode:
|
||||
play_wav(wav_file)
|
||||
self.play_wav(wav_file)
|
||||
else:
|
||||
play_wav('./da_stim/DA_170.wav')
|
||||
self.play_wav('./da_stim/DA_170.wav')
|
||||
|
||||
self.socketio.emit("{}_stim_done".format(test_name), namespace="/main")
|
||||
self.socketio.emit("{}_stim_done".format(self.test_name), namespace="/main")
|
||||
|
||||
|
||||
def playStimulus(self, y, fs):
|
||||
@@ -231,8 +234,6 @@ class BaseThread(Thread):
|
||||
self.clinPageLoaded = True
|
||||
else:
|
||||
self.partPageLoaded = True
|
||||
print("PART: {}".format(self.partPageLoaded))
|
||||
print("CLIN: {}".format(self.clinPageLoaded))
|
||||
self.pageLoaded = self.clinPageLoaded and self.partPageLoaded
|
||||
|
||||
|
||||
@@ -261,6 +262,7 @@ class BaseThread(Thread):
|
||||
previously generated pickle file
|
||||
'''
|
||||
filepath = msg['data']
|
||||
set_trace()
|
||||
self.loadState(filepath)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user