Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add headphone-check plugin #146

Merged
merged 11 commits into from
Jan 29, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/wicked-humans-grow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@jspsych-contrib/plugin-headphone-check": major
---

Initial headphone check plugin release.
24,015 changes: 13,075 additions & 10,940 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
},
"jest": {
"projects": [
"<rootDir>/packages/*"
"<rootDir>/packages/*/jest.config.cjs"
]
}
}
42 changes: 42 additions & 0 deletions packages/plugin-headphone-check/CITATION.cff
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
cff-version: 1.2.0
title: >-
Headphone screening to facilitate web-based auditory
experiments
message: >-
If you use this software, please cite it using the
metadata from this file.
type: software
authors:
- given-names: Kevin J. P.
family-names: Woods
orcid: 'https://orcid.org/0000-0003-3981-9235'
- given-names: Max H.
family-names: Siegel
- given-names: James
family-names: Traer
- given-names: Josh H.
family-names: McDermott
identifiers:
- type: doi
value: 10.3758/s13414-017-1361-2
preferred-citation:
authors:
- given-names: Kevin J. P.
family-names: Woods
orcid: 'https://orcid.org/0000-0003-3981-9235'
- given-names: Max H.
family-names: Siegel
- given-names: James
family-names: Traer
- given-names: Josh H.
family-names: McDermott
date-published: 2017-07-10
doi: 10.3758/s13414-017-1361-2
journal: Atten Percept Psychophys
publisher:
name: Springer
start: 2064
title: "Headphone screening to facilitate web-based auditory experiments."
type: article
url: "https://link.springer.com/article/10.3758/s13414-017-1361-2"
volume: 79
37 changes: 37 additions & 0 deletions packages/plugin-headphone-check/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# headphone-check

## Overview

