This page documents some aspects of the internals of GNU LilyPond. Some of
this stuff comes from e-mail I wrote, some from e-mail others wrote,
-some are large comments taken away from the headers
+some are large comments taken away from the headers. This is why this
+page may be a little incoherent.
You should use doc++ to take a peek at the sources.
=item Parsing:
-No difficult algorithms. Associated datastructures have prefix Input
-(eg Input_score, Input_command). The .ly file is read, and converted
-to
+No difficult algorithms. The .ly file is read, and converted to a list
+of C<Scores>, which each contain C<Music> and paper/midi-definitions.
=item Creating elements
-Requests are processed and used to create elements (like balls, stems,
-slurs etc). This is done by a hierarchy of "brokers" (called
-Translators: the ones for paper output are Engravers, for MIDI
-Performers), which swallow requests, broadcast them and couple
-different elements.
+The music is walked column by column. The iterators which do the
+walking report the Request to Translators which use this information
+to create elements, either MIDI or "visual" elements. The translators
+form a hierarchy; the ones for paper output are Engravers, for MIDI
+Performers).
-In this step data-structures for the next steps are created and filled
-with data: Score_elements, PScore, PCol.
+The translators swallow requests, create elements, broadcast them to
+other translators on higher or same level in the hierarchy:
+
+The stem of a voice A is broadcast to the staff which contains A, but
+not to the noteheads of A, and not to the stems, beams and noteheads
+of a different voice (say B) or a different staff. The stem and
+noteheads of A are coupled, because the the Notehead_engraver
+broadcasts its heads, and the Stem catches these.
+
+The engraver which agrees to handle a request decides whether to to
+honor the request, ignore it, or merge it with other requests. Merging
+of requests is preferably done with other requests done by members of
+the same voicegroups (beams, brackets, stems). In this way you can put
+the voices of 2 instruments in a conductor's score so they make chords
+(the Stem_reqs of both instruments will be merged).
=item Prebreaking
=item Preprocessing
Some dependencies are resolved, such as the direction of stems, beams,
+and "horizontal" placement issues (the order of clefs, keys etc,
+placement of chords in multi-voice music),
=item Break calculation:
-The lines and horizontal positions of the columns are determined
+The lines and horizontal positions of the columns are determined.
=item Breaking
-
Through some magical interactions with Line_of_score and Super_elem
(check out the source) the "lines" are produced.
All other spanners can figure across which lines they are spread. If
applicable, they break themselves into pieces. After this, each piece
-works (or, if there are no pieces) the spanner throws out any
-dependencies which are in the wrong line.
+(or, if there are no pieces, the original spanner itself) throws out
+any dependencies which are in the wrong line.
=item Postprocesing:
Some items and all spanners need computation after the PCol positions
-are determined.
+are determined. Examples: slurs, vertical positions of staffs.
=item Output paper
-
-=item Output midi
-
-The music is run through a translator (called Performer) which
-creates midi-items from the requests.
-
=back
=head1 INTERNALS
on the paper than actually fits. To reflect this idea (the user asks
more than we can do), the container for this data is called Request.
-The music (requests) are read/interpreted by a set of objects
-(translators), the Performers/Engravers. The engraver which agrees to
-handle a request decides whether to to honor the request, ignore it,
-or merge it with other requests. Merging of requests is preferably
-done with other requests done by members of the same voicegroups
-(beams, brackets, stems).
-
-The result of a request will be an C<Item> or a C<Spanner>, which
-will be put on the score.
-
-Different staffs can produce different outputs; a melodious voice
-which is put into a percussion-Staff, will be typeset as the rythm of
-that voice.
-
-After C<Staff> made up her mind, the resultant items and
-spanners are put on the PScore.
-
-Some of the important requests are:
+In a lot of other formats this would be called an 'Event'
=over 4
C<Stem_beam_engraver> about the C<Notehead>, which will add the
C<Notehead> to the C<Stem> it just created.
-To decide on merging, C<Complex_staff> has grouped several
-engravers. Please check F<init/engraver.ly>.
+To decide on merging, several engravers have been grouped. Please
+check F<init/engraver.ly>.
=head1 ITEMS and SPANNERS
=head1 BREAKING
-So what's the deal with PREBREAK and POSTBREAK and all this
-stuff?
+So what is this PREBREAK and POSTBREAK stuff?
Let's take text as an example. In German some compound
words change their spelling if they are broken: "backen" becomes
=head1 SPACING
-I think my method is the most elegant algorithm i've seen so far.
+
Some terminology: I call a vertical group of symbols (notes) which
start at the same time a "column". Each line of a score has notes in
it, grouped in columns. The difference in starting time between those
Example:
- time ----->
+ time ----->
- col1 col2 col3 col4
+ cols: col1 col2 col3 col4
voice1 1 1
time_difference (col2 , col3) = 0.5 wholes,
etc.
-these differences are translated into ideal distances (these translations
-have been the subject of discussion in this thread).
+these differences are translated into ideal distances
distance (col1,col2) = 10 pt
distance (col1,col3) = 14.1 pt
solution to find is not of a mathematical nature.
Gourlay's solution is used.
+
+
Most of the items are marked in the code as well, with full explanation.
grep for TODO and ugh/ugr
+ * generate stuff in out/default, out/sun5-irix etc iso out/
+and out-sun5/
+
+ * derive dstream, texstream from ostream?
+
+ * A typical pop-music example.
+
+ * check libtool, automake
+
+ * have make dist produce tarball in out/ directory.
+
+ * write a faster Spring_spacer ( without matrices if possible )
+
+ * A decent scalar type
+
+ * relate energybound to linelen unitspace fontsize etc.
+
+ * naming of Voice_group/Voice
+
+ * benchmark band_matrices.
+
* versioning stuff (cvt mudela, mudela, etc.)
* get rid of gif files.
* lyrics in chords still fuck up.
* rewire acknowledge_element() logic with a process_acknowledged()
+
+ * Global type registration.
+
+ My_class * p = create_object( My_class )
+ Type t = get_type ( *p );
+ if ( t <= get_type( q ))
+ ..
* progress when creating MIDI elts.
* piano staff
- * implement better breaking algorithm
-
* update 20 pt table
* decent TeX page layout
* a tutorial
+3RD PARTY BUGS:
+
+ * bugreport to doc++ devel: struct not in class hier; public
+ virtual baseclasses
+
+ * DOC++ bugs/ newer version?
+
+ * Rational infty(HUGE_VAL) on glibc / w32
+
+ * Fix profiling. gprof bugreport?
+
+ * read from mmap directly: bugreport to flex developers->
+ yy_scan_buffer in C++..
+
+ * (where are the) gcc compile warnings on linux
+
+
PROJECTS
+ * input converters
+ - NIFF?
+ - ABC?
+ - SMDL?
+
* add to MIDI output:
- tempo change
- repeat
BUGS
- * fix mysterious Flex malloc bug
-
* should adjust stemlength for flag number.
* lilypond - -> crash
- * standchen triool beam up/down
-
- * (where are the) gcc compile warnings on linux
-
SEVERELY LACKING:
* SPEED!
* shared lib on Solaris too.
- * bugreport to doc++ devel: struct not in class hier; public
- virtual baseclasses
-
- * get rid of init_end;
-
* cleanup lily-proto.hh and proto.hh
* half-sharps, half-flats
* parshape
- * read from mmap directly: bugreport to flex developers->
- yy_scan_buffer in C++..
-
* binsearch/hash for identifiers
* stafftypes: voice names/ instrument names.
* guitar chord
- * better beamslope calculation: QLP for beams?
-
* Text_crescendo
* clean solution for staffsize in items.
// for testing new Matrix_storage.
//#define PARANOID
-Vector
-Choleski_decomposition::solve(Vector rhs)const
+void
+Choleski_decomposition::full_matrix_solve(Vector &out, Vector const &rhs)const
{
int n= rhs.dim();
assert(n == L.dim());
- Vector y(n);
-
+ Vector y;
+ y.set_dim( n);
+ out.set_dim(n);
+
// forward substitution
for (int i=0; i < n; i++) {
Real sum(0.0);
sum += y(j) * L(i,j);
y(i) = (rhs(i) - sum)/L(i,i);
}
+
for (int i=0; i < n; i++)
y(i) /= D(i);
// backward subst
- Vector &x(rhs); // using input as return val.
+ Vector &x(out); // using input as return val.
for (int i=n-1; i >= 0; i--) {
Real sum(0.0);
for (int j=i+1; j < n; j++)
sum += L(j,i)*x(j);
x(i) = (y(i) - sum)/L(i,i);
}
- return x;
+}
+
+void
+Choleski_decomposition::band_matrix_solve(Vector &out, Vector const &rhs)const
+{
+ int n= rhs.dim();
+ int b = L.band_i();
+ assert(n == L.dim());
+
+ out.set_dim(n);
+
+ Vector y;
+ y.set_dim(n);
+
+ // forward substitution
+ for (int i=0; i < n; i++) {
+ Real sum(0.0);
+ for (int j= 0 >? i - b; j < i; j++)
+ sum += y(j) * L(i,j);
+ y(i) = (rhs(i) - sum)/L(i,i);
+ }
+ for (int i=0; i < n; i++)
+ y(i) /= D(i);
+
+ // backward subst
+ Vector &x(out); // using input as return val.
+ for (int i=n-1; i >= 0; i--) {
+ Real sum(0.0);
+ for (int j=i+1; j <= i + b&&j < n ; j++)
+ sum += L(j,i)*x(j);
+ x(i) = (y(i) - sum)/L(i,i);
+ }
+}
+
+void
+Choleski_decomposition::solve(Vector &x, Vector const &rhs)const
+{
+ if (L.band_b()) {
+ band_matrix_solve(x,rhs);
+ } else
+ full_matrix_solve(x,rhs);
+}
+
+Vector
+Choleski_decomposition::solve(Vector rhs)const
+{
+ Vector r;
+ solve(r, rhs);
+ return r;
}
void
int n=L.dim();
Matrix invm(n);
Vector e_i(n);
+ Vector inv(n);
for (int i = 0; i < n; i++) {
e_i.set_unit(i);
- Vector inv(solve(e_i));
+ solve(inv, e_i);
for (int j = 0 ; j<n; j++)
invm(i,j) = inv(j);
}