sound/AudioClipPlayer.js

/**
 * AudioClip Player.
 *
 * @author Alain Pitiot
 * @version 2022.2.3
 * @copyright (c) 2017-2020 Ilixa Ltd. (http://ilixa.com) (c) 2020-2022 Open Science Tools Ltd. (https://opensciencetools.org)
 * @license Distributed under the terms of the MIT License
 */

import { AudioClip } from "./AudioClip.js";
import { SoundPlayer } from "./SoundPlayer.js";

/**
 * <p>This class handles the playback of an audio clip, e.g. a microphone recording.</p>
 *
 * @extends SoundPlayer
 */
export class AudioClipPlayer extends SoundPlayer
{
	/**
	 * @memberOf module:sound
	 * @param {Object} options
	 * @param {module:core.PsychoJS} options.psychoJS - the PsychoJS instance
	 * @param {Object} options.audioClip - the module:sound.AudioClip
	 * @param {number} [options.startTime= 0] - start of playback (in seconds)
	 * @param {number} [options.stopTime= -1] - end of playback (in seconds)
	 * @param {boolean} [options.stereo= true] whether or not to play the sound or track in stereo
	 * @param {number} [options.volume= 1.0] - volume of the sound (must be between 0 and 1.0)
	 * @param {number} [options.loops= 0] - how many times to repeat the track or tone after it has played *
	 */
	constructor({
		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._currentLoopIndex = -1;
	}

	/**
	 * Determine whether this player can play the given sound.
	 *
	 * @param {module:sound.Sound} sound - the sound object, which should be an AudioClip
	 * @return {Object|undefined} an instance of AudioClipPlayer if sound is an AudioClip or undefined otherwise
	 */
	static accept(sound)
	{
		if (sound.value instanceof AudioClip)
		{
			// build the player:
			const player = new AudioClipPlayer({
				psychoJS: sound.psychoJS,
				audioClip: sound.value,
				startTime: sound.startTime,
				stopTime: sound.stopTime,
				stereo: sound.stereo,
				loops: sound.loops,
				volume: sound.volume,
			});
			return player;
		}

		// AudioClipPlayer is not an appropriate player for the given sound:
		return undefined;
	}

	/**
	 * Get the duration of the AudioClip, in seconds.
	 *
	 * @return {number} the duration of the clip, in seconds
	 */
	getDuration()
	{
		return this._audioClip.getDuration();
	}

	/**
	 * Set the duration of the audio clip.
	 *
	 * @param {number} duration_s - the duration of the clip in seconds
	 */
	setDuration(duration_s)
	{
		// TODO

		throw {
			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.
	 *
	 * @param {number} volume - the volume of the playback (must be between 0.0 and 1.0)
	 * @param {boolean} [mute= false] - whether or not to mute the playback
	 */
	setVolume(volume, mute = false)
	{
		this._volume = volume;

		this._audioClip.setVolume((mute) ? 0.0 : volume);
	}

	/**
	 * Set the number of loops.
	 *
	 * @param {number} loops - how many times to repeat the clip after it has played once. If loops == -1, the clip will repeat indefinitely until stopped.
	 */
	setLoops(loops)
	{
		this._loops = loops;
		this._currentLoopIndex = -1;

		// TODO
	}

	/**
	 * Start playing the sound.
	 *
	 * @param {number} loops - how many times to repeat the track after it has played once. If loops == -1, the track will repeat indefinitely until stopped.
	 * @param {number} [fadeDuration = 17] - how long should the fading in last in ms
	 */
	play(loops, fadeDuration = 17)
	{
		if (typeof loops !== "undefined")
		{
			this.setLoops(loops);
		}

		// handle repeats:
		if (loops > 0)
		{
			// TODO
		}

		this._audioClip.startPlayback();
	}

	/**
	 * Stop playing the sound immediately.
	 *
	 * @param {number} [fadeDuration = 17] - how long the fading out should last, in ms
	 */
	stop(fadeDuration = 17)
	{
		this._audioClip.stopPlayback(fadeDuration);
	}
}