chord name engraver plus capo

classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

chord name engraver plus capo

Wols Lists
 At last :-)

I've managed to work my way through (having lost my first attempt), and
here's my crack at doing the engraver.  I've just done process_music in
this mail, since it's the only thing I've really changed.

I've added the capo variables, filled them in, and got down almost to
the bottom.  There's just a couple of things to fix before I can try a
"compile and test". How do I actually get hold of the property capoFret?
And how do I combine the markups? I'm not going to bother with vertical
markup at the moment. That'll be easier once I've got to grips with the
rest of it.

Note that all my added comments are C++ style - // - and I tend to mark
"to dos" in my code with a triple bang !!!

So how do I fix those two issues? and then you'll probably hear the
screaming as it blows up (or hopefully the cheering as it works :-)

Cheers,
Wol

------------------------------------------------------

void
Chord_name_engraver::process_music ()
// This is called for each note or rest.
// It is called as a result of being registered with
IMPLEMENT_TRANSLATOR_LISTENER
{
  SCM markup;        // to store markup in
  SCM bass = SCM_EOL;    // remember notes to create chord
  SCM inversion = SCM_EOL;
  SCM pitches = SCM_EOL;

  SCM capo_markup;    // and transposed notes for capo chord
  SCM capo_bass = SCM_EOL;
  SCM capo_inversion = SCM_EOL;
  SCM capo_pitches = SCM_EOL;
 
  if (rest_event_)
    {    // process a rest
      SCM no_chord_markup = get_property ("noChordSymbol");
      if (!Text_interface::is_markup (no_chord_markup))
        return;
      markup = no_chord_markup;
    }
  else
    {  // process a note event
      if (!notes_.size ())
        return;

      // get capo fret !!!
      // This is set by "\set ChordNames.capoFret = #3" in the lily
source file
      SCM capofret = whatever->get_property ("capoFret");
      int capo = 0;
      if (scm_is_number (capofret))
    capo = scm_to_int (capofret);
     
      Stream_event *inversion_event = 0;
      for (vsize i = 0; i < notes_.size (); i++)
      {    // step through each note in turn
        Stream_event *n = notes_[i];
        SCM p = n->get_property ("pitch");
        if (!unsmob_pitch (p))
          continue;

        if (n->get_property ("inversion") == SCM_BOOL_T)
        {
          inversion_event = n;
          inversion = p;
      if (capo)
        capo_inversion = p->transposed (Pitch (-capo, 0, 0));
    }
        else if (n->get_property ("bass") == SCM_BOOL_T)
          bass = p;
      if (capo)
        capo_bass = p->transposed (Pitch (-capo, 0, 0));
        else
          pitches = scm_cons (p, pitches);
      if (capo)
        capo_pitches = scm_cons ( p->transposed (Pitch (-capo, 0, 0)),
capo_pitches);
      }

      if (inversion_event)
      {
        SCM oct = inversion_event->get_property ("octavation");
        if (scm_is_number (oct))
        {
          Pitch *p = unsmob_pitch (inversion_event->get_property ("pitch"));
          int octavation = scm_to_int (oct);
          Pitch orig = p->transposed (Pitch (-octavation, 0, 0));

          pitches = scm_cons (orig.smobbed_copy (), pitches);
     
      // if capo sort this out later !!!
     
        }
        else
          programming_error ("inversion does not have original pitch");
      }

      pitches = scm_sort_list (pitches, Pitch::less_p_proc);
      if (capo)
    capo_pitches = scm_sort_list (capo_pitches, Pitch::less_p_proc);
   
      SCM name_proc = get_property ("chordNameFunction");
      markup = scm_call_4 (name_proc, pitches, bass, inversion,
          context ()->self_scm ());
      if (capo)
    capo_markup = scm_call_4 (name_proc, capo_pitches, capo_bass,
capo_inversion,
        context ()->self_scm ());
    }
  /*
    Ugh. // Why's this ughly?
  */
 
  // do we need any more capo stuff here beyond setting the chord name text?
 
  SCM chord_as_scm = scm_cons (pitches, scm_cons (bass, inversion));

  chord_name_ = make_item ("ChordName",
      rest_event_ ? rest_event_->self_scm () : notes_[0]->self_scm ());
  if (!capo)
    chord_name_->set_property ("text", markup);
  else
    // how do I combine text and markup to get "markup (capo_markup)" !!!

  SCM chord_changes = get_property("chordChanges");
  if (to_boolean (chord_changes) && scm_is_pair (last_chord_)
      && ly_is_equal (chord_as_scm, last_chord_))
    chord_name_->set_property ("begin-of-line-visible", SCM_BOOL_T);

  last_chord_ = chord_as_scm;
}

