Explorar o código

moved backgound capture to the main script

dianamaro hai 1 ano
pai
achega
35207bc658
Modificáronse 6 ficheiros con 188 adicións e 208 borrados
  1. 64 28
      SIT.ipynb
  2. 0 138
      background.ipynb
  3. 7 1
      controllers/position.ipynb
  4. 79 20
      controllers/serial.ipynb
  5. 31 15
      controllers/sound.ipynb
  6. 7 6
      controllers/sound.py

+ 64 - 28
SIT.ipynb

@@ -2,7 +2,7 @@
  "cells": [
   {
    "cell_type": "code",
-   "execution_count": 136,
+   "execution_count": 31,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -50,16 +50,16 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 137,
+   "execution_count": 32,
    "metadata": {},
    "outputs": [],
    "source": [
-    "cfg_filename = os.path.join('profiles', 'andrey_hippoSIT_008228_continuous.json')"
+    "cfg_filename = os.path.join('profiles', 'andrey_hippoSIT_008229_multiple.json')"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 138,
+   "execution_count": 33,
    "metadata": {
     "scrolled": false
    },
@@ -75,7 +75,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 139,
+   "execution_count": 34,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -97,7 +97,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 140,
+   "execution_count": 35,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -137,7 +137,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 141,
+   "execution_count": 36,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -155,7 +155,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 142,
+   "execution_count": 37,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -194,7 +194,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 143,
+   "execution_count": 38,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -224,7 +224,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 144,
+   "execution_count": 39,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -234,7 +234,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 145,
+   "execution_count": 40,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -245,7 +245,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 146,
+   "execution_count": 41,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -260,7 +260,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 147,
+   "execution_count": 42,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -286,17 +286,18 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 43,
    "metadata": {
-    "scrolled": false
+    "scrolled": true
    },
    "outputs": [
     {
      "name": "stdout",
      "output_type": "stream",
      "text": [
-      "Continuous sound stream started at 48000 Hz\n",
-      "Webcam stream 1024.0:768.0 at 25.00 FPS started\n",
+      "Webcam stream 1024.0:768.0 at 30.00 FPS started\n",
+      "Position tracker - background reloaded\n",
+      "Position tracker - background reloaded\n",
       "Position tracker stopped\n",
       "Video writer stopped\n",
       "Camera released\n"
@@ -304,8 +305,10 @@
     }
    ],
    "source": [
-    "# actual sound selector: 0 - silence, 1 - foraging, 2 - target, 3 - distractor\n",
+    "# actual sound selector: -1 - noise, 0 - silence, 1 - foraging, 2 - target, 3 - distractor\n",
     "sound = mp.Value('i', 1)\n",
+    "if 'noise_when_idle' in cfg_exp and cfg_exp['noise_when_idle']:\n",
+    "    sound.value = -1\n",
     "\n",
     "# experiment status: 1 - idle, 2 - running (recording, logging), 0 - stopped\n",
     "status = mp.Value('i', 1)\n",
@@ -401,7 +404,7 @@
     "        #frame = cv2.absdiff(frame, pt.background)\n",
     "        #frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)\n",
     "        frame = cv2.bitwise_and(src1=frame, src2=pt.mask)\n",
-    "        #frame_copy = frame.copy()\n",
+    "        frame_copy = frame.copy()\n",
     "\n",
     "        # draw position center and contours\n",
     "        if pt.x_in_px is not None:\n",
@@ -581,13 +584,24 @@
     "        \n",
     "        k = cv2.waitKey(33)\n",
     "        \n",
+    "        # light on/off\n",
     "        if k == ord('l'):\n",
     "            switch_light(pt, board)\n",
     "        \n",
+    "        # motors\n",
     "        if k == ord('d'):\n",
     "            if cfg['experiment']['enable_motors']:\n",
     "                motor_board.switch_diodes()\n",
     "            \n",
+    "        if k == ord('t'):\n",
+    "            tm = threading.Timer(20, motor_board.rotate, args=(False, 90, 30))\n",
+    "            tm.start()\n",
+    "            #motor_board.rotate(False, 90, 30)\n",
+    "        if k == ord('r'):\n",
+    "            tm = threading.Timer(20, motor_board.rotate, args=(True, 90, 30))\n",
+    "            tm.start()\n",
+    "        \n",
+    "        # ephys cable on top\n",
     "        if k == ord('i') and 'cable_motor_port' in cfg['experiment']:\n",
     "            tf = threading.Timer(0, cable_board.turn_CCW, args=[])\n",
     "            tf.start()\n",
@@ -595,20 +609,29 @@
     "            tf = threading.Timer(0, cable_board.turn_CW, args=[])\n",
     "            tf.start()\n",
     "            \n",
+    "        # feeding\n",
     "        if k == ord('f'):\n",
     "            tf = threading.Timer(0, board.feed, args=[])\n",
     "            tf.start()\n",
     "\n",
     "        if k == ord('c'):\n",
     "            f_name = cfg_pos['background_light'] if pt.is_light else cfg_pos['background_dark']\n",
-    "            cv2.imwrite(os.path.join('assets', f_name), frame_copy)\n",
+    "            cv2.imwrite(f_name, frame_copy)\n",
+    "            tf = threading.Timer(0.2, pt.reload_background, args=[])\n",
+    "            tf.start()            \n",
     "\n",
+    "        # quit the session\n",
     "        if k == ord('q'):\n",
     "            break\n",
     "\n",
+    "        # start the experiment\n",
     "        if k == ord('s'):\n",
     "            board.start_or_stop()  # start/stop data acquisition\n",
     "            c_time = time.time()   # more accurate time\n",
+    "            \n",
+    "            if cfg['experiment']['enable_motors']:\n",
+    "                if not motor_board.diodes_on:\n",
+    "                    motor_board.switch_diodes()\n",
     "\n",
     "            if status.value == 1: # start the session\n",
     "                if t_start is None:\n",
@@ -639,12 +662,12 @@
     "                    timers.append(threading.Timer(event_t, switch_light, args=(pt, board)))\n",
     "                    \n",
     "                if cfg['experiment']['enable_motors']:\n",
-    "                    motor_board.switch_diodes()\n",
-    "                    if cfg['experiment']['phi_max'] > 0:\n",
+    "                    if not cfg['experiment']['phi_max'] == 0:\n",
+    "                        direction = False if cfg['experiment']['phi_max'] > 0 else True\n",
     "                        t0, t1 = cfg['experiment']['timepoints'][0], cfg['experiment']['timepoints'][1]\n",
-    "                        timers.append(threading.Timer(t0, motor_board.rotate, args=(False, cfg['experiment']['phi_max'], t1-t0)))\n",
+    "                        timers.append(threading.Timer(t0, motor_board.rotate, args=(direction, abs(cfg['experiment']['phi_max']), t1-t0)))\n",
     "                        t0, t1 = cfg['experiment']['timepoints'][2], cfg['experiment']['timepoints'][3]\n",
-    "                        timers.append(threading.Timer(t0, motor_board.rotate, args=(True, cfg['experiment']['phi_max'], t1-t0)))\n",
+    "                        timers.append(threading.Timer(t0, motor_board.rotate, args=(not direction, abs(cfg['experiment']['phi_max']), t1-t0)))\n",
     "                    \n",
     "                for t in timers:\n",
     "                    t.start()\n",
@@ -657,6 +680,8 @@
     "                    x, y, r = 0, 0, 0\n",
     "                log_event(c_time, x, y, r, trial, -1)  # log experiment break\n",
     "                \n",
+    "                if 'noise_when_idle' in cfg_exp and cfg_exp['noise_when_idle']:\n",
+    "                    sound.value = -1\n",
     "                status.value = 1\n",
     "                phase = 0\n",
     "                islands = []\n",
@@ -664,7 +689,8 @@
     "                    t.cancel()\n",
     "                    \n",
     "        if k == ord('a'):\n",
-    "            sound.value = 0 if sound.value == 1 else 1\n",
+    "            sound.value = -1 if sound.value >= 0 else 0\n",
+    "            switch_light(pt, board)  # turn lights off \n",
     "\n",
     "finally:\n",
     "    if status.value == 2:  # stop data acquisition, in case exited via timeout\n",
@@ -712,7 +738,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 44,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -723,9 +749,19 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 45,
    "metadata": {},
-   "outputs": [],
+   "outputs": [
+    {
+     "ename": "SystemExit",
+     "evalue": "Nothing recorded. No sense to continue.",
+     "output_type": "error",
+     "traceback": [
+      "An exception has occurred, use %tb to see the full traceback.\n",
+      "\u001b[1;31mSystemExit\u001b[0m\u001b[1;31m:\u001b[0m Nothing recorded. No sense to continue.\n"
+     ]
+    }
+   ],
    "source": [
     "if not trial > 0:\n",
     "    raise SystemExit('Nothing recorded. No sense to continue.')\n",

+ 0 - 138
background.ipynb

@@ -1,138 +0,0 @@
-{
- "cells": [
-  {
-   "cell_type": "code",
-   "execution_count": 22,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "import cv2\n",
-    "import os, json\n",
-    "import numpy as np\n",
-    "import time\n",
-    "\n",
-    "import nbimporter\n",
-    "from controllers.situtils import FPSTimes\n",
-    "from controllers.serial import MCSArduino"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "## Capture a background image"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 23,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "is_light = True\n",
-    "#settings_filename = os.path.join('profiles', 'kate_postrack.json')\n",
-    "#settings_filename = os.path.join('profiles', 'kate_aSIT_single.json')\n",
-    "settings_filename = os.path.join('profiles', 'andrey_hippoSIT_008228_SL_train.json')\n",
-    "\n",
-    "with open(settings_filename) as json_file:\n",
-    "    cfg = json.load(json_file)"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 24,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "board = MCSArduino(cfg['experiment']['MCSArduinoPort'])\n",
-    "\n",
-    "# Define BGR colors\n",
-    "BGR_COLOR = {\n",
-    "    'red': (0,0,255),\n",
-    "    'green': (127,255,0),\n",
-    "    'blue': (255,127,0),\n",
-    "    'yellow': (0,127,255),\n",
-    "    'black': (0,0,0),\n",
-    "    'white': (255,255,255)\n",
-    "}\n",
-    "\n",
-    "cfg_exp = cfg['experiment']\n",
-    "cfg_cam = cfg['camera']\n",
-    "cfg_pos = cfg['position']\n",
-    "\n",
-    "cap = cv2.VideoCapture(cfg_cam['source'], cfg_cam['api']) if cfg_cam['api'] else cv2.VideoCapture(cfg_cam['source'])\n",
-    "cap.set(cv2.CAP_PROP_FPS, cfg_cam['fps'])\n",
-    "time.sleep(2)  # this helps to keep the FPS stable\n",
-    "cap.set(cv2.CAP_PROP_FRAME_WIDTH, cfg_cam['frame_width'])\n",
-    "cap.set(cv2.CAP_PROP_FRAME_HEIGHT, cfg_cam['frame_height'])\n",
-    "\n",
-    "cap.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter_fourcc('M', 'J', 'P', 'G'))    \n",
-    "\n",
-    "fps = FPSTimes()\n",
-    "\n",
-    "while(True):\n",
-    "    ret, frame = cap.read()\n",
-    "    fps.count()\n",
-    "\n",
-    "    # Draw the arena area\n",
-    "    cv2.circle(frame, (cfg_pos['arena_x'], cfg_pos['arena_y']), cfg_pos['arena_radius'], BGR_COLOR['red'], 2)\n",
-    "\n",
-    "    # Mask the space outside the arena\n",
-    "    mask = np.zeros(shape=frame.shape, dtype=\"uint8\")\n",
-    "    cv2.circle(mask, (cfg_pos['arena_x'], cfg_pos['arena_y']), cfg_pos['arena_radius'], BGR_COLOR['white'], -1)\n",
-    "    \n",
-    "    frame = cv2.bitwise_and(src1=frame, src2=mask)\n",
-    "    \n",
-    "    k = cv2.waitKey(33)\n",
-    "    if k == ord('c'):\n",
-    "        f_name = cfg_pos['background_light'] if is_light else cfg_pos['background_dark']\n",
-    "        cv2.imwrite(os.path.join('assets', f_name), frame)\n",
-    "    if k == ord('l'):\n",
-    "        board.switch_light()\n",
-    "        is_light = not is_light\n",
-    "    if k == ord('q'):  # full quit\n",
-    "        break\n",
-    "        \n",
-    "    cv2.putText(frame, 'LIGHT' if is_light else 'DARK', (10, 20), cv2.FONT_HERSHEY_DUPLEX, .5, BGR_COLOR['white'])\n",
-    "    cv2.putText(frame, '%.2f FPS' % fps.get_avg_fps(), (10, 40), cv2.FONT_HERSHEY_DUPLEX, .5, BGR_COLOR['white'])    \n",
-    "    cv2.imshow('Press \"c\" to capture, \"q\" to quit', frame)\n",
-    "\n",
-    "# When the background image is captured, release the capture\n",
-    "if board.is_light_off:\n",
-    "    board.switch_light()  # turn light back on\n",
-    "    time.sleep(0.1)\n",
-    "board.exit()\n",
-    "cap.release()\n",
-    "cv2.destroyAllWindows()"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": []
-  }
- ],
- "metadata": {
-  "kernelspec": {
-   "display_name": "Python 3",
-   "language": "python",
-   "name": "python3"
-  },
-  "language_info": {
-   "codemirror_mode": {
-    "name": "ipython",
-    "version": 3
-   },
-   "file_extension": ".py",
-   "mimetype": "text/x-python",
-   "name": "python",
-   "nbconvert_exporter": "python",
-   "pygments_lexer": "ipython3",
-   "version": "3.8.8"
-  }
- },
- "nbformat": 4,
- "nbformat_minor": 4
-}

+ 7 - 1
controllers/position.ipynb

@@ -66,7 +66,13 @@
     "            f.write(\"time,x,y\\n\")\n",
     "        with open(cfg['contour_path'], 'w') as f:\n",
     "            f.write(\"x:y,...\\n\")\n",
-    "            \n",
+    "\n",
+    "    def reload_background(self):\n",
+    "        self.bg_light = cv2.imread(self.cfg['background_light'], 1)\n",
+    "        self.bg_dark  = cv2.imread(self.cfg['background_dark'], 1)\n",
+    "        self.background = self.bg_light if self.is_light else self.bg_dark\n",
+    "        print('Position tracker - background reloaded')\n",
+    "        \n",
     "    def px_to_meters(self, x, y):\n",
     "        x_m = float(self.cfg['arena_x'] - x) * self.pixel_size * (-1 if self.cfg['flip_x'] else 1)\n",
     "        y_m = float(self.cfg['arena_y'] - y) * self.pixel_size * (-1 if self.cfg['flip_y'] else 1)\n",

+ 79 - 20
controllers/serial.ipynb

@@ -2,7 +2,7 @@
  "cells": [
   {
    "cell_type": "code",
-   "execution_count": 5,
+   "execution_count": 1,
    "id": "82162890",
    "metadata": {},
    "outputs": [],
@@ -14,7 +14,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 12,
+   "execution_count": 2,
    "id": "2fc2905a",
    "metadata": {},
    "outputs": [],
@@ -48,7 +48,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 9,
+   "execution_count": 3,
    "id": "fe78b7d4",
    "metadata": {},
    "outputs": [],
@@ -101,7 +101,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 3,
+   "execution_count": 4,
    "id": "99209a2c",
    "metadata": {},
    "outputs": [],
@@ -130,7 +130,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 4,
+   "execution_count": 5,
    "id": "4b6156b5",
    "metadata": {},
    "outputs": [],
@@ -414,7 +414,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 3,
+   "execution_count": 2,
    "id": "7aac6801",
    "metadata": {},
    "outputs": [],
@@ -475,7 +475,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 2,
+   "execution_count": 9,
    "id": "f069063a",
    "metadata": {},
    "outputs": [],
@@ -507,15 +507,19 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 34,
+   "execution_count": 1,
    "id": "6cb83682",
    "metadata": {},
    "outputs": [
     {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "q pressed, ending loop\n"
+     "ename": "NameError",
+     "evalue": "name 'SpeakerMotor' is not defined",
+     "output_type": "error",
+     "traceback": [
+      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
+      "\u001b[1;31mNameError\u001b[0m                                 Traceback (most recent call last)",
+      "\u001b[1;32m<ipython-input-1-c34f87c6d5ba>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[0;32m      4\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      5\u001b[0m \u001b[1;31m# r - rotate right, t - rotate left, q - quit\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 6\u001b[1;33m \u001b[0msm\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mSpeakerMotor\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'COM12'\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m      7\u001b[0m \u001b[0mout1\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;34m''\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      8\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n",
+      "\u001b[1;31mNameError\u001b[0m: name 'SpeakerMotor' is not defined"
      ]
     }
    ],
@@ -567,28 +571,83 @@
    ]
   },
   {
-   "cell_type": "raw",
-   "id": "ddbae54e",
+   "cell_type": "markdown",
+   "id": "fdb584fe",
    "metadata": {},
-   "source": []
+   "source": [
+    "## Rotate speakers manually"
+   ]
   },
   {
    "cell_type": "code",
-   "execution_count": 40,
-   "id": "b1de2fb2",
+   "execution_count": 3,
+   "id": "97e091e6",
    "metadata": {},
    "outputs": [],
    "source": [
-    "board.exit()"
+    "import keyboard\n",
+    "import serial\n",
+    "import time\n",
+    "import threading\n",
+    "\n",
+    "degrees = 90\n",
+    "duration = 30\n",
+    "\n",
+    "# 1st - CW\n",
+    "direction = False\n",
+    "\n",
+    "# 2nd - CCW\n",
+    "#direction = True"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 4,
+   "id": "e2e5b88d",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "sm = SpeakerMotor('COM12')"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 9,
+   "id": "affd93ca",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "sm.switch_diodes()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 24,
+   "id": "822ff96a",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "sending +17100:570\n",
+      "\n"
+     ]
+    }
+   ],
+   "source": [
+    "sm.rotate(direction, degrees, duration)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 5,
    "id": "8263dee5",
    "metadata": {},
    "outputs": [],
-   "source": []
+   "source": [
+    "sm.exit()"
+   ]
   },
   {
    "cell_type": "code",

+ 31 - 15
controllers/sound.ipynb

@@ -2,7 +2,7 @@
  "cells": [
   {
    "cell_type": "code",
-   "execution_count": 34,
+   "execution_count": 3,
    "metadata": {},
    "outputs": [
     {
@@ -31,9 +31,9 @@
     "        \"device\": [1, 26],\n",
     "        \"n_channels\": 10,\n",
     "        \"sounds\": {\n",
-    "            \"noise\": {\"amp\": 0.5, \"channels\": [6, 8]},\n",
-    "            \"background\": {\"freq\": 660, \"amp\": 0.1, \"duration\": 0.05, \"harmonics\": True, \"channels\": [1, 8]},\n",
-    "            \"target\": {\"freq\": 660, \"amp\": 0.1, \"duration\": 0.05, \"harmonics\": True, \"channels\": [3, 8]}, \n",
+    "            \"noise\": {\"amp\": 0.2, \"channels\": [6, 8]},\n",
+    "            \"background\": {\"freq\": 660, \"amp\": 0.1, \"duration\": 0.05, \"harmonics\": True, \"channels\": [3, 8]},\n",
+    "            \"target\": {\"freq\": 1320, \"amp\": 0.1, \"duration\": 0.05, \"harmonics\": True, \"channels\": [3, 8]}, \n",
     "            \"distractor1\": {\"freq\": 860, \"amp\": 0.15, \"duration\": 0.05, \"harmonics\": True, \"channels\": [6, 8], \"enabled\": False},\n",
     "            \"distractor2\": {\"freq\": 1060, \"amp\": 0.25, \"duration\": 0.05, \"harmonics\": True, \"channels\": [6, 8], \"enabled\": False},\n",
     "            \"distractor3\": {\"freq\": 1320, \"amp\": 0.2, \"duration\": 0.05, \"harmonics\": True, \"channels\": [6, 8], \"enabled\": False}\n",
@@ -140,7 +140,7 @@
     "            f.write(\"time,id\\n\")\n",
     "\n",
     "        while status.value > 0:\n",
-    "            if status.value == 2:  # running state\n",
+    "            if status.value == 2 or (status.value == 1 and selector.value == -1):  # running state or masking noise\n",
     "                t0 = time.time()\n",
     "                if t0 < next_beat:\n",
     "                    #time.sleep(0.0001)  # not to spin the wheels too much\n",
@@ -151,8 +151,9 @@
     "                roving = 10**((np.random.rand() * cfg['roving'] - cfg['roving']/2.0)/20.)\n",
     "                roving = roving if int(selector.value) > -1 else 1  # no roving for noise\n",
     "                stream.write(sounds[commutator[int(selector.value)]] * roving)\n",
-    "                with open(cfg['file_path'], 'a') as f:\n",
-    "                    f.write(\",\".join([str(x) for x in (t0, selector.value)]) + \"\\n\")\n",
+    "                if status.value == 2:\n",
+    "                    with open(cfg['file_path'], 'a') as f:\n",
+    "                        f.write(\",\".join([str(x) for x in (t0, selector.value)]) + \"\\n\")\n",
     "\n",
     "                next_beat += cfg['latency']\n",
     "                \n",
@@ -395,9 +396,24 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 2,
+   "execution_count": 1,
    "metadata": {},
-   "outputs": [],
+   "outputs": [
+    {
+     "ename": "KeyboardInterrupt",
+     "evalue": "",
+     "output_type": "error",
+     "traceback": [
+      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
+      "\u001b[1;31mKeyboardInterrupt\u001b[0m                         Traceback (most recent call last)",
+      "\u001b[1;32m<ipython-input-1-c2b7fcf1451e>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[0;32m     12\u001b[0m \u001b[0mcfg\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mSoundController\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mdefault_cfg\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     13\u001b[0m \u001b[1;31m#cfg['device'] = [1, 26]  # 'M-Audio Delta ASIO'\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 14\u001b[1;33m \u001b[0mSoundController\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mrun\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mselector\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mstatus\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mcfg\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m     15\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     16\u001b[0m \u001b[1;31m# nothing happens for a second\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
+      "\u001b[1;32mD:\\runSIT\\controllers\\sound.py\u001b[0m in \u001b[0;36mrun\u001b[1;34m(cls, selector, status, cfg)\u001b[0m\n\u001b[0;32m    134\u001b[0m                 \u001b[0mroving\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;36m10\u001b[0m\u001b[1;33m**\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mnp\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mrandom\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mrand\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;33m*\u001b[0m \u001b[0mcfg\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;34m'roving'\u001b[0m\u001b[1;33m]\u001b[0m \u001b[1;33m-\u001b[0m \u001b[0mcfg\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;34m'roving'\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m/\u001b[0m\u001b[1;36m2.0\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m/\u001b[0m\u001b[1;36m20.\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    135\u001b[0m                 \u001b[0mroving\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mroving\u001b[0m \u001b[1;32mif\u001b[0m \u001b[0mint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mselector\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mvalue\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;33m>\u001b[0m \u001b[1;33m-\u001b[0m\u001b[1;36m1\u001b[0m \u001b[1;32melse\u001b[0m \u001b[1;36m1\u001b[0m  \u001b[1;31m# no roving for noise\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 136\u001b[1;33m                 \u001b[0mstream\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mwrite\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0msounds\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0mcommutator\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0mint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mselector\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mvalue\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m]\u001b[0m \u001b[1;33m*\u001b[0m \u001b[0mroving\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m    137\u001b[0m                 \u001b[1;32mwith\u001b[0m \u001b[0mopen\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mcfg\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;34m'file_path'\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;34m'a'\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;32mas\u001b[0m \u001b[0mf\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    138\u001b[0m                     \u001b[0mf\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mwrite\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m\",\"\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mjoin\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0mstr\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mx\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;32mfor\u001b[0m \u001b[0mx\u001b[0m \u001b[1;32min\u001b[0m \u001b[1;33m(\u001b[0m\u001b[0mt0\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mselector\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mvalue\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;33m+\u001b[0m \u001b[1;34m\"\\n\"\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
+      "\u001b[1;32m~\\.conda\\envs\\runsit\\lib\\site-packages\\sounddevice.py\u001b[0m in \u001b[0;36mwrite\u001b[1;34m(self, data)\u001b[0m\n\u001b[0;32m   1532\u001b[0m         \u001b[1;32mif\u001b[0m \u001b[1;32mnot\u001b[0m \u001b[0mdata\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mflags\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mc_contiguous\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m   1533\u001b[0m             \u001b[1;32mraise\u001b[0m \u001b[0mTypeError\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'data must be C-contiguous'\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m-> 1534\u001b[1;33m         \u001b[1;32mreturn\u001b[0m \u001b[0mRawOutputStream\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mwrite\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mdata\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m   1535\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m   1536\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n",
+      "\u001b[1;32m~\\.conda\\envs\\runsit\\lib\\site-packages\\sounddevice.py\u001b[0m in \u001b[0;36mwrite\u001b[1;34m(self, data)\u001b[0m\n\u001b[0;32m   1319\u001b[0m         \u001b[1;32mif\u001b[0m \u001b[0mremainder\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m   1320\u001b[0m             \u001b[1;32mraise\u001b[0m \u001b[0mValueError\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'Number of samples not divisible by channels'\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m-> 1321\u001b[1;33m         \u001b[0merr\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0m_lib\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mPa_WriteStream\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_ptr\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mdata\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mframes\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m   1322\u001b[0m         \u001b[1;32mif\u001b[0m \u001b[0merr\u001b[0m \u001b[1;33m==\u001b[0m \u001b[0m_lib\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mpaOutputUnderflowed\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m   1323\u001b[0m             \u001b[0munderflowed\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;32mTrue\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
+      "\u001b[1;31mKeyboardInterrupt\u001b[0m: "
+     ]
+    }
+   ],
    "source": [
     "import numpy as np\n",
     "import time, os\n",
@@ -412,15 +428,15 @@
     "\n",
     "cfg = SoundController.default_cfg\n",
     "#cfg['device'] = [1, 26]  # 'M-Audio Delta ASIO'\n",
-    "#SoundController.run(selector, status, cfg)\n",
+    "SoundController.run(selector, status, cfg)\n",
     "\n",
     "# nothing happens for a second\n",
     "time.sleep(1)\n",
     "\n",
     "status.value = 2\n",
-    "for i in range(6):\n",
+    "for i in range(2):\n",
     "    time.sleep(1)\n",
-    "    selector.value = -1 if selector.value == 1 else 1\n",
+    "    selector.value = -1 if selector.value == 2 else 2\n",
     "\n",
     "# stop\n",
     "status.value = 0\n",
@@ -436,7 +452,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 2,
+   "execution_count": 1,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -446,7 +462,7 @@
     "from sound import SoundController\n",
     "\n",
     "# sound selector: 0 - silence, 1 - tone 1, 2 - tone 2\n",
-    "selector = mp.Value('i', 1)\n",
+    "selector = mp.Value('i', -1)\n",
     "\n",
     "# loggin status: 1 - idle, 2 - running, 0 - stopped\n",
     "status = mp.Value('i', 1)\n",
@@ -460,7 +476,7 @@
     "time.sleep(1)\n",
     "\n",
     "status.value = 2\n",
-    "for i in range(10):\n",
+    "for i in range(3):\n",
     "    time.sleep(1)\n",
     "    selector.value = -1 if selector.value == 1 else 1\n",
     "\n",

+ 7 - 6
controllers/sound.py

@@ -14,9 +14,9 @@ class SoundController:
         "device": [1, 26],
         "n_channels": 10,
         "sounds": {
-            "noise": {"amp": 0.5, "channels": [6, 8]},
-            "background": {"freq": 660, "amp": 0.1, "duration": 0.05, "harmonics": True, "channels": [1, 8]},
-            "target": {"freq": 660, "amp": 0.1, "duration": 0.05, "harmonics": True, "channels": [3, 8]}, 
+            "noise": {"amp": 0.2, "channels": [6, 8]},
+            "background": {"freq": 660, "amp": 0.1, "duration": 0.05, "harmonics": True, "channels": [3, 8]},
+            "target": {"freq": 1320, "amp": 0.1, "duration": 0.05, "harmonics": True, "channels": [3, 8]}, 
             "distractor1": {"freq": 860, "amp": 0.15, "duration": 0.05, "harmonics": True, "channels": [6, 8], "enabled": False},
             "distractor2": {"freq": 1060, "amp": 0.25, "duration": 0.05, "harmonics": True, "channels": [6, 8], "enabled": False},
             "distractor3": {"freq": 1320, "amp": 0.2, "duration": 0.05, "harmonics": True, "channels": [6, 8], "enabled": False}
@@ -123,7 +123,7 @@ class SoundController:
             f.write("time,id\n")
 
         while status.value > 0:
-            if status.value == 2:  # running state
+            if status.value == 2 or (status.value == 1 and selector.value == -1):  # running state or masking noise
                 t0 = time.time()
                 if t0 < next_beat:
                     #time.sleep(0.0001)  # not to spin the wheels too much
@@ -134,8 +134,9 @@ class SoundController:
                 roving = 10**((np.random.rand() * cfg['roving'] - cfg['roving']/2.0)/20.)
                 roving = roving if int(selector.value) > -1 else 1  # no roving for noise
                 stream.write(sounds[commutator[int(selector.value)]] * roving)
-                with open(cfg['file_path'], 'a') as f:
-                    f.write(",".join([str(x) for x in (t0, selector.value)]) + "\n")
+                if status.value == 2:
+                    with open(cfg['file_path'], 'a') as f:
+                        f.write(",".join([str(x) for x in (t0, selector.value)]) + "\n")
 
                 next_beat += cfg['latency']