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 complex rhythms through rhythm-makers and meter-rewriting
- Construct powerful component selectors and iterators for transforming musical objects in a score
- Control all of the typographic details of music notation
- Play musical scores through scsynth and MIDI
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. After you install LilyPond, check to see if LilyPond is callable from your command line.
~$ lilypond --version
GNU LilyPond 2.19.83
Copyright (c) 1996--2015 by
Han-Wen Nienhuys <hanwen@xs4all.nl>
Jan Nieuwenhuizen <janneke@gnu.org>
and others.
This program is free software. It is covered by the GNU General Public
License and you are welcome to change it and/or distribute copies of it
under certain conditions. Invoke as `lilypond --warranty` for more
information.
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 binary may be installed somewhere different to the standard locations below.
Mac OS X
FoscConfiguration.lilypondExecutablePath = "/Applications/LilyPond.app/Contents/Resources/bin/lilypond";
Linux
FoscConfiguration.lilypondExecutablePath = "/usr/local/bin/lilypond";
Once you've saved your changes, recompile the SuperCollider class library and test that Fosc is able to call LilyPond.
FoscConfiguration.getLilypondVersionString;
2.19.82
Display a note.
a = FoscNote(60, 1/4);
a.show;
Display some notes in sequence.
a = FoscVoice([FoscNote('C4', 1/4), FoscNote('D4', 1/8)]);
a.show;
View LilyPond output in the Post window.
a = FoscVoice([FoscNote('C4', 1/4), FoscNote('D4', 1/8)]);
a.format;
\new Voice {
c'4
d'8
}
Display a score.
a = FoscVoice([FoscNote('C4', 1/4), FoscNote('D4', 1/8)]);
b = FoscVoice([FoscNote('Bb3', 1/8), FoscNote('Ab3', 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(FoscLeafMaker().(#[60,62,64,65], [1/8]));
a.selectLeaves.slur;
a.selectLeaves.hairpin('p < f');
a.show;
Tweak LilyPond Grob properties.
a = FoscNote(60, 1/4);
tweak(a.noteHead).style = 'harmonic';
a.show;
Override LilyPond Grob properties.
a = FoscNote(60, 1/4);
override(a).noteHead.color = 'red';
a.show;
Set LilyPond Context properties.
a = FoscScore([FoscStaff(FoscLeafMaker().(#[60,62,64,65], 1/8))]);
set(a[0]).instrumentName = FoscMarkup("Violin");
set(a).proportionalNotationDuration = FoscSchemeMoment(#[1,64]);
a.show;
Integer, String or Symbol elements in 'pitches' slot result in notes.
m = FoscLeafMaker().(pitches: #[60,64,"G4",'Bb4'], durations: [1/4]);
m.show;
Array elements in 'pitches' result in chords.
m = FoscLeafMaker().(pitches: #[[60,64,67],['Eb4','G4','Bb4']], durations: [1/2]);
m.show;
Nil-valued elements in 'pitches' result in rests.
m = FoscLeafMaker().(pitches: nil, durations: 1/4 ! 4);
m.show;
Values passed to 'pitches' can be mixed and matched.
m = FoscLeafMaker().(pitches: #[[60,64,67],nil,'Eb4','Bb4'], durations: [1/4]);
m.show;
Pitches are repeated cyclically when the length of 'pitches' is less than the length of 'durations'.
m = FoscLeafMaker().(pitches: #[72,71], durations: [3/8,1/8,2/8,2/8]);
m.show;
Durations are repeated cyclically when the length of 'durations' is less than the length of 'pitches'.
m = FoscLeafMaker().(pitches: #[72,74,76,77], durations: [3/8,1/8]);
m.show;
Elements in 'durations' with non-power-of-two denominators result in tuplet-nested leaves.
m = FoscLeafMaker().(pitches: #[60,62,64,65], durations: [1/4, 1/12, 1/6, 1/2]);
m.show;
'Ratios' embed into 'divisions' as rhythmic proportions.
a = FoscRhythmMaker();
a.(divisions: [2/16,3/16,5/16], ratios: #[[3,1],[3,2],[4,3]]);
a.show;
Negative values in 'divisions' result in rests.
a = FoscRhythmMaker();
a.(divisions: [2/16,3/16,5/16], ratios: #[[-3,1],[3,2],[4,-3]]);
a.show;
Add the output of a FoscRhythmMaker to a FoscStaff and rewrite pitches.
a = FoscRhythmMaker();
b = a.(divisions: [2/16,3/16,5/16], ratios: #[[-3,1],[3,2],[4,-3]]);
c = FoscStaff(b);
mutate(c).rewritePitches(#[60,62,64,65]);
c.show;
Rhythm cells are repeated cyclically when the length of 'divisions' is less than the length of 'ratios'.
a = FoscRhythmMaker();
a.(divisions: [1/4], ratios: #[1,1,1,1,1] ! 4);
a.show;
Rhythm cells are repeated cyclically when the length of 'ratios' is less than the length of 'divisions'.
a = FoscRhythmMaker();
a.(divisions: 1/4 ! 4, ratios: #[[1,1,1,1,1]]);
a.show;
Apply a silence mask.
m = FoscSilenceMask(FoscPattern(indices: #[0,1,4,5,17,18,19]));
a = FoscRhythmMaker();
a.(divisions: 1/4 ! 4, ratios: #[[1,1,1,1,1]], masks: [m]);
a.show;
Apply a sustain mask.
m = FoscSustainMask(FoscPattern(indices: #[0,1,4,5,17,18,19]));
a = FoscRhythmMaker();
a.(divisions: 1/4 ! 4, ratios: #[[1,1,1,1,1]], masks: [m]);
a.show;
Apply a sustain mask and fuse leaves between successive onsets.
m = FoscSustainMask(FoscPattern(indices: #[0,1,4,5,17,18,19]), fuse: true);
a = FoscRhythmMaker();
a.(divisions: 1/4 ! 4, ratios: #[[1,1,1,1,1]], masks: [m]);
a.show;
Apply a sustain mask, fuse leaves, and apply formatting rules with a FoscTupletSpecifier.
m = FoscSustainMask(FoscPattern(indices: #[0,1,4,5,17,18,19]), fuse: true);
t = FoscTupletSpecifier(extractTrivial: true, rewriteSustained: true, rewriteRestFilled: true);
a = FoscRhythmMaker(tupletSpecifier: t);
a.(divisions: 1/4 ! 4, ratios: #[[1,1,1,1,1]], masks: [m]);
a.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)
FoscRest(1/4)
FoscNote('C4', 1/4)
FoscNote('D4', 1/4)
Select notes and rests only.
a = FoscStaff([FoscRest(1/4), FoscNote(60, 1/4), FoscNote(62, 1/4)]);
b = a.selectComponents(prototype: [FoscNote, FoscRest]);
b.do { |each| each.cs.postln };
FoscRest(1/4)
FoscNote('C4', 1/4)
FoscNote('D4', 1/4)
Select pitched leaves only.
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('C4', 1/4)
FoscChord("C4 E4 G4", 1/4)
Attach indicators to all selected pitched leaves.
a = FoscStaff(FoscLeafMaker().(#[nil,62,64,65,67,69,71,72], [1/8]));
b = a.selectLeaves(pitched: true);
b.do { |each| each.attach(FoscArticulation('>')) };
a.show;
Iterate over all score components.
a = FoscStaff(FoscLeafMaker().(#[60,62,64,65,67,69,71,72], [1/8]));
a.doComponents({ |each| each.cs.postln });
FoscStaff([ ], 'Staff', false)
FoscNote('C4', 1/8)
FoscNote('D4', 1/8)
FoscNote('E4', 1/8)
FoscNote('F4', 1/8)
FoscNote('G4', 1/8)
FoscNote('A4', 1/8)
FoscNote('B4', 1/8)
FoscNote('C5', 1/8)
Iterate over notes, attach indicators.
a = FoscStaff(FoscLeafMaker().(#[nil,62,64,65,67,69,71,72], [1/8]));
a.doComponents({ |note| note.attach(FoscArticulation('>')) }, prototype: FoscNote);
a.show;
Iterate over pitched logical ties.
a = FoscStaff(FoscLeafMaker().(#[60,60,62,nil,64,64], [1/4,1/24,1/12,1/8,1/4,1/4]));
m = a.selectLeaves;
tie(m[0..1]);
tie(m[4..]);
a.doLogicalTies({ |each| each[0].attach(FoscArticulation('>')) }, pitched: true);
a.show;
Iterate over runs, attach slur to each run.
a = FoscStaff(FoscLeafMaker().(#[60,62,64,nil,65,nil,67,69], [1/8]));
a.doRuns { |run| if (run.size > 1) { run.slur } };
a.show;
Fosc is free software available under Version 3.0 of the GNU General Public License.