---
----
Join the Frogs!

Reply | Threaded
Open this post in threaded view
|

Re: chord name engraver plus capo

Neil Puttock
On 25 August 2010 18:02, Wols Lists <[hidden email]> wrote:

> How do I actually get hold of the property capoFret?

get_property ("capoFret");

You could do context ()->get_property ("...") but there's no need
since get_property is overloaded for translators:

this->get_property ("...")

is equivalent to

daddy_context_->get_property ("...")

where daddy_context_ is the context where the engraver's defined
(i.e., ChordNames).

> And how do I combine the markups? I'm not going to bother with vertical
> markup at the moment. That'll be easier once I've got to grips with the
> rest of it.

This is really something that should be done in scheme, since it's
tedious in C++ to call markup commands (see clef-engraver.cc for a
simple example using \vcenter).

Ideally you'd get the formatting done in the existing chord name formatter.

Cheers,
Neil

---
----
Join the Frogs!

Reply | Threaded
Open this post in threaded view
|

Re: chord name engraver plus capo

Wols Lists
 On 25/08/10 20:44, Neil Puttock wrote:

> On 25 August 2010 18:02, Wols Lists <[hidden email]> wrote:
>
>> How do I actually get hold of the property capoFret?
> get_property ("capoFret");
>
> You could do context ()->get_property ("...") but there's no need
> since get_property is overloaded for translators:
>
> this->get_property ("...")
>
> is equivalent to
>
> daddy_context_->get_property ("...")
>
> where daddy_context_ is the context where the engraver's defined
> (i.e., ChordNames).
>
>> And how do I combine the markups? I'm not going to bother with vertical
>> markup at the moment. That'll be easier once I've got to grips with the
>> rest of it.
> This is really something that should be done in scheme, since it's
> tedious in C++ to call markup commands (see clef-engraver.cc for a
> simple example using \vcenter).
>
> Ideally you'd get the formatting done in the existing chord name formatter.
This is actually the whole point of this change - afaict I *can't* use
the existing chord name formatter. Because I've got TWO chords that I'm
trying to print as two chords but one markup.

But thanks for the pointer to clef-engraver - I'll investigate. And
thanks for the property stuff.
> Cheers,
> Neil
>
Here's hoping it all works :-)

Cheers,
Wol

---
----
Join the Frogs!

Reply | Threaded
Open this post in threaded view
|

Re: chord name engraver plus capo

Wols Lists
On 25/08/10 21:51, Wols Lists wrote:
And how do I combine the markups? I'm not going to bother with vertical
>> markup at the moment. That'll be easier once I've got to grips with the
>> rest of it.
> This is really something that should be done in scheme, since it's
> tedious in C++ to call markup commands (see clef-engraver.cc for a
> simple example using \vcenter).
>
> Ideally you'd get the formatting done in the existing chord name formatter.
This is actually the whole point of this change - afaict I *can't* use
the existing chord name formatter. Because I've got TWO chords that I'm
trying to print as two chords but one markup.

But thanks for the pointer to clef-engraver - I'll investigate. And
thanks for the property stuff.
> Cheers,
> Neil
>
Here's hoping it all works :-)

I've now had a look at clef-engraver ... and I'm none the wiser :-(

What I need to do is:

chord-name-engraver creates, let's say, "C" as markup. I've added code that makes it *also* generate "A" as markup (but at the moment, it does nothing with it).

Now, instead of it returning "C" as it does at present, I want it to return "C (A)". I gather there's a function to parenthesize things? And then I need to stick them together, with a space between them, before returning the result.

Cheers,
Wol
Reply | Threaded
Open this post in threaded view
|

Re: chord name engraver plus capo

Wols Lists
 Next problem ... just typed "make" and it's blown up on me :-)

I've messed up transposing my pitches. I've got all my code like this:

      if (capo)
        capo_inversion = p->transposed (Pitch (-capo, 0, 0));

But of course I haven't set Pitch until long after I use it :-(
And I don't know if I'll actually have an inversion event at all!

So am I using completely the wrong method to transpose my notes, anyway?
Quite likely, I suspect. Where will I find the source for \transpose,
because I guess that will be a far better template for what I'm trying
to do?

Cheers,
Wol

---
----
Join the Frogs!