/fosc

A SuperCollider API for generating musical notation in LilyPond.

Primary LanguageSuperColliderGNU General Public License v3.0GPL-3.0

Fosc

Fosc is a SuperCollider API for generating musical notation in LilyPond.

Fosc stands for FO-rmalised S-core C-ontrol (FO-r S-uperC-ollider). It's a close relative of Abjad, and ports much of Abjad's Python code base to SuperCollider.

Fosc lets you:

  • Create musical notation in an object-oriented way
  • Generate and transform musical materials
  • Construct powerful component selectors and iterators for modifying musical objects in a score
  • Control all of the typographic details of music notation
  • Play musical scores through scsynth


Installation

Install LilyPond

LilyPond is an open-source program that engraves music notation in an automated way. Fosc uses LilyPond to produce notational output. It's recommended that you install the most recent version of LilyPond directly from the LilyPond website.


Install Fosc

Download the fosc master branch and unzip. Rename the 'fosc-master' folder to 'fosc'. Move the 'fosc' folder to your SuperCollider Extensions directory. Information on installing SuperCollider extensions can be found here: https://doc.sccode.org/Guides/UsingExtensions.html.


Configure Fosc

In your sclang startup file, add code to allow Fosc to communicate with LilyPond. Note: it's possible that your LilyPond executable is installed somewhere different to the standard locations below.

Mac OS X

Fosc.lilypondPath = "/Applications/LilyPond.app/Contents/Resources/bin/lilypond";

Linux

Fosc.lilypondPath = "/usr/local/bin/lilypond";


Once you've saved your changes, recompile the SuperCollider class library and test that Fosc is able to call LilyPond.

Fosc.lilypondVersion;
2.19.82


Creating score objects


Display a note.

a = FoscNote(60, 1/4);
a.show;


Display some notes in sequence.

a = FoscVoice([FoscNote(60, 1/4), FoscNote(62, 1/8)]);
a.show;


View LilyPond output in the Post window.

a = FoscVoice([FoscNote(60, 1/4), FoscNote(62, 1/8)]);
a.lilypond;
\new Voice {
    c'4
    d'8
}


Display a score.

a = FoscVoice([FoscNote("c'", 1/4), FoscNote("d'", 1/8)]);
b = FoscVoice([FoscNote("bf", 1/8), FoscNote("af", 1/4)]);
c = FoscScore([FoscStaff([a]), FoscStaff([b])]);
c.show;


Augmenting and tweaking score objects


Indicators attach to leaves.

a = FoscNote(60, 1/4);
a.attach(FoscArticulation('>'));
a.attach(FoscDynamic('f'));
a.show;


Spanners attach to two or more contiguous leaves.

