Browse Source

upload wave files

DESKTOP-4GKCI80\Neuracle 1 year ago
parent
commit
2d4728954a

+ 1 - 1
.vscode/launch.json

@@ -25,7 +25,7 @@
             "name": "Grasp training",
             "type": "python",
             "request": "launch",
-            "program": "grasp-data_collection.py",
+            "program": "grasp_data_collection.py",
             "console": "integratedTerminal",
             "cwd": "${workspaceFolder}/backend",
             "justMyCode": true,

+ 81 - 1
backend/grasp_data_collection.psyexp

@@ -134,7 +134,7 @@
         <Param val="True" valType="bool" updates="constant" name="syncScreenRefresh"/>
       </KeyboardComponent>
       <CodeComponent name="config" plugin="None">
-        <Param val="import time&amp;#10;from device.fubo_pneumatic_finger import FuboPneumaticFingerClient&amp;#10;from device.trigger_box import TriggerNeuracle&amp;#10;from settings.config import settings&amp;#10;&amp;#10;&amp;#10;# get train params&amp;#10;&amp;#10;def parse_args():&amp;#10;&amp;#10;    parser = argparse.ArgumentParser(&amp;#10;&amp;#10;        description='Grasp training'&amp;#10;&amp;#10;    )&amp;#10;&amp;#10;    parser.add_argument(&amp;#10;&amp;#10;        '--n-trials',&amp;#10;&amp;#10;        dest='n_trials',&amp;#10;&amp;#10;        help='Trial number',&amp;#10;&amp;#10;        type=int,&amp;#10;&amp;#10;    )&amp;#10;&amp;#10;    parser.add_argument(&amp;#10;&amp;#10;        '--com',&amp;#10;&amp;#10;        dest='com',&amp;#10;&amp;#10;        help='Peripheral serial port',&amp;#10;&amp;#10;        type=str&amp;#10;&amp;#10;    )&amp;#10;&amp;#10;    parser.add_argument(&amp;#10;&amp;#10;        '--finger-model',&amp;#10;&amp;#10;        '-fm',&amp;#10;&amp;#10;        dest='finger_model',&amp;#10;&amp;#10;        help='Gesture to train',&amp;#10;&amp;#10;        type=str&amp;#10;&amp;#10;    )&amp;#10;&amp;#10;    return parser.parse_args()&amp;#10;&amp;#10;&amp;#10;&amp;#10;args = parse_args()&amp;#10;&amp;#10;hand_device = FuboPneumaticFingerClient({'port': args.com})&amp;#10;&amp;#10;# connect to trigger box&amp;#10;trigger = TriggerNeuracle()&amp;#10;" valType="extendedCode" updates="constant" name="Before Experiment"/>
+        <Param val="import argparse&amp;#10;import time&amp;#10;from device.fubo_pneumatic_finger import FuboPneumaticFingerClient&amp;#10;from device.trigger_box import TriggerNeuracle&amp;#10;from settings.config import settings&amp;#10;&amp;#10;&amp;#10;# get train params&amp;#10;&amp;#10;def parse_args():&amp;#10;&amp;#10;    parser = argparse.ArgumentParser(&amp;#10;&amp;#10;        description='Grasp training'&amp;#10;&amp;#10;    )&amp;#10;&amp;#10;    parser.add_argument(&amp;#10;&amp;#10;        '--n-trials',&amp;#10;&amp;#10;        dest='n_trials',&amp;#10;&amp;#10;        help='Trial number',&amp;#10;&amp;#10;        type=int,&amp;#10;&amp;#10;    )&amp;#10;&amp;#10;    parser.add_argument(&amp;#10;&amp;#10;        '--com',&amp;#10;&amp;#10;        dest='com',&amp;#10;&amp;#10;        help='Peripheral serial port',&amp;#10;&amp;#10;        type=str&amp;#10;&amp;#10;    )&amp;#10;&amp;#10;    parser.add_argument(&amp;#10;&amp;#10;        '--finger-model',&amp;#10;&amp;#10;        '-fm',&amp;#10;&amp;#10;        dest='finger_model',&amp;#10;&amp;#10;        help='Gesture to train',&amp;#10;&amp;#10;        type=str&amp;#10;&amp;#10;    )&amp;#10;&amp;#10;    return parser.parse_args()&amp;#10;&amp;#10;&amp;#10;&amp;#10;args = parse_args()&amp;#10;&amp;#10;hand_device = FuboPneumaticFingerClient({'port': args.com})&amp;#10;&amp;#10;# connect to trigger box&amp;#10;trigger = TriggerNeuracle()&amp;#10;" valType="extendedCode" updates="constant" name="Before Experiment"/>
         <Param val="" valType="extendedCode" updates="constant" name="Before JS Experiment"/>
         <Param val="" valType="extendedCode" updates="constant" name="Begin Experiment"/>
         <Param val="" valType="extendedCode" updates="constant" name="Begin JS Experiment"/>
