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
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.
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.
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
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;
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;
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;
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;
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;
Fosc is free software available under Version 3.0 of the GNU General Public License.