psychopy 2024.2.4__py3-none-any.whl → 2025.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of psychopy might be problematic. Click here for more details.
- psychopy/CHANGELOG.txt +208 -4
- psychopy/LICENSE.txt +1 -1
- psychopy/VERSION +1 -1
- psychopy/__init__.py +10 -7
- psychopy/alerts/__init__.py +1 -1
- psychopy/alerts/_alerts.py +53 -17
- psychopy/alerts/_errorHandler.py +3 -4
- psychopy/alerts/alertsCatalogue/3210.yaml +27 -0
- psychopy/alerts/alertsCatalogue/3610.yaml +19 -0
- psychopy/alerts/alertsCatalogue/4130.yaml +19 -0
- psychopy/alerts/alertsCatalogue/alertCategories.yaml +8 -1
- psychopy/alerts/alertsCatalogue/alertmsg.py +1 -1
- psychopy/alerts/alerttools.py +0 -16
- psychopy/app/Resources/betasplash.png +0 -0
- psychopy/app/Resources/betasplash@2x.png +0 -0
- psychopy/app/Resources/classic/case.png +0 -0
- psychopy/app/Resources/classic/case@2x.png +0 -0
- psychopy/app/Resources/classic/fileaudio.png +0 -0
- psychopy/app/Resources/classic/fileaudio@2x.png +0 -0
- psychopy/app/Resources/classic/filecss.png +0 -0
- psychopy/app/Resources/classic/filecss@2x.png +0 -0
- psychopy/app/Resources/classic/filecsv.png +0 -0
- psychopy/app/Resources/classic/filecsv@2x.png +0 -0
- psychopy/app/Resources/classic/filedesign.png +0 -0
- psychopy/app/Resources/classic/filedesign@2x.png +0 -0
- psychopy/app/Resources/classic/filefont.png +0 -0
- psychopy/app/Resources/classic/filefont@2x.png +0 -0
- psychopy/app/Resources/classic/filegit.png +0 -0
- psychopy/app/Resources/classic/filegit@2x.png +0 -0
- psychopy/app/Resources/classic/filehtml.png +0 -0
- psychopy/app/Resources/classic/filehtml@2x.png +0 -0
- psychopy/app/Resources/classic/fileimage.png +0 -0
- psychopy/app/Resources/classic/fileimage@2x.png +0 -0
- psychopy/app/Resources/classic/fileinfo.png +0 -0
- psychopy/app/Resources/classic/fileinfo@2x.png +0 -0
- psychopy/app/Resources/classic/filejs.png +0 -0
- psychopy/app/Resources/classic/filejs@2x.png +0 -0
- psychopy/app/Resources/classic/filejson.png +0 -0
- psychopy/app/Resources/classic/filejson@2x.png +0 -0
- psychopy/app/Resources/classic/filepkg.png +0 -0
- psychopy/app/Resources/classic/filepkg@2x.png +0 -0
- psychopy/app/Resources/classic/filepsyexp.png +0 -0
- psychopy/app/Resources/classic/filepsyexp@2x.png +0 -0
- psychopy/app/Resources/classic/filepy.png +0 -0
- psychopy/app/Resources/classic/filepy@2x.png +0 -0
- psychopy/app/Resources/classic/filetxt.png +0 -0
- psychopy/app/Resources/classic/filetxt@2x.png +0 -0
- psychopy/app/Resources/classic/fileunknown.png +0 -0
- psychopy/app/Resources/classic/fileunknown@2x.png +0 -0
- psychopy/app/Resources/classic/filevideo.png +0 -0
- psychopy/app/Resources/classic/filevideo@2x.png +0 -0
- psychopy/app/Resources/classic/find.png +0 -0
- psychopy/app/Resources/classic/find@2x.png +0 -0
- psychopy/app/Resources/classic/loop.png +0 -0
- psychopy/app/Resources/classic/loop@2x.png +0 -0
- psychopy/app/Resources/classic/regex.png +0 -0
- psychopy/app/Resources/classic/regex@2x.png +0 -0
- psychopy/app/Resources/dark/case.png +0 -0
- psychopy/app/Resources/dark/case@2x.png +0 -0
- psychopy/app/Resources/dark/fileaudio.png +0 -0
- psychopy/app/Resources/dark/fileaudio@2x.png +0 -0
- psychopy/app/Resources/dark/filecss.png +0 -0
- psychopy/app/Resources/dark/filecss@2x.png +0 -0
- psychopy/app/Resources/dark/filecsv.png +0 -0
- psychopy/app/Resources/dark/filecsv@2x.png +0 -0
- psychopy/app/Resources/dark/filedesign.png +0 -0
- psychopy/app/Resources/dark/filedesign@2x.png +0 -0
- psychopy/app/Resources/dark/filefont.png +0 -0
- psychopy/app/Resources/dark/filefont@2x.png +0 -0
- psychopy/app/Resources/dark/filegit.png +0 -0
- psychopy/app/Resources/dark/filegit@2x.png +0 -0
- psychopy/app/Resources/dark/filehtml.png +0 -0
- psychopy/app/Resources/dark/filehtml@2x.png +0 -0
- psychopy/app/Resources/dark/fileimage.png +0 -0
- psychopy/app/Resources/dark/fileimage@2x.png +0 -0
- psychopy/app/Resources/dark/fileinfo.png +0 -0
- psychopy/app/Resources/dark/fileinfo@2x.png +0 -0
- psychopy/app/Resources/dark/filejs.png +0 -0
- psychopy/app/Resources/dark/filejs@2x.png +0 -0
- psychopy/app/Resources/dark/filejson.png +0 -0
- psychopy/app/Resources/dark/filejson@2x.png +0 -0
- psychopy/app/Resources/dark/filepkg.png +0 -0
- psychopy/app/Resources/dark/filepkg@2x.png +0 -0
- psychopy/app/Resources/dark/filepsyexp.png +0 -0
- psychopy/app/Resources/dark/filepsyexp@2x.png +0 -0
- psychopy/app/Resources/dark/filepy.png +0 -0
- psychopy/app/Resources/dark/filepy@2x.png +0 -0
- psychopy/app/Resources/dark/filetxt.png +0 -0
- psychopy/app/Resources/dark/filetxt@2x.png +0 -0
- psychopy/app/Resources/dark/fileunknown.png +0 -0
- psychopy/app/Resources/dark/fileunknown@2x.png +0 -0
- psychopy/app/Resources/dark/filevideo.png +0 -0
- psychopy/app/Resources/dark/filevideo@2x.png +0 -0
- psychopy/app/Resources/dark/find.png +0 -0
- psychopy/app/Resources/dark/find@2x.png +0 -0
- psychopy/app/Resources/dark/loop.png +0 -0
- psychopy/app/Resources/dark/loop@2x.png +0 -0
- psychopy/app/Resources/dark/regex.png +0 -0
- psychopy/app/Resources/dark/regex@2x.png +0 -0
- psychopy/app/Resources/light/case.png +0 -0
- psychopy/app/Resources/light/case@2x.png +0 -0
- psychopy/app/Resources/light/fileaudio.png +0 -0
- psychopy/app/Resources/light/fileaudio@2x.png +0 -0
- psychopy/app/Resources/light/filecss.png +0 -0
- psychopy/app/Resources/light/filecss@2x.png +0 -0
- psychopy/app/Resources/light/filecsv.png +0 -0
- psychopy/app/Resources/light/filecsv@2x.png +0 -0
- psychopy/app/Resources/light/filedesign.png +0 -0
- psychopy/app/Resources/light/filedesign@2x.png +0 -0
- psychopy/app/Resources/light/filefont.png +0 -0
- psychopy/app/Resources/light/filefont@2x.png +0 -0
- psychopy/app/Resources/light/filegit.png +0 -0
- psychopy/app/Resources/light/filegit@2x.png +0 -0
- psychopy/app/Resources/light/filehtml.png +0 -0
- psychopy/app/Resources/light/filehtml@2x.png +0 -0
- psychopy/app/Resources/light/fileimage.png +0 -0
- psychopy/app/Resources/light/fileimage@2x.png +0 -0
- psychopy/app/Resources/light/fileinfo.png +0 -0
- psychopy/app/Resources/light/fileinfo@2x.png +0 -0
- psychopy/app/Resources/light/filejs.png +0 -0
- psychopy/app/Resources/light/filejs@2x.png +0 -0
- psychopy/app/Resources/light/filejson.png +0 -0
- psychopy/app/Resources/light/filejson@2x.png +0 -0
- psychopy/app/Resources/light/filepkg.png +0 -0
- psychopy/app/Resources/light/filepkg@2x.png +0 -0
- psychopy/app/Resources/light/filepsyexp.png +0 -0
- psychopy/app/Resources/light/filepsyexp@2x.png +0 -0
- psychopy/app/Resources/light/filepy.png +0 -0
- psychopy/app/Resources/light/filepy@2x.png +0 -0
- psychopy/app/Resources/light/filetxt.png +0 -0
- psychopy/app/Resources/light/filetxt@2x.png +0 -0
- psychopy/app/Resources/light/fileunknown.png +0 -0
- psychopy/app/Resources/light/fileunknown@2x.png +0 -0
- psychopy/app/Resources/light/filevideo.png +0 -0
- psychopy/app/Resources/light/filevideo@2x.png +0 -0
- psychopy/app/Resources/light/find.png +0 -0
- psychopy/app/Resources/light/find@2x.png +0 -0
- psychopy/app/Resources/light/loop.png +0 -0
- psychopy/app/Resources/light/loop@2x.png +0 -0
- psychopy/app/Resources/light/regex.png +0 -0
- psychopy/app/Resources/light/regex@2x.png +0 -0
- psychopy/app/Resources/routine_templates/Basic.psyexp +0 -1
- psychopy/app/Resources/routine_templates/Misc.psyexp +0 -1
- psychopy/app/Resources/routine_templates/Online.psyexp +0 -2
- psychopy/app/Resources/routine_templates/Trials.psyexp +0 -1
- psychopy/app/Resources/splash.png +0 -0
- psychopy/app/Resources/splash@2x.png +0 -0
- psychopy/app/__init__.py +49 -8
- psychopy/app/__main__.py +3 -0
- psychopy/app/_psychopyApp.py +134 -125
- psychopy/app/builder/builder.py +42 -22
- psychopy/app/builder/dialogs/__init__.py +44 -11
- psychopy/app/builder/dialogs/dlgsCode.py +1 -1
- psychopy/app/builder/dialogs/dlgsConditions.py +1 -1
- psychopy/app/builder/dialogs/findDlg.py +106 -20
- psychopy/app/builder/dialogs/paramCtrls.py +42 -1
- psychopy/app/builder/validators.py +1 -1
- psychopy/app/coder/codeEditorBase.py +8 -8
- psychopy/app/coder/coder.py +32 -29
- psychopy/app/coder/fileBrowser.py +68 -22
- psychopy/app/coder/folding.py +1 -1
- psychopy/app/coder/psychoParser.py +1 -1
- psychopy/app/coder/repl.py +1 -1
- psychopy/app/coder/sourceTree.py +1 -1
- psychopy/app/connections/__init__.py +1 -1
- psychopy/app/connections/news.py +1 -1
- psychopy/app/connections/sendusage.py +1 -1
- psychopy/app/connections/updates.py +1 -1
- psychopy/app/console.py +1 -1
- psychopy/app/errorDlg.py +1 -1
- psychopy/app/frametracker.py +1 -1
- psychopy/app/idle.py +1 -1
- psychopy/app/jobs.py +5 -2
- psychopy/app/linuxconfig/__init__.py +1 -1
- psychopy/app/locale/ar_001/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/ar_001/LC_MESSAGE/messages.po +1514 -3259
- psychopy/app/locale/cs_CZ/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/da_DK/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/de_DE/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/de_DE/LC_MESSAGE/messages.po +3 -3
- psychopy/app/locale/el_GR/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/en_NZ/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/en_US/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/es_CO/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/es_CO/LC_MESSAGE/messages.po +4 -4
- psychopy/app/locale/es_ES/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/es_ES/LC_MESSAGE/messages.po +4 -4
- psychopy/app/locale/es_US/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/es_US/LC_MESSAGE/messages.po +4 -4
- psychopy/app/locale/et_EE/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/et_EE/LC_MESSAGE/messages.po +2 -2
- psychopy/app/locale/fa_IR/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/fa_IR/LC_MESSAGE/messages.po +1 -1
- psychopy/app/locale/fi_FI/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/fr_FR/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/fr_FR/LC_MESSAGE/messages.po +2 -2
- psychopy/app/locale/he_IL/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/he_IL/LC_MESSAGE/messages.po +2 -2
- psychopy/app/locale/hi_IN/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/hi_IN/LC_MESSAGE/messages.po +2 -2
- psychopy/app/locale/hu_HU/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/it_IT/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/it_IT/LC_MESSAGE/messages.po +2 -2
- psychopy/app/locale/ja_JP/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/ja_JP/LC_MESSAGE/messages.po +3421 -2396
- psychopy/app/locale/ko_KR/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/ms_MY/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/ms_MY/LC_MESSAGE/messages.po +2 -2
- psychopy/app/locale/nl_NL/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/nn_NO/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/pl_PL/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/pt_PT/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/pt_PT/LC_MESSAGE/messages.po +4 -4
- psychopy/app/locale/ro_RO/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/ru_RU/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/sv_SE/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/sv_SE/LC_MESSAGE/messages.po +2 -2
- psychopy/app/locale/tr_TR/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/tr_TR/LC_MESSAGE/messages.po +2 -2
- psychopy/app/locale/zh_CN/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/zh_CN/LC_MESSAGE/messages.po +3 -3
- psychopy/app/locale/zh_TW/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/zh_TW/LC_MESSAGE/messages.po +2 -2
- psychopy/app/{builder/localizedStrings.py → localizedStrings.py} +173 -26
- psychopy/app/pavlovia_ui/__init__.py +1 -1
- psychopy/app/pavlovia_ui/_base.py +1 -1
- psychopy/app/pavlovia_ui/functions.py +1 -1
- psychopy/app/pavlovia_ui/menu.py +1 -1
- psychopy/app/pavlovia_ui/project.py +1 -1
- psychopy/app/pavlovia_ui/search.py +1 -1
- psychopy/app/pavlovia_ui/sync.py +1 -1
- psychopy/app/pavlovia_ui/user.py +1 -1
- psychopy/app/plugin_manager/dialog.py +34 -96
- psychopy/app/plugin_manager/packages.py +10 -14
- psychopy/app/plugin_manager/plugins.py +64 -4
- psychopy/app/preferencesDlg.py +12 -37
- psychopy/app/psychopyApp.py +130 -44
- psychopy/app/ribbon.py +1 -0
- psychopy/app/runner/runner.py +37 -15
- psychopy/app/runner/scriptProcess.py +11 -6
- psychopy/app/stdout/stdOutRich.py +9 -2
- psychopy/app/themes/fonts.py +1 -1
- psychopy/app/themes/icons.py +2 -38
- psychopy/app/ui/__init__.py +1 -1
- psychopy/app/utils.py +3 -3
- psychopy/assets/default.mp3 +0 -0
- psychopy/assets/fonts/NotoSans-Bold.ttf +0 -0
- psychopy/assets/fonts/NotoSans-BoldItalic.ttf +0 -0
- psychopy/assets/fonts/NotoSans-Italic.ttf +0 -0
- psychopy/assets/fonts/NotoSans-Regular.ttf +0 -0
- psychopy/assets/voicekeyThresholdStim.wav +0 -0
- psychopy/clock.py +4 -1
- psychopy/colors.py +2 -0
- psychopy/core.py +1 -1
- psychopy/data/base.py +1 -1
- psychopy/data/experiment.py +151 -46
- psychopy/data/routine.py +27 -1
- psychopy/data/staircase.py +2 -1
- psychopy/data/trial.py +62 -14
- psychopy/data/utils.py +1 -1
- psychopy/demos/builder/Design Templates/branchedExperiment/branchedExperiment.psyexp +333 -218
- psychopy/demos/builder/Design Templates/psychophysicsStaircase/psychophysicsStaircase.psyexp +261 -239
- psychopy/demos/builder/Design Templates/psychophysicsStairsInterleaved/psychophysicsStaircaseInterleaved.psyexp +319 -180
- psychopy/demos/builder/Design Templates/randomisedBlocks/randomisedBlocks.psyexp +204 -116
- psychopy/demos/builder/Experiments/BART/assets/background.jpg +0 -0
- psychopy/demos/builder/Experiments/BART/assets/blueBalloon.png +0 -0
- psychopy/demos/builder/Experiments/BART/assets/greenBalloon.png +0 -0
- psychopy/demos/builder/Experiments/BART/assets/redBalloon.png +0 -0
- psychopy/demos/builder/Experiments/BART/bart.psyexp +779 -866
- psychopy/demos/builder/Experiments/BigFiveInventory/BFI.psyexp +242 -180
- psychopy/demos/builder/Experiments/GoNoGo/gng.psyexp +419 -406
- psychopy/demos/builder/Experiments/dragAndDrop/README.md +2 -37
- psychopy/demos/builder/Experiments/dragAndDrop/drag_and_drop.psyexp +460 -1204
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/blank_grid.png +0 -0
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/make_shapes.psyexp +221 -0
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/readme.md +4 -0
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/solution_1.png +0 -0
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/solution_10.png +0 -0
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/solution_2.png +0 -0
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/solution_3.png +0 -0
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/solution_4.png +0 -0
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/solution_5.png +0 -0
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/solution_6.png +0 -0
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/solution_7.png +0 -0
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/solution_8.png +0 -0
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/solution_9.png +0 -0
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/solutions.xlsx +0 -0
- psychopy/demos/builder/Experiments/mentalRotation/MentalRotation.psyexp +583 -542
- psychopy/demos/builder/Experiments/navon/NavonTask.psyexp +458 -427
- psychopy/demos/builder/Experiments/sternberg/sternberg.psyexp +588 -550
- psychopy/demos/builder/Experiments/stroop/stroop.psyexp +303 -207
- psychopy/demos/builder/Experiments/stroopExtended/stroop.psyexp +390 -215
- psychopy/demos/builder/Experiments/stroopExtended/stroopReverse.psyexp +390 -215
- psychopy/demos/builder/Experiments/stroopVoice/stroopVoice.psyexp +357 -331
- psychopy/demos/builder/Feature Demos/buttonBox/buttonBoxDemo.psyexp +3 -2
- psychopy/demos/builder/Feature Demos/counterbalance/counterbalance.psyexp +287 -277
- psychopy/demos/builder/Feature Demos/gratings/gratings.psyexp +370 -320
- psychopy/demos/builder/Feature Demos/noise/noise.psyexp +452 -399
- psychopy/demos/builder/Feature Demos/panorama/panorama.psyexp +168 -133
- psychopy/demos/builder/Feature Demos/pilotMode/pilotMode.psyexp +4 -3
- psychopy/demos/builder/Feature Demos/progress/progressBar.psyexp +420 -392
- psychopy/demos/builder/Feature Demos/sliders/sliders.psyexp +917 -871
- psychopy/demos/builder/Feature Demos/visualValidator/readme.md +7 -0
- psychopy/demos/builder/Feature Demos/visualValidator/visualValidator.psyexp +200 -0
- psychopy/demos/builder/Hardware/EEG_parallel_component/EEG_triggers_parallel_comp.psyexp +25 -9
- psychopy/demos/builder/Hardware/EEG_serial_code/EEG_triggers_serial_code.psyexp +372 -361
- psychopy/demos/builder/Hardware/EEG_serial_component/EEG_triggers_serial_comp.psyexp +25 -9
- psychopy/demos/builder/Hardware/EGI_netstation/stroop.psyexp +320 -235
- psychopy/demos/builder/Hardware/Eyetracking_visual_search/visualSearch.psyexp +790 -651
- psychopy/demos/builder/Hardware/camera/camera.psyexp +326 -246
- psychopy/demos/builder/Hardware/eyetracking/eyetracking.psyexp +432 -327
- psychopy/demos/builder/Hardware/eyetracking_custom_cal/eyetracking_custom_cal.psyexp +440 -321
- psychopy/demos/builder/Hardware/fMRI/fMRI_demo.psyexp +190 -181
- psychopy/demos/builder/Hardware/lab_streaming_layer/lsl_triggers_demo.psyexp +323 -312
- psychopy/demos/builder/Hardware/lab_streaming_layer/lsl_triggers_demo_legacy.psyexp +360 -0
- psychopy/demos/builder/{Feature Demos/eyetracking/eyetracking.xml → Hardware/lab_streaming_layer/lsl_triggers_demo_legacy_legacy.psyexp} +154 -140
- psychopy/demos/builder/Hardware/lab_streaming_layer_legacy/lsl_triggers_demo_legacy.psyexp +329 -273
- psychopy/demos/builder/Hardware/lab_streaming_layer_legacy/lsl_triggers_demo_legacy_legacy.psyexp +360 -0
- psychopy/demos/builder/Hardware/lab_streaming_layer_legacy/lsl_triggers_demo_legacy_legacy_legacy.psyexp +312 -0
- psychopy/demos/builder/Hardware/microphone/microphone.psyexp +450 -404
- psychopy/demos/builder/Hardware/pump/pump.psyexp +593 -329
- psychopy/demos/builder/Helper Tools/achorVSalignment/FlowCircular-Regular.ttf +0 -0
- psychopy/demos/builder/Helper Tools/achorVSalignment/anchorAlignment.psyexp +336 -274
- psychopy/demos/builder/Helper Tools/clockFace/clockFace.psyexp +200 -149
- psychopy/demos/builder/Helper Tools/colors/colors.psyexp +300 -279
- psychopy/demos/builder/Helper Tools/drawPolygon/drawPolygon.psyexp +677 -564
- psychopy/demos/builder/Helper Tools/keyNameFinder/keyNameFinder.psyexp +214 -158
- psychopy/demos/builder/Helper Tools/spatialUnits/unitDemo.psyexp +195 -146
- psychopy/demos/coder/experiment control/runtimeInfo.py +1 -1
- psychopy/devices/__init__.py +1 -1
- psychopy/event.py +1 -1
- psychopy/exceptions.py +1 -1
- psychopy/experiment/__init__.py +1 -1
- psychopy/experiment/_experiment.py +62 -16
- psychopy/experiment/components/__init__.py +1 -6
- psychopy/experiment/components/_base.py +44 -19
- psychopy/experiment/components/aperture/__init__.py +1 -1
- psychopy/experiment/components/brush/__init__.py +2 -2
- psychopy/experiment/components/button/__init__.py +24 -28
- psychopy/experiment/components/camera/__init__.py +38 -39
- psychopy/experiment/components/code/__init__.py +1 -1
- psychopy/experiment/components/dots/__init__.py +1 -1
- psychopy/experiment/components/eyetracker_record/__init__.py +7 -3
- psychopy/experiment/components/form/__init__.py +3 -3
- psychopy/experiment/components/grating/__init__.py +1 -1
- psychopy/experiment/components/image/__init__.py +1 -1
- psychopy/experiment/components/joyButtons/__init__.py +2 -2
- psychopy/experiment/components/joyButtons/virtualJoyButtons.py +1 -1
- psychopy/experiment/components/joystick/__init__.py +3 -3
- psychopy/experiment/components/joystick/virtualJoystick.py +1 -1
- psychopy/experiment/components/keyboard/__init__.py +98 -122
- psychopy/experiment/components/microphone/__init__.py +54 -98
- psychopy/experiment/components/mouse/__init__.py +92 -93
- psychopy/experiment/components/movie/__init__.py +28 -50
- psychopy/experiment/components/parallelOut/__init__.py +3 -3
- psychopy/experiment/components/polygon/__init__.py +2 -3
- psychopy/experiment/components/roi/__init__.py +2 -2
- psychopy/experiment/components/routineSettings/__init__.py +2 -0
- psychopy/experiment/components/serialOut/__init__.py +7 -7
- psychopy/experiment/components/settings/__init__.py +317 -313
- psychopy/experiment/components/settings/eyetracking.py +108 -0
- psychopy/experiment/components/slider/__init__.py +5 -5
- psychopy/experiment/components/sound/__init__.py +168 -78
- psychopy/experiment/components/soundsensor/__init__.py +361 -0
- psychopy/experiment/components/soundsensor/classic/soundsensor.png +0 -0
- psychopy/experiment/components/soundsensor/classic/soundsensor@2x.png +0 -0
- psychopy/experiment/components/soundsensor/dark/soundsensor.png +0 -0
- psychopy/experiment/components/soundsensor/dark/soundsensor@2x.png +0 -0
- psychopy/experiment/components/soundsensor/light/soundsensor.png +0 -0
- psychopy/experiment/components/soundsensor/light/soundsensor@2x.png +0 -0
- psychopy/experiment/components/static/__init__.py +59 -33
- psychopy/experiment/components/text/__init__.py +2 -6
- psychopy/experiment/components/textbox/__init__.py +3 -7
- psychopy/experiment/components/unknown/__init__.py +2 -0
- psychopy/experiment/components/unknownPlugin/__init__.py +2 -0
- psychopy/experiment/exports.py +1 -1
- psychopy/experiment/flow.py +2 -2
- psychopy/experiment/localization.py +1 -1
- psychopy/experiment/loops.py +43 -10
- psychopy/experiment/params.py +6 -4
- psychopy/experiment/plugins.py +8 -1
- psychopy/experiment/py2js.py +1 -1
- psychopy/experiment/py2js_transpiler.py +1 -1
- psychopy/experiment/routines/__init__.py +1 -1
- psychopy/experiment/routines/_base.py +23 -24
- psychopy/experiment/routines/audioValidator/__init__.py +343 -0
- psychopy/experiment/routines/audioValidator/classic/audio_validator.png +0 -0
- psychopy/experiment/routines/audioValidator/classic/audio_validator@2x.png +0 -0
- psychopy/experiment/routines/audioValidator/dark/audio_validator.png +0 -0
- psychopy/experiment/routines/audioValidator/dark/audio_validator@2x.png +0 -0
- psychopy/experiment/routines/audioValidator/light/audio_validator.png +0 -0
- psychopy/experiment/routines/audioValidator/light/audio_validator@2x.png +0 -0
- psychopy/experiment/routines/eyetracker_calibrate/__init__.py +76 -17
- psychopy/experiment/routines/eyetracker_validate/__init__.py +1 -1
- psychopy/experiment/routines/unknown/__init__.py +2 -0
- psychopy/experiment/routines/{photodiodeValidator → visualValidator}/__init__.py +89 -120
- psychopy/experiment/routines/visualValidator/classic/visual_validator.png +0 -0
- psychopy/experiment/routines/visualValidator/classic/visual_validator@2x.png +0 -0
- psychopy/experiment/routines/visualValidator/dark/visual_validator.png +0 -0
- psychopy/experiment/routines/visualValidator/dark/visual_validator@2x.png +0 -0
- psychopy/experiment/routines/visualValidator/light/visual_validator.png +0 -0
- psychopy/experiment/routines/visualValidator/light/visual_validator@2x.png +0 -0
- psychopy/experiment/utils.py +1 -1
- psychopy/gui/__init__.py +1 -1
- psychopy/gui/qtgui.py +15 -6
- psychopy/gui/wxgui.py +1 -1
- psychopy/hardware/__init__.py +0 -1
- psychopy/hardware/base.py +147 -16
- psychopy/hardware/bbtk/__init__.py +10 -16
- psychopy/hardware/brainproducts.py +7 -13
- psychopy/hardware/button.py +21 -2
- psychopy/hardware/buttonbox/__init__.py +1 -1
- psychopy/hardware/camera/__init__.py +16 -3
- psychopy/hardware/cedrus.py +5 -16
- psychopy/hardware/crs/__init__.py +1 -1
- psychopy/hardware/crs/bits.py +36 -33
- psychopy/hardware/crs/colorcal.py +8 -11
- psychopy/hardware/crs/optical.py +7 -10
- psychopy/hardware/crs/shaders.py +18 -5
- psychopy/hardware/emotiv.py +1 -1
- psychopy/hardware/emulator.py +11 -5
- psychopy/hardware/exceptions.py +86 -0
- psychopy/hardware/forp.py +18 -23
- psychopy/hardware/gammasci.py +8 -3
- psychopy/hardware/iolab.py +8 -19
- psychopy/hardware/joystick/__init__.py +865 -266
- psychopy/hardware/joystick/_base.py +251 -0
- psychopy/hardware/joystick/backend_glfw.py +306 -0
- psychopy/hardware/joystick/backend_pyglet.py +309 -0
- psychopy/hardware/joystick/mappings.py +287 -0
- psychopy/hardware/keyboard.py +4 -2
- psychopy/hardware/labhackers.py +1 -1
- psychopy/hardware/labjacks.py +9 -13
- psychopy/hardware/{photodiode.py → lightsensor.py} +146 -203
- psychopy/hardware/listener.py +9 -8
- psychopy/hardware/manager.py +24 -35
- psychopy/hardware/microphone.py +534 -154
- psychopy/hardware/minolta.py +14 -4
- psychopy/hardware/mouse/__init__.py +1 -1
- psychopy/hardware/photometer/__init__.py +2 -2
- psychopy/hardware/pr.py +14 -4
- psychopy/hardware/qmix.py +18 -27
- psychopy/hardware/serialdevice.py +43 -12
- psychopy/hardware/soundsensor.py +473 -0
- psychopy/hardware/spatial/__init__.py +231 -0
- psychopy/hardware/speaker.py +298 -36
- psychopy/hardware/triggerbox/__init__.py +1 -1
- psychopy/hardware/triggerbox/base.py +1 -1
- psychopy/hardware/triggerbox/parallel.py +1 -1
- psychopy/info.py +1 -1
- psychopy/iohub/client/__init__.py +17 -0
- psychopy/iohub/client/keyboard.py +5 -0
- psychopy/iohub/devices/eyetracker/__init__.py +10 -18
- psychopy/iohub/devices/eyetracker/calibration/procedure.py +15 -33
- psychopy/iohub/devices/eyetracker/hw/pupil_labs/neon/__init__.py +1 -0
- psychopy/iohub/devices/mouse/linux2.py +6 -1
- psychopy/iohub/devices/mouse/win32.py +5 -0
- psychopy/layout.py +1 -1
- psychopy/liaison.py +91 -39
- psychopy/locale_setup.py +11 -1
- psychopy/localization/__init__.py +1 -1
- psychopy/localization/_localization.py +1 -1
- psychopy/localization/messages.pot +2 -2
- psychopy/logging.py +14 -12
- psychopy/microphone.py +4 -3
- psychopy/misc.py +1 -1
- psychopy/monitors/MonitorCenter.py +3 -3
- psychopy/monitors/__init__.py +1 -1
- psychopy/monitors/calibData.py +1 -1
- psychopy/monitors/calibTools.py +3 -2
- psychopy/platform_specific/__init__.py +1 -1
- psychopy/platform_specific/darwin.py +1 -1
- psychopy/platform_specific/linux.py +1 -1
- psychopy/platform_specific/win32.py +1 -1
- psychopy/plugins/__init__.py +26 -17
- psychopy/plugins/util.py +65 -0
- psychopy/preferences/Darwin.spec +11 -3
- psychopy/preferences/FreeBSD.spec +11 -3
- psychopy/preferences/Linux.spec +11 -3
- psychopy/preferences/Windows.spec +11 -3
- psychopy/preferences/__init__.py +1 -1
- psychopy/preferences/baseNoArch.spec +11 -3
- psychopy/preferences/hints.py +78 -61
- psychopy/preferences/preferences.py +82 -13
- psychopy/projects/__init__.py +1 -1
- psychopy/projects/pavlovia.py +29 -13
- psychopy/scripts/psyexpCompile.py +1 -1
- psychopy/session.py +81 -8
- psychopy/sound/__init__.py +25 -10
- psychopy/sound/_base.py +134 -34
- psychopy/sound/audioclip.py +38 -15
- psychopy/sound/audiodevice.py +1 -1
- psychopy/sound/backend_ptb.py +53 -321
- psychopy/sound/backend_pygame.py +7 -3
- psychopy/sound/backend_pyo.py +53 -22
- psychopy/sound/backend_pysound.py +10 -27
- psychopy/sound/backend_sounddevice.py +33 -21
- psychopy/sound/exceptions.py +1 -1
- psychopy/sound/microphone.py +83 -5
- psychopy/sound/transcribe.py +3 -3
- psychopy/tests/data/test_basic_run.py +1 -0
- psychopy/tests/data/test_loaded_namespace/test_counterbalance.psyexp +142 -0
- psychopy/tests/data/test_loaded_namespace/test_custom_missing.psyexp +129 -0
- psychopy/tests/data/test_loaded_namespace/test_missing_counterbalance.psyexp +116 -0
- psychopy/tests/data/test_loaded_namespace/test_mix_exp.psyexp +181 -0
- psychopy/tests/data/test_loaded_namespace/test_mix_missing.psyexp +140 -0
- psychopy/tests/data/test_loaded_namespace/test_mix_name_calibration.psyexp +164 -0
- psychopy/tests/data/test_sounds/default_16000.wav +0 -0
- psychopy/tests/data/test_sounds/default_192000.wav +0 -0
- psychopy/tests/data/test_sounds/default_22050.wav +0 -0
- psychopy/tests/data/test_sounds/default_32000.wav +0 -0
- psychopy/tests/data/test_sounds/default_44100.wav +0 -0
- psychopy/tests/data/test_sounds/default_48000.wav +0 -0
- psychopy/tests/data/test_sounds/default_8000.wav +0 -0
- psychopy/tests/data/test_sounds/default_96000.wav +0 -0
- psychopy/tests/test_alerts/test_alerttools.py +2 -1
- psychopy/tests/test_app/test_command_line.py +65 -0
- psychopy/tests/test_data/test_TrialHandler2.py +18 -7
- psychopy/tests/test_demos/test_builder_demos.py +1 -1
- psychopy/tests/test_experiment/needs_wx/componsTemplate.txt +5238 -4188
- psychopy/tests/test_experiment/needs_wx/test_components.py +1 -1
- psychopy/tests/test_experiment/test_components/test_RoutineSettingsComponent.py +16 -0
- psychopy/tests/test_experiment/test_components/test_all_components.py +1 -1
- psychopy/tests/test_experiment/test_components/test_base_components.py +26 -17
- psychopy/tests/test_experiment/test_experiment.py +96 -0
- psychopy/tests/test_experiment/test_loops.py +12 -4
- psychopy/tests/test_experiment/test_params.py +17 -4
- psychopy/tests/test_experiment/test_routines/test_PhotodiodeValidationRoutine.py +2 -2
- psychopy/tests/test_hardware/test_photodiode.py +66 -0
- psychopy/tests/test_liaison/test_Liaison.py +4 -4
- psychopy/tests/test_misc/test_clock.py +2 -0
- psychopy/tests/test_misc/test_color.py +2 -0
- psychopy/tests/test_misc/test_event.py +1 -0
- psychopy/tests/test_plugins/test_plugin_stubs.py +125 -0
- psychopy/tests/test_sound/test_sound.py +111 -40
- psychopy/tests/test_tools/test_colorspacetools.py +24 -23
- psychopy/tests/test_tools/test_mathtools.py +9 -9
- psychopy/tests/test_tools/test_viewtools.py +101 -0
- psychopy/tests/test_validators/__init__.py +0 -0
- psychopy/tests/test_validators/test_voicekeyValidator.py +95 -0
- psychopy/tests/test_visual/test_all_stimuli.py +2 -2
- psychopy/tests/test_visual/test_basevisual.py +37 -7
- psychopy/tests/test_visual/test_button.py +2 -2
- psychopy/tests/test_visual/test_circle.py +10 -2
- psychopy/tests/test_visual/test_dots.py +1 -1
- psychopy/tests/test_visual/test_form.py +13 -13
- psychopy/tests/test_visual/test_gamma.py +3 -3
- psychopy/tests/test_visual/test_image.py +2 -2
- psychopy/tests/test_visual/test_progress.py +2 -2
- psychopy/tests/test_visual/test_roi.py +8 -2
- psychopy/tests/test_visual/test_shape.py +2 -2
- psychopy/tests/test_visual/test_slider.py +2 -2
- psychopy/tests/test_visual/test_target.py +2 -2
- psychopy/tests/test_visual/test_textbox.py +6 -8
- psychopy/tests/test_visual/test_winScalePos.py +6 -5
- psychopy/tests/test_visual/test_window.py +17 -0
- psychopy/tests/utils.py +51 -1
- psychopy/tools/__init__.py +1 -1
- psychopy/tools/arraytools.py +2 -2
- psychopy/tools/attributetools.py +52 -1
- psychopy/tools/audiotools.py +4 -1
- psychopy/tools/colorspacetools.py +6 -4
- psychopy/tools/coordinatetools.py +1 -1
- psychopy/tools/fileerrortools.py +21 -9
- psychopy/tools/filetools.py +2 -2
- psychopy/tools/fontmanager.py +47 -28
- psychopy/tools/gltools.py +2964 -558
- psychopy/tools/imagetools.py +1 -1
- psychopy/tools/mathtools.py +997 -127
- psychopy/tools/monitorunittools.py +7 -1
- psychopy/tools/movietools.py +1 -2
- psychopy/tools/pkgtools.py +157 -127
- psychopy/tools/plottools.py +1 -1
- psychopy/tools/rifttools.py +1 -1
- psychopy/tools/stereotools.py +1 -1
- psychopy/tools/stimulustools.py +172 -2
- psychopy/tools/stringtools.py +22 -2
- psychopy/tools/systemtools.py +1 -1
- psychopy/tools/typetools.py +1 -1
- psychopy/tools/unittools.py +1 -1
- psychopy/tools/versionchooser.py +3 -1
- psychopy/tools/viewtools.py +54 -70
- psychopy/tools/wizard.py +2 -2
- psychopy/validation/__init__.py +6 -0
- psychopy/validation/audio.py +74 -0
- psychopy/validation/visual.py +115 -0
- psychopy/visual/__init__.py +1 -4
- psychopy/visual/aperture.py +9 -6
- psychopy/visual/backends/__init__.py +1 -1
- psychopy/visual/backends/_base.py +1 -1
- psychopy/visual/backends/gamma.py +1 -1
- psychopy/visual/backends/glfwbackend.py +8 -12
- psychopy/visual/backends/pygamebackend.py +1 -1
- psychopy/visual/backends/pygletbackend.py +32 -11
- psychopy/visual/basevisual.py +93 -13
- psychopy/visual/brush.py +1 -1
- psychopy/visual/bufferimage.py +90 -10
- psychopy/visual/button.py +1 -1
- psychopy/visual/circle.py +12 -20
- psychopy/visual/custommouse.py +1 -1
- psychopy/visual/dot.py +80 -14
- psychopy/visual/elementarray.py +84 -10
- psychopy/visual/filters.py +1 -1
- psychopy/visual/form.py +43 -28
- psychopy/visual/grating.py +105 -25
- psychopy/visual/helpers.py +1 -1
- psychopy/visual/image.py +98 -20
- psychopy/visual/line.py +15 -25
- psychopy/visual/movie.py +1 -1
- psychopy/visual/movie2.py +4 -3
- psychopy/visual/movie3.py +4 -3
- psychopy/visual/movies/__init__.py +1 -1
- psychopy/visual/movies/frame.py +1 -1
- psychopy/visual/movies/metadata.py +1 -1
- psychopy/visual/movies/players/__init__.py +1 -1
- psychopy/visual/movies/players/_base.py +1 -1
- psychopy/visual/movies/players/ffpyplayer_player.py +2 -3
- psychopy/visual/nnlvs.py +9 -6
- psychopy/visual/noise.py +4 -16
- psychopy/visual/patch.py +4 -3
- psychopy/visual/pie.py +3 -14
- psychopy/visual/polygon.py +21 -28
- psychopy/visual/radial.py +4 -18
- psychopy/visual/ratingscale.py +4 -3
- psychopy/visual/rect.py +16 -25
- psychopy/visual/rift.py +8 -2
- psychopy/visual/secondorder.py +4 -16
- psychopy/visual/shaders.py +620 -286
- psychopy/visual/shape.py +281 -90
- psychopy/visual/simpleimage.py +1 -1
- psychopy/visual/slider.py +78 -25
- psychopy/visual/stim3d.py +5 -608
- psychopy/visual/text.py +13 -3
- psychopy/visual/textbox2/textbox2.py +188 -56
- psychopy/visual/vlcmoviestim.py +1 -1
- psychopy/visual/window.py +373 -200
- psychopy/web.py +1 -1
- {psychopy-2024.2.4.dist-info → psychopy-2025.1.0.dist-info}/METADATA +9 -9
- {psychopy-2024.2.4.dist-info → psychopy-2025.1.0.dist-info}/RECORD +653 -660
- psychopy/.DS_Store +0 -0
- psychopy/__init__.py.orig +0 -65
- psychopy/app/.DS_Store +0 -0
- psychopy/app/Resources/.DS_Store +0 -0
- psychopy/app/Resources/classic/filecsv16.png +0 -0
- psychopy/app/Resources/classic/fileimage16.png +0 -0
- psychopy/app/Resources/classic/fileunknown16.png +0 -0
- psychopy/app/Resources/dark/filecsv16.png +0 -0
- psychopy/app/Resources/dark/filecsv16@2x.png +0 -0
- psychopy/app/Resources/dark/fileimage16.png +0 -0
- psychopy/app/Resources/dark/fileimage16@2x.png +0 -0
- psychopy/app/Resources/dark/fileunknown16.png +0 -0
- psychopy/app/Resources/dark/fileunknown16@2x.png +0 -0
- psychopy/app/Resources/fonts/OpenSans-Bold.ttf +0 -0
- psychopy/app/Resources/fonts/OpenSans-BoldItalic.ttf +0 -0
- psychopy/app/Resources/fonts/OpenSans-ExtraBold.ttf +0 -0
- psychopy/app/Resources/fonts/OpenSans-ExtraBoldItalic.ttf +0 -0
- psychopy/app/Resources/fonts/OpenSans-Italic.ttf +0 -0
- psychopy/app/Resources/fonts/OpenSans-Light.ttf +0 -0
- psychopy/app/Resources/fonts/OpenSans-LightItalic.ttf +0 -0
- psychopy/app/Resources/fonts/OpenSans-Regular.ttf +0 -0
- psychopy/app/Resources/fonts/OpenSans-SemiBold.ttf +0 -0
- psychopy/app/Resources/fonts/OpenSans-SemiBoldItalic.ttf +0 -0
- psychopy/app/Resources/light/filecsv16.png +0 -0
- psychopy/app/Resources/light/filecsv16@2x.png +0 -0
- psychopy/app/Resources/light/fileimage16.png +0 -0
- psychopy/app/Resources/light/fileimage16@2x.png +0 -0
- psychopy/app/Resources/light/fileunknown16.png +0 -0
- psychopy/app/Resources/light/fileunknown16@2x.png +0 -0
- psychopy/app/Resources/psychopySplash.png +0 -0
- psychopy/app/Resources/psychopySplash@2x.png +0 -0
- psychopy/app/builder/builder.py.orig +0 -3932
- psychopy/app/builder/dialogs/__init__.py.orig +0 -1679
- psychopy/app/builder/dialogs/paramCtrls.py.orig +0 -713
- psychopy/app/colorpicker/__init__.py.orig +0 -411
- psychopy/app/locale/zh_CN/LC_MESSAGE/zh_CN.mo +0 -0
- psychopy/app/locale/zh_CN/LC_MESSAGE/zh_CN.po +0 -6127
- psychopy/app/locale/zh_CN/LC_MESSAGE/zh_CN_allFlagged.mo +0 -0
- psychopy/app/locale/zh_CN/LC_MESSAGE/zh_CN_allFlagged.po +0 -7366
- psychopy/core.py.orig +0 -169
- psychopy/demos/builder/.DS_Store +0 -0
- psychopy/demos/builder/Design Templates/randomisedBlocks/html/index.html +0 -23
- psychopy/demos/builder/Design Templates/randomisedBlocks/html/randomisedBlocks-legacy-browsers.js +0 -423
- psychopy/demos/builder/Design Templates/randomisedBlocks/html/randomisedBlocks.js +0 -427
- psychopy/demos/builder/Design Templates/randomisedBlocks/html/resources/chooseBlock.xlsx +0 -0
- psychopy/demos/builder/Design Templates/randomisedBlocks/html/resources/facesBlock.xlsx +0 -0
- psychopy/demos/builder/Design Templates/randomisedBlocks/html/resources/housesBlock.xlsx +0 -0
- psychopy/demos/builder/Design Templates/randomisedBlocks/html/resources/stims/face01.jpg +0 -0
- psychopy/demos/builder/Design Templates/randomisedBlocks/html/resources/stims/face02.jpg +0 -0
- psychopy/demos/builder/Design Templates/randomisedBlocks/html/resources/stims/face03.jpg +0 -0
- psychopy/demos/builder/Design Templates/randomisedBlocks/html/resources/stims/house01.jpg +0 -0
- psychopy/demos/builder/Design Templates/randomisedBlocks/html/resources/stims/house02.jpg +0 -0
- psychopy/demos/builder/Design Templates/randomisedBlocks/html/resources/stims/house03.jpg +0 -0
- psychopy/demos/builder/Design Templates/randomisedBlocks/randomisedBlocks.py +0 -330
- psychopy/demos/builder/Design Templates/randomisedBlocks/randomisedBlocks_lastrun.py +0 -330
- psychopy/demos/builder/Experiments/.DS_Store +0 -0
- psychopy/demos/builder/Experiments/dragAndDrop/archived_conditions.xlsx +0 -0
- psychopy/demos/builder/Experiments/dragAndDrop/draw grid stim.py +0 -61
- psychopy/demos/builder/Experiments/dragAndDrop/shapeMaker.psyexp +0 -91
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/grid_image_1.png +0 -0
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/grid_image_10.png +0 -0
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/grid_image_2.png +0 -0
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/grid_image_3.png +0 -0
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/grid_image_4.png +0 -0
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/grid_image_5.png +0 -0
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/grid_image_6.png +0 -0
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/grid_image_7.png +0 -0
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/grid_image_8.png +0 -0
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/grid_image_9.png +0 -0
- psychopy/demos/builder/Experiments/dragAndDrop/updated_conditions.xlsx +0 -0
- psychopy/demos/builder/Feature Demos/eyetracking/eyetracking.xsd +0 -120
- psychopy/demos/builder/Tools/.DS_Store +0 -0
- psychopy/demos/builder/Tools/gammaCalibration/.DS_Store +0 -0
- psychopy/demos/builder/Tools/gammaCalibration/data/.DS_Store +0 -0
- psychopy/demos/builder/Tools/gammaCalibration/data/_gamma_correction_visual_2022-05-18_14h18.29.439.csv +0 -38
- psychopy/demos/builder/Tools/gammaCalibration/data/_gamma_correction_visual_2022-05-18_14h18.29.439.log +0 -3418
- psychopy/demos/builder/Tools/gammaCalibration/data/_gamma_correction_visual_2022-05-18_14h18.29.439.psydat +0 -0
- psychopy/demos/builder/Tools/gammaCalibration/data/x1_gamma_correction_visual_2022-05-17_13h59.42.928.csv +0 -2
- psychopy/demos/builder/Tools/gammaCalibration/data/x1_gamma_correction_visual_2022-05-17_13h59.42.928.log +0 -15
- psychopy/demos/builder/Tools/gammaCalibration/data/x1_gamma_correction_visual_2022-05-17_13h59.42.928.psydat +0 -0
- psychopy/demos/builder/Tools/gammaCalibration/gamma_correction_visual.psyexp +0 -323
- psychopy/demos/builder/Tools/gammaCalibration/gamma_correction_visual.py +0 -562
- psychopy/demos/builder/Tools/gammaCalibration/gamma_correction_visual_lastrun.py +0 -562
- psychopy/demos/builder/Tools/gammaCalibration/questStairs.xlsx +0 -0
- psychopy/demos/builder/Tools/gammaCalibration/resources/low_contrast.png +0 -0
- psychopy/demos/builder/Tools/gammaCalibration/resources/make_2nd_order_tex.py +0 -59
- psychopy/demos/builder/Tools/gammaCalibration/resources/second_order_tex.png +0 -0
- psychopy/demos/coder/.DS_Store +0 -0
- psychopy/demos/coder/experiment control/info_gamma.pickle +0 -0
- psychopy/demos/coder/iohub/.iohpid +0 -1
- psychopy/demos/coder/iohub/eyetracking/.iohpid +0 -1
- psychopy/demos/coder/iohub/wintab/.DS_Store +0 -0
- psychopy/demos/coder/stimuli/.DS_Store +0 -0
- psychopy/demos/coder/stimuli/radialGratingContracting.py +0 -29
- psychopy/experiment/_experiment.py.orig +0 -1032
- psychopy/experiment/components/.DS_Store +0 -0
- psychopy/experiment/components/_base.py.orig +0 -823
- psychopy/experiment/components/form/.DS_Store +0 -0
- psychopy/experiment/components/microphone/__init__.py.orig +0 -490
- psychopy/experiment/components/settings/__init__.py.orig +0 -1337
- psychopy/experiment/components/textbox/__init__.py.orig +0 -310
- psychopy/experiment/components/webcam/.DS_Store +0 -0
- psychopy/experiment/components/webcam/light/.DS_Store +0 -0
- psychopy/experiment/loops.py.orig +0 -829
- psychopy/experiment/params.py.orig +0 -408
- psychopy/experiment/routine.py.orig +0 -503
- psychopy/experiment/routines/photodiodeValidator/classic/photodiode_validator.png +0 -0
- psychopy/experiment/routines/photodiodeValidator/classic/photodiode_validator@2x.png +0 -0
- psychopy/experiment/routines/photodiodeValidator/dark/photodiode_validator.png +0 -0
- psychopy/experiment/routines/photodiodeValidator/dark/photodiode_validator@2x.png +0 -0
- psychopy/experiment/routines/photodiodeValidator/light/photodiode_validator.png +0 -0
- psychopy/experiment/routines/photodiodeValidator/light/photodiode_validator@2x.png +0 -0
- psychopy/hardware/.DS_Store +0 -0
- psychopy/hardware/brainproducts.py.orig +0 -680
- psychopy/hardware/iolab.py.orig +0 -238
- psychopy/hardware/serialport.py +0 -51
- psychopy/iohub/datastore/__init__.py.orig +0 -443
- psychopy/iohub/datastore/util.py.orig +0 -692
- psychopy/iohub/devices/mouse/darwin.py.orig +0 -427
- psychopy/iohub/devices/mouse/linux2.py.orig +0 -198
- psychopy/preferences/.DS_Store +0 -0
- psychopy/projects/pavlovia.py.orig +0 -1295
- psychopy/tests/.DS_Store +0 -0
- psychopy/tests/data/.DS_Store +0 -0
- psychopy/tests/data/TestCircle_fill_local.png +0 -0
- psychopy/tests/data/__test.png +0 -0
- psychopy/tests/data/aperture1_normHexbackground_local.png +0 -0
- psychopy/tests/data/aperture1_norm_local.png +0 -0
- psychopy/tests/data/aperture2_normHexbackground_local.png +0 -0
- psychopy/tests/data/beatandrcos_height_local.png +0 -0
- psychopy/tests/data/beatandrcos_normAddBlend_local.png +0 -0
- psychopy/tests/data/beatandrcos_normHexbackground_local.png +0 -0
- psychopy/tests/data/beatandrcos_norm_local.png +0 -0
- psychopy/tests/data/beatandrcos_stencil_local.png +0 -0
- psychopy/tests/data/blend_add_height_local.png +0 -0
- psychopy/tests/data/blend_add_normAddBlend_local.png +0 -0
- psychopy/tests/data/blend_add_normHexbackground_local.png +0 -0
- psychopy/tests/data/blend_add_normNoShade_local.png +0 -0
- psychopy/tests/data/blend_add_norm_local.png +0 -0
- psychopy/tests/data/blend_add_stencil_local.png +0 -0
- psychopy/tests/data/bufferimg_gabor_height_local.png +0 -0
- psychopy/tests/data/bufferimg_gabor_normAddBlend_local.png +0 -0
- psychopy/tests/data/bufferimg_gabor_normHexbackground_local.png +0 -0
- psychopy/tests/data/bufferimg_gabor_normNoShade_local.png +0 -0
- psychopy/tests/data/bufferimg_gabor_norm_local.png +0 -0
- psychopy/tests/data/bufferimg_gabor_stencil_local.png +0 -0
- psychopy/tests/data/circleHex_height_local.png +0 -0
- psychopy/tests/data/circleHex_normAddBlend_local.png +0 -0
- psychopy/tests/data/circleHex_normHexbackground_local.png +0 -0
- psychopy/tests/data/circleHex_normNoShade_local.png +0 -0
- psychopy/tests/data/circleHex_norm_local.png +0 -0
- psychopy/tests/data/circleHex_stencil_local.png +0 -0
- psychopy/tests/data/color_comparison_local.png +0 -0
- psychopy/tests/data/corrFullRandom_local.csv +0 -16
- psychopy/tests/data/corrFullRandom_local.tsv +0 -6
- psychopy/tests/data/correctScript/.DS_Store +0 -0
- psychopy/tests/data/dots_height_local.png +0 -0
- psychopy/tests/data/dots_normAddBlend_local.png +0 -0
- psychopy/tests/data/dots_normHexbackground_local.png +0 -0
- psychopy/tests/data/dots_normNoShade_local.png +0 -0
- psychopy/tests/data/dots_norm_local.png +0 -0
- psychopy/tests/data/dots_stencil_local.png +0 -0
- psychopy/tests/data/elarray1_height_local.png +0 -0
- psychopy/tests/data/elarray1_normAddBlend_local.png +0 -0
- psychopy/tests/data/elarray1_normHexbackground_local.png +0 -0
- psychopy/tests/data/elarray1_norm_local.png +0 -0
- psychopy/tests/data/elarray1_stencil_local.png +0 -0
- psychopy/tests/data/envelopeandrcos_height_local.png +0 -0
- psychopy/tests/data/envelopeandrcos_normAddBlend_local.png +0 -0
- psychopy/tests/data/envelopeandrcos_normHexbackground_local.png +0 -0
- psychopy/tests/data/envelopeandrcos_norm_local.png +0 -0
- psychopy/tests/data/envelopeandrcos_stencil_local.png +0 -0
- psychopy/tests/data/envelopepowerandrcos_height_local.png +0 -0
- psychopy/tests/data/envelopepowerandrcos_normAddBlend_local.png +0 -0
- psychopy/tests/data/envelopepowerandrcos_normHexbackground_local.png +0 -0
- psychopy/tests/data/envelopepowerandrcos_norm_local.png +0 -0
- psychopy/tests/data/envelopepowerandrcos_stencil_local.png +0 -0
- psychopy/tests/data/gabor1_height_local.png +0 -0
- psychopy/tests/data/gabor1_normAddBlend_local.png +0 -0
- psychopy/tests/data/gabor1_normHexbackground_local.png +0 -0
- psychopy/tests/data/gabor1_normNoShade_local.png +0 -0
- psychopy/tests/data/gabor1_norm_local.png +0 -0
- psychopy/tests/data/gabor1_stencil_local.png +0 -0
- psychopy/tests/data/greyscale_normHexbackground_local.png +0 -0
- psychopy/tests/data/imageAndGauss_height_local.png +0 -0
- psychopy/tests/data/imageAndGauss_normAddBlend_local.png +0 -0
- psychopy/tests/data/imageAndGauss_normHexbackground_local.png +0 -0
- psychopy/tests/data/imageAndGauss_normNoShade_local.png +0 -0
- psychopy/tests/data/imageAndGauss_norm_local.png +0 -0
- psychopy/tests/data/imageAndGauss_stencil_local.png +0 -0
- psychopy/tests/data/movFrame1_stencil_local.png +0 -0
- psychopy/tests/data/noiseAndRcos_height_local.png +0 -0
- psychopy/tests/data/noiseAndRcos_normAddBlend_local.png +0 -0
- psychopy/tests/data/noiseAndRcos_normHexbackground_local.png +0 -0
- psychopy/tests/data/noiseAndRcos_normNoShade_local.png +0 -0
- psychopy/tests/data/noiseAndRcos_norm_local.png +0 -0
- psychopy/tests/data/noiseAndRcos_stencil_local.png +0 -0
- psychopy/tests/data/noiseFiltersAndRcos_height_local.png +0 -0
- psychopy/tests/data/noiseFiltersAndRcos_normAddBlend_local.png +0 -0
- psychopy/tests/data/noiseFiltersAndRcos_normHexbackground_local.png +0 -0
- psychopy/tests/data/noiseFiltersAndRcos_normNoShade_local.png +0 -0
- psychopy/tests/data/noiseFiltersAndRcos_norm_local.png +0 -0
- psychopy/tests/data/noiseFiltersAndRcos_stencil_local.png +0 -0
- psychopy/tests/data/numpyImage_height_local.png +0 -0
- psychopy/tests/data/numpyImage_normAddBlend_local.png +0 -0
- psychopy/tests/data/numpyImage_normHexbackground_local.png +0 -0
- psychopy/tests/data/numpyImage_normNoShade_local.png +0 -0
- psychopy/tests/data/numpyImage_norm_local.png +0 -0
- psychopy/tests/data/numpyImage_stencil_local.png +0 -0
- psychopy/tests/data/shape2_1_normAddBlend_local.png +0 -0
- psychopy/tests/data/shape2_1_normHexbackground_local.png +0 -0
- psychopy/tests/data/shape2_1_normNoShade_local.png +0 -0
- psychopy/tests/data/shape2_1_norm_local.png +0 -0
- psychopy/tests/data/shape2_1_stencil_local.png +0 -0
- psychopy/tests/data/testLoopsBlocks.psyexp_local.py +0 -328
- psychopy/tests/data/text1_height_local.png +0 -0
- psychopy/tests/data/text1_normAddBlend_local.png +0 -0
- psychopy/tests/data/text1_normHexbackground_local.png +0 -0
- psychopy/tests/data/text1_norm_local.png +0 -0
- psychopy/tests/data/text1_stencil_local.png +0 -0
- psychopy/tests/data/text2_height.png +0 -0
- psychopy/tests/data/text2_normAddBlend.png +0 -0
- psychopy/tests/data/text2_normHexbackground.png +0 -0
- psychopy/tests/data/text2_stencil.png +0 -0
- psychopy/tests/data/wedge1_height_local.png +0 -0
- psychopy/tests/data/wedge1_normAddBlend_local.png +0 -0
- psychopy/tests/data/wedge1_normHexbackground_local.png +0 -0
- psychopy/tests/data/wedge1_normNoShade_local.png +0 -0
- psychopy/tests/data/wedge1_norm_local.png +0 -0
- psychopy/tests/data/wedge1_stencil_local.png +0 -0
- psychopy/tests/test_app/.DS_Store +0 -0
- psychopy/tests/test_app/test_builder/.DS_Store +0 -0
- psychopy/tests/test_app/test_builder/data/_2021_ 5_03_1206.csv +0 -9
- psychopy/tests/test_app/test_builder/data/_2021_ 5_03_1206.log +0 -177
- psychopy/tests/test_app/test_builder/data/_2021_ 5_03_1206.psydat +0 -0
- psychopy/tests/test_app/test_builder/data/_2021_ 5_03_1206.xlsx +0 -0
- psychopy/tests/test_app/test_builder/data/_2021_ 5_03_1324.csv +0 -9
- psychopy/tests/test_app/test_builder/data/_2021_ 5_03_1324.log +0 -168
- psychopy/tests/test_app/test_builder/data/_2021_ 5_03_1324.psydat +0 -0
- psychopy/tests/test_app/test_builder/data/_2021_ 5_03_1324.xlsx +0 -0
- psychopy/tests/test_data/.DS_Store +0 -0
- psychopy/tests/test_hardware/test_CRS_BitsSharp.py +0 -67
- psychopy/tests/test_hardware/test_CRS_BitsSharp.py.orig +0 -68
- psychopy/tests/test_hardware/test_CRS_bitsShaders.py +0 -110
- psychopy/tests/test_visual/test_image.py.orig +0 -219
- psychopy/visual/basevisual.py.orig +0 -1723
- psychopy/visual/form.py.orig +0 -1181
- psychopy/visual/text.py.orig +0 -752
- psychopy/visual/textbox2/textbox2.py.orig +0 -1315
- psychopy/visual/windowwarp.py.orig +0 -463
- /psychopy/{app/cortex.log → alerts/alertsCatalogue/3600.yaml} +0 -0
- /psychopy/{app/Resources → assets}/fonts/Arvo-Bold.ttf +0 -0
- /psychopy/{app/Resources → assets}/fonts/Arvo-BoldItalic.ttf +0 -0
- /psychopy/{app/Resources → assets}/fonts/Arvo-Italic.ttf +0 -0
- /psychopy/{app/Resources → assets}/fonts/Arvo-Regular.ttf +0 -0
- /psychopy/{app/Resources → assets}/fonts/DejaVuSerif.ttf +0 -0
- /psychopy/{app/Resources → assets}/fonts/IndieFlower-Regular.ttf +0 -0
- /psychopy/{app/Resources → assets}/fonts/JetBrainsMono-Italic-VariableFont_wght.ttf +0 -0
- /psychopy/{app/Resources → assets}/fonts/JetBrainsMono-VariableFont_wght.ttf +0 -0
- /psychopy/demos/builder/Experiments/{GoNoGo → goNoGo}/readme.md +0 -0
- /psychopy/{demos/builder/Tools/gammaCalibration/readme.md → tests/test_plugins/__init__.py} +0 -0
- {psychopy-2024.2.4.dist-info → psychopy-2025.1.0.dist-info}/WHEEL +0 -0
- {psychopy-2024.2.4.dist-info → psychopy-2025.1.0.dist-info}/entry_points.txt +0 -0
- {psychopy-2024.2.4.dist-info → psychopy-2025.1.0.dist-info}/licenses/LICENSE +0 -0
psychopy/sound/backend_ptb.py
CHANGED
|
@@ -14,10 +14,12 @@ from pathlib import Path
|
|
|
14
14
|
from psychopy import prefs, logging, exceptions
|
|
15
15
|
from psychopy.constants import (STARTED, PAUSED, FINISHED, STOPPING,
|
|
16
16
|
NOT_STARTED)
|
|
17
|
+
from psychopy.hardware.speaker import SpeakerDevice
|
|
17
18
|
from psychopy.tools import systemtools
|
|
18
19
|
from psychopy.tools import filetools as ft
|
|
19
20
|
from .exceptions import SoundFormatError, DependencyError
|
|
20
21
|
from ._base import _SoundBase, HammingWindow
|
|
22
|
+
from .audioclip import AudioClip
|
|
21
23
|
from ..hardware import DeviceManager
|
|
22
24
|
|
|
23
25
|
try:
|
|
@@ -32,18 +34,8 @@ except Exception:
|
|
|
32
34
|
|
|
33
35
|
import numpy as np
|
|
34
36
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
except (TypeError, IndexError): # maybe we were given a number instead
|
|
38
|
-
defaultLatencyClass = prefs.hardware['audioLatencyMode']
|
|
39
|
-
"""vals in prefs.hardware['audioLatencyMode'] are:
|
|
40
|
-
{0:_translate('Latency not important'),
|
|
41
|
-
1:_translate('Share low-latency driver'),
|
|
42
|
-
2:_translate('Exclusive low-latency'),
|
|
43
|
-
3:_translate('Aggressive low-latency'),
|
|
44
|
-
4:_translate('Latency critical')}
|
|
45
|
-
Based on help at http://psychtoolbox.org/docs/PsychPortAudio-Open
|
|
46
|
-
"""
|
|
37
|
+
|
|
38
|
+
defaultLatencyClass = 1
|
|
47
39
|
# suggestedLatency = 0.005 ## Not currently used. Keep < 1 scr refresh
|
|
48
40
|
|
|
49
41
|
if prefs.hardware['audioDriver']=='auto':
|
|
@@ -56,6 +48,15 @@ if prefs.hardware['audioDevice']=='auto':
|
|
|
56
48
|
else:
|
|
57
49
|
audioDevice = prefs.hardware['audioDevice']
|
|
58
50
|
|
|
51
|
+
# check if we should only use WAS host API (default is True on Windows)
|
|
52
|
+
audioWASAPIOnly = False
|
|
53
|
+
try:
|
|
54
|
+
wasapiPref = prefs.hardware['audioWASAPIOnly']
|
|
55
|
+
except KeyError:
|
|
56
|
+
wasapiPref = False
|
|
57
|
+
if sys.platform == 'win32' and wasapiPref:
|
|
58
|
+
audioWASAPIOnly = True
|
|
59
|
+
|
|
59
60
|
# these will be used by sound.__init__.py
|
|
60
61
|
defaultInput = None
|
|
61
62
|
defaultOutput = audioDevice
|
|
@@ -80,208 +81,6 @@ def init(rate=48000, stereo=True, buffer=128):
|
|
|
80
81
|
pass # for compatibility with other backends
|
|
81
82
|
|
|
82
83
|
|
|
83
|
-
def getDevices(kind=None):
|
|
84
|
-
"""Returns a dict of dict of audio devices of specified `kind`
|
|
85
|
-
|
|
86
|
-
kind can be None, 'input' or 'output'
|
|
87
|
-
The dict keys are names, and items are dicts of properties
|
|
88
|
-
"""
|
|
89
|
-
if sys.platform == 'win32':
|
|
90
|
-
deviceTypes = 13 # only WASAPI drivers need apply!
|
|
91
|
-
else:
|
|
92
|
-
deviceTypes = None
|
|
93
|
-
devs = {}
|
|
94
|
-
if systemtools.isVM_CI(): # GitHub actions VM does not have a sound device
|
|
95
|
-
return devs
|
|
96
|
-
else:
|
|
97
|
-
allDevs = audio.get_devices(device_type=deviceTypes)
|
|
98
|
-
|
|
99
|
-
# annoyingly query_devices is a DeviceList or a dict depending on number
|
|
100
|
-
if isinstance(allDevs, dict):
|
|
101
|
-
allDevs = [allDevs]
|
|
102
|
-
|
|
103
|
-
for ii, dev in enumerate(allDevs):
|
|
104
|
-
if kind and kind.startswith('in'):
|
|
105
|
-
if dev['NrInputChannels'] < 1:
|
|
106
|
-
continue
|
|
107
|
-
elif kind and kind.startswith('out'):
|
|
108
|
-
if dev['NrOutputChannels'] < 1:
|
|
109
|
-
continue
|
|
110
|
-
# we have a valid device so get its name
|
|
111
|
-
# newline characters must be removed
|
|
112
|
-
devName = dev['DeviceName'].replace('\r\n', '')
|
|
113
|
-
devs[devName] = dev
|
|
114
|
-
dev['id'] = ii
|
|
115
|
-
return devs
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
def getStreamLabel(sampleRate, channels, blockSize):
|
|
119
|
-
"""Returns the string repr of the stream label
|
|
120
|
-
"""
|
|
121
|
-
return "{}_{}_{}".format(sampleRate, channels, blockSize)
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
class _StreamsDict(dict):
|
|
125
|
-
"""Keeps track of what streams have been created. On macOS we can have
|
|
126
|
-
multiple streams under portaudio but under windows we can only have one.
|
|
127
|
-
|
|
128
|
-
use the instance `streams` rather than creating a new instance of this
|
|
129
|
-
"""
|
|
130
|
-
|
|
131
|
-
def getStream(self, sampleRate, channels, blockSize):
|
|
132
|
-
"""Gets a stream of exact match or returns a new one
|
|
133
|
-
(if possible for the current operating system)
|
|
134
|
-
"""
|
|
135
|
-
# if the query looks flexible then try getSimilar
|
|
136
|
-
if channels == -1 or blockSize == -1:
|
|
137
|
-
return self._getSimilar(sampleRate,
|
|
138
|
-
channels=channels,
|
|
139
|
-
blockSize=blockSize)
|
|
140
|
-
else:
|
|
141
|
-
return self._getStream(sampleRate,
|
|
142
|
-
channels=channels,
|
|
143
|
-
blockSize=blockSize)
|
|
144
|
-
|
|
145
|
-
def _getSimilar(self, sampleRate, channels=-1, blockSize=-1):
|
|
146
|
-
"""Do we already have a compatible stream?
|
|
147
|
-
|
|
148
|
-
Many sounds can allow channels and blocksize to change but samplerate
|
|
149
|
-
is generally fixed. Any values set to -1 above will be flexible. Any
|
|
150
|
-
values set to an alternative number will be fixed
|
|
151
|
-
|
|
152
|
-
usage:
|
|
153
|
-
|
|
154
|
-
label, stream = streams._getSimilar(sampleRate=44100, # must match
|
|
155
|
-
channels=-1, # any
|
|
156
|
-
blockSize=-1) # wildcard
|
|
157
|
-
"""
|
|
158
|
-
label = getStreamLabel(sampleRate, channels, blockSize)
|
|
159
|
-
# replace -1 with any regex integer
|
|
160
|
-
simil = re.compile(label.replace("-1", r"[-+]?(\d+)")) # I hate REGEX!
|
|
161
|
-
for thisFormat in self:
|
|
162
|
-
if simil.match(thisFormat): # we found a close-enough match
|
|
163
|
-
return thisFormat, self[thisFormat]
|
|
164
|
-
# if we've been given values in each place then create stream
|
|
165
|
-
if (sampleRate not in [None, -1, 0] and
|
|
166
|
-
channels not in [None, -1] and
|
|
167
|
-
blockSize not in [None, -1]):
|
|
168
|
-
return self._getStream(sampleRate, channels, blockSize)
|
|
169
|
-
|
|
170
|
-
def _getStream(self, sampleRate, channels, blockSize):
|
|
171
|
-
"""Strict check for this format or create new
|
|
172
|
-
"""
|
|
173
|
-
label = getStreamLabel(sampleRate, channels, blockSize)
|
|
174
|
-
# try to retrieve existing stream of that name
|
|
175
|
-
if label in self:
|
|
176
|
-
pass
|
|
177
|
-
# todo: check if this is still needed on win32
|
|
178
|
-
# on some systems more than one stream isn't supported so check
|
|
179
|
-
elif sys.platform == 'win32' and len(self):
|
|
180
|
-
raise SoundFormatError(
|
|
181
|
-
"Tried to create audio stream {} but {} already exists "
|
|
182
|
-
"and {} doesn't support multiple portaudio streams"
|
|
183
|
-
.format(label, list(self.keys())[0], sys.platform)
|
|
184
|
-
)
|
|
185
|
-
else:
|
|
186
|
-
|
|
187
|
-
# create new stream
|
|
188
|
-
self[label] = _MasterStream(sampleRate, channels, blockSize,
|
|
189
|
-
device=defaultOutput)
|
|
190
|
-
return label, self[label]
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
streams = _StreamsDict()
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
class _MasterStream(audio.Stream):
|
|
197
|
-
def __init__(self, sampleRate, channels, blockSize,
|
|
198
|
-
device=None, duplex=False, mode=1,
|
|
199
|
-
audioLatencyClass=None):
|
|
200
|
-
# initialise thread
|
|
201
|
-
if audioLatencyClass is None:
|
|
202
|
-
audioLatencyClass = defaultLatencyClass
|
|
203
|
-
self.streamLabel = None
|
|
204
|
-
self.streams = []
|
|
205
|
-
self.list = []
|
|
206
|
-
# sound stream info
|
|
207
|
-
self.sampleRate = sampleRate
|
|
208
|
-
self.channels = channels
|
|
209
|
-
self.duplex = duplex
|
|
210
|
-
self.blockSize = blockSize
|
|
211
|
-
self.label = getStreamLabel(sampleRate, channels, blockSize)
|
|
212
|
-
if isinstance(device, list) and len(device):
|
|
213
|
-
device = device[0]
|
|
214
|
-
if isinstance(device, str): # we need to convert name to an ID or make None
|
|
215
|
-
devs = getDevices('output')
|
|
216
|
-
if device in devs:
|
|
217
|
-
deviceID = devs[device]['DeviceIndex']
|
|
218
|
-
else:
|
|
219
|
-
deviceID = None
|
|
220
|
-
else:
|
|
221
|
-
deviceID = device
|
|
222
|
-
self.sounds = [] # list of dicts for sounds currently playing
|
|
223
|
-
self.takeTimeStamp = False
|
|
224
|
-
self.frameN = 1
|
|
225
|
-
# self.frameTimes = range(5) # DEBUGGING: store the last 5 callbacks
|
|
226
|
-
if not systemtools.isVM_CI(): # Github Actions VM does not have a sound device
|
|
227
|
-
try:
|
|
228
|
-
audio.Stream.__init__(self, device_id=deviceID, mode=mode+8,
|
|
229
|
-
latency_class=audioLatencyClass,
|
|
230
|
-
freq=sampleRate,
|
|
231
|
-
channels=channels,
|
|
232
|
-
) # suggested_latency=suggestedLatency
|
|
233
|
-
except OSError as e: # noqa: F841
|
|
234
|
-
audio.Stream.__init__(self, device_id=deviceID, mode=mode+8,
|
|
235
|
-
latency_class=audioLatencyClass,
|
|
236
|
-
# freq=sampleRate,
|
|
237
|
-
channels=channels,
|
|
238
|
-
)
|
|
239
|
-
self.sampleRate = self.status['SampleRate']
|
|
240
|
-
print("Failed to start PTB.audio with requested rate of "
|
|
241
|
-
"{} but succeeded with a default rate ({}). "
|
|
242
|
-
"This is depends on the selected latency class and device."
|
|
243
|
-
.format(sampleRate, self.sampleRate))
|
|
244
|
-
except TypeError as e:
|
|
245
|
-
print("device={}, mode={}, latency_class={}, freq={}, channels={}"
|
|
246
|
-
.format(device, mode+8, audioLatencyClass, sampleRate, channels))
|
|
247
|
-
raise e
|
|
248
|
-
except Exception as e:
|
|
249
|
-
if deviceID == -1:
|
|
250
|
-
# if default device doesn't setup from ptb, pick first device
|
|
251
|
-
for device in audio.get_devices(device_type=13):
|
|
252
|
-
logging.error(
|
|
253
|
-
f"System default audio device failed to connect, so using first found "
|
|
254
|
-
f"device: {device['DeviceName']}"
|
|
255
|
-
)
|
|
256
|
-
audio.Stream.__init__(
|
|
257
|
-
self,mode=mode+8,
|
|
258
|
-
device_id=device['DeviceIndex'],
|
|
259
|
-
freq=device['DefaultSampleRate'],
|
|
260
|
-
channels=device['NrOutputChannels']
|
|
261
|
-
)
|
|
262
|
-
break
|
|
263
|
-
else:
|
|
264
|
-
# any other problem, try with no device ID
|
|
265
|
-
audio.Stream.__init__(
|
|
266
|
-
self, mode=mode+8,
|
|
267
|
-
latency_class=audioLatencyClass,
|
|
268
|
-
freq=sampleRate,
|
|
269
|
-
channels=channels,
|
|
270
|
-
)
|
|
271
|
-
|
|
272
|
-
if "there isn't any audio output device" in str(e):
|
|
273
|
-
print("Failed to load audio device:\n"
|
|
274
|
-
" '{}'\n"
|
|
275
|
-
"so fetching default audio device instead: \n"
|
|
276
|
-
" '{}'"
|
|
277
|
-
.format(device, 'test'))
|
|
278
|
-
self.start(0, 0, 1)
|
|
279
|
-
# self.device = self._sdStream.device
|
|
280
|
-
# self.latency = self._sdStream.latency
|
|
281
|
-
# self.cpu_load = self._sdStream.cpu_load
|
|
282
|
-
self._tSoundRequestPlay = 0
|
|
283
|
-
|
|
284
|
-
|
|
285
84
|
class SoundPTB(_SoundBase):
|
|
286
85
|
"""Play a variety of sounds using the new PsychPortAudio library
|
|
287
86
|
"""
|
|
@@ -321,7 +120,14 @@ class SoundPTB(_SoundBase):
|
|
|
321
120
|
:param autoLog: whether to automatically log every change
|
|
322
121
|
:param syncToWin: if you want start/stop to sync with win flips add this
|
|
323
122
|
"""
|
|
324
|
-
|
|
123
|
+
# if given the name of a managed speaker, get it
|
|
124
|
+
if isinstance(speaker, str) and DeviceManager.getDevice(speaker):
|
|
125
|
+
speaker = DeviceManager.getDevice(speaker)
|
|
126
|
+
# make sure speaker is a SpeakerDevice
|
|
127
|
+
if not isinstance(speaker, SpeakerDevice):
|
|
128
|
+
speaker = SpeakerDevice(speaker)
|
|
129
|
+
self.speaker = speaker
|
|
130
|
+
|
|
325
131
|
self.sound = value
|
|
326
132
|
self.name = name
|
|
327
133
|
self.secs = secs # for any synthesised sounds (notesand freqs)
|
|
@@ -340,7 +146,6 @@ class SoundPTB(_SoundBase):
|
|
|
340
146
|
self.stereo = stereo
|
|
341
147
|
self.duplex = None
|
|
342
148
|
self.autoLog = autoLog
|
|
343
|
-
self.streamLabel = ""
|
|
344
149
|
self.sourceType = 'unknown' # set to be file, array or freq
|
|
345
150
|
self.sndFile = None
|
|
346
151
|
self.sndArr = None
|
|
@@ -366,13 +171,6 @@ class SoundPTB(_SoundBase):
|
|
|
366
171
|
"""`True` if the audio playback has completed."""
|
|
367
172
|
return self._checkPlaybackFinished()
|
|
368
173
|
|
|
369
|
-
def _getDefaultSampleRate(self):
|
|
370
|
-
"""Check what streams are open and use one of these"""
|
|
371
|
-
if len(streams):
|
|
372
|
-
return list(streams.values())[0].sampleRate
|
|
373
|
-
else:
|
|
374
|
-
return 48000 # seems most widely supported
|
|
375
|
-
|
|
376
174
|
@property
|
|
377
175
|
def statusDetailed(self):
|
|
378
176
|
if not self.track:
|
|
@@ -400,7 +198,12 @@ class SoundPTB(_SoundBase):
|
|
|
400
198
|
|
|
401
199
|
@stereo.setter
|
|
402
200
|
def stereo(self, val):
|
|
201
|
+
# if auto, get from speaker
|
|
202
|
+
if val == -1:
|
|
203
|
+
val = self.speaker.channels > 1
|
|
204
|
+
# store value
|
|
403
205
|
self.__dict__['stereo'] = val
|
|
206
|
+
# convert to n channels
|
|
404
207
|
if val is True:
|
|
405
208
|
self.__dict__['channels'] = 2
|
|
406
209
|
elif val is False:
|
|
@@ -438,84 +241,34 @@ class SoundPTB(_SoundBase):
|
|
|
438
241
|
self.loops = self._loopsRequested
|
|
439
242
|
# start with the base class method
|
|
440
243
|
_SoundBase.setSound(self, value, secs, octave, hamming, log)
|
|
441
|
-
|
|
442
|
-
def
|
|
443
|
-
#
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
self.
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
self.channels = f.channels
|
|
451
|
-
fileDuration = float(len(f)) / f.samplerate # needed for duration?
|
|
452
|
-
# process start time
|
|
453
|
-
if self.startTime and self.startTime > 0:
|
|
454
|
-
startFrame = self.startTime * self.sampleRate
|
|
455
|
-
self.sndFile.seek(int(startFrame))
|
|
456
|
-
self.t = self.startTime
|
|
457
|
-
else:
|
|
458
|
-
self.t = 0
|
|
459
|
-
# process stop time
|
|
460
|
-
if self.stopTime and self.stopTime > 0:
|
|
461
|
-
requestedDur = self.stopTime - self.t
|
|
462
|
-
self.duration = min(requestedDur, fileDuration)
|
|
463
|
-
else:
|
|
464
|
-
self.duration = fileDuration - self.t
|
|
465
|
-
# can now calculate duration in frames
|
|
466
|
-
self.durationFrames = int(round(self.duration * self.sampleRate))
|
|
467
|
-
# are we preloading or streaming?
|
|
468
|
-
if self.preBuffer == 0:
|
|
469
|
-
# no buffer - stream from disk on each call to nextBlock
|
|
470
|
-
pass
|
|
471
|
-
elif self.preBuffer == -1:
|
|
472
|
-
# full pre-buffer. Load requested duration to memory
|
|
473
|
-
sndArr = self.sndFile.read(
|
|
474
|
-
frames=int(self.sampleRate * self.duration))
|
|
475
|
-
self.sndFile.close()
|
|
476
|
-
self._setSndFromArray(sndArr)
|
|
477
|
-
self._channelCheck(
|
|
478
|
-
self.sndArr) # Check for fewer channels in stream vs data array
|
|
479
|
-
|
|
480
|
-
def _setSndFromArray(self, thisArray):
|
|
481
|
-
|
|
482
|
-
self.sndArr = np.asarray(thisArray).astype('float32')
|
|
483
|
-
if thisArray.ndim == 1:
|
|
484
|
-
self.sndArr.shape = [len(thisArray), 1] # make 2D for broadcasting
|
|
485
|
-
if self.channels == 2 and self.sndArr.shape[1] == 1: # mono -> stereo
|
|
486
|
-
self.sndArr = self.sndArr.repeat(2, axis=1)
|
|
487
|
-
elif self.sndArr.shape[1] == 1: # if channels in [-1,1] then pass
|
|
488
|
-
pass
|
|
489
|
-
else:
|
|
490
|
-
try:
|
|
491
|
-
self.sndArr.shape = [len(thisArray), 2]
|
|
492
|
-
except ValueError:
|
|
493
|
-
raise ValueError("Failed to format sound with shape {} "
|
|
494
|
-
"into sound with channels={}"
|
|
495
|
-
.format(self.sndArr.shape, self.channels))
|
|
496
|
-
|
|
497
|
-
# is this stereo?
|
|
498
|
-
if self.stereo == -1: # auto stereo. Try to detect
|
|
499
|
-
if self.sndArr.shape[1] == 1:
|
|
500
|
-
self.stereo = 0
|
|
501
|
-
elif self.sndArr.shape[1] == 2:
|
|
502
|
-
self.stereo = 1
|
|
503
|
-
else:
|
|
504
|
-
raise IOError("Couldn't determine whether array is "
|
|
505
|
-
"stereo. Shape={}".format(self.sndArr.shape))
|
|
506
|
-
self._nSamples = thisArray.shape[0]
|
|
244
|
+
|
|
245
|
+
def _setSndFromClip(self, clip: AudioClip):
|
|
246
|
+
# store clip
|
|
247
|
+
self.clip = clip
|
|
248
|
+
# resample the clip if needed and allowed
|
|
249
|
+
if self.speaker.resample:
|
|
250
|
+
if clip.sampleRateHz != self.speaker.sampleRateHz:
|
|
251
|
+
clip.resample(targetSampleRateHz=self.speaker.sampleRateHz)
|
|
252
|
+
# work out stop time
|
|
507
253
|
if self.stopTime == -1:
|
|
508
|
-
self.duration =
|
|
509
|
-
#
|
|
510
|
-
self.
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
if not self.track: # do we have one already?
|
|
514
|
-
self.track = audio.Slave(self.stream.handle, data=self.sndArr,
|
|
515
|
-
volume=self.volume)
|
|
254
|
+
self.duration = clip.samples.shape[0] / clip.sampleRateHz
|
|
255
|
+
# handle stereo/mono
|
|
256
|
+
if self.speaker.channels > 1:
|
|
257
|
+
clip = clip.asStereo()
|
|
516
258
|
else:
|
|
259
|
+
clip = clip.asMono()
|
|
260
|
+
# create/update track
|
|
261
|
+
if self.track:
|
|
517
262
|
self.track.stop()
|
|
518
|
-
self.track.fill_buffer(
|
|
263
|
+
self.track.fill_buffer(clip.samples)
|
|
264
|
+
else:
|
|
265
|
+
self.track = audio.Slave(
|
|
266
|
+
self.stream.handle,
|
|
267
|
+
data=clip.samples,
|
|
268
|
+
volume=self.volume
|
|
269
|
+
)
|
|
270
|
+
# seek to start
|
|
271
|
+
self.seek(0)
|
|
519
272
|
|
|
520
273
|
def _channelCheck(self, array):
|
|
521
274
|
"""Checks whether stream has fewer channels than data. If True, ValueError"""
|
|
@@ -570,7 +323,7 @@ class SoundPTB(_SoundBase):
|
|
|
570
323
|
self._isFinished = False
|
|
571
324
|
# time.sleep(0.)
|
|
572
325
|
if log and self.autoLog:
|
|
573
|
-
logging.exp(u"
|
|
326
|
+
logging.exp(u"Playing sound %s on speaker %s" % (self.name, self.speaker.name), obj=self, t=logTime)
|
|
574
327
|
|
|
575
328
|
def pause(self, log=True):
|
|
576
329
|
"""Stops the sound without reset, so that play will continue from here if needed
|
|
@@ -621,28 +374,7 @@ class SoundPTB(_SoundBase):
|
|
|
621
374
|
"""Read-only property returns the stream on which the sound
|
|
622
375
|
will be played
|
|
623
376
|
"""
|
|
624
|
-
|
|
625
|
-
try:
|
|
626
|
-
label, s = streams.getStream(sampleRate=self.sampleRate,
|
|
627
|
-
channels=self.channels,
|
|
628
|
-
blockSize=self.blockSize)
|
|
629
|
-
except SoundFormatError as err:
|
|
630
|
-
# try to use something similar (e.g. mono->stereo)
|
|
631
|
-
# then check we have an appropriate stream open
|
|
632
|
-
altern = streams._getSimilar(sampleRate=self.sampleRate,
|
|
633
|
-
channels=-1,
|
|
634
|
-
blockSize=-1)
|
|
635
|
-
if altern is None:
|
|
636
|
-
raise SoundFormatError(err)
|
|
637
|
-
else: # safe to extract data
|
|
638
|
-
label, s = altern
|
|
639
|
-
# update self in case it changed to fit the stream
|
|
640
|
-
self.sampleRate = s.sampleRate
|
|
641
|
-
self.channels = s.channels
|
|
642
|
-
self.blockSize = s.blockSize
|
|
643
|
-
self.streamLabel = label
|
|
644
|
-
|
|
645
|
-
return streams[self.streamLabel]
|
|
377
|
+
return self.speaker.stream
|
|
646
378
|
|
|
647
379
|
def __del__(self):
|
|
648
380
|
if self.track:
|
psychopy/sound/backend_pygame.py
CHANGED
|
@@ -153,7 +153,7 @@ class SoundPygame(_SoundBase):
|
|
|
153
153
|
hamming=False, speaker=None):
|
|
154
154
|
self.name = name # only needed for autoLogging
|
|
155
155
|
self.autoLog = autoLog
|
|
156
|
-
self.speaker =
|
|
156
|
+
self.speaker = speaker
|
|
157
157
|
|
|
158
158
|
if stereo == True:
|
|
159
159
|
stereoChans = 2
|
|
@@ -172,6 +172,8 @@ class SoundPygame(_SoundBase):
|
|
|
172
172
|
init()
|
|
173
173
|
inits = mixer.get_init()
|
|
174
174
|
self.sampleRate, self.format, self.isStereo = inits
|
|
175
|
+
self.startTime = 0
|
|
176
|
+
self.stopTime = secs
|
|
175
177
|
|
|
176
178
|
if hamming:
|
|
177
179
|
logging.warning("Hamming was requested using the 'pygame' sound "
|
|
@@ -285,9 +287,11 @@ class SoundPygame(_SoundBase):
|
|
|
285
287
|
logging.error(msg % fileName)
|
|
286
288
|
raise ValueError(msg % fileName)
|
|
287
289
|
|
|
288
|
-
def
|
|
289
|
-
|
|
290
|
+
def _setSndFromClip(self, clip):
|
|
291
|
+
self.clip = clip
|
|
292
|
+
thisArray = self.clip.samples
|
|
290
293
|
|
|
294
|
+
# get a mixer.Sound object from an array of floats (-1:1)
|
|
291
295
|
# make stereo if mono
|
|
292
296
|
if (self.isStereo == 2 and
|
|
293
297
|
(len(thisArray.shape) == 1 or
|
psychopy/sound/backend_pyo.py
CHANGED
|
@@ -8,26 +8,57 @@ These are optional components that can be obtained by installing the
|
|
|
8
8
|
|
|
9
9
|
"""
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
from .
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
11
|
+
|
|
12
|
+
from psychopy.plugins import PluginStub
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class SoundPyo(
|
|
16
|
+
PluginStub,
|
|
17
|
+
plugin="psychopy-pyo",
|
|
18
|
+
docsHome="https://github.com/psychopy/psychopy-pyo",
|
|
19
|
+
):
|
|
20
|
+
pass
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class init(
|
|
24
|
+
PluginStub,
|
|
25
|
+
plugin="psychopy-pyo",
|
|
26
|
+
docsHome="https://github.com/psychopy/psychopy-pyo",
|
|
27
|
+
):
|
|
28
|
+
pass
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class get_devices_infos(
|
|
32
|
+
PluginStub,
|
|
33
|
+
plugin="psychopy-pyo",
|
|
34
|
+
docsHome="https://github.com/psychopy/psychopy-pyo",
|
|
35
|
+
):
|
|
36
|
+
pass
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class get_input_devices(
|
|
40
|
+
PluginStub,
|
|
41
|
+
plugin="psychopy-pyo",
|
|
42
|
+
docsHome="https://github.com/psychopy/psychopy-pyo",
|
|
43
|
+
):
|
|
44
|
+
pass
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class get_output_devices(
|
|
48
|
+
PluginStub,
|
|
49
|
+
plugin="psychopy-pyo",
|
|
50
|
+
docsHome="https://github.com/psychopy/psychopy-pyo",
|
|
51
|
+
):
|
|
33
52
|
pass
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class getDevices(
|
|
56
|
+
PluginStub,
|
|
57
|
+
plugin="psychopy-pyo",
|
|
58
|
+
docsHome="https://github.com/psychopy/psychopy-pyo",
|
|
59
|
+
):
|
|
60
|
+
pass
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
pyoSndServer: SoundPyo
|
|
64
|
+
audioDriver: str
|
|
@@ -174,12 +174,14 @@ class SoundPySoundCard(_SoundBase):
|
|
|
174
174
|
self.name = name # only needed for autoLogging
|
|
175
175
|
self.autoLog = autoLog
|
|
176
176
|
|
|
177
|
-
self.speaker =
|
|
177
|
+
self.speaker = speaker
|
|
178
178
|
|
|
179
179
|
self.sampleRate = sampleRate
|
|
180
180
|
self.bufferSize = bufferSize
|
|
181
181
|
self.volume = volume
|
|
182
182
|
|
|
183
|
+
self.channels = 2
|
|
184
|
+
|
|
183
185
|
# try to create sound
|
|
184
186
|
self._snd = None
|
|
185
187
|
# distinguish the loops requested from loops actual because of
|
|
@@ -267,33 +269,13 @@ class SoundPySoundCard(_SoundBase):
|
|
|
267
269
|
attributetools.setAttribute(self, 'volume', value, log, operation)
|
|
268
270
|
return value # this is returned for historical reasons
|
|
269
271
|
|
|
270
|
-
def
|
|
271
|
-
# alias default names (so it always points to default.png)
|
|
272
|
-
if fileName in ft.defaultStim:
|
|
273
|
-
fileName = Path(prefs.paths['assets']) / ft.defaultStim[fileName]
|
|
274
|
-
# load the file
|
|
275
|
-
if not path.isfile(fileName):
|
|
276
|
-
msg = "Sound file %s could not be found." % fileName
|
|
277
|
-
logging.error(msg)
|
|
278
|
-
raise ValueError(msg)
|
|
279
|
-
self.fileName = fileName
|
|
280
|
-
# in case a tone with inf loops had been used before
|
|
281
|
-
self.loops = self.requestedLoops
|
|
282
|
-
try:
|
|
283
|
-
self.sndFile = sndfile.SoundFile(fileName)
|
|
284
|
-
sndArr = self.sndFile.read()
|
|
285
|
-
self.sndFile.close()
|
|
286
|
-
self._setSndFromArray(sndArr)
|
|
287
|
-
|
|
288
|
-
except Exception:
|
|
289
|
-
msg = "Sound file %s could not be opened using pysoundcard for sound."
|
|
290
|
-
logging.error(msg % fileName)
|
|
291
|
-
raise ValueError(msg % fileName)
|
|
292
|
-
|
|
293
|
-
def _setSndFromArray(self, thisArray):
|
|
272
|
+
def _setSndFromClip(self, clip):
|
|
294
273
|
"""For pysoundcard all sounds are ultimately played as an array so
|
|
295
274
|
other setSound methods are going to call this having created an arr
|
|
296
275
|
"""
|
|
276
|
+
self.clip = clip
|
|
277
|
+
thisArray = self.clip.samples
|
|
278
|
+
|
|
297
279
|
self._callbacks = _PySoundCallbackClass(sndInstance=self)
|
|
298
280
|
if defaultOutput is not None and type(defaultOutput) != int:
|
|
299
281
|
devs = getDevices()
|
|
@@ -307,7 +289,7 @@ class SoundPySoundCard(_SoundBase):
|
|
|
307
289
|
self._stream = soundcard.Stream(samplerate=self.sampleRate,
|
|
308
290
|
device=device,
|
|
309
291
|
blocksize=self.bufferSize,
|
|
310
|
-
channels=
|
|
292
|
+
channels=self.channels,
|
|
311
293
|
callback=self._callbacks.fillBuffer)
|
|
312
294
|
self._snd = self._stream
|
|
313
295
|
chansIn, chansOut = self._stream.channels
|
|
@@ -329,4 +311,5 @@ class SoundPySoundCard(_SoundBase):
|
|
|
329
311
|
self._isPlaying = False
|
|
330
312
|
|
|
331
313
|
def __del__(self):
|
|
332
|
-
self
|
|
314
|
+
if hasattr(self, "_stream"):
|
|
315
|
+
self._stream.close()
|