import { ModificationBase, NoteDetails } from './ModificationBase.mjs';
import * as WebAudioApiErrors from '../modules/Errors.mjs';
/**
* Class representing a Fermata modification.
*
* A Fermata modification causes a note to be played for a longer duration than specified.
* By default, the duration will be twice what is originally specified.
*
* @extends ModificationBase
*/
export class Fermata extends ModificationBase {
/**
* Constructs a new {@link Fermata} modification object.
*/
constructor(tempo, key, details) {
super(tempo, key, details);
}
/**
* Returns a list of all parameters available for use in this modification, including whether
* the parameter is required or optional when playing back either a "sequence" or just a
* single "note".
*
* @returns {Object<string,Object<string,string[]>>} List of modification-specific parameter keys and when they are required
*/
static getParameters() {
return {
required: {
singleNote: [],
sequence: []
},
optional: {
singleNote: ['relativeDelayExtension'],
sequence: []
}
};
}
/**
* Returns whether this modification can be used to modify a sequence of notes.
*
* @returns {boolean} Whether this modification can be used to modify a sequence of notes
*/
static canModifySequence() {
return false;
}
static inferParametersFromSequence() {
throw new WebAudioApiErrors.WebAudioValueError('The "Fermata" modification cannot infer any parameters from a sequence of notes');
}
/**
* Returns a list of all modified notes, durations, and velocities as generated by the
* corresponding modification class.
*
* The `details` variable may contain the following optional key:
*
* `relativeDelayExtension`: How much longer than the original duration the note should be
* held. A value of 1.0 means to hold the note for its exact duration, whereas a value of
* 2.0 means to hold the note for twice as long. If no value is specified, this parameter
* will default to 2.0.
*
* @param {Object<string, number>} details - Information about the length of the fermata
* @returns {NoteDetails[]} List of {@link NoteDetails} to replace the original note
*/
getModifiedNoteDetails(details={relativeDelayExtension: 2.0}) {
if (!('relativeDelayExtension' in details))
details.relativeDelayExtension = (('implicit' in details) ? details.implicit : 2.0);
if (Number(details.relativeDelayExtension) < 1.0)
throw new WebAudioApiErrors.WebAudioValueError(`The relative delay extension (${details.relativeDelayExtension}) must be at least 1.0`);
return [new NoteDetails(
this.unmodifiedDetails.note,
this.unmodifiedDetails.velocity,
this.unmodifiedDetails.duration / Number(details.relativeDelayExtension)
)];
}
}