X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=lily%2Fscale.cc;h=02c1dc5f8e2daca09b480ac977049c66e70d68e3;hb=a6a51abfd0195a3cf7d6ea095cf69808852f21ce;hp=4ba1a5bc2c5f11ab7ea5aa9dd05dca56488060e8;hpb=92918346012f79ef9109ef0c391947af2d3165ca;p=lilypond.git diff --git a/lily/scale.cc b/lily/scale.cc index 4ba1a5bc2c..02c1dc5f8e 100644 --- a/lily/scale.cc +++ b/lily/scale.cc @@ -1,115 +1,152 @@ -/* - scale.cc -- implement Scale - - source file of the GNU LilyPond music typesetter - - (c) 2006--2007 Han-Wen Nienhuys - +/* + This file is part of LilyPond, the GNU music typesetter. + + Copyright (C) 2006--2015 Han-Wen Nienhuys + 2007--2008 Rune Zedeler + 2008 Joe Neeman + + 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 "scale.hh" +#include "protected-scm.hh" -#include "ly-smobs.icc" /* todo: put string <-> pitch here too. - */ LY_DEFINE (ly_make_scale, "ly:make-scale", - 1, 0, 0, (SCM steps), - "Create a scale. Takes a vector of ints as argument") + 1, 0, 0, (SCM steps), + "Create a scale." + " The argument is a vector of rational numbers, each of which" + " represents the number of 200 cent tones of a pitch above the" + " tonic.") { bool type_ok = scm_is_vector (steps); - vector semitones; + vector tones; if (type_ok) { int len = scm_c_vector_length (steps); - for (int i = 0 ; i < len; i++) - { - SCM step = scm_c_vector_ref (steps, i); - type_ok = type_ok && scm_is_rational (step); - if (type_ok) - { - Rational from_c (scm_to_int (scm_numerator (step)), - scm_to_int (scm_denominator (step))); - semitones.push_back (from_c); - } - } + for (int i = 0; i < len; i++) + { + SCM step = scm_c_vector_ref (steps, i); + type_ok = type_ok && scm_is_rational (step); + if (type_ok) + { + Rational from_c (scm_to_int (scm_numerator (step)), + scm_to_int (scm_denominator (step))); + tones.push_back (from_c); + } + } } - - SCM_ASSERT_TYPE (type_ok, steps, SCM_ARG1, __FUNCTION__, "vector of int"); - Scale *s = new Scale; - s->step_tones_ = semitones; + SCM_ASSERT_TYPE (type_ok, steps, SCM_ARG1, __FUNCTION__, "vector of rational"); - SCM retval = s->self_scm (); - - s->unprotect (); - - return retval; + return (new Scale (tones))->unprotect (); } +Scale *default_global_scale = 0; +Protected_scm default_global_scale_scm (SCM_BOOL_F); + +// TODO: This is somewhat fishy: pitches protect their scale via a +// mark_smob hook. But since pitches are of Simple_smob variety, they +// are unknown to GUILE unless a smobbed_copy has been created. So +// changing the default scale might cause some existing pitches to +// lose their scale's protection. + LY_DEFINE (ly_default_scale, "ly:default-scale", - 0, 0, 0, (), - "Get the global default scale.") + 0, 0, 0, (), + "Get the global default scale.") { - return default_global_scale - ? SCM_BOOL_F - : default_global_scale->self_scm (); + return default_global_scale_scm; } - -Scale * default_global_scale = 0; - LY_DEFINE (ly_set_default_scale, "ly:set-default-scale", - 1, 0, 0, (SCM scale), - "Set the global default scale.") + 1, 0, 0, (SCM scale), + "Set the global default scale. This determines the tuning of" + " pitches with no accidentals or key signatures. The first" + " pitch is C. Alterations are calculated relative to this" + " scale. The number of pitches in this scale determines the" + " number of scale steps that make up an octave. Usually the" + " 7-note major scale.") { - LY_ASSERT_FIRST_SMOB (Scale, scale); - - Scale *s = Scale::unsmob (scale); - if (default_global_scale) - default_global_scale->unprotect (); - default_global_scale = s; - s->protect (); - + LY_ASSERT_SMOB (Scale, scale, 1); + + default_global_scale_scm = scale; + default_global_scale = unsmob (scale); + return SCM_UNSPECIFIED; } - int -Scale::print_smob (SCM x, SCM port, scm_print_state *) +Scale::step_count () const { - (void) x; - - scm_puts ("#", port); - return 1; + return step_tones_.size (); } +Rational +Scale::tones_at_step (int step, int octave) const +{ + int normalized_step = normalize_step (step); + + octave += (step - normalized_step) / step_count (); -SCM -Scale::mark_smob (SCM x) + // There are 6 tones in an octave. + return step_tones_[normalized_step] + Rational (octave * 6); +} + +Rational +Scale::step_size (int step) const { - (void) x; - return SCM_UNSPECIFIED; + int normalized_step = normalize_step (step); + + // Wrap around if we are asked for the final note of the + // scale (6 is the number of tones of the octave above the + // first note). + if (normalized_step + 1 == step_count ()) + return Rational (6) - step_tones_[normalized_step]; + + return step_tones_[normalized_step + 1] - step_tones_[normalized_step]; } -Scale::Scale () +int +Scale::normalize_step (int step) const { + int ret = step % step_count (); + if (ret < 0) + ret += step_count (); + + return ret; +} + + + +Scale::Scale (vector const &tones) +{ + step_tones_ = tones; + smobify_self (); } Scale::Scale (Scale const &src) + : Smob () { step_tones_ = src.step_tones_; smobify_self (); } - Scale::~Scale () { } - -IMPLEMENT_SMOBS(Scale); -IMPLEMENT_DEFAULT_EQUAL_P(Scale);