@@ -253,6 +253,22 @@
         <Param val="False" valType="bool" updates="None" name="disabled"/>
         <Param val="code_3" valType="code" updates="None" name="name"/>
       </CodeComponent>
+      <SoundComponent name="hold_wav" plugin="None">
+        <Param val="False" valType="bool" updates="None" name="disabled"/>
+        <Param val="" valType="code" updates="None" name="durationEstim"/>
+        <Param val="True" valType="bool" updates="constant" name="hamming"/>
+        <Param val="hold_wav" valType="code" updates="None" name="name"/>
+        <Param val="True" valType="bool" updates="None" name="saveStartStop"/>
+        <Param val="static/audios/hold.wav" valType="str" updates="constant" name="sound"/>
+        <Param val="" valType="code" updates="None" name="startEstim"/>
+        <Param val="time (s)" valType="str" updates="None" name="startType"/>
+        <Param val="0.0" valType="code" updates="None" name="startVal"/>
+        <Param val="duration (s)" valType="str" updates="None" name="stopType"/>
+        <Param val="2" valType="code" updates="constant" name="stopVal"/>
+        <Param val="True" valType="bool" updates="constant" name="stopWithRoutine"/>
+        <Param val="True" valType="bool" updates="constant" name="syncScreenRefresh"/>
+        <Param val="1" valType="num" updates="constant" name="volume"/>
+      </SoundComponent>
     </Routine>
     <Routine name="rest">
       <RoutineSettingsComponent name="rest" plugin="None">
@@ -314,6 +330,38 @@
         <Param val="False" valType="bool" updates="None" name="disabled"/>
         <Param val="code_4" valType="code" updates="None" name="name"/>
       </CodeComponent>
+      <SoundComponent name="rest_wav1" plugin="None">
+        <Param val="False" valType="bool" updates="None" name="disabled"/>
+        <Param val="" valType="code" updates="None" name="durationEstim"/>
+        <Param val="True" valType="bool" updates="constant" name="hamming"/>
+        <Param val="rest_wav1" valType="code" updates="None" name="name"/>
+        <Param val="True" valType="bool" updates="None" name="saveStartStop"/>
+        <Param val="static/audios/ding.wav" valType="str" updates="constant" name="sound"/>
+        <Param val="" valType="code" updates="None" name="startEstim"/>
+        <Param val="time (s)" valType="str" updates="None" name="startType"/>
+        <Param val="0.0" valType="code" updates="None" name="startVal"/>
+        <Param val="duration (s)" valType="str" updates="None" name="stopType"/>
+        <Param val="1.0" valType="code" updates="constant" name="stopVal"/>
+        <Param val="True" valType="bool" updates="constant" name="stopWithRoutine"/>
+        <Param val="True" valType="bool" updates="constant" name="syncScreenRefresh"/>
+        <Param val="1" valType="num" updates="constant" name="volume"/>
+      </SoundComponent>
+      <SoundComponent name="rest_wav2" plugin="None">
+        <Param val="False" valType="bool" updates="None" name="disabled"/>
+        <Param val="" valType="code" updates="None" name="durationEstim"/>
+        <Param val="True" valType="bool" updates="constant" name="hamming"/>
+        <Param val="rest_wav2" valType="code" updates="None" name="name"/>
+        <Param val="True" valType="bool" updates="None" name="saveStartStop"/>
+        <Param val="static/audios/rest.wav" valType="str" updates="constant" name="sound"/>
+        <Param val="" valType="code" updates="None" name="startEstim"/>
+        <Param val="time (s)" valType="str" updates="None" name="startType"/>
+        <Param val="0.8" valType="code" updates="None" name="startVal"/>
+        <Param val="duration (s)" valType="str" updates="None" name="stopType"/>
+        <Param val="2" valType="code" updates="constant" name="stopVal"/>
+        <Param val="True" valType="bool" updates="constant" name="stopWithRoutine"/>
+        <Param val="True" valType="bool" updates="constant" name="syncScreenRefresh"/>
+        <Param val="1" valType="num" updates="constant" name="volume"/>
+      </SoundComponent>
     </Routine>
     <Routine name="end">
       <RoutineSettingsComponent name="end" plugin="None">
