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

Value setter for various types of audio players #527

Draft
wants to merge 3 commits into
base: 2022.2.3
Choose a base branch
from
Draft
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
38 changes: 35 additions & 3 deletions src/sound/AudioClipPlayer.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,22 @@ export class AudioClipPlayer extends SoundPlayer
this._currentLoopIndex = -1;
}

/**
* Determine whether this player can play the given sound.
*
* @param {string} value - the sound object, which should be an AudioClip
* @return {boolean} whether or not the value is supported
*/
static checkValueSupport (value)
{
if (value instanceof AudioClip)
{
return true;
}

return false;
}

/**
* Determine whether this player can play the given sound.
*
Expand All @@ -58,10 +74,10 @@ export class AudioClipPlayer extends SoundPlayer
*/
static accept(sound)
{
if (sound.value instanceof AudioClip)
if (AudioClipPlayer.checkValueSupport(sound.value))
{
// build the player:
const player = new AudioClipPlayer({
return new AudioClipPlayer({
psychoJS: sound.psychoJS,
audioClip: sound.value,
startTime: sound.startTime,
Expand All @@ -70,7 +86,6 @@ export class AudioClipPlayer extends SoundPlayer
loops: sound.loops,
volume: sound.volume,
});
return player;
}

// AudioClipPlayer is not an appropriate player for the given sound:
Expand Down Expand Up @@ -129,6 +144,23 @@ export class AudioClipPlayer extends SoundPlayer
// TODO
}

/**
* Set the audio clip.
*
* @param {Object} options.audioClip - the module:sound.AudioClip.
*/
setAudioClip (audioClip)
{
if (audioClip instanceof AudioClip)
{
if (this._audioClip !== undefined)
{
this.stop();
}
this._audioClip = audioClip;
}
}

/**
* Start playing the sound.
*
Expand Down
37 changes: 37 additions & 0 deletions src/sound/Sound.js
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,43 @@ export class Sound extends PsychObject
};
}

/**
* Set value for a particular player
*
* @param {number|string} [value = "C"] the sound value (see above for a full description)
*/
setValue(value = "C", log = false)
{
this._setAttribute("value", value, log);

if (this._player === undefined)
{
return;
}

// Analyse the value and change the type of player if needed.
const valSupported = this._player.constructor.checkValueSupport(value);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not working fully yet. Issues arise when trying to convert from one type of player to the other and passing note as a string.

if (valSupported)
{
if (this._player instanceof TonePlayer)
{
this._player.setNote(value);
}
else if (this._player instanceof TrackPlayer)
{
this._player.setTrack(value);
}
else if (this._player instanceof AudioClipPlayer)
{
this._player.setAudioClip(value);
}
}
else
{
this._getPlayer();
}
}

/**
* Set the number of loops.
*
Expand Down
70 changes: 47 additions & 23 deletions src/sound/TonePlayer.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,28 +63,19 @@ export class TonePlayer extends SoundPlayer
/**
* Determine whether this player can play the given sound.
*
* <p>Note: if TonePlayer accepts the sound but Tone.js is not available, e.g. if the browser is IE11,
* we throw an exception.</p>
*
* @param {module:sound.Sound} sound - the sound
* @return {Object|undefined} an instance of TonePlayer that can play the given sound or undefined otherwise
* @param {string|number} value - potential note of the tone.
* @return {boolean} whether or not this value can be used by TonePlayer.
*/
static accept(sound)
static checkValueSupport (value)
{
// if the sound's value is an integer, we interpret it as a frequency:
if (isNumeric(sound.value))
if (isNumeric(value))
{
return new TonePlayer({
psychoJS: sound.psychoJS,
note: sound.value,
duration_s: sound.secs,
volume: sound.volume,
loops: sound.loops,
});
return true;
}

// if the sound's value is a string, we check whether it is a note:
if (typeof sound.value === "string")
if (typeof value === "string")
{
// mapping between the PsychoPY notes and the standard ones:
let psychopyToToneMap = new Map();
Expand All @@ -96,19 +87,38 @@ export class TonePlayer extends SoundPlayer
}

// check whether the sound's value is a recognised note:
const note = psychopyToToneMap.get(sound.value);
const note = psychopyToToneMap.get(value);
if (typeof note !== "undefined")
{
return new TonePlayer({
psychoJS: sound.psychoJS,
note: note + sound.octave,
duration_s: sound.secs,
volume: sound.volume,
loops: sound.loops,
});
return true;
}
}

return false;
}

/**
* Determine whether this player can play the given sound and if so return an instance of the player.
*
* <p>Note: if TonePlayer accepts the sound but Tone.js is not available, e.g. if the browser is IE11,
* we throw an exception.</p>
*
* @param {module:sound.Sound} sound - the sound
* @return {Object|undefined} an instance of TonePlayer that can play the given sound or undefined otherwise
*/
static accept(sound)
{
if (TonePlayer.checkValueSupport(sound.value))
{
return new TonePlayer({
psychoJS: sound.psychoJS,
note: sound.value,
duration_s: sound.secs,
volume: sound.volume,
loops: sound.loops,
});
}

// TonePlayer is not an appropriate player for the given sound:
return undefined;
}
Expand Down Expand Up @@ -172,6 +182,20 @@ export class TonePlayer extends SoundPlayer
}
}

