UNPKG

satie

Version:

A sheet music renderer for the web

220 lines (198 loc) 8.71 kB
/** * This file is part of Satie music engraver <https://github.com/jnetterf/satie>. * Copyright (C) Joshua Netterfield <joshua.ca> 2015 - present. * * Satie is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * Satie is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with Satie. If not, see <http://www.gnu.org/licenses/>. */ /** * @file part of Satie test suite */ import {hasAccidental, lineForClef, linesForClef, heightDeterminingLine, startingLine, onLedger, ledgerLines} from "../private_chordUtil"; import {Note, Count} from "musicxml-interfaces"; import {buildClef, buildNote, INoteBuilder} from "musicxml-interfaces/builders"; import {expect} from "chai"; import {makeCursor} from "./attributes_test"; describe("[engine/ichord.ts]", function() { describe("hasAccidental", function() { it("works with rests", function() { let notes: Note[] = [{ rest: {} }]; let cursor = makeCursor(null, <any> [notes]); expect(hasAccidental(notes, cursor)).to.eq(false); }); }); const treble = buildClef(clef => clef .sign("G") .line(2)); const withRoot = (root: string, octave: number) => (note: INoteBuilder) => note .pitch(pitch => pitch .step(root) .octave(octave)) .duration(1) .noteType(noteType => noteType .duration(Count.Quarter)); const noteC = buildNote(withRoot("C", 4)); const noteD = buildNote(withRoot("D", 4)); const noteG = buildNote(withRoot("G", 5)); const noteA = buildNote(withRoot("A", 5)); const noteCHigher = buildNote(withRoot("C", 6)); const noteR = buildNote(note => note .rest({}) .noteType(noteType => noteType .duration(Count.Half))); describe("lineForClef", function() { it("handles a null note", function() { expect(lineForClef(null, treble)).to.equal(3); }); it("throws on a null clef", function() { expect(() => lineForClef(noteC, null)).to.throw(); expect(() => lineForClef(null, null)).to.throw(); }); it("calculates middle C", function() { let bass = buildClef(clef => clef .sign("F") .line(4)); expect(lineForClef(noteC, treble)).to.equal(0); expect(lineForClef(noteC, bass)).to.equal(6); }); it("calculates whole rest", function() { let note = buildNote(note => note .rest({}) .noteType(noteType => noteType .duration(Count.Whole))); let clef2 = buildClef(clef => clef .sign("C") .line(2)); expect(lineForClef(note, treble)).to.equal(4); expect(lineForClef(note, clef2)).to.equal(4); }); it("calculates half rest", function() { let clef = buildClef(clef => clef .sign("G") .line(2)); expect(lineForClef(noteR, clef)).to.equal(3); }); }); describe("linesForClef", function() { it("doesn't choke on empty chord", function() { expect(linesForClef([], treble)).to.deep.equal([]); }); it ("throws on null clef", function() { const note1 = buildNote(note => note .rest({}) .noteType(noteType => noteType .duration(Count.Half))); expect(() => linesForClef([], null)).to.throw(); expect(() => linesForClef([note1], null)).to.throw(); }); it("seems to work", function() { const note1 = buildNote(note => note .rest({}) .noteType(noteType => noteType .duration(Count.Half))); expect(linesForClef([note1, noteC], treble)).to.deep.equal([3, 0]); }); }); describe("heightDeterminingLine", function() { it("calculates single line", function() { const note1 = buildNote(note => note .rest({}) .noteType(noteType => noteType .duration(Count.Half))); expect(heightDeterminingLine([note1], 1, treble)).to.deep.equal(3); expect(heightDeterminingLine([note1], -1, treble)).to.deep.equal(3); }); it("calculates inner line", function() { const note2 = buildNote(note => note .pitch(pitch => pitch .step("C") .octave(5)) .duration(1) .noteType(noteType => noteType .duration(Count.Quarter))); expect(heightDeterminingLine([noteC, note2], 1 /* Up */, treble)).to.equal(3.5); expect(heightDeterminingLine([note2, noteC], 1 /* Up */, treble)).to.equal(3.5); expect(heightDeterminingLine([noteC, note2], -1 /* Down */, treble)).to.equal(0); expect(heightDeterminingLine([note2, noteC], -1 /* Down */, treble)).to.equal(0); }); it("throws on invalid direction", function() { expect(() => heightDeterminingLine([noteC], <any> "1", treble)).to.throw(); expect(() => heightDeterminingLine([noteC], NaN, treble)).to.throw(); expect(() => heightDeterminingLine([noteC], 0.5, treble)).to.throw(); expect(() => heightDeterminingLine([noteC], 0, treble)).to.throw(); }); }); describe("startingLine", function() { it("calculates outer line for 3 notes", function() { const note2 = buildNote(note => note .pitch(pitch => pitch .step("C") .octave(5)) .duration(1) .noteType(noteType => noteType .duration(Count.Quarter))); const note3 = buildNote(note => note .pitch(pitch => pitch .step("G") .octave(4)) .duration(1) .noteType(noteType => noteType .duration(Count.Quarter))); expect(startingLine([noteC, note2, note3], -1 /* Down */, treble)).to.equal(3.5); expect(startingLine([note2, noteC, note3], -1 /* Down */, treble)).to.equal(3.5); expect(startingLine([noteC, note3, note2], 1 /* Up */, treble)).to.equal(0); expect(startingLine([noteC, note3, note2], 1 /* Up */, treble)).to.equal(0); }); }); describe("onLedger", function() { it("determines middle C to have a ledger", function() { expect(onLedger(noteC, treble)).to.be.true; }); it("determines middle D to not have a ledger", function() { expect(onLedger(noteD, treble)).to.be.false; }); it("determines high G to not have a ledger", function() { expect(onLedger(noteG, treble)).to.be.false; }); it("determines high A to have a ledger", function() { expect(onLedger(noteA, treble)).to.be.true; }); it("determintes rests to not have ledgers", function() { expect(onLedger(noteR, treble)).to.be.false; const noteROdd = buildNote(note => note .rest(rest => rest .displayStep("A") .displayOctave(5)) .noteType(type => type .duration(Count.Half))); expect(onLedger(noteROdd, treble)).to.be.false; }); }); describe("ledgerLines", function() { it("throws if clef is missing", function() { expect(() => ledgerLines([noteC], null)).to.throw(); }); it("calculates valid answers for single notes", function() { expect(ledgerLines([noteC], treble)).to.deep.equal([0]); expect(ledgerLines([noteD], treble)).to.deep.equal([]); expect(ledgerLines([noteG], treble)).to.deep.equal([]); expect(ledgerLines([noteA], treble)).to.deep.equal([6]); }); it("does not double count", function() { expect(ledgerLines([noteA, noteCHigher], treble)).to.deep.equal([6, 7]); }); }); });