Repeat button for sounds does not work on Pavlovia

OS (e.g. Win10): Win10
PsychoPy version : 2024.2.4
What are you trying to achieve? : I would like a repeat button to replay a sound with each new click in a routine.

Hi! I’m trying to make a repeat button for sound stimuli on Psychopy 2.4 Py 3.8.
It is very simple: the participant listens to a sound in a routine, and there it has the option, on the bottom left screen, to listen to this sound again by clicking on a button.
It works fine on Psychopy, but the same does not happen on Pavlovia. There is no error pop up, the sound simply does not play. In fact, I can hear a millisecond of sound playing when the button is clicked, but that’s it.
Here it is the routine:

Here it is the simple py function I’ve used on the button function:

I reckon it might be some problem with py > JS when the experiment syncs with Pavlovia, but I don’t know how to solve the question. Maybe creating a code in the routine with a JS that works on Pavlovia?

Here is the link to the experiment:

Hi Marcus, I think I’m having the same issue. Did you solve this?

For this to work I think you would need the sound_1 component to be created in an earlier routine.

Thanks, I’ll try this. In the meantime, if anyone has a similar issue, I kind of got around this via a code snippet where I had to initialise the auditory stimulus every frame, with the caveat that the first time the participant clicks the button, there is no sound and you need to wait for the sound to stop playing (abour 3 seconds in my case). But on the second click it works. The first four lines are in the “Begin routine” tab and the rest is in the “each frame” tab. Best I could do after about 5 hours of testing (I tinkered a lot and had all sorts of issues)!

mouseClicked = 0
playbackAllowed = true; // Control whether a new playback is allowed
playbackTimer = new util.Clock(); // Timer to track sound playback duration
playbackTimer.reset();

// Check if the button is clicked
if (button.isClicked && mouseClicked === 0) { // Process first click
mouseClicked = 1; // Mark this click as handled
console.log(“Button clicked.”);

if (playbackAllowed) {  // Only allow playback if sound is not currently playing
    aud_stim = new sound.Sound({
        win: psychoJS.window,
        value: stimFilename,  // The current sound file for this trial
        secs: -1,             // Play the full file length
        loop: false           // No looping
    });
    playbackAllowed = false;  // Block further plays until reset
    playbackTimer.reset();  // Start timer

    console.log("Playing sound.");
    aud_stim.play();  // Play the sound
} else {
    console.log("Sound is still playing. Cannot replay yet.");
}
}

// Reset status when button is released
if (!button.isClicked) {
mouseClicked = 0;
}

// Manually track when playback finishes
if (playbackTimer.getTime() > aud_stim.getDuration()) {  // Check if playback time is over
playbackAllowed = true;  // Allow sound to play again
console.log(“Playback finished. Ready for next click.”);
}

An update: the suggestion by wakecarter did not work. Still trying to figure out why the sound does not play the first time the button is clicked. An alternative method where participants must press R on the keyboard gives me the exact same issue. In my experiment, the sound is initialised via Begin Routine, plays automatically at the start of the trial via a sound component (NOT via the code component), and then I want people to be able to replay the sound (which I am using via a code component where I initialise the sound each frame). Seems like the sound plays automatically, but on the first click it isn’t initialised properly or something and plays silently… After that, clicks/keypresses can play the sound as normal.

Okay, solved! Sorry for hijacking the thread Marcus :grin: Full steps here:

  • First, I updated Psychopy to latest version (this did not fix my original issues, but may be worth mentioning)
  • I removed my sound component so that everything is controlled by the code component
  • In my code component “begin routine” tab, I initialise aud_stim (stimFilename is defined within trials loop) and play it immediately after via aud_stim.play(), as I want the sound to play automatically at the start of the trial:
//Initialize sound object for the trial (ensure path is valid)
aud_stim = new sound.Sound({
win: psychoJS.window,
value: stimFilename,   // This should be dynamically set before this code runs
secs: -1,
loop: false
});
aud_stim.play()

mouseClicked = 0
playbackAllowed = true;  // Control whether a new playback is allowed
playbackTimer = new util.Clock();  // Timer to track sound playback duration
playbackTimer.reset();
  • In my code component “each frame” tab, I play the sound when the button is pressed (and when playback has finished as I don’t want the sounds to overlap):

    // Check if the button is clicked
    if (button.isClicked && mouseClicked === 0) {  // Process first click
    mouseClicked = 1; // Mark this click as handled
    console.log(“Button clicked.”);
    
    if (playbackAllowed) {  // Only allow playback if sound is not currently playing
        playbackAllowed = false;  // Block further plays until reset
        playbackTimer.reset();  // Start timer
        console.log("Playing sound.");
        aud_stim.play();  // Play the sound
    } else {
        console.log("Sound is still playing. Cannot replay yet.");
    }
    
    }
    
    // Reset status when button is released
    if (!button.isClicked) {
    mouseClicked = 0;
    }
    
    // Manually track when playback finishes
    if (playbackTimer.getTime() > aud_stim.getDuration()) {  // Check if playback time is over
    playbackAllowed = true;  // Allow sound to play again
    console.log(“Playback finished. Ready for next click.”);
    }
    
    
    

Sounds simple and perhaps obvious, and I thought I had tried this and it didn’t work, but the TLDR is that the sound component and button component do not work together (doesn’t seem to matter what you put in the callback function for the button component): everything needs to be a code component, as a combination of sound component + code component does not work either. I think it is problematic that the basic function of a button that plays a sound does not work, but currently it is what it is. Would be happy to help others who have a similar issue.