在id里面 png图片有白边_jsPsych 图片描述范式

49f2b72dd64fc0972bcff8f69fd9721e.png

分享下一个图片描述范式的运用 jsPsych 的JavaScript, 因为有录音部分,实验需要用Chrome 或者 Firefox 进行浏览。 小白一枚,欢迎补充和指导。

实验流程是:看fixation -》图片-》听录音-》判断对错(对d,错k)-》哔音 - 》看图片描述(并录音)(如图)

aab4533661a17dba46f9ab00a1937004.png
window.alert('Hello, you will be audio recorded in this experiment. '); //随便打个招呼

//ID assignment (给被试分配ID)

var subject_id = Math.floor(Math.random()*100000); //give participant a random id
jsPsych.data.addProperties({
 subject: subject_id
});

//提示被试的浏览器有问题,并且被试需要同意被录音的对话框。 这个部分是关于允许录音和储存

var wrong_browser_message = "Sorry, it's not possible to run the experiment on your web browser. Please try using Chrome or Firefox instead.";
var declined_audio_message = "You must allow audio recording to take part in the experiment. Please allow access to your microphone and reload the page to proceed.";

//声音生成variables

var audio_chunks = []; //empty array for blob content
var rec; // MediaRecorder
var next_audio_filename; //holder for complete audio file name
var trial_counter = 0; //increments to differentiate audio file names, without different names files may overwrite

//欢迎部分

var welcome_block = {
  data:{
  screen_id:'Welcome',
  },
  type:'html-button-response',
  stimulus: '<p> Welcome to this experiment! </p>'+
'<p>This experiment requires you to listen to the audio and then click the correpsonding pictures,</p>'+
'<p>after the choice, you need to finish a question,</p>'+
'<p>You will be recorded when you answer questions,</p>'+
'<p>Clicking the button below counts as an interaction.If you understand the information above </p>'+
'<p>please click the <b>[Continue]</b> botton</p>',
 choices: ['Continue']
};

// 同意意向书

