recording audio production

PennController for IBEX Forums Support recording audio production

Viewing 6 posts - 1 through 6 (of 6 total)
  • Author
    Posts
  • #8205
    HPI
    Participant

    Hi Jeremy,
    I am implementing a new experiment and recording as data the production of the speakers.

    I am setting up the skeleton of the experiment and I got to the point in which I present some written stimuli and a button appears to record, they can hear what they recorded, try again, submit, and the experiment closes.

    The data file appears on my server.

    First questions:

    1) can I automatically match from some information stored by Ibex the results of “speaker 1” in the result file, and the audio file of “speaker 1” in the server?
    Could I manage to save the audio file assigning a label that corresponds either to an alphanumeric ID assigned at the opening of the experiment, or I don’t know, something like a counter increasing every time someone finishes the experiment?

    2) Could I act on the type of audio file I save? It would be optimal to store .wav files.

    Thank you!

    HPI

    #8206
    Jeremy
    Keymaster

    Hi,

    1) As long as (all) UploadRecordings complete(s) before SendResults (eg. because you inserted UploadRecordings("upload") before SendResults() — no second argument in UploadRecordings, because otherwise it would be non-blocking and would therefore likely complete *after* SendResults) you will have a line for each uploaded zip file in your results file, which you can use to pair zip files with submissions. The recorded audio files are named after the MediaRecorder element that produced them. More details in this post

    2) Unfortunately that is not currently supported, since all major browsers support only webm/opus when recording via the MediaRecorder API, which PennController uses in its own MediaRecorder element type. The webm files can easily be converted to wav files though, eg. using ffmpeg: ffmpeg -i "file.webm" -vn "file.wav"

    Jeremy

    #8213
    HPI
    Participant

    Hi,

    so I was using as reference a previous experiment, but I don’t get the difference between two strategies of using the sequence to save audio files.

    I have now something like this and it runs.

    Sequence(“initiate”,”welcome”, randomize(“experiment”), “Sync”, “send”, “completion_screen”);

    InitiateRecorder(“https://ibexfarm.ung.si/uporabniki/ckzj1/Irony/mediarec.php”, “Please adjust your browser settings to allow microphone access, then click the link below.”)
    .label(“initiate”)
    //UploadRecordings(“sendAsync”, “noblock”)

    ….

    UploadRecordings(“Sync”);
    SendResults(“send”);

    What I see in the previous experiment I have is that they write with the strategy to send the audio file within the trial:

    so they had written in the sequence SepWith(“Async”, randomize(experiment)), “Sync”.

    The idea is that Async sends within the trial, Sync sends the last trial of the experiment.

    And they have the command to uploadrecordings written as in //. with the second part “noblock” that is not mentioned anywhere else, and I don’t understand exactly what it does.

    I am not getting how to have this correctly running.

    Right now it works if I write it the way you see above, so the audio files are sent at the end.

    But in this way, I am not sure I understand how to recognize the participant and match him with his data.

    —–

    Can you explain to me how to use correctly the Uploadrecording command and SepWith function?
    thank you

    HPI

    #8214
    Jeremy
    Keymaster

    Hi,

    How sepWith works is explained in the Ibex manual. If UploadRecordings("sendAsync", "noblock") is commented out with //, and assuming there is no other trial labeled sendAsync defined in the code, then any reference to sendAsync in the sequence will have no effect, since there will be no trial with a matching label to include. Note, however, that you mention sepWith("Async", randomize(experiment)) (I assume the code has sepWith, which is the Ibex function to use in a sequence, rather than SepWith): the reference here is Async, not sendAsync, so you need to look for a trial labeled Async in the code, which does not correspond to UploadRecordings("sendAsync", "noblock"), so it’s not relevant whether that line is commented out or not

    Re. how to match the files, here’s a made-up sample of selected lines from a results file:

    1612992170,SUBMISSION1,PennController,28,0,experiment,NULL,MediaRecorder,filler1,Filename,filler1.webm,1612991498311,NULL
    1612992170,SUBMISSION1,PennController,30,0,experiment,NULL,PennController,UploadRecordings,Filename,12345678-abcd-efgh-ijkl-901234567890.zip,1612991504982,async
    1612992170,SUBMISSION1,PennController,29,0,experiment,NULL,MediaRecorder,filler2,Filename,filler2.webm,1612991501417,NULL
    1612992170,SUBMISSION1,PennController,31,0,experiment,NULL,PennController,UploadRecordings,Filename,90123456-mnop-qrst-uvwx-789012345678.zip,1612991505176,sync
    1612993451,SUBMISSION2,PennController,28,0,experiment,NULL,MediaRecorder,filler1,Filename,filler1.webm,1612991506231,NULL
    1612993451,SUBMISSION2,PennController,30,0,experiment,NULL,PennController,UploadRecordings,Filename,abcdefgh-1234-5678-9012-ijklmnopqrst.zip,1612991507023,async
    1612993451,SUBMISSION2,PennController,29,0,experiment,NULL,MediaRecorder,filler2,Filename,filler2.webm,1612991507189,NULL
    1612993451,SUBMISSION2,PennController,31,0,experiment,NULL,PennController,UploadRecordings,Filename,uvwxyzab-3456-7890-1234-cdefghijklmn.zip,1612991508309,sync

    Here, you can see that two zip files correspond to SUBMISSION1: 12345678-abcd-efgh-ijkl-901234567890.zip and 90123456-mnop-qrst-uvwx-789012345678.zip. The recordings filler1.webm and filler2.webm reported in the lines above for SUBMISSION1 will be included in those zip files (they might both be in just one of the two, or one in each, depending on how upload went)

    Then two zip files correspond to SUBMISSION2: abcdefgh-1234-5678-9012-ijklmnopqrst.zip and uvwxyzab-3456-7890-1234-cdefghijklmn.zip. Likewise, you will find the recordings filler1.webm and filler2.webm from SUBMISSION1 in those zip files

    Jeremy

    #8234
    HPI
    Participant

    Hi, One question on to best use .callback

    I have implemented this:

    newButton("trigger", "RECORD")
        .log()
         .css("font-size", 20)
        .css("font-family", "Verdana", "sans-serif")
            .callback(
                //clear()
                //,
                
                getButton("trigger")
                 .css("font-size", 20)
                 .css("font-family", "Verdana", "sans-serif")
                .remove() // Print the button now: clicking it will end the trial (=validate the wait command)
                ,
        
                getButton("CONTINUE")
                 .css("font-size", 20)
                 .css("font-family", "Verdana", "sans-serif")
                .remove() // Print the button now: clicking it will end the trial (=validate the wait command)
                
                ,
            
                newMediaRecorder(variable_practice.Output_audio+"_"+id_participant, "audio")
                .log()
                .center()
                .record()
                ,
                
                 newText("spazio", " ")
                 .center()
                .print()
                 ,
                 
                newButton("STOP")
                 .css("font-size", 20)
                 .css("font-family", "Verdana", "sans-serif")
                .print()
                .wait()
                .remove()
                ,
            
                getMediaRecorder(variable_practice.Output_audio+"_"+id_participant)
                .stop()
                .log()
                ,
                  
              newText("empty"," ")
              .center()
              .print()
                 ,
                
            
                newButton("PLAY")
                 .css("font-size", 20)
                 .css("font-family", "Verdana", "sans-serif")
                 .log()
                .print()
                .wait()
                .remove()
                ,
            
                
                getMediaRecorder(variable_practice.Output_audio+"_"+id_participant)
                .play()
                .wait("playback")
                .log()
                ,
                
              newText("spazio2", " ")
              .center()
              .print()
                 ,
                 
                newText("Exit1","If you wish to record again, press RECORD")
                .css("font-size", 20)
                 .css("font-family", "Verdana", "sans-serif")
                ,
                
                newText("Exit2","If the audio seems clear and of good quality, press CONTINUE")
                .css("font-size", 20)
                 .css("font-family", "Verdana", "sans-serif")
                ,
                
                getButton("trigger")
                .print()  // Clicking this will execute the callback sequence again
            
                //.wait()
                //.remove()
                ,
            
                getButton("CONTINUE")
                 .css("font-size", 20)
                 .css("font-family", "Verdana", "sans-serif")
                .print() // Print the button now: clicking it will end the trial (=validate the wait command)
                
            )
            .print()
            .wait()
            .log()
            .remove()
        ,
    
    
    
        // This button will only be printed at the end of a test,
        // So the script won't have a chance to move past the wait command until then
        newButton("CONTINUE")
         .css("font-size", 20)
        .css("font-family", "Verdana", "sans-serif")
        .css("margin-top","1em")
        .wait()
        .log()
        ,

    I would like actually to save two separate audio files if the participant click CALLBACKS.
    Can i index the mediarecording like in a for cycle?

    Like something everytime the participants hits the trigger, a variable + 1 (i + 1), the name of the audio file + “id_participant_” + i

    So that if the participant records 10 times the same thing I save 10 version of the file, and I don’t overwrite the same variable?

    Thanks!

    HPI

    #8235
    Jeremy
    Keymaster

    Hi,

    You cannot do that, because there is one recording per MediaRecorder element, and elements are created before the sequence of trials is run, they cannot be created on the fly

    My suggestion is you give unique labels to your recording trials and use jump to run them again if needed, eg:

    Template( row => 
      newTrial( "recorder-"+row.item ,
        newMediaRecorder("mediarecorder-"+row.item, "audio").print().wait().log()
        ,
        // Jump to this trial (= recorder-ITEM#)
        newButton("Again").print().callback( jump("recorder-"+row.item) , getButton("Next").click() )
        ,
        newButton("Next").print().wait()
      )
      .log("item#", row.item)
    )

    Jeremy

Viewing 6 posts - 1 through 6 (of 6 total)
  • You must be logged in to reply to this topic.