ianring/php-music-tools

A PHP library for music analysis, construction, generation, and more


Keywords
php, music, musicxml, lilypond
License
CNRI-Python-GPL-Compatible

Documentation

PHPMusicTools

A PHP library for music analysis, generation, manipulation, and more

This project is a work in progress. Features described here may not exist or may not work, and there may be features that work that aren't documented here yet. This is a public, open-source project so if you see something that isn't right, be a hero: fork it and fix it!

The class structure in PHPMusicTools (PMT) is modelled closely after the markup of MusicXML, and was derived from an older project named PHPMusicXML. One goal of this project is to be able to manipulate musical language programmatically, and export the result as MusicXML, for easy rendering by a 3rd party typesetting tool. In addition to MusicXML, the project also integrates in certain ways to output for LilyPond, MIDI, SVG, CSV, etc.

Basic Usage

Create a file in your project named composer.json, and put this in it:

{
    "require": {
        "ianring/PHPMusicTools": "dev-master"
    }
}

Then install composer, using this command:

curl -sS https://getcomposer.org/installer | php

Then execute this command:

php composer.phar install

Now you may use PHPMusicTools Classes in your project. For example:

<?php
use ianring\PHPMusicTools;
require 'vendor/autoload.php';

$score = new Score();
// ... lots of things here
echo $score->toXML();

Parts of MusicTools

Parts of MusicTools

Object construction

Every class in PHPMusicTools has two ways to create an instance. The first is to use the "new" keyword, providing its properties as arguments, like this:

$pitch = new Pitch('C', 4, -1);

Each class also has a static constructFromArray() method, which accepts a PHP array for its properties.

$pitch = Pitch::constructFromArray(array(
    'step' => 'C',
    'alter' => 1,
    'octave' => 4,
))

The constructFromArray method is recursive, so if your chord array contains a note array, and your note arrays contain a pitch array, they will be transformed into Chord and Note and Pitch objects.

$chord = Chord::constructFromArray(
    array(
        0 => array(
            'notes' => array(
                0 => array(
                    'pitch' => array(
                        'step' => 'C',
                        'alter' => 1,
                        'octave' => 4,
                    ),
                    'rest' => false,
                )
            )
        )
    )
);

Some object properties are singular, but some properties are plural, like the notes in a Chord or the measures in a Part. In the object construction these are named with their plural nouns, e.g. "notes" is an array of Note objects, "measures" is the array of Measure objects, and so on.

Classes

Pitch

A pitch object has three properties: step, alter, and octave. These are directly mapped to the MusicXML elements that represent the notation of a pitch, so there is a difference between B flat and A sharp.

You can create a pitch like this:

$pitch = new Pitch('C', -1, 4);

You can also use this shorthand:

$p = new Pitch('C-4');

Pitches are cool because you can do transposition on them:

$p->transpose(6); // transposes the pitch up 6 semitones
$p->transpose(-3); // transposes the pitch down 3 semitones

A transposition might result in an altered note, e.g. if $pitch is 'C4', $pitch->transpose(-4) will result in either a G sharp or an A flat. To resolve this ambiguity, transpose() accepts a second argument for its preferred alteration. If omitted, the alteration will be the same as the original note if there is one.

$p->transpose(6, 1); // will create an F sharp.
$p->transpose(6, -1); // will create a G flat.

In MusicXML, pitch is described using "step", "alter", and "octave", whereas in music analysis, pitch is often described using "chroma" and "height". Chroma is the chromatic position in the 12-tone scale, for which we have names like "C sharp". Whereas music notation cares about "step" and "alter" to know the difference between the visual representation of a B flat or A sharp, chroma doesn't carry information about notation, and can be represented as a number from 0 to 12. "Height" is the octave in which the chroma resides. Two pitches can have the same chroma in different heights (e.g. C#4 and C#5), and notes can of course have the same height and different chromas (e.g. D4 and F4).

Heightless pitches

