Replay stimulus multiple times in PsychoPy - psychopy

I'm building an experiment where in each trial, the subjects can replay stimulus as many times as they wish by pressing certain keys.
For example, there're 2 sounds: s1 and s2. s1 is associated with key 'a', and s2 is associated with key 'j'. Whenever the subject presses 'a', s1 will be played. Same for s2. Space bar is used to terminate the present trial and jump to the next trial.
Now I'm able to play stimulus after key press, by having '$event.getKeys('a')' in the condition field in s1 sound component, and '$event.getKeys('j')' in s2 sound component. But this will only play each stimulus once in a trial. The second time the keys are pressed, there are no sounds.
So my question is, what should I do so that in each trial, a stimulus can be played EACH time a designated key is pressed?

The Builder sound component is not ideal for this: as you noticed, if a condition is specified for the onset, it can only trigger the sound once per trial.
An alternative is to create a non-graphical sound object in a code component, and then check for key presses on every frame of each trial, and trigger the sound as required. Insert a Code component. In the "Begin Experiment" tab, put something like this:
j_sound = sound.Sound(u'A', secs=0.5)
a_sound = sound.Sound(u'B', secs=0.5)
Then, in the "Each frame" tab, put something like this:
response = event.getKeys(keyList=['a','j'])
if 'a' in response:
a_sound.play()
elif 'j' in response:
j_sound.play()
This could be improved to handle key presses made while a sound is already playing, but should get you started.

Related

Apex, Dynamic action, Confirm action, not picking up correct text - what am I missing?

I'm obviously missing something and hoping someone might be able to help.
I've an Interactive Grid, and a button.
When the button is pressed the dynamic action on the button has 2 steps.
Action 1 - Execute Javascript to take a value from one of the IG cells and put it into a page item.
Action 2 - Confirm Action - Are you sure you wish to delete &P10_JOB_ID.
I've made the page item, &P10_JOB_ID, visible and I can see the value has correctly been changed to the value from the IG.
I write P10_JOB_ID into a database table - I get the correct value
But the confirm message isn't picking up the correct value from P10_JOB_ID.
Namely it uses the value in P10_JOB_ID when the page starts, but then as I move around the IG pressing the button and changing the value of P10_JOB_ID, the text in the confirm message never changes.
Can anyone suggest what I might have missed, I'm baffled.
Thanks a lot
Substitutions like &P10_JOB_ID. are made when the page is rendered, not dynamically, so reflect the value at time of page load.
You will need to use Javascript to perform the conform action, something like:
apex.page.confirm ('Are you sure you wish to delete ' + $v('P10_JOB_ID') + '?', 'DELETE');
$v is an APEX Javascript function that returns the current value of a page item.
I used 'DELETE' as an example of a request value; you may want to do something different here.
Ok - having the setting of value and confirm as 2 separate actions is what causes the problem.
As per fac586
That is the expected behaviour. Static text substitutions are performed once during page show processing. They are not evaluated dynamically in the browser at runtime as values change.
Drop the second action and extend the first to display the confirm dialog using the apex.message.confirm JS API method, accessing the item value using the $v shorthand method.

videojs: How to get actual text of subtitle on 'cuechange'

