diff --git a/src/sound/AudioClip.js b/src/sound/AudioClip.js index 72c07db..61f05af 100644 --- a/src/sound/AudioClip.js +++ b/src/sound/AudioClip.js @@ -7,11 +7,10 @@ * @license Distributed under the terms of the MIT License */ -import {PsychObject} from '../util/PsychObject.js'; -import {PsychoJS} from '../core/PsychoJS.js'; -import {ExperimentHandler} from '../data/ExperimentHandler.js'; -import * as util from '../util/Util.js'; - +import { PsychoJS } from "../core/PsychoJS.js"; +import { ExperimentHandler } from "../data/ExperimentHandler.js"; +import { PsychObject } from "../util/PsychObject.js"; +import * as util from "../util/Util.js"; /** *

AudioClip encapsulates an audio recording.

@@ -28,20 +27,19 @@ import * as util from '../util/Util.js'; */ export class AudioClip extends PsychObject { - - constructor({psychoJS, name, sampleRateHz, format, data, autoLog} = {}) + constructor({ psychoJS, name, sampleRateHz, format, data, autoLog } = {}) { super(psychoJS); - this._addAttribute('name', name, 'audioclip'); - this._addAttribute('format', format); - this._addAttribute('sampleRateHz', sampleRateHz); - this._addAttribute('data', data); - this._addAttribute('autoLog', false, autoLog); - this._addAttribute('status', AudioClip.Status.CREATED); + this._addAttribute("name", name, "audioclip"); + this._addAttribute("format", format); + this._addAttribute("sampleRateHz", sampleRateHz); + this._addAttribute("data", data); + this._addAttribute("autoLog", false, autoLog); + this._addAttribute("status", AudioClip.Status.CREATED); // add a volume attribute, for playback: - this._addAttribute('volume', 1.0); + this._addAttribute("volume", 1.0); if (this._autoLog) { @@ -52,7 +50,6 @@ export class AudioClip extends PsychObject this._decodeAudio(); } - /** * Set the volume of the playback. * @@ -66,7 +63,6 @@ export class AudioClip extends PsychObject this._volume = volume; } - /** * Start playing the audio clip. * @@ -76,7 +72,7 @@ export class AudioClip extends PsychObject */ async startPlayback() { - this._psychoJS.logger.debug('request to play the audio clip'); + this._psychoJS.logger.debug("request to play the audio clip"); // wait for the decoding to complete: await this._decodeAudio(); @@ -103,7 +99,6 @@ export class AudioClip extends PsychObject this._source.start(); } - /** * Stop playing the audio clip. * @@ -120,7 +115,6 @@ export class AudioClip extends PsychObject this._source.stop(); } - /** * Get the duration of the audio clip, in seconds. * @@ -137,7 +131,6 @@ export class AudioClip extends PsychObject return this._audioBuffer.duration; } - /** * Upload the audio clip to the pavlovia server. * @@ -147,17 +140,18 @@ export class AudioClip extends PsychObject */ upload() { - this._psychoJS.logger.debug('request to upload the audio clip to pavlovia.org'); + this._psychoJS.logger.debug("request to upload the audio clip to pavlovia.org"); // add a format-dependent audio extension to the name: const filename = this._name + util.extensionFromMimeType(this._format); - // if the audio recording cannot be uploaded, e.g. the experiment is running locally, or // if it is piloting mode, then we offer the audio clip as a file for download: - if (this._psychoJS.getEnvironment() !== ExperimentHandler.Environment.SERVER || - this._psychoJS.config.experiment.status !== 'RUNNING' || - this._psychoJS._serverMsg.has('__pilotToken')) + if ( + this._psychoJS.getEnvironment() !== ExperimentHandler.Environment.SERVER + || this._psychoJS.config.experiment.status !== "RUNNING" + || this._psychoJS._serverMsg.has("__pilotToken") + ) { return this.download(filename); } @@ -166,8 +160,6 @@ export class AudioClip extends PsychObject return this._psychoJS.serverManager.uploadAudio(this._data, filename); } - - /** * Offer the audio clip to the participant as a sound file to download. * @@ -175,9 +167,9 @@ export class AudioClip extends PsychObject * @function * @public */ - download(filename = 'audio.webm') + download(filename = "audio.webm") { - const anchor = document.createElement('a'); + const anchor = document.createElement("a"); anchor.href = window.URL.createObjectURL(this._data); anchor.download = filename; document.body.appendChild(anchor); @@ -185,7 +177,6 @@ export class AudioClip extends PsychObject document.body.removeChild(anchor); } - /** * Transcribe the audio clip. * @@ -196,10 +187,10 @@ export class AudioClip extends PsychObject * @return {Promise<>} a promise resolving to the transcript and associated * transcription confidence */ - async transcribe({engine, languageCode} = {}) + async transcribe({ engine, languageCode } = {}) { const response = { - origin: 'AudioClip.transcribe', + origin: "AudioClip.transcribe", context: `when transcribing audio clip: ${this._name}`, }; @@ -215,11 +206,11 @@ export class AudioClip extends PsychObject transcriptionKey = key.value; } } - if (typeof transcriptionKey === 'undefined') + if (typeof transcriptionKey === "undefined") { throw { ...response, - error: `missing key for engine: ${fullEngineName}` + error: `missing key for engine: ${fullEngineName}`, }; } @@ -235,13 +226,11 @@ export class AudioClip extends PsychObject { throw { ...response, - error: `unsupported speech-to-text engine: ${engine}` + error: `unsupported speech-to-text engine: ${engine}`, }; } - } - /** * Transcribe the audio clip using the Google Cloud Speech-To-Text Engine. * @@ -272,31 +261,31 @@ export class AudioClip extends PsychObject // query the Google speech-to-text service: const body = { config: { - encoding: 'LINEAR16', + encoding: "LINEAR16", sampleRateHertz: this._sampleRateHz, - languageCode + languageCode, }, audio: { - content: base64Data + content: base64Data, }, }; const url = `https://speech.googleapis.com/v1/speech:recognize?key=${transcriptionKey}`; const response = await fetch(url, { - method: 'POST', + method: "POST", headers: { - 'Content-Type': 'application/json', + "Content-Type": "application/json", }, - body: JSON.stringify(body) + body: JSON.stringify(body), }); // convert the response to json: const decodedResponse = await response.json(); - this._psychoJS.logger.debug('speech.googleapis.com response:', JSON.stringify(decodedResponse)); + this._psychoJS.logger.debug("speech.googleapis.com response:", JSON.stringify(decodedResponse)); // TODO deal with more than one results and/or alternatives - if (('results' in decodedResponse) && (decodedResponse.results.length > 0)) + if (("results" in decodedResponse) && (decodedResponse.results.length > 0)) { resolve(decodedResponse.results[0].alternatives[0]); } @@ -304,21 +293,20 @@ export class AudioClip extends PsychObject { // no transcription available: resolve({ - transcript: '', - confidence: -1 + transcript: "", + confidence: -1, }); } }); } - /** * Decode the formatted audio data (e.g. webm) into a 32bit float PCM audio buffer. * */ _decodeAudio() { - this._psychoJS.logger.debug('request to decode the data of the audio clip'); + this._psychoJS.logger.debug("request to decode the data of the audio clip"); // if the audio clip is ready, the PCM audio data is available in _audioData, a Float32Array: if (this._status === AudioClip.Status.READY) @@ -326,12 +314,11 @@ export class AudioClip extends PsychObject return; } - // if we are already decoding, wait until the process completed: if (this._status === AudioClip.Status.DECODING) { const self = this; - return new Promise(function (resolve, reject) + return new Promise(function(resolve, reject) { self._decodingCallbacks.push(resolve); @@ -339,7 +326,6 @@ export class AudioClip extends PsychObject }.bind(this)); } - // otherwise, start decoding the input formatted audio data: this._status = AudioClip.Status.DECODING; this._audioData = null; @@ -348,7 +334,7 @@ export class AudioClip extends PsychObject this._decodingCallbacks = []; this._audioContext = new (window.AudioContext || window.webkitAudioContext)({ - sampleRate: this._sampleRateHz + sampleRate: this._sampleRateHz, }); const reader = new window.FileReader(); @@ -383,12 +369,11 @@ export class AudioClip extends PsychObject reader.onerror = (error) => { // TODO - } + }; reader.readAsArrayBuffer(this._data); } - /** * Convert an array buffer to a base64 string. * @@ -403,63 +388,65 @@ export class AudioClip extends PsychObject */ _base64ArrayBuffer(arrayBuffer) { - let base64 = ''; - const encodings = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; + let base64 = ""; + const encodings = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - const bytes = new Uint8Array(arrayBuffer); - const byteLength = bytes.byteLength; - const byteRemainder = byteLength % 3; - const mainLength = byteLength - byteRemainder; + const bytes = new Uint8Array(arrayBuffer); + const byteLength = bytes.byteLength; + const byteRemainder = byteLength % 3; + const mainLength = byteLength - byteRemainder; - let a; - let b; - let c; - let d; - let chunk; + let a; + let b; + let c; + let d; + let chunk; - // Main loop deals with bytes in chunks of 3 - for (let i = 0; i < mainLength; i += 3) { - // Combine the three bytes into a single integer - chunk = (bytes[i] << 16) | (bytes[i + 1] << 8) | bytes[i + 2]; + // Main loop deals with bytes in chunks of 3 + for (let i = 0; i < mainLength; i += 3) + { + // Combine the three bytes into a single integer + chunk = (bytes[i] << 16) | (bytes[i + 1] << 8) | bytes[i + 2]; - // Use bitmasks to extract 6-bit segments from the triplet - a = (chunk & 16515072) >> 18; // 16515072 = (2^6 - 1) << 18 - b = (chunk & 258048) >> 12; // 258048 = (2^6 - 1) << 12 - c = (chunk & 4032) >> 6; // 4032 = (2^6 - 1) << 6 - d = chunk & 63; // 63 = 2^6 - 1 + // Use bitmasks to extract 6-bit segments from the triplet + a = (chunk & 16515072) >> 18; // 16515072 = (2^6 - 1) << 18 + b = (chunk & 258048) >> 12; // 258048 = (2^6 - 1) << 12 + c = (chunk & 4032) >> 6; // 4032 = (2^6 - 1) << 6 + d = chunk & 63; // 63 = 2^6 - 1 - // Convert the raw binary segments to the appropriate ASCII encoding - base64 += encodings[a] + encodings[b] + encodings[c] + encodings[d]; + // Convert the raw binary segments to the appropriate ASCII encoding + base64 += encodings[a] + encodings[b] + encodings[c] + encodings[d]; + } + + // Deal with the remaining bytes and padding + if (byteRemainder === 1) + { + chunk = bytes[mainLength]; + + a = (chunk & 252) >> 2; // 252 = (2^6 - 1) << 2 + + // Set the 4 least significant bits to zero + b = (chunk & 3) << 4; // 3 = 2^2 - 1 + + base64 += `${encodings[a]}${encodings[b]}==`; + } + else if (byteRemainder === 2) + { + chunk = (bytes[mainLength] << 8) | bytes[mainLength + 1]; + + a = (chunk & 64512) >> 10; // 64512 = (2^6 - 1) << 10 + b = (chunk & 1008) >> 4; // 1008 = (2^6 - 1) << 4 + + // Set the 2 least significant bits to zero + c = (chunk & 15) << 2; // 15 = 2^4 - 1 + + base64 += `${encodings[a]}${encodings[b]}${encodings[c]}=`; + } + + return base64; } - - // Deal with the remaining bytes and padding - if (byteRemainder === 1) { - chunk = bytes[mainLength]; - - a = (chunk & 252) >> 2; // 252 = (2^6 - 1) << 2 - - // Set the 4 least significant bits to zero - b = (chunk & 3) << 4; // 3 = 2^2 - 1 - - base64 += `${encodings[a]}${encodings[b]}==`; - } else if (byteRemainder === 2) { - chunk = (bytes[mainLength] << 8) | bytes[mainLength + 1]; - - a = (chunk & 64512) >> 10; // 64512 = (2^6 - 1) << 10 - b = (chunk & 1008) >> 4; // 1008 = (2^6 - 1) << 4 - - // Set the 2 least significant bits to zero - c = (chunk & 15) << 2; // 15 = 2^4 - 1 - - base64 += `${encodings[a]}${encodings[b]}${encodings[c]}=`; - } - - return base64; } -} - - /** * Recognition engines. * @@ -472,10 +459,9 @@ AudioClip.Engine = { /** * Google Cloud Speech-to-Text. */ - GOOGLE: Symbol.for('GOOGLE') + GOOGLE: Symbol.for("GOOGLE"), }; - /** * AudioClip status. * @@ -484,9 +470,9 @@ AudioClip.Engine = { * @public */ AudioClip.Status = { - CREATED: Symbol.for('CREATED'), + CREATED: Symbol.for("CREATED"), - DECODING: Symbol.for('DECODING'), + DECODING: Symbol.for("DECODING"), - READY: Symbol.for('READY') + READY: Symbol.for("READY"), }; diff --git a/src/sound/AudioClipPlayer.js b/src/sound/AudioClipPlayer.js index 6e819be..082a71a 100644 --- a/src/sound/AudioClipPlayer.js +++ b/src/sound/AudioClipPlayer.js @@ -7,9 +7,8 @@ * @license Distributed under the terms of the MIT License */ -import {SoundPlayer} from './SoundPlayer.js'; -import {AudioClip} from "./AudioClip.js"; - +import { AudioClip } from "./AudioClip.js"; +import { SoundPlayer } from "./SoundPlayer.js"; /** *

This class handles the playback of an audio clip, e.g. a microphone recording.

@@ -29,28 +28,27 @@ import {AudioClip} from "./AudioClip.js"; export class AudioClipPlayer extends SoundPlayer { constructor({ - psychoJS, - audioClip, - startTime = 0, - stopTime = -1, - stereo = true, - volume = 0, - loops = 0 - } = {}) + psychoJS, + audioClip, + startTime = 0, + stopTime = -1, + stereo = true, + volume = 0, + loops = 0, + } = {}) { super(psychoJS); - this._addAttribute('audioClip', audioClip); - this._addAttribute('startTime', startTime); - this._addAttribute('stopTime', stopTime); - this._addAttribute('stereo', stereo); - this._addAttribute('loops', loops); - this._addAttribute('volume', volume); + this._addAttribute("audioClip", audioClip); + this._addAttribute("startTime", startTime); + this._addAttribute("stopTime", stopTime); + this._addAttribute("stereo", stereo); + this._addAttribute("loops", loops); + this._addAttribute("volume", volume); this._currentLoopIndex = -1; } - /** * Determine whether this player can play the given sound. * @@ -73,7 +71,7 @@ export class AudioClipPlayer extends SoundPlayer stopTime: sound.stopTime, stereo: sound.stereo, loops: sound.loops, - volume: sound.volume + volume: sound.volume, }); return player; } @@ -82,7 +80,6 @@ export class AudioClipPlayer extends SoundPlayer return undefined; } - /** * Get the duration of the AudioClip, in seconds. * @@ -96,7 +93,6 @@ export class AudioClipPlayer extends SoundPlayer return this._audioClip.getDuration(); } - /** * Set the duration of the audio clip. * @@ -110,13 +106,12 @@ export class AudioClipPlayer extends SoundPlayer // TODO throw { - origin: 'AudioClipPlayer.setDuration', - context: 'when setting the duration of the playback for audio clip player: ' + this._name, - error: 'not implemented yet' + origin: "AudioClipPlayer.setDuration", + context: "when setting the duration of the playback for audio clip player: " + this._name, + error: "not implemented yet", }; } - /** * Set the volume of the playback. * @@ -133,7 +128,6 @@ export class AudioClipPlayer extends SoundPlayer this._audioClip.setVolume((mute) ? 0.0 : volume); } - /** * Set the number of loops. * @@ -150,7 +144,6 @@ export class AudioClipPlayer extends SoundPlayer // TODO } - /** * Start playing the sound. * @@ -162,7 +155,7 @@ export class AudioClipPlayer extends SoundPlayer */ play(loops, fadeDuration = 17) { - if (typeof loops !== 'undefined') + if (typeof loops !== "undefined") { this.setLoops(loops); } @@ -176,7 +169,6 @@ export class AudioClipPlayer extends SoundPlayer this._audioClip.startPlayback(); } - /** * Stop playing the sound immediately. * @@ -189,5 +181,4 @@ export class AudioClipPlayer extends SoundPlayer { this._audioClip.stopPlayback(fadeDuration); } - } diff --git a/src/sound/Microphone.js b/src/sound/Microphone.js index a4dbc17..a042bc9 100644 --- a/src/sound/Microphone.js +++ b/src/sound/Microphone.js @@ -7,12 +7,12 @@ * @license Distributed under the terms of the MIT License */ -import {Clock} from "../util/Clock.js"; -import {PsychObject} from "../util/PsychObject.js"; -import {PsychoJS} from "../core/PsychoJS.js"; -import * as util from '../util/Util.js'; -import {ExperimentHandler} from "../data/ExperimentHandler.js"; -import {AudioClip} from "./AudioClip.js"; +import { PsychoJS } from "../core/PsychoJS.js"; +import { ExperimentHandler } from "../data/ExperimentHandler.js"; +import { Clock } from "../util/Clock.js"; +import { PsychObject } from "../util/PsychObject.js"; +import * as util from "../util/Util.js"; +import { AudioClip } from "./AudioClip.js"; /** *

This manager handles the recording of audio signal.

@@ -29,18 +29,17 @@ import {AudioClip} from "./AudioClip.js"; */ export class Microphone extends PsychObject { - - constructor({win, name, format, sampleRateHz, clock, autoLog} = {}) + constructor({ win, name, format, sampleRateHz, clock, autoLog } = {}) { super(win._psychoJS); - this._addAttribute('win', win, undefined); - this._addAttribute('name', name, 'microphone'); - this._addAttribute('format', format, 'audio/webm;codecs=opus', this._onChange); - this._addAttribute('sampleRateHz', sampleRateHz, 48000, this._onChange); - this._addAttribute('clock', clock, new Clock()); - this._addAttribute('autoLog', false, autoLog); - this._addAttribute('status', PsychoJS.Status.NOT_STARTED); + this._addAttribute("win", win, undefined); + this._addAttribute("name", name, "microphone"); + this._addAttribute("format", format, "audio/webm;codecs=opus", this._onChange); + this._addAttribute("sampleRateHz", sampleRateHz, 48000, this._onChange); + this._addAttribute("clock", clock, new Clock()); + this._addAttribute("autoLog", false, autoLog); + this._addAttribute("status", PsychoJS.Status.NOT_STARTED); // prepare the recording: this._prepareRecording(); @@ -51,7 +50,6 @@ export class Microphone extends PsychObject } } - /** * Submit a request to start the recording. * @@ -68,19 +66,18 @@ export class Microphone extends PsychObject // with a new recording: if (this._status === PsychoJS.Status.PAUSED) { - return this.resume({clear: true}); + return this.resume({ clear: true }); } - if (this._status !== PsychoJS.Status.STARTED) { - this._psychoJS.logger.debug('request to start audio recording'); + this._psychoJS.logger.debug("request to start audio recording"); try { if (!this._recorder) { - throw 'the recorder has not been created yet, possibly because the participant has not given the authorisation to record audio'; + throw "the recorder has not been created yet, possibly because the participant has not given the authorisation to record audio"; } this._recorder.start(); @@ -96,21 +93,18 @@ export class Microphone extends PsychObject } catch (error) { - this._psychoJS.logger.error('unable to start the audio recording: ' + JSON.stringify(error)); + this._psychoJS.logger.error("unable to start the audio recording: " + JSON.stringify(error)); this._status = PsychoJS.Status.ERROR; throw { - origin: 'Microphone.start', - context: 'when starting the audio recording for microphone: ' + this._name, - error + origin: "Microphone.start", + context: "when starting the audio recording for microphone: " + this._name, + error, }; } - } - } - /** * Submit a request to stop the recording. * @@ -122,14 +116,14 @@ export class Microphone extends PsychObject * @return {Promise} promise fulfilled when the recording actually stopped, and the recorded * data was made available */ - stop({filename} = {}) + stop({ filename } = {}) { if (this._status === PsychoJS.Status.STARTED || this._status === PsychoJS.Status.PAUSED) { - this._psychoJS.logger.debug('request to stop audio recording'); + this._psychoJS.logger.debug("request to stop audio recording"); this._stopOptions = { - filename + filename, }; // note: calling the stop method of the MediaRecorder will first raise a dataavailable event, @@ -148,7 +142,6 @@ export class Microphone extends PsychObject } } - /** * Submit a request to pause the recording. * @@ -160,13 +153,13 @@ export class Microphone extends PsychObject { if (this._status === PsychoJS.Status.STARTED) { - this._psychoJS.logger.debug('request to pause audio recording'); + this._psychoJS.logger.debug("request to pause audio recording"); try { if (!this._recorder) { - throw 'the recorder has not been created yet, possibly because the participant has not given the authorisation to record audio'; + throw "the recorder has not been created yet, possibly because the participant has not given the authorisation to record audio"; } // note: calling the pause method of the MediaRecorder raises a pause event @@ -182,20 +175,18 @@ export class Microphone extends PsychObject } catch (error) { - self._psychoJS.logger.error('unable to pause the audio recording: ' + JSON.stringify(error)); + self._psychoJS.logger.error("unable to pause the audio recording: " + JSON.stringify(error)); this._status = PsychoJS.Status.ERROR; throw { - origin: 'Microphone.pause', - context: 'when pausing the audio recording for microphone: ' + this._name, - error + origin: "Microphone.pause", + context: "when pausing the audio recording for microphone: " + this._name, + error, }; } - } } - /** * Submit a request to resume the recording. * @@ -207,17 +198,17 @@ export class Microphone extends PsychObject * resuming the recording * @return {Promise} promise fulfilled when the recording actually resumed */ - resume({clear = false } = {}) + resume({ clear = false } = {}) { if (this._status === PsychoJS.Status.PAUSED) { - this._psychoJS.logger.debug('request to resume audio recording'); + this._psychoJS.logger.debug("request to resume audio recording"); try { if (!this._recorder) { - throw 'the recorder has not been created yet, possibly because the participant has not given the authorisation to record audio'; + throw "the recorder has not been created yet, possibly because the participant has not given the authorisation to record audio"; } // empty the audio buffer is needed: @@ -239,20 +230,18 @@ export class Microphone extends PsychObject } catch (error) { - self._psychoJS.logger.error('unable to resume the audio recording: ' + JSON.stringify(error)); + self._psychoJS.logger.error("unable to resume the audio recording: " + JSON.stringify(error)); this._status = PsychoJS.Status.ERROR; throw { - origin: 'Microphone.resume', - context: 'when resuming the audio recording for microphone: ' + this._name, - error + origin: "Microphone.resume", + context: "when resuming the audio recording for microphone: " + this._name, + error, }; } - } } - /** * Submit a request to flush the recording. * @@ -264,7 +253,7 @@ export class Microphone extends PsychObject { if (this._status === PsychoJS.Status.STARTED || this._status === PsychoJS.Status.PAUSED) { - this._psychoJS.logger.debug('request to flush audio recording'); + this._psychoJS.logger.debug("request to flush audio recording"); // note: calling the requestData method of the MediaRecorder will raise a // dataavailable event @@ -281,7 +270,6 @@ export class Microphone extends PsychObject } } - /** * Offer the audio recording to the participant as a sound file to download. * @@ -290,11 +278,11 @@ export class Microphone extends PsychObject * @public * @param {string} filename the filename */ - download(filename = 'audio.webm') + download(filename = "audio.webm") { const audioBlob = new Blob(this._audioBuffer); - const anchor = document.createElement('a'); + const anchor = document.createElement("a"); anchor.href = window.URL.createObjectURL(audioBlob); anchor.download = filename; document.body.appendChild(anchor); @@ -302,7 +290,6 @@ export class Microphone extends PsychObject document.body.removeChild(anchor); } - /** * Upload the audio recording to the pavlovia server. * @@ -311,10 +298,10 @@ export class Microphone extends PsychObject * @public * @param {string} tag an optional tag for the audio file */ - async upload({tag} = {}) + async upload({ tag } = {}) { // default tag: the name of this Microphone object - if (typeof tag === 'undefined') + if (typeof tag === "undefined") { tag = this._name; } @@ -322,12 +309,13 @@ export class Microphone extends PsychObject // add a format-dependent audio extension to the tag: tag += util.extensionFromMimeType(this._format); - // if the audio recording cannot be uploaded, e.g. the experiment is running locally, or // if it is piloting mode, then we offer the audio recording as a file for download: - if (this._psychoJS.getEnvironment() !== ExperimentHandler.Environment.SERVER || - this._psychoJS.config.experiment.status !== 'RUNNING' || - this._psychoJS._serverMsg.has('__pilotToken')) + if ( + this._psychoJS.getEnvironment() !== ExperimentHandler.Environment.SERVER + || this._psychoJS.config.experiment.status !== "RUNNING" + || this._psychoJS._serverMsg.has("__pilotToken") + ) { return this.download(tag); } @@ -337,7 +325,6 @@ export class Microphone extends PsychObject return this._psychoJS.serverManager.uploadAudio(audioBlob, tag); } - /** * Get the current audio recording as an AudioClip in the given format. * @@ -347,27 +334,25 @@ export class Microphone extends PsychObject * @param {string} tag an optional tag for the audio clip * @param {boolean} [flush=false] whether or not to first flush the recording */ - async getRecording({tag, flush = false} = {}) + async getRecording({ tag, flush = false } = {}) { // default tag: the name of this Microphone object - if (typeof tag === 'undefined') + if (typeof tag === "undefined") { tag = this._name; } - const audioClip = new AudioClip({ psychoJS: this._psychoJS, name: tag, format: this._format, sampleRateHz: this._sampleRateHz, - data: new Blob(this._audioBuffer) + data: new Blob(this._audioBuffer), }); return audioClip; } - /** * Callback for changes to the recording settings. * @@ -389,7 +374,6 @@ export class Microphone extends PsychObject this.start(); } - /** * Prepare the recording. * @@ -409,15 +393,15 @@ export class Microphone extends PsychObject advanced: [ { channelCount: 1, - sampleRate: this._sampleRateHz - } - ] - } + sampleRate: this._sampleRateHz, + }, + ], + }, }); // check that the specified format is supported, use default if it is not: let options; - if (typeof this._format === 'string' && MediaRecorder.isTypeSupported(this._format)) + if (typeof this._format === "string" && MediaRecorder.isTypeSupported(this._format)) { options = { type: this._format }; } @@ -428,7 +412,6 @@ export class Microphone extends PsychObject this._recorder = new MediaRecorder(stream, options); - // setup the callbacks: const self = this; @@ -440,7 +423,7 @@ export class Microphone extends PsychObject self._audioBuffer.length = 0; self._clock.reset(); self._status = PsychoJS.Status.STARTED; - self._psychoJS.logger.debug('audio recording started'); + self._psychoJS.logger.debug("audio recording started"); // resolve the Microphone.start promise: if (self._startCallback) @@ -453,7 +436,7 @@ export class Microphone extends PsychObject this._recorder.onpause = () => { self._status = PsychoJS.Status.PAUSED; - self._psychoJS.logger.debug('audio recording paused'); + self._psychoJS.logger.debug("audio recording paused"); // resolve the Microphone.pause promise: if (self._pauseCallback) @@ -466,7 +449,7 @@ export class Microphone extends PsychObject this._recorder.onresume = () => { self._status = PsychoJS.Status.STARTED; - self._psychoJS.logger.debug('audio recording resumed'); + self._psychoJS.logger.debug("audio recording resumed"); // resolve the Microphone.resume promise: if (self._resumeCallback) @@ -482,7 +465,7 @@ export class Microphone extends PsychObject // add data to the buffer: self._audioBuffer.push(data); - self._psychoJS.logger.debug('audio data added to the buffer'); + self._psychoJS.logger.debug("audio data added to the buffer"); // resolve the data available promise, if needed: if (self._dataAvailableCallback) @@ -494,7 +477,7 @@ export class Microphone extends PsychObject // called upon Microphone.stop(), after data has been made available: this._recorder.onstop = () => { - self._psychoJS.logger.debug('audio recording stopped'); + self._psychoJS.logger.debug("audio recording stopped"); self._status = PsychoJS.Status.NOT_STARTED; // resolve the Microphone.stop promise: @@ -506,7 +489,7 @@ export class Microphone extends PsychObject // treat stop options if there are any: // download to a file, immediately offered to the participant: - if (typeof self._stopOptions.filename === 'string') + if (typeof self._stopOptions.filename === "string") { self.download(self._stopOptions.filename); } @@ -516,12 +499,8 @@ export class Microphone extends PsychObject this._recorder.onerror = (event) => { // TODO - self._psychoJS.logger.error('audio recording error: ' + JSON.stringify(event)); + self._psychoJS.logger.error("audio recording error: " + JSON.stringify(event)); self._status = PsychoJS.Status.ERROR; }; - } - } - - diff --git a/src/sound/Sound.js b/src/sound/Sound.js index 6d9e0c1..51f1b01 100644 --- a/src/sound/Sound.js +++ b/src/sound/Sound.js @@ -8,12 +8,11 @@ * @license Distributed under the terms of the MIT License */ -import {PsychoJS} from '../core/PsychoJS.js'; -import {PsychObject} from '../util/PsychObject.js'; -import {TonePlayer} from './TonePlayer.js'; -import {TrackPlayer} from './TrackPlayer.js'; -import {AudioClipPlayer} from './AudioClipPlayer.js'; - +import { PsychoJS } from "../core/PsychoJS.js"; +import { PsychObject } from "../util/PsychObject.js"; +import { AudioClipPlayer } from "./AudioClipPlayer.js"; +import { TonePlayer } from "./TonePlayer.js"; +import { TrackPlayer } from "./TrackPlayer.js"; /** *

This class handles sound playing (tones and tracks)

@@ -54,35 +53,35 @@ import {AudioClipPlayer} from './AudioClipPlayer.js'; export class Sound extends PsychObject { constructor({ - name, - win, - value = 'C', - octave = 4, - secs = 0.5, - startTime = 0, - stopTime = -1, - stereo = true, - volume = 1.0, - loops = 0, - //hamming = true, - autoLog = true - } = {}) + name, + win, + value = "C", + octave = 4, + secs = 0.5, + startTime = 0, + stopTime = -1, + stereo = true, + volume = 1.0, + loops = 0, + // hamming = true, + autoLog = true, + } = {}) { super(win._psychoJS, name); // the SoundPlayer, e.g. TonePlayer: this._player = undefined; - this._addAttribute('win', win); - this._addAttribute('value', value); - this._addAttribute('octave', octave); - this._addAttribute('secs', secs); - this._addAttribute('startTime', startTime); - this._addAttribute('stopTime', stopTime); - this._addAttribute('stereo', stereo); - this._addAttribute('volume', volume); - this._addAttribute('loops', loops); - this._addAttribute('autoLog', autoLog); + this._addAttribute("win", win); + this._addAttribute("value", value); + this._addAttribute("octave", octave); + this._addAttribute("secs", secs); + this._addAttribute("startTime", startTime); + this._addAttribute("stopTime", stopTime); + this._addAttribute("stereo", stereo); + this._addAttribute("volume", volume); + this._addAttribute("loops", loops); + this._addAttribute("autoLog", autoLog); // identify an appropriate player: this._getPlayer(); @@ -90,7 +89,6 @@ export class Sound extends PsychObject this.status = PsychoJS.Status.NOT_STARTED; } - /** * Start playing the sound. * @@ -107,7 +105,6 @@ export class Sound extends PsychObject this._player.play(loops); } - /** * Stop playing the sound immediately. * @@ -116,14 +113,13 @@ export class Sound extends PsychObject * @param {boolean} [options.log= true] - whether or not to log */ stop({ - log = true - } = {}) + log = true, + } = {}) { this._player.stop(); this.status = PsychoJS.Status.STOPPED; } - /** * Get the duration of the sound, in seconds. * @@ -135,7 +131,6 @@ export class Sound extends PsychObject return this._player.getDuration(); } - /** * Set the playing volume of the sound. * @@ -146,15 +141,14 @@ export class Sound extends PsychObject */ setVolume(volume, mute = false, log = true) { - this._setAttribute('volume', volume, log); + this._setAttribute("volume", volume, log); - if (typeof this._player !== 'undefined') + if (typeof this._player !== "undefined") { this._player.setVolume(volume, mute); } } - /** * Set the sound value on demand past initialisation. * @@ -166,9 +160,9 @@ export class Sound extends PsychObject { if (sound instanceof Sound) { - this._setAttribute('value', sound.value, log); + this._setAttribute("value", sound.value, log); - if (typeof this._player !== 'undefined') + if (typeof this._player !== "undefined") { this._player = this._player.constructor.accept(this); } @@ -178,13 +172,12 @@ export class Sound extends PsychObject } throw { - origin: 'Sound.setSound', - context: 'when replacing the current sound', - error: 'invalid input, need an instance of the Sound class.' + origin: "Sound.setSound", + context: "when replacing the current sound", + error: "invalid input, need an instance of the Sound class.", }; } - /** * Set the number of loops. * @@ -194,15 +187,14 @@ export class Sound extends PsychObject */ setLoops(loops = 0, log = true) { - this._setAttribute('loops', loops, log); + this._setAttribute("loops", loops, log); - if (typeof this._player !== 'undefined') + if (typeof this._player !== "undefined") { this._player.setLoops(loops); } } - /** * Set the duration (in seconds) * @@ -212,15 +204,14 @@ export class Sound extends PsychObject */ setSecs(secs = 0.5, log = true) { - this._setAttribute('secs', secs, log); + this._setAttribute("secs", secs, log); - if (typeof this._player !== 'undefined') + if (typeof this._player !== "undefined") { this._player.setDuration(secs); } } - /** * Identify the appropriate player for the sound. * @@ -231,26 +222,24 @@ export class Sound extends PsychObject _getPlayer() { const acceptFns = [ - sound => TonePlayer.accept(sound), - sound => TrackPlayer.accept(sound), - sound => AudioClipPlayer.accept(sound) + (sound) => TonePlayer.accept(sound), + (sound) => TrackPlayer.accept(sound), + (sound) => AudioClipPlayer.accept(sound), ]; for (const acceptFn of acceptFns) { this._player = acceptFn(this); - if (typeof this._player !== 'undefined') + if (typeof this._player !== "undefined") { return this._player; } } throw { - origin: 'SoundPlayer._getPlayer', - context: 'when finding a player for the sound', - error: 'could not find an appropriate player.' + origin: "SoundPlayer._getPlayer", + context: "when finding a player for the sound", + error: "could not find an appropriate player.", }; } - - } diff --git a/src/sound/SoundPlayer.js b/src/sound/SoundPlayer.js index 9b55d0e..4ba5bdb 100644 --- a/src/sound/SoundPlayer.js +++ b/src/sound/SoundPlayer.js @@ -7,8 +7,7 @@ * @license Distributed under the terms of the MIT License */ -import {PsychObject} from '../util/PsychObject.js'; - +import { PsychObject } from "../util/PsychObject.js"; /** *

SoundPlayer is an interface for the sound players, who are responsible for actually playing the sounds, i.e. the tracks or the tones.

@@ -25,7 +24,6 @@ export class SoundPlayer extends PsychObject super(psychoJS); } - /** * Determine whether this player can play the given sound. * @@ -40,13 +38,12 @@ export class SoundPlayer extends PsychObject static accept(sound) { throw { - origin: 'SoundPlayer.accept', - context: 'when evaluating whether this player can play a given sound', - error: 'this method is abstract and should not be called.' + origin: "SoundPlayer.accept", + context: "when evaluating whether this player can play a given sound", + error: "this method is abstract and should not be called.", }; } - /** * Start playing the sound. * @@ -59,13 +56,12 @@ export class SoundPlayer extends PsychObject play(loops) { throw { - origin: 'SoundPlayer.play', - context: 'when starting the playback of a sound', - error: 'this method is abstract and should not be called.' + origin: "SoundPlayer.play", + context: "when starting the playback of a sound", + error: "this method is abstract and should not be called.", }; } - /** * Stop playing the sound immediately. * @@ -77,13 +73,12 @@ export class SoundPlayer extends PsychObject stop() { throw { - origin: 'SoundPlayer.stop', - context: 'when stopping the playback of a sound', - error: 'this method is abstract and should not be called.' + origin: "SoundPlayer.stop", + context: "when stopping the playback of a sound", + error: "this method is abstract and should not be called.", }; } - /** * Get the duration of the sound, in seconds. * @@ -95,13 +90,12 @@ export class SoundPlayer extends PsychObject getDuration() { throw { - origin: 'SoundPlayer.getDuration', - context: 'when getting the duration of the sound', - error: 'this method is abstract and should not be called.' + origin: "SoundPlayer.getDuration", + context: "when getting the duration of the sound", + error: "this method is abstract and should not be called.", }; } - /** * Set the duration of the sound, in seconds. * @@ -113,13 +107,12 @@ export class SoundPlayer extends PsychObject setDuration(duration_s) { throw { - origin: 'SoundPlayer.setDuration', - context: 'when setting the duration of the sound', - error: 'this method is abstract and should not be called.' + origin: "SoundPlayer.setDuration", + context: "when setting the duration of the sound", + error: "this method is abstract and should not be called.", }; } - /** * Set the number of loops. * @@ -132,13 +125,12 @@ export class SoundPlayer extends PsychObject setLoops(loops) { throw { - origin: 'SoundPlayer.setLoops', - context: 'when setting the number of loops', - error: 'this method is abstract and should not be called.' + origin: "SoundPlayer.setLoops", + context: "when setting the number of loops", + error: "this method is abstract and should not be called.", }; } - /** * Set the volume of the tone. * @@ -152,10 +144,9 @@ export class SoundPlayer extends PsychObject setVolume(volume, mute = false) { throw { - origin: 'SoundPlayer.setVolume', - context: 'when setting the volume of the sound', - error: 'this method is abstract and should not be called.' + origin: "SoundPlayer.setVolume", + context: "when setting the volume of the sound", + error: "this method is abstract and should not be called.", }; } - } diff --git a/src/sound/TonePlayer.js b/src/sound/TonePlayer.js index a7a064e..a552162 100644 --- a/src/sound/TonePlayer.js +++ b/src/sound/TonePlayer.js @@ -7,10 +7,9 @@ * @license Distributed under the terms of the MIT License */ -import * as Tone from 'tone'; +import * as Tone from "tone"; import { isNumeric } from "../util/Util.js"; -import {SoundPlayer} from './SoundPlayer.js'; - +import { SoundPlayer } from "./SoundPlayer.js"; /** *

This class handles the playing of tones.

@@ -28,23 +27,23 @@ import {SoundPlayer} from './SoundPlayer.js'; export class TonePlayer extends SoundPlayer { constructor({ - psychoJS, - note = 'C4', - duration_s = 0.5, - volume = 1.0, - loops = 0, - soundLibrary = TonePlayer.SoundLibrary.TONE_JS, - autoLog = true - } = {}) + psychoJS, + note = "C4", + duration_s = 0.5, + volume = 1.0, + loops = 0, + soundLibrary = TonePlayer.SoundLibrary.TONE_JS, + autoLog = true, + } = {}) { super(psychoJS); - this._addAttribute('note', note); - this._addAttribute('duration_s', duration_s); - this._addAttribute('volume', volume); - this._addAttribute('loops', loops); - this._addAttribute('soundLibrary', soundLibrary); - this._addAttribute('autoLog', autoLog); + this._addAttribute("note", note); + this._addAttribute("duration_s", duration_s); + this._addAttribute("volume", volume); + this._addAttribute("loops", loops); + this._addAttribute("soundLibrary", soundLibrary); + this._addAttribute("autoLog", autoLog); // initialise the sound library: this._initSoundLibrary(); @@ -58,7 +57,6 @@ export class TonePlayer extends SoundPlayer } } - /** * Determine whether this player can play the given sound. * @@ -82,32 +80,32 @@ export class TonePlayer extends SoundPlayer note: sound.value, duration_s: sound.secs, volume: sound.volume, - loops: sound.loops + loops: sound.loops, }); } // if the sound's value is a string, we check whether it is a note: - if (typeof sound.value === 'string') + if (typeof sound.value === "string") { // mapping between the PsychoPY notes and the standard ones: let psychopyToToneMap = new Map(); - for (const note of ['A', 'B', 'C', 'D', 'E', 'F', 'G']) + for (const note of ["A", "B", "C", "D", "E", "F", "G"]) { psychopyToToneMap.set(note, note); - psychopyToToneMap.set(note + 'fl', note + 'b'); - psychopyToToneMap.set(note + 'sh', note + '#'); + psychopyToToneMap.set(note + "fl", note + "b"); + psychopyToToneMap.set(note + "sh", note + "#"); } // check whether the sound's value is a recognised note: const note = psychopyToToneMap.get(sound.value); - if (typeof note !== 'undefined') + if (typeof note !== "undefined") { return new TonePlayer({ psychoJS: sound.psychoJS, note: note + sound.octave, duration_s: sound.secs, volume: sound.volume, - loops: sound.loops + loops: sound.loops, }); } } @@ -116,7 +114,6 @@ export class TonePlayer extends SoundPlayer return undefined; } - /** * Get the duration of the sound. * @@ -130,7 +127,6 @@ export class TonePlayer extends SoundPlayer return this.duration_s; } - /** * Set the duration of the tone. * @@ -144,7 +140,6 @@ export class TonePlayer extends SoundPlayer this.duration_s = duration_s; } - /** * Set the number of loops. * @@ -158,7 +153,6 @@ export class TonePlayer extends SoundPlayer this._loops = loops; } - /** * Set the volume of the tone. * @@ -174,7 +168,7 @@ export class TonePlayer extends SoundPlayer if (this._soundLibrary === TonePlayer.SoundLibrary.TONE_JS) { - if (typeof this._volumeNode !== 'undefined') + if (typeof this._volumeNode !== "undefined") { this._volumeNode.mute = mute; this._volumeNode.volume.value = -60 + volume * 66; @@ -191,7 +185,6 @@ export class TonePlayer extends SoundPlayer } } - /** * Start playing the sound. * @@ -202,7 +195,7 @@ export class TonePlayer extends SoundPlayer */ play(loops) { - if (typeof loops !== 'undefined') + if (typeof loops !== "undefined") { this._loops = loops; } @@ -223,7 +216,7 @@ export class TonePlayer extends SoundPlayer playToneCallback = () => { self._webAudioOscillator = self._audioContext.createOscillator(); - self._webAudioOscillator.type = 'sine'; + self._webAudioOscillator.type = "sine"; self._webAudioOscillator.frequency.value = 440; self._webAudioOscillator.connect(self._audioContext.destination); const contextCurrentTime = self._audioContext.currentTime; @@ -237,7 +230,6 @@ export class TonePlayer extends SoundPlayer { playToneCallback(); } - // repeat forever: else if (this.loops === -1) { @@ -245,22 +237,21 @@ export class TonePlayer extends SoundPlayer playToneCallback, this.duration_s, Tone.now(), - Infinity + Infinity, ); } - else // repeat this._loops times: + else { this._toneId = Tone.Transport.scheduleRepeat( playToneCallback, this.duration_s, Tone.now(), - this.duration_s * (this._loops + 1) + this.duration_s * (this._loops + 1), ); } } - /** * Stop playing the sound immediately. * @@ -288,7 +279,6 @@ export class TonePlayer extends SoundPlayer } } - /** * Initialise the sound library. * @@ -302,24 +292,24 @@ export class TonePlayer extends SoundPlayer _initSoundLibrary() { const response = { - origin: 'TonePlayer._initSoundLibrary', - context: 'when initialising the sound library' + origin: "TonePlayer._initSoundLibrary", + context: "when initialising the sound library", }; if (this._soundLibrary === TonePlayer.SoundLibrary.TONE_JS) { // check that Tone.js is available: - if (typeof Tone === 'undefined') + if (typeof Tone === "undefined") { throw Object.assign(response, { - error: "Tone.js is not available. A different sound library must be selected. Please contact the experiment designer." + error: "Tone.js is not available. A different sound library must be selected. Please contact the experiment designer.", }); } // start the Tone Transport if it has not started already: - if (typeof Tone !== 'undefined' && Tone.Transport.state !== 'started') + if (typeof Tone !== "undefined" && Tone.Transport.state !== "started") { - this.psychoJS.logger.info('[PsychoJS] start Tone Transport'); + this.psychoJS.logger.info("[PsychoJS] start Tone Transport"); Tone.Transport.start(Tone.now()); // this is necessary to prevent Tone from introducing a delay when triggering a note @@ -330,14 +320,14 @@ export class TonePlayer extends SoundPlayer // create a synth: we use a triangular oscillator with hardly any envelope: this._synthOtions = { oscillator: { - type: 'square' //'triangle' + type: "square", // 'triangle' }, envelope: { attack: 0.001, // 1ms - decay: 0.001, // 1ms + decay: 0.001, // 1ms sustain: 1, - release: 0.001 // 1ms - } + release: 0.001, // 1ms + }, }; this._synth = new Tone.Synth(this._synthOtions); @@ -346,7 +336,7 @@ export class TonePlayer extends SoundPlayer this._synth.connect(this._volumeNode); // connect the volume node to the master output: - if (typeof this._volumeNode.toDestination === 'function') + if (typeof this._volumeNode.toDestination === "function") { this._volumeNode.toDestination(); } @@ -358,15 +348,15 @@ export class TonePlayer extends SoundPlayer else { // create an AudioContext: - if (typeof this._audioContext === 'undefined') + if (typeof this._audioContext === "undefined") { const AudioContext = window.AudioContext || window.webkitAudioContext; // if AudioContext is not available (e.g. on IE), we throw an exception: - if (typeof AudioContext === 'undefined') + if (typeof AudioContext === "undefined") { throw Object.assign(response, { - error: `AudioContext is not available on your browser, ${this._psychoJS.browser}, please contact the experiment designer.` + error: `AudioContext is not available on your browser, ${this._psychoJS.browser}, please contact the experiment designer.`, }); } @@ -374,15 +364,13 @@ export class TonePlayer extends SoundPlayer } } } - } - /** * * @type {{TONE_JS: *, AUDIO_CONTEXT: *}} */ TonePlayer.SoundLibrary = { - AUDIO_CONTEXT: Symbol.for('AUDIO_CONTEXT'), - TONE_JS: Symbol.for('TONE_JS') + AUDIO_CONTEXT: Symbol.for("AUDIO_CONTEXT"), + TONE_JS: Symbol.for("TONE_JS"), }; diff --git a/src/sound/TrackPlayer.js b/src/sound/TrackPlayer.js index a481a66..a5dcbda 100644 --- a/src/sound/TrackPlayer.js +++ b/src/sound/TrackPlayer.js @@ -7,8 +7,7 @@ * @license Distributed under the terms of the MIT License */ -import {SoundPlayer} from './SoundPlayer.js'; - +import { SoundPlayer } from "./SoundPlayer.js"; /** *

This class handles the playback of sound tracks.

@@ -30,28 +29,27 @@ import {SoundPlayer} from './SoundPlayer.js'; export class TrackPlayer extends SoundPlayer { constructor({ - psychoJS, - howl, - startTime = 0, - stopTime = -1, - stereo = true, - volume = 0, - loops = 0 - } = {}) + psychoJS, + howl, + startTime = 0, + stopTime = -1, + stereo = true, + volume = 0, + loops = 0, + } = {}) { super(psychoJS); - this._addAttribute('howl', howl); - this._addAttribute('startTime', startTime); - this._addAttribute('stopTime', stopTime); - this._addAttribute('stereo', stereo); - this._addAttribute('loops', loops); - this._addAttribute('volume', volume); + this._addAttribute("howl", howl); + this._addAttribute("startTime", startTime); + this._addAttribute("stopTime", stopTime); + this._addAttribute("stereo", stereo); + this._addAttribute("loops", loops); + this._addAttribute("volume", volume); this._currentLoopIndex = -1; } - /** * Determine whether this player can play the given sound. * @@ -66,10 +64,10 @@ export class TrackPlayer extends SoundPlayer static accept(sound) { // if the sound's value is a string, we check whether it is the name of a resource: - if (typeof sound.value === 'string') + if (typeof sound.value === "string") { const howl = sound.psychoJS.serverManager.getResource(sound.value); - if (typeof howl !== 'undefined') + if (typeof howl !== "undefined") { // build the player: const player = new TrackPlayer({ @@ -79,7 +77,7 @@ export class TrackPlayer extends SoundPlayer stopTime: sound.stopTime, stereo: sound.stereo, loops: sound.loops, - volume: sound.volume + volume: sound.volume, }); return player; } @@ -89,7 +87,6 @@ export class TrackPlayer extends SoundPlayer return undefined; } - /** * Get the duration of the sound, in seconds. * @@ -103,7 +100,6 @@ export class TrackPlayer extends SoundPlayer return this._howl.duration(); } - /** * Set the duration of the track. * @@ -114,14 +110,13 @@ export class TrackPlayer extends SoundPlayer */ setDuration(duration_s) { - if (typeof this._howl !== 'undefined') + if (typeof this._howl !== "undefined") { // Unfortunately Howler.js provides duration setting method this._howl._duration = duration_s; } } - /** * Set the volume of the tone. * @@ -139,7 +134,6 @@ export class TrackPlayer extends SoundPlayer this._howl.mute(mute); } - /** * Set the number of loops. * @@ -163,7 +157,6 @@ export class TrackPlayer extends SoundPlayer } } - /** * Start playing the sound. * @@ -175,7 +168,7 @@ export class TrackPlayer extends SoundPlayer */ play(loops, fadeDuration = 17) { - if (typeof loops !== 'undefined') + if (typeof loops !== "undefined") { this.setLoops(loops); } @@ -184,7 +177,7 @@ export class TrackPlayer extends SoundPlayer if (loops > 0) { const self = this; - this._howl.on('end', (event) => + this._howl.on("end", (event) => { ++this._currentLoopIndex; if (self._currentLoopIndex > self._loops) @@ -205,7 +198,6 @@ export class TrackPlayer extends SoundPlayer this._howl.fade(0, this._volume, fadeDuration, this._id); } - /** * Stop playing the sound immediately. * @@ -216,11 +208,11 @@ export class TrackPlayer extends SoundPlayer */ stop(fadeDuration = 17) { - this._howl.once('fade', (id) => { + this._howl.once("fade", (id) => + { this._howl.stop(id); - this._howl.off('end'); + this._howl.off("end"); }); this._howl.fade(this._howl.volume(), 0, fadeDuration, this._id); } - } diff --git a/src/sound/index.js b/src/sound/index.js index 6cec21e..81637d7 100644 --- a/src/sound/index.js +++ b/src/sound/index.js @@ -1,9 +1,9 @@ -export * from './Sound.js'; -export * from './SoundPlayer.js'; -export * from './TonePlayer.js'; -export * from './TrackPlayer.js'; +export * from "./Sound.js"; +export * from "./SoundPlayer.js"; +export * from "./TonePlayer.js"; +export * from "./TrackPlayer.js"; -export * from './Microphone.js'; -export * from './AudioClip.js'; -export * from './AudioClipPlayer.js'; -//export * from './Transcriber.js'; +export * from "./AudioClip.js"; +export * from "./AudioClipPlayer.js"; +export * from "./Microphone.js"; +// export * from './Transcriber.js';