A Pitch might be "heightless", when it represents a Chroma with no "octave" property. Heightlessness is a useful concept in music analysis, because it allows you to examine the use of chromas without regard for their octave. Transposing a heightless pitch will result in another heightless pitch. Heightless pitches can be assigned to Notes (which would be a weird thing to do, but it is possible), but they can not be rendered as XML, so if you're mixing heightless pitches into music that is being rendered as XML, be careful. A heightless pitch may seem like a theoretical construct, but it is in fact possible to generate sounds that have no perceptual height. These are called "Shepard's Tones", and consist of layered harmonics balanced in a way that makes the pitch perceptually heightless.

Note

A Note has many properties; the object constructor is a little crazy

$note = new Note(
    $pitch = new Pitch(),
    $rest = false,
    $duration = 4,
    $voice = 1,
    $type = 'quarter',
    $accidental = 'flat',
    $dot = false,
    $tie = false,
    $timeModification = new TimeModification(),
    $beams = new NoteBeam(),
    $defaultX = null,
    $defaultY = null,
    $chord = false,
    $notations = array(),
    $articulations = array(),
    $staff = 1
);

It's actually easier and more sensible to use the constructFromArray method, because you can pass in only the properties that aren't default:

$note = Note::constructFromArray(
    array(
        'pitch' => array(
            'step' => 'A',
            'alter' => -1,
            'octave' => 3,
        ),
        'duration' => 8
    )
)

Here is the complete construction of a Note with everything provided:

$note = Note::constructFromArray(
    array(
        'pitch' => array( // becomes a Pitch object
            'step' => 'C',
            'alter' => 1,
            'octave' => 4,
        ),
        'rest' => false,
        'duration' => 4,
        'voice' => 1,
        'type' => 'eighth',
        'accidental' => 'sharp',
        'dot' => false,
        'tie' => true,
        'timeModification' => array( // becomes a TimeModification object
            'actualNotes' => 3,
            'normalNotes' => 2,
        ),
        'defaultX' => 3,
        'defaultY' => 1,
        'chord' => true,
        'notations' => array(
            array( // becomes a Tuplet object
                'notationType' => 'tuplet',
                'number' => 1,
                'type' => 'stop',
            ),
            array( // becomes a Slur object
                'notationType' => 'slur',
                'type' => 'start',
                'number' => 1,
            )
        ),
        'articulations' => array(
            array( // becomes an Articulation object
                'articulationType' => 'accent',
                'defaultX' => -1,
                'defaultY' => -71,
                'placement' => 'below',
            ),
        ),
        'staff' => 1,
        'beams' => array(
            array( // becomes a NoteBeam object
                'number' => 1,
                'type' => 'begin',
            ),
            array( // becomes another NoteBeam object
                'number' => 2,
                'type' => 'begin',
            )
        ),
        'stem' => array( // becomes a NoteStem object
            'defaultX' => 2,
            'defaultY' => 3,
            'direction' => 'up',
        )
    )
);

A note can be transposed too.

$note->transpose(5, -1); // transpose up 5 semitones, preferring flats.

Chord

A chord is a group of notes that sound simultaneously. Its only properties is $notes, an array of Note objects.

$chord = new Chord(array($note1, $note2, $note3));

$chord = Chord::constructFromArray(
    array(
        'notes' => array($note1, $note2, $note3)
    )
);


$chord->addNote($note4);

Chords may be transposed:

$chord->transpose(5, -1); // transpose up 5 semitones, preferring flats.

Layer

A layer allows multiple sequences of chords to share a single measure. This is common for notation of counterpoint, and for polyphonic instruments like the piano. Layers have no special properties of their own.

$layer = new Layer();

You can add a chord, or a note.

$layer->addChord($chord);
$layer->addNote($note);

You can add a Note directly to a Layer, but internally it's creating a Chord with one Note in it, and adding that.

Layers may be transposed:

$layer->transpose(5, -1); // transpose up 5 semitones, preferring flats.

Measure

A measure is a collection of layers, together describing one discrete duration of music defined by the time signature.

$measure = new Measure($properties);
$measure->addLayer($layer);

A measure has many properties:

