X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=lily%2Fduration.cc;h=782804e9da31d90b610543c2570a2c71d744a3c7;hb=84cad110c3bbaeca8e5144dba7f8756b89100396;hp=7710e4dcc037d9a9c349674f67784c9adf65f434;hpb=11be23f380bcb249d49269cfa6f7889c6829011f;p=lilypond.git diff --git a/lily/duration.cc b/lily/duration.cc index 7710e4dcc0..782804e9da 100644 --- a/lily/duration.cc +++ b/lily/duration.cc @@ -1,99 +1,184 @@ /* - duration.cc -- implement Duration, Plet, + This file is part of LilyPond, the GNU music typesetter. - source file of the LilyPond music typesetter + Copyright (C) 1997--2012 Jan Nieuwenhuizen + Han-Wen Nienhuys - (c) 1997--2000 Jan Nieuwenhuizen - Han-Wen Nienhuys + LilyPond is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + LilyPond is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with LilyPond. If not, see . */ -#include +#include "duration.hh" +#include "misc.hh" #include "lily-proto.hh" -#include "string.hh" -#include "moment.hh" -#include "duration.hh" -int -compare (Array* left, Array* right) -{ - assert (left); - assert (right); - - if (left->size () == right->size ()) - { - for (int i = 0; i < left->size (); i++) - { - int r = Duration::compare ((*left)[i], (*right)[i]); - if (r) - return r; - } - } - else - return 1; - return 0; -} +#include "ly-smobs.icc" int Duration::compare (Duration const &left, Duration const &right) { - return Rational::compare (left.length_mom (), right.length_mom ()); + return Rational::compare (left.get_length (), right.get_length ()); } Duration::Duration () { - durlog_i_ = 0; - dots_i_ = 0; - tuplet_iso_i_ = 1; - tuplet_type_i_ = 1; + durlog_ = 0; + dots_ = 0; + factor_ = Rational (1, 1); +} + +Duration::Duration (int log, int d) +{ + durlog_ = log; + dots_ = d; + factor_ = Rational (1, 1); +} + +Duration::Duration (Rational r, bool scale) +{ + factor_ = Rational (1, 1); + + if (r.num () == 0.0) + { + durlog_ = 0; + dots_ = 0; + } + else + { + /* we want to find the integer k for which 2q/p > 2^k >= q/p. + It's simple to check that k' = \floor \log q - \floor \log p + satisfies the left inequality and is within a factor of 2 of + satistying the right one. Therefore either k = k' or k = k'+1 */ + + int p = (int) r.num (); + int q = (int) r.den (); + int k = intlog2 (q) - intlog2 (p); + if (shift_left (p, k) < q) + k++; + + assert (shift_left (p, k) >= q && shift_left (p, (k - 1)) < q); + + /* If we were to write out log (p/q) in base 2, then the position of the + first non-zero bit (ie. k in our notation) would be the durlog + and the number of consecutive 1s after that bit would be the number of + dots */ + p = shift_left (p, k) - q; + dots_ = 0; + while ((p *= 2) >= q) + { + p -= q; + dots_++; + } + + /* we only go up to 64th notes */ + if (k > 6) + { + durlog_ = 6; + dots_ = 0; + } + else + durlog_ = k; + + if (scale || k > 6) + factor_ = r / get_length (); + } } -void -Duration::compress (Rational m) +Duration +Duration::compressed (Rational m) const { - tuplet_iso_i_ *= m.num_i (); - tuplet_type_i_ *= m.den_i (); + Duration d (*this); + d.factor_ *= m; + return d; } Rational -Duration::length_mom () const +Duration::get_length () const { - Rational mom (1 << abs (durlog_i_)); + Rational mom (1 << abs (durlog_)); - if (durlog_i_> 0) - mom = Moment (1)/mom; + if (durlog_ > 0) + mom = Rational (1) / mom; Rational delta = mom; - - for (int d = dots_i_; d; d--) + for (int i = 0; i < dots_; i++) { - delta /= Moment (2); + delta /= Rational (2); mom += delta; } - return mom * Moment (tuplet_iso_i_, tuplet_type_i_); + return mom * factor_; } -void -Duration::set_plet (int i, int t) +string +Duration::to_string () const { - tuplet_iso_i_ = i; - tuplet_type_i_ = t; + string s; + + if (durlog_ < 0) + s = "log = " + ::to_string (durlog_); + else + s = ::to_string (1 << durlog_); + + s += ::to_string ('.', dots_); + if (factor_ != Moment (Rational (1, 1))) + s += "*" + factor_.to_string (); + return s; } +IMPLEMENT_TYPE_P (Duration, "ly:duration?"); -String -Duration::str () const +SCM +Duration::mark_smob (SCM) { - return to_str (durlog_i_) + to_str ('.', dots_i_); + return SCM_EOL; } +IMPLEMENT_SIMPLE_SMOBS (Duration); +int +Duration::print_smob (SCM s, SCM port, scm_print_state *) +{ + Duration *r = (Duration *) SCM_CELL_WORD_1 (s); -bool -Duration::plet_b () + scm_puts ("#to_string ()), port); + scm_puts (" >", port); + + return 1; +} + +SCM +Duration::equal_p (SCM a, SCM b) { - return tuplet_iso_i_ != 1 || tuplet_type_i_ != 1; + Duration *p = (Duration *) SCM_CELL_WORD_1 (a); + Duration *q = (Duration *) SCM_CELL_WORD_1 (b); + + bool eq = p->dots_ == q->dots_ + && p->durlog_ == q->durlog_ + && p->factor_ == q->factor_; + + return eq ? SCM_BOOL_T : SCM_BOOL_F; } +int +Duration::duration_log () const +{ + return durlog_; +} +int +Duration::dot_count () const +{ + return dots_; +}