a = FoscStaff(#[60,62,64,65].collect { |pitch| FoscNote(pitch, 1/8) });
a.selectLeaves.slur;
a.selectLeaves.hairpin('p < f');
a.show;


Override LilyPond Grob properties.

a = FoscNote(60, 1/4);
override(a).noteHead.style = 'harmonic';
a.show;


Set LilyPond Context properties.

a = FoscScore([FoscStaff(#[60,62,64,65].collect { |pitch| FoscNote(pitch, 1/8) })]);
set(a[0]).instrumentName = FoscMarkup("Violin");
set(a).proportionalNotationDuration = FoscSchemeMoment(#[1,64]);
a.show;


Creating music with FoscMusicMaker


Make music from durations and pitches.

a = FoscMusicMaker();
b = a.(durations: 1/4 ! 4, pitches: #[60,62,64,65]);
b.show;


Use a string of LilyPond note names.

a = FoscMusicMaker();
b = a.(durations: 1/4 ! 4, pitches: "c' d' ef' f'");
b.show;


Pitches are repeated cyclically when the length of pitches is less than the length of durations.

a = FoscMusicMaker();
b = a.(durations: [3/8,1/8,2/8,2/8], pitches: #[60,62]);
b.show;


divisions embed into durations as rhythmic proportions.

a = FoscMusicMaker();
b = a.(durations: [2/16,3/16,5/16], divisions: #[[3,1],[3,2],[4,3]]);
b.show;


Negative divisions are rests.

a = FoscMusicMaker();
b = a.(durations: [2/16,3/16,5/16], divisions: #[[-3,1],[3,2],[4,-3]]);
b.show;


Rhythm cells are repeated cyclically when the length of durations is less than the length of divisions.

a = FoscMusicMaker();
b = a.(durations: [1/4], divisions: #[1,1,1,1,1] ! 4);
b.show;


Rhythm cells are repeated cyclically when the length of divisions is less than the length of durations.

a = FoscMusicMaker();
b = a.(durations: 1/4 ! 4, divisions: #[[-1,2,2],[4,-1]]);
b.show;


Apply a mask to fuse contiguous musical events. Mask patterns repeat cyclically. pitches are added after a mask is applied.

a = FoscMusicMaker();
b = a.(durations: 1/4 ! 4, divisions: #[[1,1,1,1,1]], mask: #[2,1], pitches: #[60,62]);
b.show;


Negative mask values are rests.

a = FoscMusicMaker();
b = a.(durations: 1/4 ! 4, divisions: #[[1,1,1,1,1]], mask: #[2,-1], pitches: #[60,62]);
b.show;


Selections


Select all score components.

a = FoscStaff([FoscRest(1/4), FoscNote(60, 1/4), FoscNote(62, 1/4)]);
b = a.selectComponents;
b.do { |each| each.cs.postln };
FoscStaff([  ], Staff, false, nil)
FoscRest(1/4)
FoscNote("c'", 1/4)
FoscNote("d'", 1/4)


Select notes and rests.

a = FoscStaff([FoscRest(1/4), FoscNote(60, 1/4), FoscNote(62, 1/4)]);
b = a.selectComponents(type: [FoscNote, FoscRest]);
b.do { |each| each.cs.postln };
FoscRest(1/4)
FoscNote("c'", 1/4)
FoscNote("d'", 1/4)


Select pitched leaves.

a = FoscStaff([FoscRest(1/4), FoscNote(60, 1/4), FoscChord(#[60,64,67], 1/4)]);
b = a.selectLeaves(pitched: true);
b.do { |each| each.cs.postln };
FoscNote("c'", 1/4)
FoscChord("c' e' g'", 1/4)


Attach indicators to all leaves in a selection.

a = FoscMusicMaker();
b = a.(durations: 1/8 ! 8, pitches: (60..67));
c = FoscStaff(b);
c.selectLeaves(pitched: true).do { |each| each.attach(FoscArticulation('>')) };
c.show;


Iteration


Iterate over all score components.

a = FoscMusicMaker();
b = a.(durations: 1/8 ! 8, pitches: (60..67));
c = FoscStaff(b);
c.doComponents({ |each| each.cs.postln });
FoscStaff([  ], Staff, false, nil)
FoscNote("c'", 1/8)
FoscNote("cs'", 1/8)
FoscNote("d'", 1/8)
FoscNote("ef'", 1/8)
FoscNote("e'", 1/8)
FoscNote("f'", 1/8)
FoscNote("fs'", 1/8)
FoscNote("g'", 1/8)


Iterate over notes, attaching indicators.

a = FoscMusicMaker();
b = a.(durations: 1/8 ! 4, mask: #[-1,1,1,1], pitches: #[60,61,62]);
c = FoscStaff(b);
c.doComponents({ |note| note.attach(FoscArticulation('>')) }, type: FoscNote);
c.show;


Iterate over runs, attaching slurs.

a = FoscMusicMaker();
b = a.(durations: 1/8 ! 8, mask: #[-1,1,1,1,-1,1,1,1], pitches: (60..65));
c = FoscStaff(b);
c.doRuns { |run| if (run.size > 1) { run.slur } };
c.show;


License

Fosc is free software available under Version 3.0 of the GNU General Public License.