number
the sequential number of this measure, starting from 1
division
the number of divisions of a single beat. If the time signature is 4/4, then one beat is a quarter note. If your measure contains any sixteenth notes, you will need the division to be at least 4. If you also use eighth-note triplets, then the division must be 12. The number of "ticks" (discrete equal time durations, as in a ticking clock) in a measure is beats * divisions, and each note in your measure must be assigned to one of the ticks.
key
Must be a Key object, as described below
time
has properties "beats", and "beat-type", and optionally "symbol".
clef
must be a Clef object, as described below
barlines
may be a single barline or an array of barlines, if the measure has multiple staves. each must be a Barline object, as described below
implicit
boolean. Defaults to false if omitted. If true, then the measure won't be counted with a measure number, as in pickup measures and the last half of mid-measure repeats.
non-controlling
boolean, defaults to false. If true, the left barline of this measure does not coincide with the left barline of measures in other parts.
width
to explicitly set the width of a measure

Key

The Key class builds a Key, to use as the 'key' property in your Measure. It is represented using the properties "fifths" and "mode". In major mode, C major is 0 fifths, G is 1, D is 2... F is -1, B flat is -2. The class provides a shorthand for building a key, by constructing it with a string (like "F minor") instead of an array.

These three ways of creating $key all accomplish the same thing:

$key = new Key(3, 'major');

$key = Key::constructFromArray(
    array(
        'fifths' => 3,
        'mode' => 'major'
    )
);

$key = Key::constructFromString('D major'));

Clef

There is a Clef class which provides a shorthand for creating common clefs. The clef has two properties: sign and line.

// this creates a treble clef
$clef = new Clef(array('sign' => 'G', 'line' => 4));

$clef = Clef::constructFromArray(
    array(
        'sign' => 'G',
        'line' => 4
    )
);

$clef = Clef::constructFromString('treble');

Staves

A measure may contain multiple staves. Each of these has its own clef. The number of staves is controlled by the number of clefs. To override the number of staves for complex notation situations, put a number in the "staves" property.

// This measure will have two staves, without having to set the "staves" property
$measure->setProperty('clef', array(
    new Clef('treble'),
    new Clef('bass')
));

// explicitly use a different number of staves
$measure->setProperty('staves', 3);

Barline

The Barline class has four main properties: "location", "bar-style", "repeat", and "ending". "repeat" has sub-properties "direction" and "winged". "ending" has sub-properties "type" and "number".

$barline = Barline::constructFromArray(
    array(
        'location' => 'right',
        'bar-style' => 'heavy-light',
        'repeat' => array( // this becomes a BarlineRepeat object
            'direction' => 'backward',
            'winged' => 'none'
        ),
        'ending' => array( // this becomes a BarlineEnding object
            'type' => 'stop',
            'number' => 2
        )
    )
);

Barlines are added to a Measure by setting to the "barline" property.

$measure->setProperty('barline', $barline);
$measure->setProperty('barline', array($barline1, $barline2));
$measure->addBarline($barline);

Part

A part is a sequence of measures intended to be played by the same instrument. Parts have a name, and an array of measures.

$part = new Part('Pianoforte', array());
$part->addMeasure($measure);

bv

Score

A score is the collection of all the parts being played by all the instruments. It is the highest-level element in MusicXML, and so it's usually where you will call the toXML() method.

$score = new Score();
$score->addPart($part);

echo $score->toXML();

Helper Classes

PHPMusicTools contains some interesting helper classes, that have no influence on typesetting scores, but which have application for music analysis or transformation.

Scale

The scale class gives you access to a collection of common scales, by name. A Scale object has two properties; one is the "root" which must be a Pitch object, and the other is the "mode". You can create a scale using shorthand,

$scale = new Scale('D# Phrygian');

$scale = new Scale(array(
    'root' => new Pitch('D#'),
    'mode' => 'phrygian'
));

$scale = new Scale(array(
    'root' => 'D#4',
    'mode' => 'Phrygian',
    'direction' => 1
));

Mode names are case-insensitive, but spelling counts. The class understands aliases for modes with more than one common name, e.g. "ionian" is the same as "major".

Note that the root can be a heightless pitch to describe a heightless Scale, or it may be a pitch with an octave to anchor the scale at a certain height.

Scales can also have an optional property of "direction", which is either 1 (ascending) or -1 (descending).

$scale->setProperty('direction', -1);

Scale objects are used for autoTune(), can be returned by functions that do analysis, and can be used to render sequences of Notes.

Resources