Allows for one to check if a participant is wearing headphones using an auditory task. In the default configuration, participants listen to 6 audio samples with 3 tones each, and asked for which is the quietest. Upon meeting a threshold (at least 5), we can accurately conclude that the participant is wearing headphones, as per the findings in the [paper describing the original HeadphoneCheck](http://mcdermottlab.mit.edu/papers/Woods_etal_2017_headphone_screening.pdf). The default configuration is also meant to work immediately with the original sounds and no further setup.

## Loading

### In browser

```js
<script src="https://unpkg.com/@jspsych-contrib/[email protected]"></script>
```

### Via NPM

```
npm install @jspsych-contrib/plugin-headphone-check
```

```js
import jsPsychHeadphoneCheck from '@jspsych-contrib/plugin-headphone-check';
```

## Compatibility

jsPsych 8.0.0

## Documentation

See [documentation](https://github.com/jspsych/jspsych-contrib/blob/main/packages/plugin-headphone-check/docs/jspsych-headphone-check.md)

## Author / Citation

jadeddelta, adapted from the original [HeadphoneCheck](https://github.com/mcdermottLab/HeadphoneCheck) repository. The paper is:

[Woods KJP, Siegel MH, Traer J & McDermott JH (2017) Headphone screening to facilitate web-based auditory experiments. Attention, Perception & Psychophysics.](http://mcdermottlab.mit.edu/papers/Woods_etal_2017_headphone_screening.pdf)
99 changes: 99 additions & 0 deletions packages/plugin-headphone-check/docs/headphone-check.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
# headphone-check

Allows for one to check if a participant is wearing headphones using an auditory task. Adapted from the original [HeadphoneCheck](https://github.com/mcdermottLab/HeadphoneCheck) repository, which adapts from the paper [Woods KJP, Siegel MH, Traer J & McDermott JH (2017) Headphone screening to facilitate web-based auditory experiments. Attention, Perception & Psychophysics.](http://mcdermottlab.mit.edu/papers/Woods_etal_2017_headphone_screening.pdf).

## Parameters

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 |
| --------- | ------- | ------------------ | ------------------ |
| stimuli | array of audio files | see aws file names | The list of tones that will be played. |
| correct | array of integers | `[2, 3, 1, 1, 2, 3]` | 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 | `"<p>Listen to the following sounds and select which option is quietest. <br> Click the play button to listen to the sound, and select the correct option. <br> Test sounds can only be played once!</p>"` | 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 | see aws file name | The audio file that will be played for calibration. |
| calibration_prompt | function | ``function (calibration_counter: number) { return `<p>Calibrating Volume: Press the play button below to play a sound. <br> Adjust the volume of the sound to a comfortable level, and click continue when you are ready. <br> You have ${calibration_counter} calibration attempts remaining.</p>`;}`` | 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. |

### Default Configuration with AWS Files

The plugin is meant to work out of the box with as little setup as possible. The stimuli files, as shown in the original paper, are hosted on the following links:
```javascript
[
"https://s3.amazonaws.com/mcd-headphone-check/v1.0/assets/antiphase_HC_ISO.wav",
"https://s3.amazonaws.com/mcd-headphone-check/v1.0/assets/antiphase_HC_IOS.wav",
"https://s3.amazonaws.com/mcd-headphone-check/v1.0/assets/antiphase_HC_SOI.wav",
"https://s3.amazonaws.com/mcd-headphone-check/v1.0/assets/antiphase_HC_SIO.wav",
"https://s3.amazonaws.com/mcd-headphone-check/v1.0/assets/antiphase_HC_OSI.wav",
"https://s3.amazonaws.com/mcd-headphone-check/v1.0/assets/antiphase_HC_OIS.wav",
]
```

The default calibration file is found on `"https://s3.amazonaws.com/mcd-headphone-check/v1.0/assets/noise_calib_stim.wav"`.

## Data Generated

In addition to the [default data collected by all plugins](https://jspsych.org/latest/overview/plugins.md#data-collected-by-all-plugins), this plugin collects the following data for each trial.

| 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

Using the CDN-hosted JavaScript file:

```js
<script src="https://unpkg.com/@jspsych-contrib/plugin-headphone-check"></script>
```

Using the JavaScript file downloaded from a GitHub release dist archive:

```js
<script src="jspsych/plugin-headphone-check.js"></script>
```

Using NPM:

```
npm install @jspsych-contrib/plugin-headphone-check
```

```js
import HeadphoneCheck from '@jspsych-contrib/plugin-headphone-check';
```

## Examples

### Basic Configuration
This example mimics the default configurations in the [original Headphone Check](https://github.com/mcdermottLab/HeadphoneCheck) plugin.

```javascript
var trial = {
type: jsPsychHeadphoneCheck,
}
```

### File System Configuration
If you'd like to use custom sounds or just source the files locally, see below. **Note**: make sure if you're using custom sounds, change the value of the `correct` field or you will be getting incorrect readings!

```javascript
var trial = {
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"
};
```
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
34 changes: 34 additions & 0 deletions packages/plugin-headphone-check/examples/basic-configuration.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<!DOCTYPE html>
<html>

<head>
<script src="https://unpkg.com/jspsych@8"></script>
<script src="https://unpkg.com/@jspsych/plugin-preload@2"></script>
<script src="../dist/index.browser.js"></script>
<link rel="stylesheet" href="https://unpkg.com/jspsych/css/jspsych.css">
</head>

<body></body>
<script>
// --- NOTE: do not use live server as you'll have to deal with a CORS error, just run this experiment from the file explorer ---
const jsPsych = initJsPsych({
on_finish: function() {
jsPsych.data.displayData();
}
});

const preload = {
type: jsPsychPreload,
auto_preload: true
}

// this trial uses the default configuration described in the original headphonecheck
// https://github.com/mcdermottLab/HeadphoneCheck?tab=readme-ov-file#configure-and-start-the-headphone-check
const trial = {
type: jsPsychHeadphoneCheck
};

jsPsych.run([preload, trial])
</script>

</html>
36 changes: 36 additions & 0 deletions packages/plugin-headphone-check/examples/file-configuration.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<!DOCTYPE html>
<html>

<head>
<script src="https://unpkg.com/jspsych@8"></script>
<script src="https://unpkg.com/@jspsych/plugin-preload@2"></script>
<script src="../dist/index.browser.js"></script>
<link rel="stylesheet" href="https://unpkg.com/jspsych/css/jspsych.css">
</head>

<body></body>
<script>
const jsPsych = initJsPsych({
on_finish: function() {
jsPsych.data.displayData();
}
});

const preload = {
type: jsPsychPreload,
auto_preload: true
}

// this trial uses the default configuration described in the original headphonecheck
// https://github.com/mcdermottLab/HeadphoneCheck?tab=readme-ov-file#configure-and-start-the-headphone-check
const trial = {
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"
};

jsPsych.run([preload, trial])
</script>

</html>
1 change: 1 addition & 0 deletions packages/plugin-headphone-check/jest.config.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require("@jspsych/config/jest").makePackageConfig(__dirname);
48 changes: 48 additions & 0 deletions packages/plugin-headphone-check/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
{
"name": "@jspsych-contrib/plugin-headphone-check",
"version": "0.0.1",
"description": "Allows for one to check if a participant is wearing headphones using an auditory task. ([Woods et al., 2017](http://mcdermottlab.mit.edu/papers/Woods_etal_2017_headphone_screening.pdf))",
"type": "module",
"main": "dist/index.cjs",
"exports": {
"import": "./dist/index.js",
"require": "./dist/index.cjs"
},
"typings": "dist/index.d.ts",
"unpkg": "dist/index.browser.min.js",
"files": [
"src",
"dist"
],
"source": "src/index.ts",
"scripts": {
"test": "jest",
"test:watch": "npm test -- --watch",
"tsc": "tsc",
"build": "rollup --config",
"build:watch": "npm run build -- --watch"
},
"repository": {
"type": "git",
"url": "git+https://github.com/jspsych/jspsych-contrib.git",
"directory": "packages/plugin-headphone-check"
},
"author": {
"name": "jadeddelta",
"email": "[email protected]",
"url": "https://github.com/jadeddelta"
},
"license": "MIT",
"bugs": {
"url": "https://github.com/jspsych/jspsych-contrib/issues"
},
"homepage": "https://github.com/jspsych/jspsych-contrib/tree/main/packages/plugin-headphone-check",
"peerDependencies": {
"jspsych": ">=8.0.0"
},
"devDependencies": {
"@jspsych/config": "^3.2.1",
"@jspsych/test-utils": "^1.0.0",
"jspsych": "^8.0.0"
}
}
3 changes: 3 additions & 0 deletions packages/plugin-headphone-check/rollup.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { makeRollupConfig } from "@jspsych/config/rollup";

export default makeRollupConfig("jsPsychHeadphoneCheck");
29 changes: 29 additions & 0 deletions packages/plugin-headphone-check/src/index.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
jest.mock("../node_modules/jspsych/src/modules/plugin-api/AudioPlayer");

import { clickTarget, startTimeline } from "@jspsych/test-utils";

import jsPsychHeadphoneCheck from ".";

jest.useFakeTimers();

describe("headphone-check plugin", () => {
it.skip("should complete", async () => {
const { expectFinished, expectRunning, getHTML, getData, displayElement, jsPsych } =
await startTimeline([
{
type: jsPsychHeadphoneCheck,
stimuli: ["foo1.mp3"],
correct: [0],
calibration: false,
},
]);

expectRunning();

clickTarget(displayElement.querySelector("#jspsych-headphone-check-play-0"));
clickTarget(displayElement.querySelector("#jspsych-headphone-check-radio-0-0"));
clickTarget(displayElement.querySelector("#jspsych-headphone-check-continue"));

expectFinished();
});
});
Loading
Loading