mirror of
https://github.com/jspsych/jsPsych.git
synced 2025-05-10 11:10:54 +00:00
add allow_playback
option for rerecording audio
This commit is contained in:
parent
827df6c95d
commit
ffd7e1e45a
@ -18,6 +18,7 @@
|
|||||||
let ar = {
|
let ar = {
|
||||||
type: jsPsychHtmlAudioResponse,
|
type: jsPsychHtmlAudioResponse,
|
||||||
stimulus: '<p>Speak!</p>',
|
stimulus: '<p>Speak!</p>',
|
||||||
|
allow_playback: true,
|
||||||
on_finish: (data) => {
|
on_finish: (data) => {
|
||||||
console.log(data);
|
console.log(data);
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@ const info = <const>{
|
|||||||
default: null,
|
default: null,
|
||||||
},
|
},
|
||||||
/** How long to show the trial. */
|
/** How long to show the trial. */
|
||||||
trial_duration: {
|
recording_duration: {
|
||||||
type: ParameterType.INT,
|
type: ParameterType.INT,
|
||||||
pretty_name: "Trial duration",
|
pretty_name: "Trial duration",
|
||||||
default: 2000,
|
default: 2000,
|
||||||
@ -25,6 +25,10 @@ const info = <const>{
|
|||||||
type: ParameterType.STRING,
|
type: ParameterType.STRING,
|
||||||
default: "Continue",
|
default: "Continue",
|
||||||
},
|
},
|
||||||
|
allow_playback: {
|
||||||
|
type: ParameterType.BOOL,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -41,8 +45,10 @@ class HtmlAudioResponsePlugin implements JsPsychPlugin<Info> {
|
|||||||
private stimulus_start_time;
|
private stimulus_start_time;
|
||||||
private recorder_start_time;
|
private recorder_start_time;
|
||||||
private recorder: MediaRecorder;
|
private recorder: MediaRecorder;
|
||||||
|
private audio_url;
|
||||||
private response;
|
private response;
|
||||||
private load_resolver;
|
private load_resolver;
|
||||||
|
private rt: number = null;
|
||||||
|
|
||||||
constructor(private jsPsych: JsPsych) {}
|
constructor(private jsPsych: JsPsych) {}
|
||||||
|
|
||||||
@ -52,22 +58,6 @@ class HtmlAudioResponsePlugin implements JsPsychPlugin<Info> {
|
|||||||
this.setupRecordingEvents(display_element, trial);
|
this.setupRecordingEvents(display_element, trial);
|
||||||
|
|
||||||
this.startRecording();
|
this.startRecording();
|
||||||
|
|
||||||
// setup timer for hiding the stimulus
|
|
||||||
if (trial.stimulus_duration !== null) {
|
|
||||||
this.jsPsych.pluginAPI.setTimeout(() => {
|
|
||||||
this.hideStimulus(display_element);
|
|
||||||
}, trial.stimulus_duration);
|
|
||||||
}
|
|
||||||
|
|
||||||
// setup timer for ending the trial
|
|
||||||
if (trial.trial_duration !== null) {
|
|
||||||
this.jsPsych.pluginAPI.setTimeout(() => {
|
|
||||||
this.stopRecording().then(() => {
|
|
||||||
this.endTrial(display_element, trial);
|
|
||||||
});
|
|
||||||
}, trial.trial_duration);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private showDisplay(display_element, trial) {
|
private showDisplay(display_element, trial) {
|
||||||
@ -95,9 +85,13 @@ class HtmlAudioResponsePlugin implements JsPsychPlugin<Info> {
|
|||||||
private addButtonEvent(display_element, trial) {
|
private addButtonEvent(display_element, trial) {
|
||||||
display_element.querySelector("#finish-trial").addEventListener("click", () => {
|
display_element.querySelector("#finish-trial").addEventListener("click", () => {
|
||||||
const end_time = performance.now();
|
const end_time = performance.now();
|
||||||
const rt = Math.round(end_time - this.stimulus_start_time);
|
this.rt = Math.round(end_time - this.stimulus_start_time);
|
||||||
this.stopRecording().then(() => {
|
this.stopRecording().then(() => {
|
||||||
this.endTrial(display_element, trial, rt);
|
if (trial.allow_playback) {
|
||||||
|
this.showPlaybackControls(display_element, trial);
|
||||||
|
} else {
|
||||||
|
this.endTrial(display_element, trial);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -112,20 +106,44 @@ class HtmlAudioResponsePlugin implements JsPsychPlugin<Info> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
this.recorder.addEventListener("stop", () => {
|
this.recorder.addEventListener("stop", () => {
|
||||||
const url = new Blob(recorded_data_chunks, { type: "audio/webm" });
|
const data = new Blob(recorded_data_chunks, { type: "audio/webm" });
|
||||||
|
this.audio_url = URL.createObjectURL(data);
|
||||||
const reader = new FileReader();
|
const reader = new FileReader();
|
||||||
reader.addEventListener("load", () => {
|
reader.addEventListener("load", () => {
|
||||||
const base64 = (reader.result as string).split(",")[1];
|
const base64 = (reader.result as string).split(",")[1];
|
||||||
this.response = base64;
|
this.response = base64;
|
||||||
this.load_resolver();
|
this.load_resolver();
|
||||||
});
|
});
|
||||||
reader.readAsDataURL(url);
|
reader.readAsDataURL(data);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.recorder.addEventListener("start", (e) => {
|
this.recorder.addEventListener("start", (e) => {
|
||||||
|
// resets the recorded data
|
||||||
|
recorded_data_chunks.length = 0;
|
||||||
|
|
||||||
this.recorder_start_time = e.timeStamp;
|
this.recorder_start_time = e.timeStamp;
|
||||||
this.showDisplay(display_element, trial);
|
this.showDisplay(display_element, trial);
|
||||||
this.addButtonEvent(display_element, trial);
|
this.addButtonEvent(display_element, trial);
|
||||||
|
|
||||||
|
// setup timer for hiding the stimulus
|
||||||
|
if (trial.stimulus_duration !== null) {
|
||||||
|
this.jsPsych.pluginAPI.setTimeout(() => {
|
||||||
|
this.hideStimulus(display_element);
|
||||||
|
}, trial.stimulus_duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
// setup timer for ending the trial
|
||||||
|
if (trial.recording_duration !== null) {
|
||||||
|
this.jsPsych.pluginAPI.setTimeout(() => {
|
||||||
|
this.stopRecording().then(() => {
|
||||||
|
if (trial.allow_playback) {
|
||||||
|
this.showPlaybackControls(display_element, trial);
|
||||||
|
} else {
|
||||||
|
this.endTrial(display_element, trial);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, trial.recording_duration);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,13 +158,29 @@ class HtmlAudioResponsePlugin implements JsPsychPlugin<Info> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private endTrial(display_element, trial, rt: number = null) {
|
private showPlaybackControls(display_element, trial) {
|
||||||
|
display_element.innerHTML = `
|
||||||
|
<p><audio id="playback" src="${this.audio_url}" controls></audio></p>
|
||||||
|
<button id="record-again" class="jspsych-btn">Record Again</button>
|
||||||
|
<button id="continue" class="jspsych-btn">Continue</button>
|
||||||
|
`;
|
||||||
|
|
||||||
|
display_element.querySelector("#record-again").addEventListener("click", this.startRecording);
|
||||||
|
display_element.querySelector("#continue").addEventListener("click", () => {
|
||||||
|
this.endTrial(display_element, trial);
|
||||||
|
});
|
||||||
|
|
||||||
|
// const audio = display_element.querySelector('#playback');
|
||||||
|
// audio.src =
|
||||||
|
}
|
||||||
|
|
||||||
|
private endTrial(display_element, trial) {
|
||||||
// kill any remaining setTimeout handlers
|
// kill any remaining setTimeout handlers
|
||||||
this.jsPsych.pluginAPI.clearAllTimeouts();
|
this.jsPsych.pluginAPI.clearAllTimeouts();
|
||||||
|
|
||||||
// gather the data to store for the trial
|
// gather the data to store for the trial
|
||||||
var trial_data = {
|
var trial_data = {
|
||||||
rt: rt,
|
rt: this.rt,
|
||||||
stimulus: trial.stimulus,
|
stimulus: trial.stimulus,
|
||||||
response: this.response,
|
response: this.response,
|
||||||
estimated_stimulus_onset: Math.round(this.stimulus_start_time - this.recorder_start_time),
|
estimated_stimulus_onset: Math.round(this.stimulus_start_time - this.recorder_start_time),
|
||||||
|
Loading…
Reference in New Issue
Block a user