@@ -433,6 +481,22 @@
         <Param val="False" valType="bool" updates="None" name="disabled"/>
         <Param val="code" valType="code" updates="None" name="name"/>
       </CodeComponent>
+      <SoundComponent name="extend_wav" plugin="None">
+        <Param val="False" valType="bool" updates="None" name="disabled"/>
+        <Param val="" valType="code" updates="None" name="durationEstim"/>
+        <Param val="True" valType="bool" updates="constant" name="hamming"/>
+        <Param val="extend_wav" valType="code" updates="None" name="name"/>
+        <Param val="True" valType="bool" updates="None" name="saveStartStop"/>
+        <Param val="static/audios/extend.wav" valType="str" updates="constant" name="sound"/>
+        <Param val="" valType="code" updates="None" name="startEstim"/>
+        <Param val="time (s)" valType="str" updates="None" name="startType"/>
+        <Param val="1.8" valType="code" updates="None" name="startVal"/>
+        <Param val="duration (s)" valType="str" updates="None" name="stopType"/>
+        <Param val="2" valType="code" updates="constant" name="stopVal"/>
+        <Param val="True" valType="bool" updates="constant" name="stopWithRoutine"/>
+        <Param val="True" valType="bool" updates="constant" name="syncScreenRefresh"/>
+        <Param val="1" valType="num" updates="constant" name="volume"/>
+      </SoundComponent>
     </Routine>
     <Routine name="flex">
       <RoutineSettingsComponent name="flex" plugin="None">
@@ -494,6 +558,22 @@
         <Param val="False" valType="bool" updates="None" name="disabled"/>
         <Param val="code_2" valType="code" updates="None" name="name"/>
       </CodeComponent>
+      <SoundComponent name="flex_wav" plugin="None">
+        <Param val="False" valType="bool" updates="None" name="disabled"/>
+        <Param val="" valType="code" updates="None" name="durationEstim"/>
+        <Param val="True" valType="bool" updates="constant" name="hamming"/>
+        <Param val="flex_wav" valType="code" updates="None" name="name"/>
+        <Param val="True" valType="bool" updates="None" name="saveStartStop"/>
+        <Param val="static/audios/flex.wav" valType="str" updates="constant" name="sound"/>
+        <Param val="" valType="code" updates="None" name="startEstim"/>
+        <Param val="time (s)" valType="str" updates="None" name="startType"/>
+        <Param val="0.0" valType="code" updates="None" name="startVal"/>
+        <Param val="duration (s)" valType="str" updates="None" name="stopType"/>
+        <Param val="2" valType="code" updates="constant" name="stopVal"/>
+        <Param val="True" valType="bool" updates="constant" name="stopWithRoutine"/>
+        <Param val="True" valType="bool" updates="constant" name="syncScreenRefresh"/>
+        <Param val="1" valType="num" updates="constant" name="volume"/>
+      </SoundComponent>
     </Routine>
   </Routines>
   <Flow>

+ 192 - 6
backend/grasp_data_collection.py

