X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=lily%2Fduration.cc;h=4768f015b501c6510f52b373fb4625d94f168889;hb=47db9a3883d726ca53e2133a3b2298f78dd6a32e;hp=6145731b4b1c94ee34573f1607e4af28eef1f073;hpb=7e72a1e50e94a7f9738d62599de79fe7745f600c;p=lilypond.git diff --git a/lily/duration.cc b/lily/duration.cc index 6145731b4b..4768f015b5 100644 --- a/lily/duration.cc +++ b/lily/duration.cc @@ -1,22 +1,27 @@ /* - duration.cc -- implement Duration - - source file of the LilyPond music typesetter + This file is part of LilyPond, the GNU music typesetter. - (c) 1997--2004 Jan Nieuwenhuizen - Han-Wen Nienhuys + Copyright (C) 1997--2015 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" -#include "ly-smobs.icc" - int @@ -29,14 +34,64 @@ Duration::Duration () { durlog_ = 0; dots_ = 0; - factor_ = Rational (1,1); + factor_ = Rational (1, 1); } -Duration::Duration (int l, int d) +Duration::Duration (int log, int d) { - durlog_ = l; + durlog_ = log; dots_ = d; - factor_ = Rational (1,1); + 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 (); + } } Duration @@ -52,12 +107,11 @@ Duration::get_length () const { Rational mom (1 << abs (durlog_)); - if (durlog_> 0) - mom = Rational (1)/mom; + if (durlog_ > 0) + mom = Rational (1) / mom; Rational delta = mom; - - for (int d = dots_; d; d--) + for (int i = 0; i < dots_; i++) { delta /= Rational (2); mom += delta; @@ -66,187 +120,47 @@ Duration::get_length () const return mom * factor_; } - - -String +string Duration::to_string () const { - String s; + string s; - if (durlog_ < 0 ) - s = "log = " + ::to_string (durlog_); + 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 (); - } + if (factor_ != Moment (Rational (1, 1))) + s += "*" + factor_.to_string (); return s; } +const char Duration::type_p_name_[] = "ly:duration?"; -IMPLEMENT_TYPE_P (Duration, "ly:duration?"); - -SCM -Duration::mark_smob (SCM) -{ - return SCM_EOL; -} -IMPLEMENT_SIMPLE_SMOBS (Duration); int -Duration::print_smob (SCM s, SCM port, scm_print_state *) +Duration::print_smob (SCM port, scm_print_state *) { - Duration *r = (Duration *) ly_cdr (s); - scm_puts ("#to_string ().to_str0 ()), port); + scm_display (ly_string2scm (to_string ()), port); scm_puts (" >", port); - + return 1; } SCM -Duration::equal_p (SCM a , SCM b) +Duration::equal_p (SCM a, SCM b) { - Duration *p = (Duration *) ly_cdr (a); - Duration *q = (Duration *) ly_cdr (b); + 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_; + && p->durlog_ == q->durlog_ + && p->factor_ == q->factor_; return eq ? SCM_BOOL_T : SCM_BOOL_F; } - -MAKE_SCHEME_CALLBACK (Duration, less_p, 2); -SCM -Duration::less_p (SCM p1, SCM p2) -{ - Duration *a = unsmob_duration (p1); - Duration *b = unsmob_duration (p2); - - if (compare (*a, *b) < 0) - return SCM_BOOL_T; - else - return SCM_BOOL_F; -} - -LY_DEFINE(duration_less, "ly:durationduration_log ()); -} - - -LY_DEFINE(dot_count_log, - "ly:duration-dot-count", 1, 0, 0, (SCM dur), - "Extract the dot count from @var{dur}" -) -{ - SCM_ASSERT_TYPE(unsmob_duration(dur), dur, SCM_ARG1, __FUNCTION__, "duration"); - - return gh_int2scm (unsmob_duration (dur)->dot_count ()); -} - - -LY_DEFINE(ly_intlog2, - "ly:intlog2", 1, 0, 0, (SCM d), - "The 2-logarithm of 1/@var{d}." -) -{ - SCM_ASSERT_TYPE(gh_number_p (d), d, SCM_ARG1, __FUNCTION__, "integer"); - - int l = intlog2 (gh_scm2int (d)); - - return gh_int2scm (l); -} - -LY_DEFINE(compression_factor, - "ly:duration-factor", 1, 0, 0, (SCM dur), - "Extract the compression factor from @var{dur}. Return as a pair." -) -{ - SCM_ASSERT_TYPE(unsmob_duration(dur), dur, SCM_ARG1, __FUNCTION__, "duration"); - Rational r =unsmob_duration (dur)->factor (); - - return gh_cons(gh_int2scm (r.num()),gh_int2scm (r.den ())); -} - -SCM -Duration::smobbed_copy ()const -{ - Duration * p = new Duration (*this); - return p->smobbed_self (); -} int Duration::duration_log () const @@ -259,4 +173,3 @@ Duration::dot_count () const { return dots_; } -