From 3a50f61d3a9b6e17223457fa33236722591fec54 Mon Sep 17 00:00:00 2001 From: jade <101148768+jadeddelta@users.noreply.github.com> Date: Mon, 11 Nov 2024 23:19:04 -0500 Subject: [PATCH] add docs, allow for shuffling of stimuli --- .../docs/headphone-check.md | 36 ++++++++++-- .../{index.html => basic-configuration.html} | 3 +- packages/plugin-headphone-check/src/index.ts | 55 ++++++++++++++++--- 3 files changed, 80 insertions(+), 14 deletions(-) rename packages/plugin-headphone-check/examples/{index.html => basic-configuration.html} (95%) diff --git a/packages/plugin-headphone-check/docs/headphone-check.md b/packages/plugin-headphone-check/docs/headphone-check.md index 643b2e1..37a5708 100644 --- a/packages/plugin-headphone-check/docs/headphone-check.md +++ b/packages/plugin-headphone-check/docs/headphone-check.md @@ -6,9 +6,25 @@ Allows for one to check if a participant is wearing headphones using an auditory In addition to the [parameters available in all plugins](https://www.jspsych.org/latest/overview/plugins/#parameters-available-in-all-plugins), this plugin accepts the following parameters. Parameters with a default value of undefined must be specified. Other parameters can be left unspecified if the default value is acceptable. -| Parameter | Type | Default Value | Description | -| ------------------- | ---------------- | ------------------ | ---------------------------------------- | -| | | | | +| Parameter | Type | Default Value | Description | +| --------- | ------- | ------------------ | ------------------ | +| stimuli | array of audio files | *undefined* | The list of tones that will be played. | +| correct | array of integers | *undefined* | The list of correct answers, corresponding to each tone. Each number in the array is between 1-3, corresponding to the first, second, and third being the correct response. | +| total_trials | integer | 6 | Number of trials that will be played. | +| threshold | integer | 5 | Threshold of correct trials needed to pass the headphone screening. | +| trials_per_page | integer | 3 | Number of trials that are rendered on a single page. Must be a factor of `total_trials` so each page gets their own equal set of trials. | +| prompt | HTML string | `"

Listen to the following sounds and select which option is quietest.
Click the play button to listen to the sound, and select the correct option.
Test sounds can only be played once!

"` | An HTML-formatted string presented to the participant above the audio questions. | +| labels | array of strings | `["FIRST sound is SOFTEST", "SECOND sound is SOFTEST", "THIRD sound is SOFTEST"]` | A 3 element array containing the labels of the three radio buttons. | +| play_button_label | string | `"Play"` | The label of the play button. Will be used for calibration as well if enabled. | +| continue_button_label | string | `"Continue"` | The label of the continue button. Will be used for calibration as well if enabled. | +| sequential | boolean | `false` | If true, each stimulus must be played and completed from first to last. | +| shuffle | boolean | `true` | If true, the trials will be shuffled before being displayed to the participant. | +| sample_with_replacement | boolean | `false` | If true, on shuffle, the trials will be shuffled with replacement, meaning some trials may contain duplicates. | +| calibration | boolean | `true` | If true, a calibration sound will be played to allow the participant to adjust their volume. | +| calibration_stimulus | audio file | `null` | The audio file that will be played for calibration. | +| calibration_prompt | function | ``function (calibration_counter: number) { return `

Calibrating Volume: Press the play button below to play a sound.
Adjust the volume of the sound to a comfortable level, and click continue when you are ready.
You have ${calibration_counter} calibration attempts remaining.

`;}`` | A function taking in the current amount of calibration attempts, which acts to present this info along with a stimulus to the participant above the calibration button. | +| calibration_attempts | integer | 3 | The amount of times the user may play the calibration sound. | + ## Data Generated @@ -16,7 +32,9 @@ In addition to the [default data collected by all plugins](https://jspsych.org/l | Name | Type | Value | | --------- | ------- | ---------------------------------------- | -| | | | +| did_pass | boolean | If the participant passed the headphone screen. | +| total_correct | integer | Total number of correct responses. | +| responses | array of objects | An array of objects indicating what the headphone check stimulus was, which option the participant selected, and if it was correct. Has three fields: `stimulus`: Filepath of the stimulus object. `response`: The option the participant selected, from 1-3. `correct`: If the participant's response was correct. | ## Install @@ -44,10 +62,16 @@ import HeadphoneCheck from '@jspsych-contrib/plugin-headphone-check'; ## Examples -### Title of Example +### Basic Headphone Check +This example mimics the default configurations in the [original Headphone Check](https://github.com/mcdermottLab/HeadphoneCheck) plugin. ```javascript var trial = { - type: jsPsychHeadphoneCheck + type: jsPsychHeadphoneCheck, + stimuli: ["./audio/antiphase_HC_ISO.wav", "./audio/antiphase_HC_IOS.wav", "./audio/antiphase_HC_SOI.wav", "./audio/antiphase_HC_SIO.wav", "./audio/antiphase_HC_OSI.wav", "./audio/antiphase_HC_OIS.wav"], + correct: [2, 3, 1, 1, 2, 3], + calibration_stimulus: "./audio/noise_calib_stim.wav", + sample_with_replacement: true, + sequential: true, } ``` \ No newline at end of file diff --git a/packages/plugin-headphone-check/examples/index.html b/packages/plugin-headphone-check/examples/basic-configuration.html similarity index 95% rename from packages/plugin-headphone-check/examples/index.html rename to packages/plugin-headphone-check/examples/basic-configuration.html index 6f0261d..95bbd58 100644 --- a/packages/plugin-headphone-check/examples/index.html +++ b/packages/plugin-headphone-check/examples/basic-configuration.html @@ -25,8 +25,9 @@ type: jsPsychHeadphoneCheck, stimuli: ["./audio/antiphase_HC_ISO.wav", "./audio/antiphase_HC_IOS.wav", "./audio/antiphase_HC_SOI.wav", "./audio/antiphase_HC_SIO.wav", "./audio/antiphase_HC_OSI.wav", "./audio/antiphase_HC_OIS.wav"], correct: [2, 3, 1, 1, 2, 3], - calibration: true, calibration_stimulus: "./audio/noise_calib_stim.wav", + sequential: true, + shuffle: false, }; jsPsych.run([preload, trial]) diff --git a/packages/plugin-headphone-check/src/index.ts b/packages/plugin-headphone-check/src/index.ts index 683f214..b6067b5 100644 --- a/packages/plugin-headphone-check/src/index.ts +++ b/packages/plugin-headphone-check/src/index.ts @@ -15,7 +15,7 @@ const info = { array: true, }, /** The list of correct answers, corresponding to each tone. Each number in the array is between 1-3, - * corresponding to the first, second, and third being correct or not. */ + * corresponding to the first, second, and third being the correct response. */ correct: { type: ParameterType.INT, default: undefined, @@ -58,11 +58,26 @@ const info = { type: ParameterType.STRING, default: "Continue", }, - /** If a calibration sound will be played to allow the participant to adjust their volume. */ - calibration: { + /** If true, each stimulus must be played and completed from first to last. */ + sequential: { type: ParameterType.BOOL, default: false, }, + /** If true, the trials will be shuffled before being displayed to the participant. */ + shuffle: { + type: ParameterType.BOOL, + default: true, + }, + /** If true, on shuffle, the trials will be shuffled with replacement, meaning some trials may contain duplicates. */ + sample_with_replacement: { + type: ParameterType.BOOL, + default: false, + }, + /** If true, a calibration sound will be played to allow the participant to adjust their volume. */ + calibration: { + type: ParameterType.BOOL, + default: true, + }, /** The audio file that will be played for calibration. */ calibration_stimulus: { type: ParameterType.AUDIO, @@ -76,7 +91,7 @@ const info = { return `

Calibrating Volume: Press the play button below to play a sound.
Adjust the volume of the sound to a comfortable level, and click continue when you are ready.
You have ${calibration_counter} calibration attempts remaining.

`; }, }, - /** The amount of times the user may play the calibraiton sound. */ + /** The amount of times the user may play the calibration sound. */ calibration_attempts: { type: ParameterType.INT, default: 3, @@ -149,6 +164,8 @@ class HeadphoneCheckPlugin implements JsPsychPlugin { alreadyPlayed: boolean; }[]; private trialContinueButton: HTMLButtonElement; + private stimuliList: string[]; + private correctList: number[]; private currentPage: number; @@ -170,6 +187,8 @@ class HeadphoneCheckPlugin implements JsPsychPlugin { this.container = display_element; this.container.innerHTML = this.css; this.trialResources = []; + this.stimuliList = trial.stimuli; + this.correctList = trial.correct; this.trialData = { did_pass: null, total_correct: 0, @@ -225,8 +244,30 @@ class HeadphoneCheckPlugin implements JsPsychPlugin { "Error from HeadphoneCheckPlugin: Calibration is enabled, but no calibration stimulus was provided." ); + // shuffle stimuli + this.stimuliList = this.params.stimuli; + this.correctList = this.params.correct; + if (this.params.shuffle) { + if (this.params.sample_with_replacement) { + this.stimuliList = this.jsPsych.randomization.sampleWithReplacement( + this.stimuliList, + this.params.total_trials + ); + this.correctList = this.jsPsych.randomization.sampleWithReplacement( + this.correctList, + this.params.total_trials + ); + } else { + var shuffled = this.jsPsych.randomization.shuffle([ + ...Array(this.params.total_trials).keys(), + ]); + this.stimuliList = shuffled.map((i) => this.params.stimuli[i]); + this.correctList = shuffled.map((i) => this.params.correct[i]); + } + } + // instantiate trial resources - for (const [stimuliIndex, stimuli] of this.params.stimuli.entries()) { + for (const [stimuliIndex, stimuli] of this.stimuliList.entries()) { var fieldset = document.createElement("fieldset"); fieldset.id = `jspsych-headphone-check-fieldset-${stimuliIndex}`; fieldset.className = "jspsych-headphone-check-fieldset"; @@ -444,11 +485,11 @@ class HeadphoneCheckPlugin implements JsPsychPlugin { var selected = Array.from(radioButtons).find((radio) => (radio as HTMLInputElement).checked); if (selected) { var selectedValue = parseInt((selected as HTMLInputElement).value); - var correctValue = this.params.correct[absoluteIndex] - 1; + var correctValue = this.correctList[absoluteIndex] - 1; var correct = selectedValue === correctValue; this.trialData.total_correct += correct ? 1 : 0; this.trialData.responses.push({ - stimulus: this.params.stimuli[absoluteIndex], + stimulus: this.stimuliList[absoluteIndex], response: selectedValue + 1, correct: correct, });