var consent = {
  data:{
    screen_id:'consent',
  },
  type:'instructions',
  pages:[
 If you understand above, please click [Next]"],
  stimulus:'',
  show_clickable_nav:true 
};

//Randomize trial number(一共有8个trials,所以排序从0开始到7, 然后是随机选择)

var trial_num = [0,1,2,3,4,5,6,7]
var trial_num = jsPsych.randomization.shuffle(trial_num);
console.log(trial_num) // randomize trial numbers

//Create stimuli array 创建实验刺激串 imgs指的是文件夹,E01PA...指得图片png文件, xxx.wav是音频文件。

prime_stimuli = [
  'imgs/E01PA.png',
  'imgs/E04PA.png',
  'imgs/E03PA.png',
  'imgs/E07PA.png',
  'imgs/E05PA.png',
  'imgs/E02PA.png',
  'imgs/E06PA.png',
  'imgs/E08PA.png',
]

//用html图片使用在图片播放的同时获取录音,方便利用后面的audio-button-response 的plugin

html_prime_stimuli = [
  '<img src = "imgs/E01PA.png" width = 100% height = 100%"/>',
  '<img src = "imgs/E04PA.png" width = 100% height = 100%"/>',
  '<img src = "imgs/E03PA.png" width = 100% height = 100%"/>',
  '<img src = "imgs/E07PA.png" width = 100% height = 100%"/>',
  '<img src = "imgs/E05PA.png" width = 100% height = 100%"/>',
  '<img src = "imgs/E02PA.png" width = 100% height = 100%"/>',
  '<img src = "imgs/E06PA.png" width = 100% height = 100%"/>',
  '<img src = "imgs/E08PA.png" width = 100% height = 100%"/>',
] 

//同上

prime_audio = [
  'sound/E01A.wav',
  'sound/E04A.wav',
  'sound/E03A.wav',
  'sound/E07A.wav',
  'sound/E05A.wav',
  'sound/E02A.wav',
  'sound/E06A.wav',
  'sound/E08A.wav',
]
target_stimuli = [
  'imgs/E01TA.png',
  'imgs/E04TA.png',
  'imgs/E03TA.png',
  'imgs/E07TA.png',
  'imgs/E05TA.png',
  'imgs/E02TA.png',
  'imgs/E06TA.png',
  'imgs/E08TA.png',
]

//从这里开始开始图片描述的任务

var experiment_blocks = [welcome_block, consent];
for (i in trial_num){
  jsPsych.data.addProperties({
    trial:trial_num
  });    // 当 i是0-7的时候

//这里被试听看到的是一个类似与fixation的图片。listen.png是图片中耳机的图片

 listening_sign = {
    type: 'image-keyboard-response', 
    stimulus: 'imgs/listen.png',
    choices: jsPsych.NO_KEYS,
    trial_duration:1500,
    prompt:'<p> Please listen it carefully </p>'
  };     

//这里被试看到了图片并且听到了相匹配的录音, 这里在一个block中

  experiment_blocks.push(listening_sign);
  priming_sound_block = {
        // creates trial-internal timeline
    timeline: [{
      // audio exposure trial with associated image displayed as button
      type: 'audio-button-response',
      stimulus: prime_audio[trial_num[i]],
      choices: [prime_stimuli[trial_num[i]]],
      button_html:'<img src="%choice%" />', // html image to overlay button
      trial_name: 'priming_audio_trial',
      response_ends_trial: false, //prevents response from ending trial
      trial_ends_after_audio: true,
    }, 
    {
      type: 'image-keyboard-response',
          stimulus: prime_stimuli[trial_num[i]], // calls image stimuli
          choices: ['d','j'], // only allows progression using spacebar
          trial_name: 'noun_image_following_trial',
          post_trial_gap: 1500
    },    //这里需要被试判断对错
    ],
  };
  experiment_blocks.push(priming_sound_block);

//这里是一个fixation 并提示被试描述接下来的图片

  speaking_sign = {
    type:'image-keyboard-response',
    stimulus:'imgs/speak.png',
    choices:jsPsych.NO_KEYS,
    trial_duration:1500,
    prompt:'<p> Please describe the following picture </p>'
  }; 
  experiment_blocks.push(speaking_sign);

//这里是一个哔声,哔声后被试开始作答

  beep_sound ={
    type:'audio-keyboard-response',
    choices:jsPsych.NO_KEYS,
    stimulus:'sound/beep.mp3',
    trial_ends_after_audio:true,
    response_ends_trial:false,
    on_finish:function(){
      jsPsych.data.addDataToLastTrial();
    }   
  };
  experiment_blocks.push(beep_sound);

// 这里是目标图片,被试描述并且在描述的同时,录音

  target_block = {
    type:'image-keyboard-response',
    choices:['spacebar'],
    stimulus:target_stimuli[trial_num[i]],
    response_ends_trial:true,
    on_finish:function(){
      jsPsych.data.addDataToLastTrial();
    } 
  };

//这里选择性有或者没有,有的话,被试在录音后可以听到自己的录音,可以选择没有这部分

  replay_trial = {
    type:'html-button-response',
    stimulus:'<p>Use the controls below to hear the answer you gave. Then press 
    continue to progress.</p>',
    choices:['Continue'] 
  };

// 录音

  audio_recording_trial = { //internal timeline defines the order in which the abover trials happen and when recording functions are called
    timeline: [
      start_recording(subject_id),
      target_block,
      stop_recording(),
      replay_trial
    ],
    timeline_variables: target_block
  };  
  experiment_blocks.push(audio_recording_trial);

//开始录音的function

  function start_recording(filename) {
    return {
      type: "call-function", //make sure you load this as a plugin in your html file just like you would with something like audio-keyboard-response
      func: function() {
        audio_chunks = []; //clears global audio_chunks of previous blob content, needed for recording multipe trials in seperate files
        next_audio_filename = filename + '_test_' + trial_counter; //name of audio file will be something like rxe32hl37h_test_0.webm
        rec.start(); // starts audio recording
        trial_counter += 1; //adds 1 to trial counter
      }
    }
  };

// 停止录音的function

  function stop_recording() {
    return {
      type: "call-function",
      func: function() {
        rec.stop(); // stops recording and triggers onstop event below
      }
    }
  };

}  

//在重新播放的部分的音频的设置的 function

function generate_replay(item) {
    var div = document.getElementById("jspsych-content");//makes div key to access jspsych content part of window
    var audio = document.createElement("audio");//creates an audio element
    audioUrl = URL.createObjectURL(item); //constructs URL that references the blob passed into the function
    audio.src = audioUrl;//sets file url as src of audio
    audio.style.cssFloat = "right";//sets where the controls appear 
    audio.controls=true;//activates browser internal audio controls
    div.appendChild(audio);//appends audio element as child of "jspsych-content"
};

//保存data

function saveData(name, data){
    var url = 'record_result.php'; // external .php file
    var data = {filename: name, filedata: data};
    data = JSON.stringify(data);
    fetch(url, {
        method: 'POST',
        body: data,
        headers: new Headers({
              'Content-Type': 'application/json'
        })
    });
};

//想要保存的data 的部分

function saveDataLine(data) {
        // choose the data we want to save
        var data_to_save = [
          data.rt, data.stimulus, data.key_press, data.name, data.trial_type,
          data.trial_index, data.time_elapsed, data.internal_node_id,
          data.Worker_ID, data.choices, data.answer, data.button_pressed,
          data.value, data.responses
        ];

//在存储csv的时候在数据中加入逗号

        var line = data_to_save.join(',')+"n";
        saveData(participant_id + ".csv", line);
      }

// 存储音频的data

function saveAudio(name, audio_data) {
  var url = 'record_audio.php'; // external .php file that should be in same folder as your experiment
  form_data = new FormData();
  form_data.append("filename", name);
  form_data.append("filedata", audio_data);
  fetch(url, {
      method: 'POST',
      body: form_data
  });
};

// 如果浏览器不支持MediaRecorder,或者麦克风没有被允许。会给出提示。

function errorQuit(message) {
  var body = document.getElementsByTagName('body')[0];
  body.innerHTML = '<p style="color: #FF0000">'+message+'</p>'+body.innerHTML;//defines the style of error messages
  throw error;
};

//如果浏览器或者音频介入有错误,会退出

navigator.mediaDevices.getUserMedia({audio:true})
    .then(stream => {handlerFunction(stream)})
    .catch(error => {errorQuit(declined_audio_message)});

//还是录音的一个function,这里有点没懂,抄来的一段。

function handlerFunction(stream) {
    try {
      rec = new MediaRecorder(stream);
    } catch(error) {
       errorQuit(wrong_browser_message);
       };

    rec.ondataavailable = e => {
        audio_chunks.push(e.data);//pushes blob to "audio_chunks" variable above
    };

    rec.onstop = e => { //handles the stop event, everything below happens when stop_recording() is called
        //note that this audio needs to be converted after it has been saved to the server
        let blob = new Blob(audio_chunks,{type:'audio/webm'});
        generate_replay(blob);//call to function that generates replay for next trial
        saveAudio(next_audio_filename, blob); //calls saveAudio, one parameter for the name of audio file and one for audio content

    };
};

//通用结尾

jsPsych.init({
  timeline: experiment_blocks,
  use_webaudio: false,
  on_finish: function(data){
    var alldata = jsPsych.data.get();
    SaveData("test.csv",experiment_data.csv());
  }
});

//}).call(this); 

-------------------

补充一条遇到过的bug的解决方法,如果这一行出现如下的提示,把网址 http 改成https。

navigat or.mediaDevices.getUserMedia({audio:true})这一行如果出现如下的提示
  Uncaught TypeError: Cannot read property 'getUserMedia' of undefined

--------------------

补充第二条,录音需要收集录音的php,格式如下:

<?php
//build filename from workerId and day
function cleanInput($data) {
  $data = trim($data);
  $data = stripslashes($data);
  $data = str_replace('/','',$data);
  $data = str_replace('.','',$data);
  return $data;
}
$filename = cleanInput($_REQUEST["filename"]);
copy($_FILES['filedata']['tmp_name'], '/home/domainname/server_data/audio_data/' . $filename . ".webm");
?> // 存储在与实验文件夹相并列的文件夹中,注意:不是实验的子文件夹。把其中的domainname换成自己的domainname。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值