@@ -2,7 +2,7 @@
 # -*- coding: utf-8 -*-
 """
 This experiment was created using PsychoPy3 Experiment Builder (v2023.2.3),
-    on Thu Dec 14 13:37:19 2023
+    on 十二月 14, 2023, at 15:41
 If you publish work using this script the most relevant publication is:
 
     Peirce J, Gray JR, Simpson S, MacAskill M, Höchenberger R, Sogo H, Kastman E, Lindeløv JK. (2019) 
@@ -34,6 +34,7 @@ import psychopy.iohub as io
 from psychopy.hardware import keyboard
 
 # Run 'Before Experiment' code from config
+import argparse
 import time
 from device.fubo_pneumatic_finger import FuboPneumaticFingerClient
 from device.trigger_box import TriggerNeuracle
@@ -176,7 +177,7 @@ def setupData(expInfo, dataDir=None):
     thisExp = data.ExperimentHandler(
         name=expName, version='',
         extraInfo=expInfo, runtimeInfo=None,
-        originPath='/Users/dingkunliu/Projects/MI-BCI-Proj/kraken/backend/grasp_data_collection.py',
+        originPath='C:\\Users\\asena\\Desktop\\kraken\\backend\\grasp_data_collection.py',
         savePickle=True, saveWideText=True,
         dataFileName=dataDir + os.sep + filename, sortColumns='time'
     )
@@ -414,6 +415,9 @@ def run(expInfo, thisExp, win, inputs, globalClock=None, thisSession=None):
     attention = sound.Sound('static/audios/ding.wav', secs=1.0, stereo=True, hamming=True,
         name='attention')
     attention.setVolume(1.0)
+    extend_wav = sound.Sound('static/audios/extend.wav', secs=2, stereo=True, hamming=True,
+        name='extend_wav')
+    extend_wav.setVolume(1.0)
     
     # --- Initialize components for Routine "flex" ---
     flex_img = visual.ImageStim(
@@ -424,6 +428,9 @@ def run(expInfo, thisExp, win, inputs, globalClock=None, thisSession=None):
         color=[1,1,1], colorSpace='rgb', opacity=None,
         flipHoriz=False, flipVert=False,
         texRes=128.0, interpolate=True, depth=0.0)
+    flex_wav = sound.Sound('static/audios/flex.wav', secs=2, stereo=True, hamming=True,
+        name='flex_wav')
+    flex_wav.setVolume(1.0)
     
     # --- Initialize components for Routine "hold" ---
     hold_img = visual.ImageStim(
@@ -434,6 +441,9 @@ def run(expInfo, thisExp, win, inputs, globalClock=None, thisSession=None):
         color=[1,1,1], colorSpace='rgb', opacity=None,
         flipHoriz=False, flipVert=False,
         texRes=128.0, interpolate=True, depth=0.0)
+    hold_wav = sound.Sound('static/audios/hold.wav', secs=2, stereo=True, hamming=True,
+        name='hold_wav')
+    hold_wav.setVolume(1.0)
     
     # --- Initialize components for Routine "rest" ---
     rest_img = visual.ImageStim(
@@ -444,6 +454,12 @@ def run(expInfo, thisExp, win, inputs, globalClock=None, thisSession=None):
         color=[1,1,1], colorSpace='rgb', opacity=None,
         flipHoriz=False, flipVert=False,
         texRes=128.0, interpolate=True, depth=0.0)
+    rest_wav1 = sound.Sound('static/audios/ding.wav', secs=1.0, stereo=True, hamming=True,
+        name='rest_wav1')
+    rest_wav1.setVolume(1.0)
+    rest_wav2 = sound.Sound('static/audios/rest.wav', secs=2, stereo=True, hamming=True,
+        name='rest_wav2')
+    rest_wav2.setVolume(1.0)
     
     # --- Initialize components for Routine "end" ---
     end_text = visual.TextStim(win=win, name='end_text',
@@ -716,8 +732,11 @@ def run(expInfo, thisExp, win, inputs, globalClock=None, thisSession=None):
         # Run 'Begin Routine' code from code
         i = 0
         
+        extend_wav.setSound('static/audios/extend.wav', secs=2, hamming=True)
+        extend_wav.setVolume(1.0, log=False)
+        extend_wav.seek(0)
         # keep track of which components have finished
-        extendComponents = [extend_img, attention]
+        extendComponents = [extend_img, attention, extend_wav]
         for thisComponent in extendComponents:
             thisComponent.tStart = None
             thisComponent.tStop = None
@@ -813,6 +832,36 @@ def run(expInfo, thisExp, win, inputs, globalClock=None, thisSession=None):
             i += 1    
             # 每轮开始前空白等待1s + 反应时1s + 新版extend时间4.5s + 1s裕量 = 7.5s
             
+            # if extend_wav is starting this frame...
+            if extend_wav.status == NOT_STARTED and tThisFlip >= 1.8-frameTolerance:
+                # keep track of start time/frame for later
+                extend_wav.frameNStart = frameN  # exact frame index
+                extend_wav.tStart = t  # local t and not account for scr refresh
+                extend_wav.tStartRefresh = tThisFlipGlobal  # on global time
+                # add timestamp to datafile
+                thisExp.addData('extend_wav.started', tThisFlipGlobal)
+                # update status
+                extend_wav.status = STARTED
+                extend_wav.play(when=win)  # sync with win flip
+            
+            # if extend_wav is stopping this frame...
+            if extend_wav.status == STARTED:
+                # is it time to stop? (based on global clock, using actual start)
+                if tThisFlipGlobal > extend_wav.tStartRefresh + 2-frameTolerance:
+                    # keep track of stop time/frame for later
+                    extend_wav.tStop = t  # not accounting for scr refresh
+                    extend_wav.frameNStop = frameN  # exact frame index
+                    # add timestamp to datafile
+                    thisExp.timestampOnFlip(win, 'extend_wav.stopped')
+                    # update status
+                    extend_wav.status = FINISHED
+                    extend_wav.stop()
+            # update extend_wav status according to whether it's playing
+            if extend_wav.isPlaying:
+                extend_wav.status = STARTED
+            elif extend_wav.isFinished:
+                extend_wav.status = FINISHED
+            
             # check for quit (typically the Esc key)
             if defaultKeyboard.getKeys(keyList=["escape"]):
                 thisExp.status = FINISHED
@@ -840,6 +889,7 @@ def run(expInfo, thisExp, win, inputs, globalClock=None, thisSession=None):
                 thisComponent.setAutoDraw(False)
         thisExp.addData('extend.stopped', globalClock.getTime())
         attention.pause()  # ensure sound has stopped at end of Routine
+        extend_wav.pause()  # ensure sound has stopped at end of Routine
         # using non-slip timing so subtract the expected duration of this Routine (unless ended on request)
         if routineForceEnded:
             routineTimer.reset()
@@ -853,8 +903,11 @@ def run(expInfo, thisExp, win, inputs, globalClock=None, thisSession=None):
         # Run 'Begin Routine' code from code_2
         i = 0
         
+        flex_wav.setSound('static/audios/flex.wav', secs=2, hamming=True)
+        flex_wav.setVolume(1.0, log=False)
+        flex_wav.seek(0)
         # keep track of which components have finished
-        flexComponents = [flex_img]
+        flexComponents = [flex_img, flex_wav]
         for thisComponent in flexComponents:
             thisComponent.tStart = None
             thisComponent.tStop = None
@@ -920,6 +973,36 @@ def run(expInfo, thisExp, win, inputs, globalClock=None, thisSession=None):
             
             # 反应时1s+新版气动手flex时间4.5s + 1s裕量 = 6.5s
             
+            # if flex_wav is starting this frame...
+            if flex_wav.status == NOT_STARTED and tThisFlip >= 0.0-frameTolerance:
+                # keep track of start time/frame for later
+                flex_wav.frameNStart = frameN  # exact frame index
+                flex_wav.tStart = t  # local t and not account for scr refresh
+                flex_wav.tStartRefresh = tThisFlipGlobal  # on global time
+                # add timestamp to datafile
+                thisExp.addData('flex_wav.started', tThisFlipGlobal)
+                # update status
+                flex_wav.status = STARTED
+                flex_wav.play(when=win)  # sync with win flip
+            
+            # if flex_wav is stopping this frame...
+            if flex_wav.status == STARTED:
+                # is it time to stop? (based on global clock, using actual start)
+                if tThisFlipGlobal > flex_wav.tStartRefresh + 2-frameTolerance:
+                    # keep track of stop time/frame for later
+                    flex_wav.tStop = t  # not accounting for scr refresh
+                    flex_wav.frameNStop = frameN  # exact frame index
+                    # add timestamp to datafile
+                    thisExp.timestampOnFlip(win, 'flex_wav.stopped')
+                    # update status
+                    flex_wav.status = FINISHED
+                    flex_wav.stop()
+            # update flex_wav status according to whether it's playing
+            if flex_wav.isPlaying:
+                flex_wav.status = STARTED
+            elif flex_wav.isFinished:
+                flex_wav.status = FINISHED
+            
             # check for quit (typically the Esc key)
             if defaultKeyboard.getKeys(keyList=["escape"]):
                 thisExp.status = FINISHED
@@ -946,6 +1029,7 @@ def run(expInfo, thisExp, win, inputs, globalClock=None, thisSession=None):
             if hasattr(thisComponent, "setAutoDraw"):
                 thisComponent.setAutoDraw(False)
         thisExp.addData('flex.stopped', globalClock.getTime())
+        flex_wav.pause()  # ensure sound has stopped at end of Routine
         # using non-slip timing so subtract the expected duration of this Routine (unless ended on request)
         if routineForceEnded:
             routineTimer.reset()
@@ -958,8 +1042,11 @@ def run(expInfo, thisExp, win, inputs, globalClock=None, thisSession=None):
         thisExp.addData('hold.started', globalClock.getTime())
         # Run 'Begin Routine' code from code_3
         win.callOnFlip(trigger.send_trigger, settings.FINGERMODEL_IDS['hold'])
+        hold_wav.setSound('static/audios/hold.wav', secs=2, hamming=True)
+        hold_wav.setVolume(1.0, log=False)
+        hold_wav.seek(0)
         # keep track of which components have finished
-        holdComponents = [hold_img]
+        holdComponents = [hold_img, hold_wav]
         for thisComponent in holdComponents:
             thisComponent.tStart = None
             thisComponent.tStop = None
@@ -1015,6 +1102,36 @@ def run(expInfo, thisExp, win, inputs, globalClock=None, thisSession=None):
                     hold_img.status = FINISHED
                     hold_img.setAutoDraw(False)
             
+            # if hold_wav is starting this frame...
+            if hold_wav.status == NOT_STARTED and tThisFlip >= 0.0-frameTolerance:
+                # keep track of start time/frame for later
+                hold_wav.frameNStart = frameN  # exact frame index
+                hold_wav.tStart = t  # local t and not account for scr refresh
+                hold_wav.tStartRefresh = tThisFlipGlobal  # on global time
+                # add timestamp to datafile
+                thisExp.addData('hold_wav.started', tThisFlipGlobal)
+                # update status
+                hold_wav.status = STARTED
+                hold_wav.play(when=win)  # sync with win flip
+            
+            # if hold_wav is stopping this frame...
+            if hold_wav.status == STARTED:
+                # is it time to stop? (based on global clock, using actual start)
+                if tThisFlipGlobal > hold_wav.tStartRefresh + 2-frameTolerance:
+                    # keep track of stop time/frame for later
+                    hold_wav.tStop = t  # not accounting for scr refresh
+                    hold_wav.frameNStop = frameN  # exact frame index
+                    # add timestamp to datafile
+                    thisExp.timestampOnFlip(win, 'hold_wav.stopped')
+                    # update status
+                    hold_wav.status = FINISHED
+                    hold_wav.stop()
+            # update hold_wav status according to whether it's playing
+            if hold_wav.isPlaying:
+                hold_wav.status = STARTED
+            elif hold_wav.isFinished:
+                hold_wav.status = FINISHED
+            
             # check for quit (typically the Esc key)
             if defaultKeyboard.getKeys(keyList=["escape"]):
                 thisExp.status = FINISHED
@@ -1041,6 +1158,7 @@ def run(expInfo, thisExp, win, inputs, globalClock=None, thisSession=None):
             if hasattr(thisComponent, "setAutoDraw"):
                 thisComponent.setAutoDraw(False)
         thisExp.addData('hold.stopped', globalClock.getTime())
+        hold_wav.pause()  # ensure sound has stopped at end of Routine
         # using non-slip timing so subtract the expected duration of this Routine (unless ended on request)
         if routineForceEnded:
             routineTimer.reset()
@@ -1053,8 +1171,14 @@ def run(expInfo, thisExp, win, inputs, globalClock=None, thisSession=None):
         thisExp.addData('rest.started', globalClock.getTime())
         # Run 'Begin Routine' code from code_4
         i = 0
+        rest_wav1.setSound('static/audios/ding.wav', secs=1.0, hamming=True)
+        rest_wav1.setVolume(1.0, log=False)
+        rest_wav1.seek(0)
+        rest_wav2.setSound('static/audios/rest.wav', secs=2, hamming=True)
+        rest_wav2.setVolume(1.0, log=False)
+        rest_wav2.seek(0)
         # keep track of which components have finished
-        restComponents = [rest_img]
+        restComponents = [rest_img, rest_wav1, rest_wav2]
         for thisComponent in restComponents:
             thisComponent.tStart = None
             thisComponent.tStop = None
@@ -1117,6 +1241,66 @@ def run(expInfo, thisExp, win, inputs, globalClock=None, thisSession=None):
             
             i += 1
             
+            # if rest_wav1 is starting this frame...
+            if rest_wav1.status == NOT_STARTED and tThisFlip >= 0.0-frameTolerance:
+                # keep track of start time/frame for later
+                rest_wav1.frameNStart = frameN  # exact frame index
+                rest_wav1.tStart = t  # local t and not account for scr refresh
+                rest_wav1.tStartRefresh = tThisFlipGlobal  # on global time
+                # add timestamp to datafile
+                thisExp.addData('rest_wav1.started', tThisFlipGlobal)
+                # update status
+                rest_wav1.status = STARTED
+                rest_wav1.play(when=win)  # sync with win flip
+            
+            # if rest_wav1 is stopping this frame...
+            if rest_wav1.status == STARTED:
+                # is it time to stop? (based on global clock, using actual start)
+                if tThisFlipGlobal > rest_wav1.tStartRefresh + 1.0-frameTolerance:
+                    # keep track of stop time/frame for later
+                    rest_wav1.tStop = t  # not accounting for scr refresh
+                    rest_wav1.frameNStop = frameN  # exact frame index
+                    # add timestamp to datafile
+                    thisExp.timestampOnFlip(win, 'rest_wav1.stopped')
+                    # update status
+                    rest_wav1.status = FINISHED
+                    rest_wav1.stop()
+            # update rest_wav1 status according to whether it's playing
+            if rest_wav1.isPlaying:
+                rest_wav1.status = STARTED
+            elif rest_wav1.isFinished:
+                rest_wav1.status = FINISHED
+            
+            # if rest_wav2 is starting this frame...
+            if rest_wav2.status == NOT_STARTED and tThisFlip >= 0.8-frameTolerance:
+                # keep track of start time/frame for later
+                rest_wav2.frameNStart = frameN  # exact frame index
+                rest_wav2.tStart = t  # local t and not account for scr refresh
+                rest_wav2.tStartRefresh = tThisFlipGlobal  # on global time
+                # add timestamp to datafile
+                thisExp.addData('rest_wav2.started', tThisFlipGlobal)
+                # update status
+                rest_wav2.status = STARTED
+                rest_wav2.play(when=win)  # sync with win flip
+            
+            # if rest_wav2 is stopping this frame...
+            if rest_wav2.status == STARTED:
+                # is it time to stop? (based on global clock, using actual start)
+                if tThisFlipGlobal > rest_wav2.tStartRefresh + 2-frameTolerance:
+                    # keep track of stop time/frame for later
+                    rest_wav2.tStop = t  # not accounting for scr refresh
+                    rest_wav2.frameNStop = frameN  # exact frame index
+                    # add timestamp to datafile
+                    thisExp.timestampOnFlip(win, 'rest_wav2.stopped')
+                    # update status
+                    rest_wav2.status = FINISHED
+                    rest_wav2.stop()
+            # update rest_wav2 status according to whether it's playing
+            if rest_wav2.isPlaying:
+                rest_wav2.status = STARTED
+            elif rest_wav2.isFinished:
+                rest_wav2.status = FINISHED
+            
             # check for quit (typically the Esc key)
             if defaultKeyboard.getKeys(keyList=["escape"]):
                 thisExp.status = FINISHED
@@ -1143,6 +1327,8 @@ def run(expInfo, thisExp, win, inputs, globalClock=None, thisSession=None):
             if hasattr(thisComponent, "setAutoDraw"):
                 thisComponent.setAutoDraw(False)
         thisExp.addData('rest.stopped', globalClock.getTime())
+        rest_wav1.pause()  # ensure sound has stopped at end of Routine
+        rest_wav2.pause()  # ensure sound has stopped at end of Routine
         # using non-slip timing so subtract the expected duration of this Routine (unless ended on request)
         if routineForceEnded:
             routineTimer.reset()

BIN
backend/static/audios/extend.wav


BIN
backend/static/audios/flex.wav


BIN
backend/static/audios/hold.wav


BIN
backend/static/audios/rest.wav