I'm using videojs with some of the following code:
player.addRemoteTextTrack({ src: 'http://[somepath/to/vtt]' })
(I've verified that the Network tab in chrome shows a request to the VTT file and it's sound.)
And then:
const textTrack = player.textTracks()[0]
textTrack.addEventListener('cuechange', () => {
const activeCue = textTrack.activeCues[0]
console.log(activeCue.text, activeCue.startTime, activeCue.endTime)
})
The cuechange fires during playback, but the text attribute doesn't contain the actual subtitle text, but instead looks like the source of the .m3u8 file. The startTime and endTime of the cue seem to be correct though.
I think I'm missing something, but I'm trying to get the actual text of the triggered subtitle cue, but instead looks like this:
{"bandwidth":296728,"resolution":{"width":640,"height":268},"codecs":"avc1.42c015,mp4a.40.2","byteLength":319224,"uri":"https://...... (and so on)
Ok. Hopefully this will help someone else. It's a little confusing, but seems to be what's happening.
After I addRemoteTextTrack(), player.textTracks().length becomes 2.
One of those is of kind=metadata
The other is of kind=subtitles (the one I explicitly added)
I was listening on the kind=metadata cuechange assuming the remotely added track was the only one in the tracklist, and it fires off at the correct time in the video, even without me loading the remote text track. I think this means the stream I'm loading has some kind of metadata track for cue points embedded.
When I do add the remote track, trying to listen on the kind=subtitle track doesn't seem to fire off the cuechange event however, but I think this is because of videojs track precedence. Neither of the tracks had mode=showing, so cuechange events only fired on the one with precedence (first item in the tracklist array... the metadata one).
The solution is to simply add mode=showing to the track that I explicitly add to give it precedence:
player.addRemoteTextTrack({
src: 'http://[somepath/to/vtt]',
mode: 'showing'
})
This now allows me to listen on the tracklist item where kind=subtitle and get the actual text

Vue.js drag-select for selecting multiple divs?

I'm working on an app that handles some kind of reservations by time and by court (Tennis court). I don't use tables, instead I use divs to draw a table. Horizontally I have 'courts' while vertically I have 'hours'. If user clicks on one div, let's say 'court 1, 10:00h' I store that as one event. The point is, some of reservations should be for 2h and more. So I would love to create some kind of 'drag-select' which will highlight few divs, i.e. 'court 1, from 10:00 - 12:00'. After that I would store start and end to the db.
How would you approach this problem? I didn't find any similar package that I can use.

QLineEdit: show new text before processing textEdited signal

I have a QLineEdit and a slot that processes the textEdited signal.
I don't want to validate the text, just use it to filter a list of names (different widget) with the ones matching the text in the QLineEdit.
I have found that the text shown in the QLineEdit is only updated after the signal is processed, and the question is: can I make the new text show in the QLineEdit first and then process the signal?
Now I have:
1. let's say user presses 'A' key in the QLineEdit
2. textEdited signal is emitted (but QLineEdit is not visually updated yet)
3. signal is processed in my slot (filtering a QListWidget)
4. QLineEdit is updated, showing the effect of pressing the key 'A'
If step 3 takes a long time there is too much delay between the key is pressed and it's shown in the QLineEdit, so I want:
1. let's say user presses 'A' key in the QLineEdit
2. textEdited signal is emitted (but QLineEdit is not updated yet)
3. signal is processed in my slot (filtering a QListWidget)
i) update the QLineEdit object to reflect the pressed key 'A'
ii) filter the QListWidget
How can I do that? I need something like a QLineEdit.refresh() method? As I said I don't need to validate de text, I just want to use it to filter the content of a QListWidget, so I want everything the user edit to be shown as fast as possible.
EDIT: I've found that QCoreApplication.processEvents() does the work, but it affects the process of the signal, and some pressed keys don't trigger the signal, although I don't understand why. It seems that if the user say edits the QLineEdit pressing two keys "too fast" then the call to processEvents() in my slot (while processing the first key) processes the second key, so the second key is not processed by my slot. Does it make sense?
Use a single-shot timer:
self.timer = QtCore.QTimer()
self.timer.setSingleShot(True)
self.timer.setInterval(300)
self.timer.timeout.connect(self.filterList)
self.edit.textChanged.connect(lambda: self.timer.start())
This will keeping re-starting the timer until there's a pause greater than the timer interval, at which point the timeout signal will be sent and the slot connected to it will be called.
You may need to adjust the interval to suit the typing speed.

How to respond to focus changes on ComposableModel? (Spec)

I'm trying to create a DateInputFieldModel (subclass of ComposableModel).
It uses a TextInputFieldModel as inputField.
I set inputField autoAccept: true..
I don't want to use return/enter to accept.
While typing, I'm checking with acceptBlock whether the input text is interpretable as a date.
In my case, for instance one digit is already interpretable as a date.
When you type 5, this would mean the 5th of the current month of the current year.
When the input field loses focus (tab or mouse), I'd like to render the final representation of the date into the inputField, and update the date value of my DateInputFieldModel.
Any pointers on how to achieve this?
The underlying Morph gets send #keyboardFocusChange:
You probably need to add #whenFocusChanged: somewhere in the ComposableModel hierarchy and make sure it is called from the correct AbstractMorphicAdapter subclasses
In response to Stephan Eggermont's suggestion I altered
following method
MorphicTextInputFieldAdapter>>adapt: aModel
super adapt: aModel.
aModel
whenBuiltDo: [ :w |
w widget color: Smalltalk ui theme backgroundColor.
w widget widget textMorph
onAnnouncement: MorphGotFocus, MorphLostFocus
send: #announce: to: aModel ]
This works but the drilldown w widget widget textMorph is a bit awkward.
In my DateInputFieldModel I subscribed to the announcements
inputField on: MorphLostFocus send: #lostFocus to: self.