Source: music21/figuredBass.js

/**
 * @namespace music21.figuredBass
 * @exports music21/figuredBass
 */
import * as pitch from './pitch.js';

const shorthandNotation = {
    '': [5, 3],
    '5': [5, 3],
    '6': [6, 3],
    '7': [7, 5, 3],
    '9': [9, 7, 5, 3],
    '11': [11, 9, 7, 5, 3],
    '13': [13, 11, 9, 7, 5, 3],
    '6,5': [6, 5, 3],
    '4,3': [6, 4, 3],
    '4,2': [6, 4, 2],
    '2': [6, 4, 2],
};
/**
 * In music21p is in figuredBass.notation -- eventually to be moved there.
 */


/**
 * @memberof music21.figuredBass
 */
export class Notation {
    /**
     *
     * @param {string} [notationColumn='']
     * @property {string[]} figureStrings
     * @property {int[]} origNumbers
     * @property {int[]} numbers
     * @property {string[]} modifierStrings
     * @property {Modifier[]} modifiers
     * @property {Figure[]} figures
     */
    constructor(notationColumn='') {
        this.notationColumn = notationColumn;
        this.figureStrings = undefined;
        this.origNumbers = undefined;
        this.origModStrings = undefined;
        this.numbers = undefined;
        this.modifierStrings = undefined;
        this._parseNotationColumn();
        this._translateToLonghand();

        this.modifiers = undefined;
        this.figures = undefined;
        this._getModifiers();
        this._getFigures();
    }

    /**
     * _parseNotationColumn - Given a notation column below a pitch, defines both this.numbers
     *    and this.modifierStrings, which provide the intervals above the
     *    bass and (if necessary) how to modify the corresponding pitches
     *    accordingly.
     *
     * @return {undefined}
     */

    _parseNotationColumn() {
        const nc = this.notationColumn;
        const figures = nc.split(/,/);
        const numbers = [];
        const modifierStrings = [];
        const figureStrings = [];

        for (let figure of figures) {
            figure = figure.trim();
            figureStrings.push(figure);
            let numberString = '';
            let modifierString = '';
            for (const c of figure) {
                if (c.match(/\d/)) {
                    numberString += c;
                } else {
                    modifierString += c;
                }
            }
            let number;
            if (numberString !== '') {
                number = parseInt(numberString);
            }
            numbers.push(number);
            if (modifierString === '') {
                modifierString = undefined;
            }
            modifierStrings.push(modifierString);
        }
        this.origNumbers = numbers;
        this.numbers = numbers;
        this.modifierStrings = modifierStrings;
        this.figureStrings = figureStrings;
    }

    _translateToLonghand() {
        let oldNumbers = this.numbers;
        let newNumbers = oldNumbers;
        const oldModifierStrings = this.modifierStrings;
        let newModifierStrings = oldModifierStrings;
        const oldNumbersString = oldNumbers.toString();

        if (shorthandNotation[oldNumbersString] !== undefined) {
            newNumbers = shorthandNotation[oldNumbersString];
            newModifierStrings = [];
            const temp = [];
            for (const number of oldNumbers) {
                if (number === undefined) {
                    temp.push(3);
                } else {
                    temp.push(number);
                }
            }
            oldNumbers = temp;

            for (const number of newNumbers) {
                let newModifierString;
                if (oldNumbers.includes(number)) {
                    const modifierStringIndex = oldNumbers.indexOf(number);
                    newModifierString = oldModifierStrings[modifierStringIndex];
                }
                newModifierStrings.push(newModifierString);
            }
        } else {
            const temp = [];
            for (const number of oldNumbers) {
                if (number === undefined) {
                    temp.push(3);
                } else {
                    temp.push(number);
                }
            }
            newNumbers = temp;
        }
        this.numbers = newNumbers;
        this.modifierStrings = newModifierStrings;
    }

    _getModifiers() {
        const modifiers = [];
        for (let i = 0; i < this.numbers.length; i++) {
            const modifierString = this.modifierStrings[i];
            const modifier = new Modifier(modifierString);
            modifiers.push(modifier);
        }
        this.modifiers = modifiers;
    }

    _getFigures() {
        const figures = [];
        for (let i = 0; i < this.numbers.length; i++) {
            const number = this.numbers[i];
            const modifierString = this.modifierStrings[i];
            const figure = new Figure(number, modifierString);
            figures.push(figure);
        }
        this.figures = figures;
    }
}

/**
 * @memberOf music21.figuredBass
 */
export class Figure {
    constructor(number, modifierString) {
        this.number = number;
        this.modifierString = modifierString;
        this.modifier = new Modifier(modifierString);
    }
}

const specialModifiers = {
    '+': '#',
    '/': '-',
    '\\': '#',
    b: '-',
    bb: '--',
    bbb: '---',
    bbbb: '-----',
    '++': '##',
    '+++': '###',
    '++++': '####',
};

/**
 * @memberOf music21.figuredBass
 */
export class Modifier {
    constructor(modifierString) {
        this.modifierString = modifierString;
        this.accidental = this._toAccidental();
    }

    _toAccidental() {
        let modStr = this.modifierString;
        if (modStr === undefined || modStr === '') {
            return undefined;
        }
        const a = new pitch.Accidental();
        if (specialModifiers[modStr] !== undefined) {
            modStr = specialModifiers[modStr];
        }
        a.set(modStr);
        return a;
    }

    modifyPitchName(pitchNameToAlter) {
        const pitchToAlter = new pitch.Pitch(pitchNameToAlter);
        this.modifyPitch(pitchToAlter, true);
        return pitchToAlter.name;
    }

    modifyPitch(pitchToAlter, inPlace) {
        if (inPlace !== true) {
            pitchToAlter = pitchToAlter.clone();
        }

        if (this.accidental === undefined) {
            return pitchToAlter;
        }

        if (
            this.accidental.alter === 0.0
            || pitchToAlter.accidental === undefined
        ) {
            pitchToAlter.accidental = this.accidental.clone();
        } else {
            const newAccidental = new pitch.Accidental();
            const newAlter
                = pitchToAlter.accidental.alter + this.accidental.alter;
            newAccidental.set(newAlter);
            pitchToAlter.accidental = newAccidental;
        }
        return pitchToAlter;
    }
}

Music21j, Copyright © 2013-2021 Michael Scott Asato Cuthbert.
Documentation generated by JSDoc 3.6.3 on Wed Jul 31st 2019 using the DocStrap template.