/**
* Set the note for tone.
*
* @param {string|number} - note (if string) or frequency (if number)
*/
setNote (note = "C4")
{
this._note = note;
if (this._synth !== undefined)
{
this._synth.setNote(note);
}
}

/**
* Start playing the sound.
*
Expand Down
58 changes: 53 additions & 5 deletions src/sound/TrackPlayer.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
*/

import { SoundPlayer } from "./SoundPlayer.js";
import { Howl } from "howler";

/**
* <p>This class handles the playback of sound tracks.</p>
Expand Down Expand Up @@ -51,6 +52,22 @@ export class TrackPlayer extends SoundPlayer
this._currentLoopIndex = -1;
}

/**
* Determine whether this player can play the given sound.
*
* @param {string} value - the sound, which should be the name of an audio resource file
* @return {boolean} whether or not value is supported
*/
static checkValueSupport (value)
{
if (typeof value === "string")
{
return true;
}

return false;
}

/**
* Determine whether this player can play the given sound.
*
Expand All @@ -60,14 +77,16 @@ export class TrackPlayer extends SoundPlayer
*/
static accept(sound)
{
let howl = undefined;

// if the sound's value is a string, we check whether it is the name of a resource:
if (typeof sound.value === "string")
if (TrackPlayer.checkValueSupport(sound.value))
{
const howl = sound.psychoJS.serverManager.getResource(sound.value);
if (typeof howl !== "undefined")
howl = sound.psychoJS.serverManager.getResource(sound.value);
if (howl !== undefined)
{
// build the player:
const player = new TrackPlayer({
return new TrackPlayer({
psychoJS: sound.psychoJS,
howl: howl,
startTime: sound.startTime,
Expand All @@ -76,7 +95,6 @@ export class TrackPlayer extends SoundPlayer
loops: sound.loops,
volume: sound.volume,
});
return player;
}
}

Expand Down Expand Up @@ -142,6 +160,36 @@ export class TrackPlayer extends SoundPlayer
}
}

/**
* Set new track to play.
*
* @param {Object|string} track - a track resource name or Howl object (see {@link https://howlerjs.com/})
*/
setTrack (track)
{
let newHowl = undefined;

if (typeof track === "string")
{
newHowl = this.psychoJS.serverManager.getResource(track);
}
else if (track instanceof Howl)
{
newHowl = track;
}

if (newHowl !== undefined)
{
this._howl.once("fade", (id) =>
{
this._howl.stop(id);
this._howl.off("end");
this._howl = newHowl;
});
this._howl.fade(this._howl.volume(), 0, 17, this._id);
}
}

/**
* Start playing the sound.
*
Expand Down