Implemented /da/ and click stimulus presentation
This commit is contained in:
@@ -24,7 +24,6 @@ class WavPlayer(Thread):
|
||||
super(WavPlayer, self).__init__()
|
||||
self.socketio = socketio
|
||||
self._stopevent = Event()
|
||||
self.socketio.on_event(stop_string, self.join, namespace='/main')
|
||||
self.wav_file = wav_file
|
||||
|
||||
def join(self, timeout=None):
|
||||
|
||||
@@ -0,0 +1,929 @@
|
||||
{
|
||||
"patcher" : {
|
||||
"fileversion" : 1,
|
||||
"appversion" : {
|
||||
"major" : 6,
|
||||
"minor" : 1,
|
||||
"revision" : 10,
|
||||
"architecture" : "x64"
|
||||
}
|
||||
,
|
||||
"rect" : [ 0.0, 44.0, 1223.0, 678.0 ],
|
||||
"bglocked" : 0,
|
||||
"openinpresentation" : 0,
|
||||
"default_fontsize" : 12.0,
|
||||
"default_fontface" : 0,
|
||||
"default_fontname" : "Arial",
|
||||
"gridonopen" : 0,
|
||||
"gridsize" : [ 15.0, 15.0 ],
|
||||
"gridsnaponopen" : 0,
|
||||
"statusbarvisible" : 2,
|
||||
"toolbarvisible" : 1,
|
||||
"boxanimatetime" : 200,
|
||||
"imprint" : 0,
|
||||
"enablehscroll" : 1,
|
||||
"enablevscroll" : 1,
|
||||
"devicewidth" : 0.0,
|
||||
"description" : "",
|
||||
"digest" : "",
|
||||
"tags" : "",
|
||||
"boxes" : [ {
|
||||
"box" : {
|
||||
"fontname" : "Arial",
|
||||
"fontsize" : 12.0,
|
||||
"id" : "obj-51",
|
||||
"maxclass" : "flonum",
|
||||
"numinlets" : 1,
|
||||
"numoutlets" : 2,
|
||||
"outlettype" : [ "float", "bang" ],
|
||||
"parameter_enable" : 0,
|
||||
"patching_rect" : [ 53.25, 407.0, 88.0, 20.0 ],
|
||||
"presentation_rect" : [ 376.0, 544.0, 0.0, 0.0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"box" : {
|
||||
"fontname" : "Arial",
|
||||
"fontsize" : 12.0,
|
||||
"id" : "obj-52",
|
||||
"maxclass" : "newobj",
|
||||
"numinlets" : 2,
|
||||
"numoutlets" : 1,
|
||||
"outlettype" : [ "signal" ],
|
||||
"patching_rect" : [ 141.25, 447.0, 32.5, 20.0 ],
|
||||
"presentation_rect" : [ 464.0, 584.0, 0.0, 0.0 ],
|
||||
"text" : "*~"
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"box" : {
|
||||
"fontname" : "Arial",
|
||||
"fontsize" : 12.0,
|
||||
"id" : "obj-53",
|
||||
"maxclass" : "newobj",
|
||||
"numinlets" : 2,
|
||||
"numoutlets" : 1,
|
||||
"outlettype" : [ "signal" ],
|
||||
"patching_rect" : [ 175.25, 447.0, 32.5, 20.0 ],
|
||||
"presentation_rect" : [ 498.0, 584.0, 0.0, 0.0 ],
|
||||
"text" : "*~"
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"box" : {
|
||||
"fontname" : "Arial",
|
||||
"fontsize" : 12.0,
|
||||
"id" : "obj-54",
|
||||
"maxclass" : "newobj",
|
||||
"numinlets" : 1,
|
||||
"numoutlets" : 1,
|
||||
"outlettype" : [ "signal" ],
|
||||
"patching_rect" : [ 141.25, 373.0, 33.0, 20.0 ],
|
||||
"presentation_rect" : [ 464.0, 510.0, 0.0, 0.0 ],
|
||||
"text" : "sig~"
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"box" : {
|
||||
"fontname" : "Arial",
|
||||
"fontsize" : 12.0,
|
||||
"id" : "obj-55",
|
||||
"maxclass" : "message",
|
||||
"numinlets" : 2,
|
||||
"numoutlets" : 1,
|
||||
"outlettype" : [ "" ],
|
||||
"patching_rect" : [ 173.75, 333.0, 32.5, 18.0 ],
|
||||
"presentation_rect" : [ 496.5, 470.0, 0.0, 0.0 ],
|
||||
"text" : "1"
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"box" : {
|
||||
"fontname" : "Arial",
|
||||
"fontsize" : 12.0,
|
||||
"id" : "obj-56",
|
||||
"maxclass" : "message",
|
||||
"numinlets" : 2,
|
||||
"numoutlets" : 1,
|
||||
"outlettype" : [ "" ],
|
||||
"patching_rect" : [ 141.25, 333.0, 32.5, 18.0 ],
|
||||
"presentation_rect" : [ 464.0, 470.0, 0.0, 0.0 ],
|
||||
"text" : "0"
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"box" : {
|
||||
"fontname" : "Arial",
|
||||
"fontsize" : 12.0,
|
||||
"id" : "obj-57",
|
||||
"maxclass" : "newobj",
|
||||
"numinlets" : 3,
|
||||
"numoutlets" : 2,
|
||||
"outlettype" : [ "signal", "signal" ],
|
||||
"patching_rect" : [ 141.25, 407.0, 110.0, 20.0 ],
|
||||
"text" : "groove~ noise_buf"
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"box" : {
|
||||
"fontname" : "Arial",
|
||||
"fontsize" : 12.0,
|
||||
"id" : "obj-33",
|
||||
"maxclass" : "flonum",
|
||||
"numinlets" : 1,
|
||||
"numoutlets" : 2,
|
||||
"outlettype" : [ "float", "bang" ],
|
||||
"parameter_enable" : 0,
|
||||
"patching_rect" : [ 253.25, 407.0, 88.0, 20.0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"box" : {
|
||||
"fontname" : "Arial",
|
||||
"fontsize" : 12.0,
|
||||
"id" : "obj-34",
|
||||
"maxclass" : "newobj",
|
||||
"numinlets" : 2,
|
||||
"numoutlets" : 1,
|
||||
"outlettype" : [ "signal" ],
|
||||
"patching_rect" : [ 341.25, 447.0, 32.5, 20.0 ],
|
||||
"text" : "*~"
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"box" : {
|
||||
"fontname" : "Arial",
|
||||
"fontsize" : 12.0,
|
||||
"id" : "obj-35",
|
||||
"maxclass" : "newobj",
|
||||
"numinlets" : 2,
|
||||
"numoutlets" : 1,
|
||||
"outlettype" : [ "signal" ],
|
||||
"patching_rect" : [ 375.25, 447.0, 32.5, 20.0 ],
|
||||
"text" : "*~"
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"box" : {
|
||||
"fontname" : "Arial",
|
||||
"fontsize" : 12.0,
|
||||
"id" : "obj-37",
|
||||
"maxclass" : "newobj",
|
||||
"numinlets" : 1,
|
||||
"numoutlets" : 1,
|
||||
"outlettype" : [ "signal" ],
|
||||
"patching_rect" : [ 341.25, 373.0, 33.0, 20.0 ],
|
||||
"text" : "sig~"
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"box" : {
|
||||
"fontname" : "Arial",
|
||||
"fontsize" : 12.0,
|
||||
"id" : "obj-39",
|
||||
"maxclass" : "message",
|
||||
"numinlets" : 2,
|
||||
"numoutlets" : 1,
|
||||
"outlettype" : [ "" ],
|
||||
"patching_rect" : [ 373.75, 333.0, 32.5, 18.0 ],
|
||||
"text" : "1"
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"box" : {
|
||||
"fontname" : "Arial",
|
||||
"fontsize" : 12.0,
|
||||
"id" : "obj-48",
|
||||
"maxclass" : "message",
|
||||
"numinlets" : 2,
|
||||
"numoutlets" : 1,
|
||||
"outlettype" : [ "" ],
|
||||
"patching_rect" : [ 341.25, 333.0, 32.5, 18.0 ],
|
||||
"text" : "0"
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"box" : {
|
||||
"fontname" : "Arial",
|
||||
"fontsize" : 12.0,
|
||||
"id" : "obj-50",
|
||||
"maxclass" : "newobj",
|
||||
"numinlets" : 3,
|
||||
"numoutlets" : 2,
|
||||
"outlettype" : [ "signal", "signal" ],
|
||||
"patching_rect" : [ 341.25, 407.0, 94.0, 20.0 ],
|
||||
"text" : "groove~ da_buf"
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"box" : {
|
||||
"fontname" : "Arial",
|
||||
"fontsize" : 12.0,
|
||||
"id" : "obj-32",
|
||||
"maxclass" : "flonum",
|
||||
"numinlets" : 1,
|
||||
"numoutlets" : 2,
|
||||
"outlettype" : [ "float", "bang" ],
|
||||
"parameter_enable" : 0,
|
||||
"patching_rect" : [ 442.25, 407.0, 88.0, 20.0 ],
|
||||
"presentation_rect" : [ 557.0, 512.0, 0.0, 0.0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"box" : {
|
||||
"fontname" : "Arial",
|
||||
"fontsize" : 12.0,
|
||||
"id" : "obj-30",
|
||||
"maxclass" : "newobj",
|
||||
"numinlets" : 2,
|
||||
"numoutlets" : 1,
|
||||
"outlettype" : [ "signal" ],
|
||||
"patching_rect" : [ 530.25, 447.0, 32.5, 20.0 ],
|
||||
"presentation_rect" : [ 503.0, 573.0, 0.0, 0.0 ],
|
||||
"text" : "*~"
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"box" : {
|
||||
"fontname" : "Arial",
|
||||
"fontsize" : 12.0,
|
||||
"id" : "obj-31",
|
||||
"maxclass" : "newobj",
|
||||
"numinlets" : 2,
|
||||
"numoutlets" : 1,
|
||||
"outlettype" : [ "signal" ],
|
||||
"patching_rect" : [ 564.25, 447.0, 32.5, 20.0 ],
|
||||
"presentation_rect" : [ 537.0, 573.0, 0.0, 0.0 ],
|
||||
"text" : "*~"
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"box" : {
|
||||
"fontname" : "Arial",
|
||||
"fontsize" : 12.0,
|
||||
"id" : "obj-19",
|
||||
"maxclass" : "newobj",
|
||||
"numinlets" : 1,
|
||||
"numoutlets" : 1,
|
||||
"outlettype" : [ "signal" ],
|
||||
"patching_rect" : [ 530.25, 373.0, 33.0, 20.0 ],
|
||||
"presentation_rect" : [ 732.0, 455.0, 0.0, 0.0 ],
|
||||
"text" : "sig~"
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"box" : {
|
||||
"fontname" : "Arial",
|
||||
"fontsize" : 12.0,
|
||||
"id" : "obj-25",
|
||||
"maxclass" : "message",
|
||||
"numinlets" : 2,
|
||||
"numoutlets" : 1,
|
||||
"outlettype" : [ "" ],
|
||||
"patching_rect" : [ 562.75, 333.0, 32.5, 18.0 ],
|
||||
"presentation_rect" : [ 697.0, 411.0, 0.0, 0.0 ],
|
||||
"text" : "1"
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"box" : {
|
||||
"fontname" : "Arial",
|
||||
"fontsize" : 12.0,
|
||||
"id" : "obj-26",
|
||||
"maxclass" : "message",
|
||||
"numinlets" : 2,
|
||||
"numoutlets" : 1,
|
||||
"outlettype" : [ "" ],
|
||||
"patching_rect" : [ 530.25, 333.0, 32.5, 18.0 ],
|
||||
"presentation_rect" : [ 622.0, 416.0, 0.0, 0.0 ],
|
||||
"text" : "0"
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"box" : {
|
||||
"fontname" : "Arial",
|
||||
"fontsize" : 12.0,
|
||||
"id" : "obj-29",
|
||||
"maxclass" : "newobj",
|
||||
"numinlets" : 3,
|
||||
"numoutlets" : 2,
|
||||
"outlettype" : [ "signal", "signal" ],
|
||||
"patching_rect" : [ 530.25, 407.0, 104.0, 20.0 ],
|
||||
"text" : "groove~ click_buf"
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"box" : {
|
||||
"fontname" : "Arial",
|
||||
"fontsize" : 12.0,
|
||||
"id" : "obj-17",
|
||||
"maxclass" : "newobj",
|
||||
"numinlets" : 1,
|
||||
"numoutlets" : 1,
|
||||
"outlettype" : [ "" ],
|
||||
"patching_rect" : [ 53.25, 682.0, 486.0, 20.0 ],
|
||||
"text" : "loadmess append OSX:/Users/samuelperry/Work/SOTON/Initial_work/BPLabs/click_stim/"
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"box" : {
|
||||
"fontname" : "Arial",
|
||||
"fontsize" : 12.0,
|
||||
"id" : "obj-13",
|
||||
"maxclass" : "newobj",
|
||||
"numinlets" : 1,
|
||||
"numoutlets" : 1,
|
||||
"outlettype" : [ "" ],
|
||||
"patching_rect" : [ 835.75, 204.0, 97.0, 20.0 ],
|
||||
"presentation_rect" : [ 512.0, 408.0, 0.0, 0.0 ],
|
||||
"text" : "prepend replace"
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"box" : {
|
||||
"fontname" : "Arial",
|
||||
"fontsize" : 12.0,
|
||||
"id" : "obj-14",
|
||||
"maxclass" : "newobj",
|
||||
"numinlets" : 1,
|
||||
"numoutlets" : 1,
|
||||
"outlettype" : [ "" ],
|
||||
"patching_rect" : [ 835.75, 164.0, 79.0, 20.0 ],
|
||||
"presentation_rect" : [ 512.0, 368.0, 0.0, 0.0 ],
|
||||
"text" : "absolutepath"
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"box" : {
|
||||
"fontname" : "Arial",
|
||||
"fontsize" : 12.0,
|
||||
"id" : "obj-15",
|
||||
"maxclass" : "message",
|
||||
"numinlets" : 2,
|
||||
"numoutlets" : 1,
|
||||
"outlettype" : [ "" ],
|
||||
"patching_rect" : [ 835.75, 132.0, 127.0, 18.0 ],
|
||||
"presentation_rect" : [ 512.0, 299.0, 0.0, 0.0 ],
|
||||
"text" : "click_3000_20Hz.wav"
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"box" : {
|
||||
"fontname" : "Arial",
|
||||
"fontsize" : 12.0,
|
||||
"id" : "obj-16",
|
||||
"maxclass" : "newobj",
|
||||
"numinlets" : 1,
|
||||
"numoutlets" : 2,
|
||||
"outlettype" : [ "float", "bang" ],
|
||||
"patching_rect" : [ 835.75, 235.0, 98.0, 20.0 ],
|
||||
"text" : "buffer~ click_buf"
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"box" : {
|
||||
"fontname" : "Arial",
|
||||
"fontsize" : 12.0,
|
||||
"id" : "obj-28",
|
||||
"maxclass" : "newobj",
|
||||
"numinlets" : 1,
|
||||
"numoutlets" : 1,
|
||||
"outlettype" : [ "" ],
|
||||
"patching_rect" : [ 53.25, 702.0, 476.0, 20.0 ],
|
||||
"text" : "loadmess append OSX:/Users/samuelperry/Work/SOTON/Initial_work/BPLabs/da_stim/"
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"box" : {
|
||||
"fontname" : "Arial",
|
||||
"fontsize" : 12.0,
|
||||
"id" : "obj-27",
|
||||
"maxclass" : "newobj",
|
||||
"numinlets" : 1,
|
||||
"numoutlets" : 1,
|
||||
"outlettype" : [ "" ],
|
||||
"patching_rect" : [ 53.25, 662.0, 596.0, 20.0 ],
|
||||
"text" : "loadmess append OSX:/Users/samuelperry/Work/SOTON/Initial_work/BPLabs/matrix_test/stimulus/wav/noise/"
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"box" : {
|
||||
"fontname" : "Arial",
|
||||
"fontsize" : 12.0,
|
||||
"id" : "obj-23",
|
||||
"maxclass" : "message",
|
||||
"numinlets" : 2,
|
||||
"numoutlets" : 1,
|
||||
"outlettype" : [ "" ],
|
||||
"patching_rect" : [ 650.0, 132.0, 64.0, 18.0 ],
|
||||
"text" : "noise.wav"
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"box" : {
|
||||
"fontname" : "Arial",
|
||||
"fontsize" : 12.0,
|
||||
"id" : "obj-20",
|
||||
"maxclass" : "newobj",
|
||||
"numinlets" : 1,
|
||||
"numoutlets" : 1,
|
||||
"outlettype" : [ "" ],
|
||||
"patching_rect" : [ 650.0, 204.0, 97.0, 20.0 ],
|
||||
"text" : "prepend replace"
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"box" : {
|
||||
"fontname" : "Arial",
|
||||
"fontsize" : 12.0,
|
||||
"id" : "obj-21",
|
||||
"maxclass" : "newobj",
|
||||
"numinlets" : 1,
|
||||
"numoutlets" : 1,
|
||||
"outlettype" : [ "" ],
|
||||
"patching_rect" : [ 650.0, 164.0, 79.0, 20.0 ],
|
||||
"text" : "absolutepath"
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"box" : {
|
||||
"fontname" : "Arial",
|
||||
"fontsize" : 12.0,
|
||||
"id" : "obj-22",
|
||||
"maxclass" : "newobj",
|
||||
"numinlets" : 1,
|
||||
"numoutlets" : 2,
|
||||
"outlettype" : [ "float", "bang" ],
|
||||
"patching_rect" : [ 650.0, 235.0, 103.0, 20.0 ],
|
||||
"text" : "buffer~ noise_buf"
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"box" : {
|
||||
"fontname" : "Arial",
|
||||
"fontsize" : 12.0,
|
||||
"id" : "obj-18",
|
||||
"maxclass" : "newobj",
|
||||
"numinlets" : 1,
|
||||
"numoutlets" : 1,
|
||||
"outlettype" : [ "" ],
|
||||
"patching_rect" : [ 508.0, 204.0, 97.0, 20.0 ],
|
||||
"text" : "prepend replace"
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"box" : {
|
||||
"fontname" : "Arial",
|
||||
"fontsize" : 12.0,
|
||||
"id" : "obj-2",
|
||||
"maxclass" : "newobj",
|
||||
"numinlets" : 1,
|
||||
"numoutlets" : 1,
|
||||
"outlettype" : [ "" ],
|
||||
"patching_rect" : [ 53.25, 750.0, 49.0, 20.0 ],
|
||||
"text" : "filepath"
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"box" : {
|
||||
"fontname" : "Arial",
|
||||
"fontsize" : 12.0,
|
||||
"id" : "obj-11",
|
||||
"maxclass" : "newobj",
|
||||
"numinlets" : 1,
|
||||
"numoutlets" : 1,
|
||||
"outlettype" : [ "" ],
|
||||
"patching_rect" : [ 508.0, 164.0, 79.0, 20.0 ],
|
||||
"text" : "absolutepath"
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"box" : {
|
||||
"fontname" : "Arial",
|
||||
"fontsize" : 12.0,
|
||||
"id" : "obj-10",
|
||||
"maxclass" : "message",
|
||||
"numinlets" : 2,
|
||||
"numoutlets" : 1,
|
||||
"outlettype" : [ "" ],
|
||||
"patching_rect" : [ 508.0, 132.0, 82.0, 18.0 ],
|
||||
"text" : "3000_da.wav"
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"box" : {
|
||||
"fontname" : "Arial",
|
||||
"fontsize" : 12.0,
|
||||
"id" : "obj-8",
|
||||
"maxclass" : "newobj",
|
||||
"numinlets" : 1,
|
||||
"numoutlets" : 2,
|
||||
"outlettype" : [ "float", "bang" ],
|
||||
"patching_rect" : [ 508.0, 235.0, 88.0, 20.0 ],
|
||||
"text" : "buffer~ da_buf"
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"box" : {
|
||||
"id" : "obj-6",
|
||||
"maxclass" : "ezdac~",
|
||||
"numinlets" : 2,
|
||||
"numoutlets" : 0,
|
||||
"patching_rect" : [ 341.25, 537.0, 45.0, 45.0 ]
|
||||
}
|
||||
|
||||
}
|
||||
],
|
||||
"lines" : [ {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-11", 0 ],
|
||||
"disabled" : 0,
|
||||
"hidden" : 0,
|
||||
"source" : [ "obj-10", 0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-18", 0 ],
|
||||
"disabled" : 0,
|
||||
"hidden" : 0,
|
||||
"source" : [ "obj-11", 0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-16", 0 ],
|
||||
"disabled" : 0,
|
||||
"hidden" : 0,
|
||||
"source" : [ "obj-13", 0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-13", 0 ],
|
||||
"disabled" : 0,
|
||||
"hidden" : 0,
|
||||
"source" : [ "obj-14", 0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-14", 0 ],
|
||||
"disabled" : 0,
|
||||
"hidden" : 0,
|
||||
"source" : [ "obj-15", 0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-2", 0 ],
|
||||
"disabled" : 0,
|
||||
"hidden" : 0,
|
||||
"source" : [ "obj-17", 0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-8", 0 ],
|
||||
"disabled" : 0,
|
||||
"hidden" : 0,
|
||||
"source" : [ "obj-18", 0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-29", 0 ],
|
||||
"disabled" : 0,
|
||||
"hidden" : 0,
|
||||
"source" : [ "obj-19", 0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-22", 0 ],
|
||||
"disabled" : 0,
|
||||
"hidden" : 0,
|
||||
"source" : [ "obj-20", 0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-20", 0 ],
|
||||
"disabled" : 0,
|
||||
"hidden" : 0,
|
||||
"source" : [ "obj-21", 0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-21", 0 ],
|
||||
"disabled" : 0,
|
||||
"hidden" : 0,
|
||||
"source" : [ "obj-23", 0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-19", 0 ],
|
||||
"disabled" : 0,
|
||||
"hidden" : 0,
|
||||
"source" : [ "obj-25", 0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-19", 0 ],
|
||||
"disabled" : 0,
|
||||
"hidden" : 0,
|
||||
"source" : [ "obj-26", 0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-2", 0 ],
|
||||
"disabled" : 0,
|
||||
"hidden" : 0,
|
||||
"source" : [ "obj-27", 0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-2", 0 ],
|
||||
"disabled" : 0,
|
||||
"hidden" : 0,
|
||||
"source" : [ "obj-28", 0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-30", 0 ],
|
||||
"disabled" : 0,
|
||||
"hidden" : 0,
|
||||
"source" : [ "obj-29", 0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-31", 0 ],
|
||||
"disabled" : 0,
|
||||
"hidden" : 0,
|
||||
"source" : [ "obj-29", 1 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-6", 0 ],
|
||||
"disabled" : 0,
|
||||
"hidden" : 0,
|
||||
"source" : [ "obj-30", 0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-6", 1 ],
|
||||
"disabled" : 0,
|
||||
"hidden" : 0,
|
||||
"source" : [ "obj-31", 0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-30", 1 ],
|
||||
"disabled" : 0,
|
||||
"hidden" : 0,
|
||||
"source" : [ "obj-32", 0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-31", 1 ],
|
||||
"disabled" : 0,
|
||||
"hidden" : 0,
|
||||
"source" : [ "obj-32", 0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-34", 1 ],
|
||||
"disabled" : 0,
|
||||
"hidden" : 0,
|
||||
"source" : [ "obj-33", 0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-35", 1 ],
|
||||
"disabled" : 0,
|
||||
"hidden" : 0,
|
||||
"source" : [ "obj-33", 0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-6", 0 ],
|
||||
"disabled" : 0,
|
||||
"hidden" : 0,
|
||||
"source" : [ "obj-34", 0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-6", 1 ],
|
||||
"disabled" : 0,
|
||||
"hidden" : 0,
|
||||
"source" : [ "obj-35", 0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-50", 0 ],
|
||||
"disabled" : 0,
|
||||
"hidden" : 0,
|
||||
"source" : [ "obj-37", 0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-37", 0 ],
|
||||
"disabled" : 0,
|
||||
"hidden" : 0,
|
||||
"source" : [ "obj-39", 0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-37", 0 ],
|
||||
"disabled" : 0,
|
||||
"hidden" : 0,
|
||||
"source" : [ "obj-48", 0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-34", 0 ],
|
||||
"disabled" : 0,
|
||||
"hidden" : 0,
|
||||
"source" : [ "obj-50", 0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-35", 0 ],
|
||||
"disabled" : 0,
|
||||
"hidden" : 0,
|
||||
"source" : [ "obj-50", 1 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-52", 1 ],
|
||||
"disabled" : 0,
|
||||
"hidden" : 0,
|
||||
"source" : [ "obj-51", 0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-53", 1 ],
|
||||
"disabled" : 0,
|
||||
"hidden" : 0,
|
||||
"source" : [ "obj-51", 0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-6", 0 ],
|
||||
"disabled" : 0,
|
||||
"hidden" : 0,
|
||||
"source" : [ "obj-52", 0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-6", 1 ],
|
||||
"disabled" : 0,
|
||||
"hidden" : 0,
|
||||
"source" : [ "obj-53", 0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-57", 0 ],
|
||||
"disabled" : 0,
|
||||
"hidden" : 0,
|
||||
"source" : [ "obj-54", 0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-54", 0 ],
|
||||
"disabled" : 0,
|
||||
"hidden" : 0,
|
||||
"source" : [ "obj-55", 0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-54", 0 ],
|
||||
"disabled" : 0,
|
||||
"hidden" : 0,
|
||||
"source" : [ "obj-56", 0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-52", 0 ],
|
||||
"disabled" : 0,
|
||||
"hidden" : 0,
|
||||
"source" : [ "obj-57", 0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-53", 0 ],
|
||||
"disabled" : 0,
|
||||
"hidden" : 0,
|
||||
"source" : [ "obj-57", 1 ]
|
||||
}
|
||||
|
||||
}
|
||||
],
|
||||
"dependency_cache" : [ ]
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
from threading import Thread, Event
|
||||
import os
|
||||
import numpy as np
|
||||
from matrix_test.filesystem import globDir
|
||||
from pysndfile import PySndfile, sndio
|
||||
from random import randint, shuffle
|
||||
from shutil import copyfile
|
||||
from natsort import natsorted
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
from shutil import copy2
|
||||
|
||||
from test_base import BaseThread
|
||||
|
||||
from matrix_test.signalops import play_wav
|
||||
from scipy.special import logit
|
||||
from config import socketio
|
||||
import csv
|
||||
import pdb
|
||||
import dill
|
||||
|
||||
symb_dict = {
|
||||
True: 10003,
|
||||
False: 10007
|
||||
}
|
||||
|
||||
def set_trace():
|
||||
import logging
|
||||
log = logging.getLogger('werkzeug')
|
||||
log.setLevel(logging.ERROR)
|
||||
log = logging.getLogger('engineio')
|
||||
log.setLevel(logging.ERROR)
|
||||
pdb.set_trace()
|
||||
|
||||
|
||||
class ClickTestThread(BaseThread):
|
||||
'''
|
||||
Thread for running server side matrix test operations
|
||||
'''
|
||||
def __init__(self, sessionFilepath=None,
|
||||
stimFolder='./click_stim/', nTrials=2,
|
||||
socketio=None, participant=None, srt_50=None, s_50=None):
|
||||
self.wav_file = os.path.join(stimFolder, 'click_3000_20Hz.wav')
|
||||
|
||||
self.test_name = 'click_test'
|
||||
self.nTrials = nTrials
|
||||
self.trial_ind = 0
|
||||
self._stopevent = Event()
|
||||
|
||||
super(ClickTestThread, self).__init__(self.test_name,
|
||||
sessionFilepath=sessionFilepath,
|
||||
socketio=socketio,
|
||||
participant=participant)
|
||||
|
||||
self.toSave = ['trial_ind', 'nTrials', 'wav_file', 'test_name']
|
||||
|
||||
self.socketio.on_event('finalise_results', self.finaliseResults, namespace='/main')
|
||||
|
||||
self.dev_mode = False
|
||||
|
||||
|
||||
def testLoop(self):
|
||||
'''
|
||||
Main loop for iteratively finding the SRT
|
||||
'''
|
||||
self.waitForPageLoad()
|
||||
self.socketio.emit('test_ready', namespace='/main')
|
||||
for self.trial_ind in range(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.saveState(out=self.backupFilepath)
|
||||
if not self._stopevent.isSet():
|
||||
self.unsetPageLoaded()
|
||||
self.socketio.emit('processing-complete', namespace='/main')
|
||||
|
||||
|
||||
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)
|
||||
|
||||
|
||||
def saveState(self, out="test_state.pkl"):
|
||||
saveDict = {k:self.__dict__[k] for k in self.toSave}
|
||||
with open(out, 'wb') as f:
|
||||
dill.dump(saveDict, f)
|
||||
@@ -0,0 +1,109 @@
|
||||
from threading import Thread, Event
|
||||
import os
|
||||
import numpy as np
|
||||
from matrix_test.filesystem import globDir
|
||||
from pysndfile import PySndfile, sndio
|
||||
from random import randint, shuffle
|
||||
from shutil import copyfile
|
||||
from natsort import natsorted
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
from shutil import copy2
|
||||
|
||||
from test_base import BaseThread
|
||||
|
||||
from matrix_test.signalops import play_wav
|
||||
from scipy.special import logit
|
||||
from config import socketio
|
||||
import csv
|
||||
import pdb
|
||||
import dill
|
||||
|
||||
symb_dict = {
|
||||
True: 10003,
|
||||
False: 10007
|
||||
}
|
||||
|
||||
def set_trace():
|
||||
import logging
|
||||
log = logging.getLogger('werkzeug')
|
||||
log.setLevel(logging.ERROR)
|
||||
log = logging.getLogger('engineio')
|
||||
log.setLevel(logging.ERROR)
|
||||
pdb.set_trace()
|
||||
|
||||
|
||||
class DaTestThread(BaseThread):
|
||||
'''
|
||||
Thread for running server side matrix test operations
|
||||
'''
|
||||
def __init__(self, sessionFilepath=None,
|
||||
stimFolder='./da_stim/', nTrials=2,
|
||||
socketio=None, participant=None, srt_50=None, s_50=None):
|
||||
self.wav_file = os.path.join(stimFolder, '3000_da.wav')
|
||||
|
||||
self.test_name = 'da_test'
|
||||
self.nTrials = nTrials
|
||||
self.trial_ind = 0
|
||||
self._stopevent = Event()
|
||||
|
||||
super(DaTestThread, self).__init__(self.test_name,
|
||||
sessionFilepath=sessionFilepath,
|
||||
socketio=socketio,
|
||||
participant=participant)
|
||||
|
||||
self.toSave = ['trial_ind', 'nTrials', 'wav_file', 'test_name']
|
||||
|
||||
self.socketio.on_event('finalise_results', self.finaliseResults, namespace='/main')
|
||||
|
||||
self.dev_mode = True
|
||||
|
||||
|
||||
def testLoop(self):
|
||||
'''
|
||||
Main loop for iteratively finding the SRT
|
||||
'''
|
||||
self.waitForPageLoad()
|
||||
self.socketio.emit('test_ready', namespace='/main')
|
||||
for self.trial_ind in range(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.saveState(out=self.backupFilepath)
|
||||
if not self._stopevent.isSet():
|
||||
self.unsetPageLoaded()
|
||||
self.socketio.emit('processing-complete', namespace='/main')
|
||||
|
||||
|
||||
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)
|
||||
|
||||
|
||||
def saveState(self, out="test_state.pkl"):
|
||||
saveDict = {k:self.__dict__[k] for k in self.toSave}
|
||||
with open(out, 'wb') as f:
|
||||
dill.dump(saveDict, f)
|
||||
+2
-9
@@ -11,7 +11,6 @@ import pandas as pd
|
||||
from shutil import copy2
|
||||
|
||||
from test_base import BaseThread, run_test_thread
|
||||
from WavPlayer import play_wav
|
||||
from scipy.special import logit
|
||||
from config import socketio
|
||||
import csv
|
||||
@@ -144,12 +143,6 @@ class EEGTestThread(BaseThread):
|
||||
self.answers[incomplete_responses] = np.nan
|
||||
self.fillTable()
|
||||
|
||||
def finishTestEarly(self):
|
||||
'''
|
||||
'''
|
||||
self.finishTest = True
|
||||
|
||||
|
||||
def finaliseResults(self):
|
||||
toSave = ['marker_files', 'clinPageLoaded', 'wav_files', 'participant',
|
||||
'response', 'backupFilepath', 'noise_path', 'question_files',
|
||||
@@ -180,9 +173,9 @@ class EEGTestThread(BaseThread):
|
||||
# Play audio
|
||||
# sd.play(self.y, self.fs, blocking=True)
|
||||
if not self.dev_mode:
|
||||
play_wav(wav_file, 'finish_test')
|
||||
self.play_wav(wav_file, 'finish_test')
|
||||
else:
|
||||
play_wav('./test.wav', 'finish_test')
|
||||
self.play_wav('./test.wav', 'finish_test')
|
||||
|
||||
self.socketio.emit("stim_done", namespace="/main")
|
||||
|
||||
|
||||
@@ -187,9 +187,26 @@ def matDecStim():
|
||||
'''
|
||||
Click stimulus routing
|
||||
'''
|
||||
@server.route('/click_stim')
|
||||
def clickStim():
|
||||
return render_template("click_stim.html")
|
||||
@server.route('/click/setup')
|
||||
def click_setup():
|
||||
participants = find_participants()
|
||||
return render_template("click_test_setup.html", part_keys=participants.keys())
|
||||
|
||||
@server.route('/click/clinician/run')
|
||||
def click_clinician_run():
|
||||
return render_template("click_test_clinician_view.html")
|
||||
|
||||
@server.route('/click/clinician/complete')
|
||||
def click_clinician_complete():
|
||||
return render_template("click_test_clinician_end.html")
|
||||
|
||||
@server.route('/click/run')
|
||||
def click_run():
|
||||
return render_template("click_test_run.html")
|
||||
|
||||
@server.route('/click/complete')
|
||||
def click_complete():
|
||||
return render_template("click_test_end.html")
|
||||
|
||||
|
||||
'''
|
||||
@@ -206,7 +223,7 @@ def da_clinician_run():
|
||||
|
||||
@server.route('/da/clinician/complete')
|
||||
def da_clinician_complete():
|
||||
return render_template("da_test_clinician_complete.html")
|
||||
return render_template("da_test_clinician_end.html")
|
||||
|
||||
@server.route('/da/run')
|
||||
def da_run():
|
||||
@@ -214,7 +231,7 @@ def da_run():
|
||||
|
||||
@server.route('/da/complete')
|
||||
def da_complete():
|
||||
return render_template("da_test_run.html")
|
||||
return render_template("da_test_end.html")
|
||||
|
||||
'''
|
||||
Calibration routing
|
||||
|
||||
@@ -34,12 +34,14 @@ from config import server, socketio, participants
|
||||
from da_test_thread import DaTestThread
|
||||
from eeg_test_thread import EEGTestThread
|
||||
from matrix_test_thread import MatTestThread
|
||||
from click_test_thread import ClickTestThread
|
||||
from test_base import run_test_thread
|
||||
|
||||
thread_types = {
|
||||
'da_test': DaTestThread,
|
||||
'eeg_test': EEGTestThread,
|
||||
'mat_test': MatTestThread,
|
||||
'click_test': ClickTestThread,
|
||||
}
|
||||
|
||||
'''
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
{% extends 'index.html' %}
|
||||
{% block content %}
|
||||
<div class="card">
|
||||
<div id="main-div" class="card-body">
|
||||
<div class="d-flex justify-content-center mt-2" role="group">
|
||||
<p>Use the controls below to play the calibration signal. The signal should be calibrated to 60dBa.</p>
|
||||
</div>
|
||||
<div class="d-flex justify-content-center mt-2" role="group">
|
||||
<button type="button" id="play_calibrate" class="btn btn-primary mx-3">Play calibration signal</button>
|
||||
<button type="button" id="stop_calibrate" class="btn btn-primary mx-3">Stop calibration signal</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$(document).ready(function(){
|
||||
var socket = io.connect(location.protocol + '//' + document.domain + ':' + location.port + '/main');
|
||||
$('#play_calibrate').click(function(event) {
|
||||
socket.emit("play_calibrate");
|
||||
});
|
||||
|
||||
$('#stop_calibrate').click(function(event) {
|
||||
socket.emit("stop_calibrate");
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,22 @@
|
||||
{% extends 'index.html' %}
|
||||
{% block content %}
|
||||
<link rel=stylesheet type=text/css href="{{ url_for('static', filename='style.css') }}">
|
||||
<div class="card">
|
||||
<div id="main-div" class="card-body">
|
||||
<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>
|
||||
</div>
|
||||
<script>
|
||||
$(document).ready(function(){
|
||||
// Initialise socketio with a namespace called "main"
|
||||
var socket = io.connect(location.protocol + '//' + document.domain + ':' + location.port + '/main');
|
||||
|
||||
$('#mat-save').click(function(event) {
|
||||
socket.emit("finalise_results")
|
||||
window.location.href = '/home';
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,39 @@
|
||||
{% extends 'index.html' %}
|
||||
{% block content %}
|
||||
<link rel=stylesheet type=text/css href="{{ url_for('static', filename='style.css') }}">
|
||||
<div class="card">
|
||||
<div id="main-div" class="card-body">
|
||||
<div class="d-flex justify-content-center mt-2" role="group">
|
||||
<button type="button" id="test_save" class="btn btn-primary mx-3">Save test state</button>
|
||||
<button type="button" id="test_finish" class="btn btn-primary mx-3">Finish test</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
$(document).ready(function(){
|
||||
// Initialise socketio with a namespace called "main"
|
||||
var socket = io.connect(location.protocol + '//' + document.domain + ':' + location.port + '/main');
|
||||
// Check if matrix stimulus is currently being processed
|
||||
waitingDialog.show('Generating stimulus');
|
||||
|
||||
socket.on('test_ready', function(msg) {
|
||||
waitingDialog.hide();
|
||||
});
|
||||
|
||||
$('#test_save').click(function(event) {
|
||||
socket.emit("open_save_file_dialog")
|
||||
});
|
||||
|
||||
$('#test_finish').click(function(event) {
|
||||
socket.emit("finish_test")
|
||||
});
|
||||
|
||||
// Catch message when asynchronous process is complete
|
||||
socket.on('processing-complete', function(msg) {
|
||||
alert("Stimulus processing complete!")
|
||||
window.location.href = '/click/clinician/complete';
|
||||
});
|
||||
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,9 @@
|
||||
{% extends 'participant_index.html' %}
|
||||
{% block content %}
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h1>Test complete!</h1>
|
||||
<p>Please wait for the experimenter to give further instructions...</p>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,92 @@
|
||||
{% extends 'participant_index.html' %}
|
||||
{% block content %}
|
||||
<link rel=stylesheet type=text/css href="{{ url_for('static', filename='style.css') }}">
|
||||
<div id="main-div" class="outer">
|
||||
<div id="overlay">
|
||||
<span id="overlay_crosshair">✚</span>
|
||||
</div>
|
||||
<div id="instructions">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h2>Instructions</h2>
|
||||
<p>
|
||||
In this test, you will be presented with repeated click sounds.
|
||||
Simply listen to the stimulus, you do not need to respond.
|
||||
</p>
|
||||
<button type="button" href="#" id="instr_continue" class="Btn Btn-primary">Continue</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$(document).ready(function(){
|
||||
jQuery.expr[':'].contains = function(a, i, m) {
|
||||
return jQuery(a).text().toUpperCase()
|
||||
.indexOf(m[3].toUpperCase()) >= 0;
|
||||
};
|
||||
// Initialise socketio with a namespace called "main"
|
||||
var socket = io.connect(location.protocol + '//' + document.domain + ':' + location.port + '/main');
|
||||
var loading = true;
|
||||
var part_ready = false;
|
||||
waitingDialog.show('Loading... Please wait');
|
||||
|
||||
function displayInstructions() {
|
||||
$("#instructions").css("display", "table-cell");
|
||||
$("#instructions").fadeIn();
|
||||
waitingDialog.hide();
|
||||
}
|
||||
|
||||
function hideInstructions() {
|
||||
$("#instructions").css("display", "none");
|
||||
$("#instructions").fadeOut();
|
||||
if(loading) {
|
||||
waitingDialog.show('Loading... Please wait');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$('#instr_continue').click(function(event) {
|
||||
hideInstructions();
|
||||
part_ready = true;
|
||||
socket.emit("part_ready")
|
||||
on()
|
||||
});
|
||||
|
||||
socket.on('display_instructions', function(msg) {
|
||||
displayInstructions();
|
||||
});
|
||||
|
||||
socket.on('test_ready', function(msg) {
|
||||
loading = false;
|
||||
waitingDialog.hide();
|
||||
});
|
||||
|
||||
socket.on('stim_playing', function(msg) {
|
||||
on()
|
||||
});
|
||||
|
||||
socket.on('stim_done', function(msg) {
|
||||
off()
|
||||
});
|
||||
|
||||
function on() {
|
||||
$("#overlay").css("display", "table-cell");
|
||||
$("#overlay_crosshair").css("display", "inline");
|
||||
$("#overlay").fadeIn();
|
||||
$("#overlay_crosshair").fadeIn();
|
||||
}
|
||||
|
||||
function off() {
|
||||
$("#overlay").fadeOut();
|
||||
}
|
||||
|
||||
socket.on('processing-complete', function(msg) {
|
||||
// Re-enable all inputs
|
||||
$('#main-div').find('input, textarea, button, select').removeAttr('disabled');
|
||||
alert("Click stimulus processing complete!")
|
||||
window.location.href = '/click/complete';
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,58 @@
|
||||
{% extends 'index.html' %}
|
||||
{% block content %}
|
||||
<div class="card">
|
||||
<div id="main-div" class="card-body">
|
||||
<form action="{{ url_for('matDecStim') }}" method="POST">
|
||||
<div class="form-group">
|
||||
<select class="form-control" name="participant" id="participant">
|
||||
<option>--</option>
|
||||
{% for p in part_keys %}
|
||||
<option>{{ p }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group d-flex justify-content-center">
|
||||
<button type="button" id="start_test" class="btn btn-primary mx-3">Start data collection</button>
|
||||
<button type="button" id="load-saved" class="btn btn-primary mx-3">Load saved session</button>
|
||||
<button type="button" id="load-backup" class="btn btn-primary mx-3">Load previous automatic backup</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
$(document).ready(function(){
|
||||
// Initialise socketio with a namespace called "main"
|
||||
var socket = io.connect(location.protocol + '//' + document.domain + ':' + location.port + '/main');
|
||||
|
||||
$('#load-backup').click(function(event) {
|
||||
// Send message to call stimulus generation function in Python
|
||||
socket.emit('load_backup_test', {part_key: $("#participant").val(), test_name: "click_test"});
|
||||
return false;
|
||||
})
|
||||
$('#load-saved').click(function(event) {
|
||||
// Send message to call stimulus generation function in Python
|
||||
socket.emit('load_session', {part_key: $("#participant").val(), test_name: "click_test"});
|
||||
return false;
|
||||
})
|
||||
$('#start_test').click(function(event) {
|
||||
// Send message to call stimulus generation function in Python
|
||||
socket.emit('start_test', {part_key: $("#participant").val(), test_name: "click_test"});
|
||||
return false;
|
||||
})
|
||||
|
||||
socket.on('participant_start_click_test', function(msg) {
|
||||
window.location.href = '/click/clinician/run';
|
||||
});
|
||||
|
||||
socket.on('save-dialog-resp', function(msg) {
|
||||
// Set form test to filepath returned by dialog
|
||||
document.getElementById("save-dir").value = msg.data
|
||||
});
|
||||
|
||||
socket.on('click-dialog-resp', function(msg) {
|
||||
// Set form test to filepath returned by dialog
|
||||
document.getElementById("da-dir").value = msg.data
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,22 @@
|
||||
{% extends 'index.html' %}
|
||||
{% block content %}
|
||||
<link rel=stylesheet type=text/css href="{{ url_for('static', filename='style.css') }}">
|
||||
<div class="card">
|
||||
<div id="main-div" class="card-body">
|
||||
<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>
|
||||
</div>
|
||||
<script>
|
||||
$(document).ready(function(){
|
||||
// Initialise socketio with a namespace called "main"
|
||||
var socket = io.connect(location.protocol + '//' + document.domain + ':' + location.port + '/main');
|
||||
|
||||
$('#mat-save').click(function(event) {
|
||||
socket.emit("finalise_results")
|
||||
window.location.href = '/home';
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,39 @@
|
||||
{% extends 'index.html' %}
|
||||
{% block content %}
|
||||
<link rel=stylesheet type=text/css href="{{ url_for('static', filename='style.css') }}">
|
||||
<div class="card">
|
||||
<div id="main-div" class="card-body">
|
||||
<div class="d-flex justify-content-center mt-2" role="group">
|
||||
<button type="button" id="test_save" class="btn btn-primary mx-3">Save test state</button>
|
||||
<button type="button" id="test_finish" class="btn btn-primary mx-3">Finish test</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
$(document).ready(function(){
|
||||
// Initialise socketio with a namespace called "main"
|
||||
var socket = io.connect(location.protocol + '//' + document.domain + ':' + location.port + '/main');
|
||||
// Check if matrix stimulus is currently being processed
|
||||
waitingDialog.show('Generating stimulus');
|
||||
|
||||
socket.on('test_ready', function(msg) {
|
||||
waitingDialog.hide();
|
||||
});
|
||||
|
||||
$('#test_save').click(function(event) {
|
||||
socket.emit("open_save_file_dialog")
|
||||
});
|
||||
|
||||
$('#test_finish').click(function(event) {
|
||||
socket.emit("finish_test")
|
||||
});
|
||||
|
||||
// Catch message when asynchronous process is complete
|
||||
socket.on('processing-complete', function(msg) {
|
||||
alert("Stimulus processing complete!")
|
||||
window.location.href = '/da/clinician/complete';
|
||||
});
|
||||
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,9 @@
|
||||
{% extends 'participant_index.html' %}
|
||||
{% block content %}
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h1>Test complete!</h1>
|
||||
<p>Please wait for the experimenter to give further instructions...</p>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,93 @@
|
||||
{% extends 'participant_index.html' %}
|
||||
{% block content %}
|
||||
<link rel=stylesheet type=text/css href="{{ url_for('static', filename='style.css') }}">
|
||||
<div id="main-div" class="outer">
|
||||
<div id="overlay">
|
||||
<span id="overlay_crosshair">✚</span>
|
||||
</div>
|
||||
<div id="instructions">
|
||||
<div class="card">
|
||||
<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>
|
||||
<button type="button" href="#" id="instr_continue" class="Btn Btn-primary">Continue</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$(document).ready(function(){
|
||||
jQuery.expr[':'].contains = function(a, i, m) {
|
||||
return jQuery(a).text().toUpperCase()
|
||||
.indexOf(m[3].toUpperCase()) >= 0;
|
||||
};
|
||||
// Initialise socketio with a namespace called "main"
|
||||
var socket = io.connect(location.protocol + '//' + document.domain + ':' + location.port + '/main');
|
||||
var loading = true;
|
||||
var part_ready = false;
|
||||
waitingDialog.show('Loading... Please wait');
|
||||
|
||||
function displayInstructions() {
|
||||
$("#instructions").css("display", "table-cell");
|
||||
$("#instructions").fadeIn();
|
||||
waitingDialog.hide();
|
||||
}
|
||||
|
||||
function hideInstructions() {
|
||||
$("#instructions").css("display", "none");
|
||||
$("#instructions").fadeOut();
|
||||
if(loading) {
|
||||
waitingDialog.show('Loading... Please wait');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$('#instr_continue').click(function(event) {
|
||||
hideInstructions();
|
||||
part_ready = true;
|
||||
socket.emit("part_ready")
|
||||
on()
|
||||
});
|
||||
|
||||
socket.on('display_instructions', function(msg) {
|
||||
displayInstructions();
|
||||
});
|
||||
|
||||
socket.on('test_ready', function(msg) {
|
||||
loading = false;
|
||||
waitingDialog.hide();
|
||||
});
|
||||
|
||||
socket.on('stim_playing', function(msg) {
|
||||
on()
|
||||
});
|
||||
|
||||
socket.on('stim_done', function(msg) {
|
||||
off()
|
||||
});
|
||||
|
||||
function on() {
|
||||
$("#overlay").css("display", "table-cell");
|
||||
$("#overlay_crosshair").css("display", "inline");
|
||||
$("#overlay").fadeIn();
|
||||
$("#overlay_crosshair").fadeIn();
|
||||
}
|
||||
|
||||
function off() {
|
||||
$("#overlay").fadeOut();
|
||||
}
|
||||
|
||||
socket.on('processing-complete', function(msg) {
|
||||
// Re-enable all inputs
|
||||
$('#main-div').find('input, textarea, button, select').removeAttr('disabled');
|
||||
alert("/da/ stimulus processing complete!")
|
||||
window.location.href = '/da/complete';
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,58 @@
|
||||
{% extends 'index.html' %}
|
||||
{% block content %}
|
||||
<div class="card">
|
||||
<div id="main-div" class="card-body">
|
||||
<form action="{{ url_for('matDecStim') }}" method="POST">
|
||||
<div class="form-group">
|
||||
<select class="form-control" name="participant" id="participant">
|
||||
<option>--</option>
|
||||
{% for p in part_keys %}
|
||||
<option>{{ p }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group d-flex justify-content-center">
|
||||
<button type="button" id="start_da_test" class="btn btn-primary mx-3">Start data collection</button>
|
||||
<button type="button" id="load-saved" class="btn btn-primary mx-3">Load saved session</button>
|
||||
<button type="button" id="load-backup" class="btn btn-primary mx-3">Load previous automatic backup</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
$(document).ready(function(){
|
||||
// Initialise socketio with a namespace called "main"
|
||||
var socket = io.connect(location.protocol + '//' + document.domain + ':' + location.port + '/main');
|
||||
|
||||
$('#load-backup').click(function(event) {
|
||||
// Send message to call stimulus generation function in Python
|
||||
socket.emit('load_backup_test', {part_key: $("#participant").val(), test_name: "da_test"});
|
||||
return false;
|
||||
})
|
||||
$('#load-saved').click(function(event) {
|
||||
// Send message to call stimulus generation function in Python
|
||||
socket.emit('load_session', {part_key: $("#participant").val(), test_name: "da_test"});
|
||||
return false;
|
||||
})
|
||||
$('#start_da_test').click(function(event) {
|
||||
// Send message to call stimulus generation function in Python
|
||||
socket.emit('start_test', {part_key: $("#participant").val(), test_name: "da_test"});
|
||||
return false;
|
||||
})
|
||||
|
||||
socket.on('participant_start_da_test', function(msg) {
|
||||
window.location.href = '/da/clinician/run';
|
||||
});
|
||||
|
||||
socket.on('save-dialog-resp', function(msg) {
|
||||
// Set form test to filepath returned by dialog
|
||||
document.getElementById("save-dir").value = msg.data
|
||||
});
|
||||
|
||||
socket.on('da-dialog-resp', function(msg) {
|
||||
// Set form test to filepath returned by dialog
|
||||
document.getElementById("da-dir").value = msg.data
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
@@ -17,11 +17,29 @@
|
||||
<input type="text" id="behav_res" name='behav_res' value="./Matrix_test_results.pkl" style="width:85%"></input>
|
||||
<button type="button" id="behav_res_button" class="btn btn-primary">Browse...</button>
|
||||
</div>
|
||||
<div class="form-group d-flex justify-content-center">
|
||||
<button type="button" id="start_eeg_train" class="btn btn-primary mx-3">Start training data collection</button>
|
||||
<button type="button" id="start_eeg_test" class="btn btn-primary mx-3">Start test data collection</button>
|
||||
<button type="button" id="load-saved" class="btn btn-primary mx-3">Load saved session</button>
|
||||
<button type="button" id="load-backup" class="btn btn-primary mx-3">Load previous automatic backup</button>
|
||||
<div class="form-group container-fluid">
|
||||
<div class="row">
|
||||
<div class="col text-center mb-3">
|
||||
<button type="button" id="start_eeg_train" class="btn btn-primary mx-3">Start training data collection</button>
|
||||
</div>
|
||||
<div class="col text-center mb-3">
|
||||
<button type="button" id="load_train_saved" class="btn btn-primary mx-3">Load saved session</button>
|
||||
</div>
|
||||
<div class="col text-center mb-3">
|
||||
<button type="button" id="load_train_backup" class="btn btn-primary mx-3">Load previous automatic backup</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col text-center mb-3">
|
||||
<button type="button" id="start_eeg_test" class="btn btn-primary mx-3">Start test data collection</button>
|
||||
</div>
|
||||
<div class="col text-center mb-3">
|
||||
<button type="button" id="load_test_saved" class="btn btn-primary mx-3">Load saved session</button>
|
||||
</div>
|
||||
<div class="col text-center mb-3">
|
||||
<button type="button" id="load_test_backup" class="btn btn-primary mx-3">Load previous automatic backup</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@@ -31,21 +49,34 @@
|
||||
// Initialise socketio with a namespace called "main"
|
||||
var socket = io.connect(location.protocol + '//' + document.domain + ':' + location.port + '/main');
|
||||
|
||||
$('#load-backup').click(function(event) {
|
||||
$('#load_test_backup').click(function(event) {
|
||||
// Send message to call stimulus generation function in Python
|
||||
socket.emit('load_backup_test', {part_key: $("#participant").val(), test_name: "eeg_test"});
|
||||
return false;
|
||||
})
|
||||
$('#load-saved').click(function(event) {
|
||||
$('#load_test_saved').click(function(event) {
|
||||
// Send message to call stimulus generation function in Python
|
||||
socket.emit('load_session', {part_key: $("#participant").val(), test_name: "eeg_test"});
|
||||
return false;
|
||||
})
|
||||
|
||||
$('#load_train_backup').click(function(event) {
|
||||
// Send message to call stimulus generation function in Python
|
||||
socket.emit('load_backup_test', {part_key: $("#participant").val(), test_name: "eeg_train"});
|
||||
return false;
|
||||
})
|
||||
$('#load_train_saved').click(function(event) {
|
||||
// Send message to call stimulus generation function in Python
|
||||
socket.emit('load_session', {part_key: $("#participant").val(), test_name: "eeg_train"});
|
||||
return false;
|
||||
})
|
||||
|
||||
$('#start_eeg_train').click(function(event) {
|
||||
// Send message to call stimulus generation function in Python
|
||||
socket.emit('start_test', {part_key: $("#participant").val(), test_name: "eeg_train"});
|
||||
return false;
|
||||
})
|
||||
|
||||
$('#start_eeg_test').click(function(event) {
|
||||
// Send message to call stimulus generation function in Python
|
||||
socket.emit('start_test', {part_key: $("#participant").val(), test_name: "eeg_test"});
|
||||
|
||||
@@ -87,7 +87,8 @@
|
||||
<a class="dropdown-item" href="/tympanometry">Tympanometry</a>
|
||||
<a class="dropdown-item" href="/matrix_test">Behavioral Matrix Test</a>
|
||||
<a class="dropdown-item" href="/eeg">Matrix EEG recording</a>
|
||||
<a class="dropdown-item" href="/da/setup">/da/ eeg recording</a>
|
||||
<a class="dropdown-item" href="/da/setup">/da/ EEG recording</a>
|
||||
<a class="dropdown-item" href="/click/setup">Click EEG recording</a>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -66,7 +66,9 @@
|
||||
|
||||
var test_locs = {
|
||||
'mat_test': "/matrix_test/run",
|
||||
'eeg_test': "/eeg/test/run"
|
||||
'eeg_test': "/eeg/test/run",
|
||||
'da_test': "/da/run",
|
||||
'click_test': "/click/run"
|
||||
}
|
||||
|
||||
socket.on('participant_start', function(msg) {
|
||||
|
||||
+273
@@ -0,0 +1,273 @@
|
||||
import pdb
|
||||
|
||||
import os
|
||||
import sounddevice as sd
|
||||
import dill
|
||||
|
||||
from threading import Thread, Event
|
||||
from config import socketio
|
||||
|
||||
from WavPlayer import WavPlayer
|
||||
|
||||
def run_test_thread(name, thread_type, sessionFilepath=None, participant=None, **kwargs):
|
||||
thread_name = '{}TestThread'.format(name)
|
||||
if thread_name in globals():
|
||||
thread = globals()[thread_name]
|
||||
if thread.isAlive() and isinstance(thread, thread_type):
|
||||
daTestThread.join()
|
||||
thread = thread_type(socketio=socketio, sessionFilepath=sessionFilepath,
|
||||
participant=participant, **kwargs)
|
||||
thread.start()
|
||||
|
||||
def set_trace():
|
||||
import logging
|
||||
log = logging.getLogger('werkzeug')
|
||||
log.setLevel(logging.ERROR)
|
||||
log = logging.getLogger('engineio')
|
||||
log.setLevel(logging.ERROR)
|
||||
pdb.set_trace()
|
||||
|
||||
|
||||
class BaseThread(Thread):
|
||||
'''
|
||||
Thread for running server side matrix test operations
|
||||
'''
|
||||
def __init__(self, test_name, sessionFilepath=None,
|
||||
socketio=None, participant=None, **kwargs):
|
||||
super(BaseThread, self).__init__()
|
||||
self.participant=participant
|
||||
self.socketio = socketio
|
||||
self.test_name = test_name
|
||||
|
||||
self.pageLoaded = False
|
||||
self.clinPageLoaded = False
|
||||
self.partPageLoaded = False
|
||||
self.finishTest = False
|
||||
self.partReady = False
|
||||
self.newResp = False
|
||||
self.finalised = False
|
||||
|
||||
# Define variables to be saved in state files. Should be implemented in
|
||||
# derived class
|
||||
self.toSave = None
|
||||
self.toFinalise = None
|
||||
|
||||
self.wavThread = None
|
||||
|
||||
# Attach handler methods to socketio messages
|
||||
self.socketio.on_event('page_loaded', self.setPageLoaded, namespace='/main')
|
||||
self.socketio.on_event('part_ready', self.setPartReady, namespace='/main')
|
||||
self.socketio.on_event('finalise_results', self.finaliseResults, namespace='/main')
|
||||
self.socketio.on_event('finish_test', self.finishTestEarly, namespace='/main')
|
||||
self.socketio.on_event('save_file_dialog_resp', self.manualSave, namespace='/main')
|
||||
self.socketio.on_event('load_file_dialog_resp', self.loadStateSocketHandle, namespace='/main')
|
||||
|
||||
self._stopevent = Event()
|
||||
# Attach messages from gui to class methods
|
||||
folder = self.participant.data_paths[test_name]
|
||||
self.backupFilepath=os.path.join(folder, '{}_state.pkl'.format(test_name))
|
||||
|
||||
# If loading session from file, load session variables from the file
|
||||
if sessionFilepath:
|
||||
self.loadState(sessionFilepath)
|
||||
else:
|
||||
# Preload audio at start of the test
|
||||
self.loadStimulus()
|
||||
|
||||
self.dev_mode = False
|
||||
|
||||
|
||||
def play_wav(self, wav_file, stop_string):
|
||||
self.wavThread = WavPlayer(wav_file, socketio=socketio, stop_string=stop_string)
|
||||
self.wavThread.run()
|
||||
|
||||
def testLoop(self):
|
||||
'''
|
||||
Main loop
|
||||
'''
|
||||
raise NotImplemented("Test loop code should not be called from the base "
|
||||
"class. This should be implemented in the derived "
|
||||
"test class")
|
||||
|
||||
def displayInstructions(self):
|
||||
'''
|
||||
Emit signal to display test instructions
|
||||
'''
|
||||
self.socketio.emit('display_instructions', data=self.test_name, namespace='/main')
|
||||
|
||||
|
||||
def finishTestEarly(self):
|
||||
'''
|
||||
Set variables to finish the test as soon as possible and exit the
|
||||
thread
|
||||
'''
|
||||
self.finishTest = True
|
||||
self.wavThread._stopevent.set()
|
||||
print(self.finishTest)
|
||||
|
||||
|
||||
def join(self, timeout=None):
|
||||
'''
|
||||
Stop the thread.
|
||||
'''
|
||||
self._stopevent.set()
|
||||
Thread.join(self, timeout)
|
||||
|
||||
|
||||
def waitForResponse(self):
|
||||
'''
|
||||
Test waits for a response from the participant. To use his function
|
||||
correctly, self.newResp must be set to True via a socketio handler in
|
||||
order to continue the test.
|
||||
'''
|
||||
while not self.newResp and not self._stopevent.isSet() and not self.finishTest:
|
||||
self._stopevent.wait(0.2)
|
||||
return
|
||||
|
||||
|
||||
def waitForPageLoad(self):
|
||||
'''
|
||||
Wait for page to load and poll for a socketio message to be sent
|
||||
informing the thread of a successfully loaded page
|
||||
'''
|
||||
while not self.pageLoaded and not self._stopevent.isSet():
|
||||
self.socketio.emit("check-loaded", namespace='/main')
|
||||
self._stopevent.wait(0.5)
|
||||
self.pageLoaded = False
|
||||
|
||||
|
||||
def waitForPartReady(self):
|
||||
'''
|
||||
Test waits for the participant to finish reading instructions. To use
|
||||
this function correctly, self.partReady must be set to True via a socketio
|
||||
handler in order to continue the test.
|
||||
'''
|
||||
while not self.partReady and not self._stopevent.isSet() and not self.finishTest:
|
||||
self._stopevent.wait(0.5)
|
||||
self.partReady = False
|
||||
return
|
||||
|
||||
def waitForFinalise(self):
|
||||
'''
|
||||
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)
|
||||
self._stopevent.wait(0.2)
|
||||
return
|
||||
|
||||
|
||||
def finaliseResults(self):
|
||||
saveDict = {k:self.__dict__[k] for k in self.toSave}
|
||||
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)
|
||||
self.finalised = True
|
||||
|
||||
|
||||
def playStimulusWav(self, wav_file, replay=False):
|
||||
'''
|
||||
output audio stimulus from wav file
|
||||
'''
|
||||
self.newResp = False
|
||||
self.socketio.emit("{}_stim_playing".format(self.test_name), namespace="/main")
|
||||
if not self.dev_mode:
|
||||
play_wav(wav_file)
|
||||
else:
|
||||
play_wav('./test.wav')
|
||||
|
||||
self.socketio.emit("{}_stim_done".format(test_name), namespace="/main")
|
||||
|
||||
|
||||
def playStimulus(self, y, fs):
|
||||
'''
|
||||
Output audio stimulus from numpy array
|
||||
'''
|
||||
self.newResp = False
|
||||
self.socketio.emit("stim_playing", namespace="/main")
|
||||
# Play audio
|
||||
sd.play(y, fs, blocking=True)
|
||||
self.socketio.emit("stim_done", namespace="/main")
|
||||
|
||||
|
||||
def loadStimulus(self):
|
||||
'''
|
||||
Method for preloading stimulus before the start of the test. Should be
|
||||
implemented in child class.
|
||||
'''
|
||||
raise NotImplemented("loadStimulus code should not be called from the base "
|
||||
"class. This should be implemented in the derived "
|
||||
"test class")
|
||||
|
||||
def unsetPageLoaded(self):
|
||||
'''
|
||||
For use in the main loop when a new page is loaded for
|
||||
participant/clinician
|
||||
'''
|
||||
self.pageLoaded = False
|
||||
self.partPageLoaded = False
|
||||
self.clinPageLoaded = False
|
||||
|
||||
|
||||
def setPartReady(self):
|
||||
'''
|
||||
Set variables indicating that the participant is ready to proceed with
|
||||
the test
|
||||
'''
|
||||
self.partReady = True
|
||||
|
||||
|
||||
def setPageLoaded(self, msg):
|
||||
'''
|
||||
Indicate that either the clinician or participant page has been loaded
|
||||
'''
|
||||
if msg['data'] == "clinician":
|
||||
self.clinPageLoaded = True
|
||||
else:
|
||||
self.partPageLoaded = True
|
||||
self.pageLoaded = self.clinPageLoaded and self.partPageLoaded
|
||||
|
||||
|
||||
def saveState(self, out=None):
|
||||
'''
|
||||
Save the state of the thread to a pickle file
|
||||
'''
|
||||
if not out:
|
||||
out = "{}_state.pkl".format(self.test_name)
|
||||
saveDict = {k:self.__dict__[k] for k in self.toSave}
|
||||
with open(out, 'wb') as f:
|
||||
dill.dump(saveDict, f)
|
||||
|
||||
|
||||
def manualSave(self, msg):
|
||||
'''
|
||||
Get and store participant response for current trial
|
||||
'''
|
||||
filepath = msg['data']
|
||||
self.saveState(out=filepath)
|
||||
|
||||
|
||||
def loadStateSocketHandle(self, msg):
|
||||
'''
|
||||
Catch messages indicating that the thread should be loaded from a
|
||||
previously generated pickle file
|
||||
'''
|
||||
filepath = msg['data']
|
||||
self.loadState(filepath)
|
||||
|
||||
|
||||
def loadState(self, filepath):
|
||||
'''
|
||||
Restore thread state from a saved session filepath
|
||||
'''
|
||||
with open(filepath, 'rb') as f:
|
||||
self.__dict__.update(dill.load(f))
|
||||
|
||||
|
||||
def run(self):
|
||||
'''
|
||||
This function is called when the thread starts
|
||||
'''
|
||||
return self.testLoop()
|
||||
Reference in New Issue
Block a user