1 /* measure.cpp
2  * functions dealing with measures
3  *
4  * for Denemo, a gtk+ frontent to GNU Lilypond
5  * (c) 2000-2005 Matthew Hiller, Adam Tee
6  */
7 
8 #include "display/accwidths.h"
9 #include "command/chord.h"
10 #include <denemo/denemo.h>
11 #include "display/drawingprims.h"
12 #include "command/measure.h"
13 #include "display/notewidths.h"
14 #include "command/object.h"
15 #include "command/staff.h"
16 #include "string.h"
17 #include "core/utils.h"
18 #include "core/cache.h"
19 #include "command/select.h"
20 #include "display/displayanimation.h"
21 #include "command/commandfuncs.h"
22 
23 #define STEMDIFFERENCE 6
24 #define HALFSTEMDIFFERENCE 3
25 
26 
27 /**
28  * Adds measures to the score at given position, and returns the
29  * measurenode * to the first one in currentstaff
30  * @param si the scoreinfo structure
31  * @param pos position in staff to insert measures
32  * @param nummeasures number of measures to insert
33  * @param all append across all staffs
34  * @return measurenode pointer to the first added in the current staff
35  */
36 measurenode *
addmeasures(DenemoMovement * si,gint pos,guint nummeasures,gint all)37 addmeasures (DenemoMovement * si, gint pos, guint nummeasures, gint all)
38 {
39   staffnode *curstaff;
40   guint i;
41   objnode *barlinenode = NULL;
42 
43   for (i = 0; i < nummeasures; i++)
44     {
45       if (all)
46         {
47           gint j;
48           for (j = 1, curstaff = si->thescore; curstaff; j++, curstaff = curstaff->next)
49             {
50               store_for_undo_measure_insert (si, j, pos);
51               barlinenode = g_malloc0 (sizeof (DenemoMeasure)); //use NULL  originally
52               ((DenemoStaff *) curstaff->data)->themeasures = g_list_insert (staff_first_measure_node (curstaff), barlinenode, pos);
53               ((DenemoStaff *) curstaff->data)->nummeasures++;
54             }
55 
56         }
57       else
58         {
59           store_for_undo_measure_insert (si, si->currentstaffnum, pos);
60            barlinenode = g_malloc0 (sizeof (DenemoMeasure)); //use NULL  originally
61           ((DenemoStaff *) si->currentstaff->data)->themeasures = g_list_insert (staff_first_measure_node (si->currentstaff), barlinenode, pos);
62           ((DenemoStaff *) si->currentstaff->data)->nummeasures++;
63         }
64 
65       gint maxmeasures = 0;
66       for (curstaff = si->thescore; curstaff; curstaff = curstaff->next)
67         {
68           maxmeasures = MAX (maxmeasures, ((DenemoStaff *) curstaff->data)->nummeasures);
69         }
70 
71       if (g_list_length (si->measurewidths) < maxmeasures)
72         {
73           si->measurewidths = g_list_insert (si->measurewidths, GINT_TO_POINTER (si->measurewidth), pos);
74         }
75 
76 
77     }
78 
79 
80     if (all)
81         cache_all();
82     else
83         cache_staff (si->currentstaff);
84   set_measure_transition (-20 * nummeasures, all);
85   measurenode *ret = g_list_nth (staff_first_measure_node (si->currentstaff), pos);
86 //  displayhelper (Denemo.project);
87  // score_status(Denemo.project, TRUE);
88 //check not returning NULL!!!!
89   si->cursoroffend = FALSE;//This was left to the drawing routine to set, but it can happen that no draw occurs before the value is needed.
90   if (ret)
91     return ret;
92   g_warning ("Add measures was going to return NULL");
93   return g_list_last (staff_first_measure_node (si->currentstaff));
94 }
95 
96 measurenode *
dnm_addmeasures(DenemoMovement * si,gint pos,guint nummeasures,gint all)97 dnm_addmeasures (DenemoMovement * si, gint pos, guint nummeasures, gint all)
98 {
99   return addmeasures (si, pos, nummeasures, all);
100 }
101 
102 /**
103  * g_list_foreach function called by freeobjlist
104  */
105 static void
freeit_object(gpointer data,gpointer user_data)106 freeit_object (gpointer data, gpointer user_data)
107 {
108   freeobject ((DenemoObject *) data);
109 }
110 
111 /**
112  * Free a measures objects
113  *
114  */
115 void
freeobjlist(gpointer data,gpointer user_data)116 freeobjlist (gpointer data, gpointer user_data)
117 {
118   objnode *delobjs = (objnode *) data;
119   if (delobjs)
120     {
121       /* Free all the Denemo objects */
122       g_list_foreach (delobjs, freeit_object, NULL);
123       /* Free the object list itself */
124       g_list_free (delobjs);
125     }
126 }
127 
128 
129 /**
130  * staffremovemeasures
131  * Contains common code to remove a measure from a staff
132  *
133  * @param curstaff the staff to remove the measure from
134  * @param pos the position in the staff to remove the measure from
135  *
136  */
137 void
staffremovemeasures(staffnode * curstaff,guint pos)138 staffremovemeasures (staffnode * curstaff, guint pos)
139 {
140   //g_debug ("In Staffremovemeasures\n");
141   take_snapshot ();
142   measurenode *firstmeasure;
143   measurenode *delmeasure;
144 
145   firstmeasure = staff_first_measure_node (curstaff);
146   delmeasure = g_list_nth (firstmeasure, pos);
147   if (delmeasure)
148     {
149 
150       //  g_debug ("Firstmeasure %x\t DelMeasure %x \t Position\n",
151       //       firstmeasure, delmeasure, pos);
152 
153 
154       freeobjlist (((DenemoMeasure*)delmeasure->data)->objects, NULL);
155       ((DenemoStaff *) curstaff->data)->themeasures = g_list_remove_link (firstmeasure, delmeasure); //FIXME DANGER
156       g_free ((DenemoMeasure*)delmeasure->data);
157       g_list_free_1 (delmeasure);
158 
159       ((DenemoStaff *) curstaff->data)->nummeasures--;
160     }
161  if ( ((DenemoStaff *) curstaff->data)->themeasures == NULL)
162     return;
163 //if the removed measures have a clef change in them the noteheights may need to change so...
164   cache_staff (curstaff);
165   staff_fix_note_heights (curstaff->data);
166 }
167 
168 /**
169  * Remove measures at given position, and return an appropriate
170  * currentmeasure
171  *
172  * @param si pointer to the scoreinfo structure
173  * @param pos position to remove the measures from
174  * @param nummeasures number of measures to remove
175  * @param all remove from all staffs
176  */
177 measurenode *
removemeasures(DenemoMovement * si,guint pos,guint nummeasures,gboolean all)178 removemeasures (DenemoMovement * si, guint pos, guint nummeasures, gboolean all)
179 {
180   staffnode *curstaff;
181   measurenode *firstmeasure;
182   GList *temp;
183   guint totalmeasures = 0;
184   guint i;
185 
186   if (nummeasures <= g_list_length (staff_first_measure_node ((staffnode *) si->currentstaff)) - pos)
187     {
188       for (i = 0; i < nummeasures; i++)
189         {
190           totalmeasures = 0;
191           for (curstaff = si->thescore; curstaff; curstaff = curstaff->next)
192             {
193               if (curstaff == si->currentstaff || all)
194                 {
195                   staffremovemeasures (curstaff, pos);
196                   if (!staff_first_measure_node (curstaff))
197                     {
198                       ((DenemoStaff *) curstaff->data)->themeasures = g_list_append (NULL, g_malloc0(sizeof (DenemoMeasure)));
199                       ((DenemoStaff *) curstaff->data)->nummeasures = 1;
200                     }
201                 }
202             }
203           for (curstaff = si->thescore; curstaff; curstaff = curstaff->next)
204             {
205               totalmeasures = MAX (totalmeasures, ((DenemoStaff *) curstaff->data)->nummeasures);
206             }
207 
208           if (totalmeasures <= (g_list_length (si->measurewidths) - 1))
209             {
210               /* And get rid of the no-longer-needed width data too */
211               temp = g_list_nth (si->measurewidths, pos);
212               si->measurewidths = g_list_remove_link (si->measurewidths, temp);
213               g_list_free_1 (temp);
214             }
215         }
216       set_measure_transition (20, all);
217       all?  cache_all (): cache_staff (si->currentstaff);
218     }
219   else
220     {
221       g_warning (_("removemeasures: received request to delete more measures\
222                    than exist.  Junking request."));
223       return si->currentmeasure;
224     }
225   firstmeasure = staff_first_measure_node (si->currentstaff);
226   if (pos == g_list_length (staff_first_measure_node ((staffnode *) si->currentstaff)))
227     {
228       /* That is, we deleted the last measure */
229       si->currentmeasurenum--;
230       return g_list_nth (firstmeasure, pos - 1);
231     }
232   else
233     return g_list_nth (firstmeasure, pos);
234 }
235 
236 
237 /**
238  * This function calculates the number of ticks per beat in a given
239  * time signature
240  */
241 gint
calcticksperbeat(gint time1,gint time2)242 calcticksperbeat (gint time1, gint time2)
243 {
244   gint ret = WHOLE_NUMTICKS / time2;
245 
246   /* If time1 is divisible by three and time2 is greater than 4;
247    * e.g.,the time signature is 3/8, 15/16, etc., it's assumed that
248    * the beat group is actually 3 times what's above */
249 
250   if (time2 > 4 && time1 % 3 == 0)
251     ret *= 3;
252 
253   return ret;
254 }
255 
256 
257 /* looks at succeeding objects to see if the current object is the last chord in a grace
258  returns ENDGRACE if it is */
259 static gint
is_end_grace(objnode * curobjnode)260 is_end_grace (objnode * curobjnode)
261 {
262   for (; curobjnode->next; curobjnode = curobjnode->next)
263     {
264       DenemoObject *obj = (DenemoObject *) curobjnode->next->data;
265       if (obj->type == CHORD)
266         {
267           if (((chord *) obj->object)->is_grace)
268             return 0;
269           else
270             return ENDGRACE;
271         }
272     }
273   return ENDGRACE;
274 }
275 
276 
277 /**
278  * This function goes through a measure and properly sets
279  * durinticks and starttickofnextnote values for everything in
280  * that measure, tuplets or no.
281  * It also marks the end of grace groups
282  *
283  * It works out that this function can be called wherever
284  * calculatebeamsandstemdirs is invoked, and would share code besides, so
285  * that's precisely where it is invoked
286  */
287 static void
settickvalsinmeasure(objnode * theobjs)288 settickvalsinmeasure (objnode * theobjs)
289 {
290   gint numerator = 1, denominator = 1;
291   objnode *curobjnode;
292   DenemoObject *theobj;
293   gint ticks_so_far = 0;
294   gint basic_ticks_in_tuplet_group = 0;
295   gboolean in_tuplet = FALSE;
296 
297   for (curobjnode = theobjs; curobjnode; curobjnode = curobjnode->next)
298     {
299       theobj = (DenemoObject *) curobjnode->data;
300       theobj->starttick = ticks_so_far + (basic_ticks_in_tuplet_group * numerator / denominator);
301 
302       if (theobj->type == CHORD)
303         {
304           if (in_tuplet)
305             {
306               if (!((chord *) theobj->object)->is_grace)
307                 {
308                   set_tuplefied_numticks (theobj, numerator, denominator);
309                   basic_ticks_in_tuplet_group += theobj->basic_durinticks;
310                 }  else
311                 {
312                     if(is_end_grace (curobjnode))
313                       ((chord *) theobj->object)->is_grace |= ENDGRACE;
314                     else
315                       ((chord *) theobj->object)->is_grace &= (~ENDGRACE);    //and re-instate if needed
316                     theobj->durinticks = 0;
317                 }
318 
319 
320             }
321           else
322             {
323 
324               ((chord *) theobj->object)->is_grace &= (GRACED_NOTE | ACCIACCATURA);     //leave any fixed grace, changed by toggle.
325 
326               if (((chord *) theobj->object)->is_grace)
327                 {
328                     if(is_end_grace (curobjnode))
329                       ((chord *) theobj->object)->is_grace |= ENDGRACE;
330                     else
331                       ((chord *) theobj->object)->is_grace &= (~ENDGRACE);    //and re-instate if needed
332                     theobj->durinticks = 0;
333                 }
334               else
335                 theobj->durinticks = theobj->basic_durinticks;
336               ticks_so_far += theobj->durinticks;
337             }
338         }
339       else if (theobj->type == TUPOPEN)
340         {
341           in_tuplet = TRUE;
342           numerator = ((tupopen *) theobj->object)->numerator;
343           denominator = ((tupopen *) theobj->object)->denominator;
344           /* basic_ticks_in_tuplet_group = 0; does not work when nested tuplets are used */
345         }
346       else if (theobj->type == TUPCLOSE)
347         {
348           in_tuplet = FALSE;
349           ticks_so_far += ((basic_ticks_in_tuplet_group * numerator) / denominator);
350           numerator = 1;
351           denominator = 1;
352           basic_ticks_in_tuplet_group = 0;
353         }
354       else if (theobj->type == LILYDIRECTIVE)
355         ticks_so_far += theobj->durinticks;
356       theobj->starttickofnextnote = ticks_so_far + (basic_ticks_in_tuplet_group * numerator / denominator);
357 
358       //this goes up too fast for grace notes...
359 
360       //g_debug("start tick next %d\n",       theobj->starttickofnextnote);
361     }
362 }
363 
364 /**
365  * This function simply sets stem directions. It probably deals with
366  * staves that have a fixed stem direction inefficiently, but this was
367  * the easiest way to add things to the existing code.
368  */
369 static void
setsdir(objnode * starter,objnode * ender,gint beamgroup_sum,gint beamgroup_number,gint beamgroup_highest,gint beamgroup_lowest,gint clef,gint stem_directive)370 setsdir (objnode * starter, objnode * ender, gint beamgroup_sum, gint beamgroup_number, gint beamgroup_highest, gint beamgroup_lowest, gint clef, gint stem_directive)
371 {
372   objnode *curobjnode;
373   DenemoObject *theobj;
374   gint avgoffset = beamgroup_number ? beamgroup_sum / beamgroup_number : 0;
375   gint avgheight = calculateheight (avgoffset, clef);
376   gboolean is_stemup = TRUE;
377   gint stemoffset;
378   gint stemy;
379 #if 0
380   {
381     static gint count = 0;
382     count++;
383     g_debug ("Call %d ++++++++++++++++++++++++++++++++\n\
384           Stem directive %s\n\
385           Clef %d\n\
386           ------------------------------\n", count, stem_directive == 2 ? "Neutral" : stem_directive == 1 ? "Down" : "Up", clef);
387   }
388 #endif
389 
390   switch (stem_directive)
391     {
392     case DENEMO_STEMUP:
393       is_stemup = TRUE;
394       break;
395     case DENEMO_STEMBOTH:
396       is_stemup = avgheight > MID_STAFF_HEIGHT;
397       break;
398     case DENEMO_STEMDOWN:
399       is_stemup = FALSE;
400       break;
401     }
402   theobj = (DenemoObject *) starter->data;
403 
404   if (theobj->type == CHORD && (((chord *) theobj->object)->is_grace))
405     is_stemup = TRUE;
406 
407   if (is_stemup)
408     stemoffset = MAX (beamgroup_lowest + 7, beamgroup_highest + 5);
409   else
410     stemoffset = MIN (beamgroup_highest - 7, beamgroup_lowest - 5);
411   stemy = calculateheight (stemoffset, clef);
412 
413   /* Okay; now that we've got everything calculated, just roll through
414    * the measure and set stem heights. */
415 
416   for (curobjnode = starter; curobjnode != ender->next; curobjnode = curobjnode->next)
417     {
418       theobj = (DenemoObject *) curobjnode->data;
419       if (theobj->type == CHORD)
420         {
421           if ((((chord *) theobj->object)->baseduration <= 0))
422             /* Whole notes are always laid out stemup */
423             ((chord *) theobj->object)->is_stemup = TRUE;
424           else
425             {
426               if (((chord *) theobj->object)->is_grace)
427                 ((chord *) theobj->object)->is_stemup = TRUE;
428               else
429                 ((chord *) theobj->object)->is_stemup = is_stemup;
430 
431               ((chord *) theobj->object)->stemy = stemy;
432             }
433           findreversealigns (theobj);
434         }
435     }
436 }
437 
438 /**
439  * This function takes all these int *s in so that appropriate values
440  * can be fed into the function when it's called again for the
441  * next measure -- see staff_beams_and_stems_dirs for details
442   */
443 void
calculatebeamsandstemdirs(DenemoMeasure * measure)444 calculatebeamsandstemdirs (DenemoMeasure *measure)
445 {
446   if (measure == NULL)
447     return;
448   objnode * theobjs = measure->objects;
449   DenemoObject *prevobj = NULL, *theobj;
450   objnode *curobjnode, *starter = NULL;
451   chord chordval;
452   gint beatendsat, ticksperbeat;
453   gint beamgroup_sum = 0;       /* Sum of mid_c_offsets in the beamgroup */
454   gint beamgroup_number = 0;
455   gint beamgroup_highest = 0;
456   gint beamgroup_lowest = 0;
457 
458 
459   gboolean isbeambreak;
460   gint  theclef = measure->clef->type;
461   gint  thetime1 = measure->timesig->time1;
462   gint  thetime2 = measure->timesig->time2;
463   gint  thestem_directive = measure->stemdir->type;
464   gint next_clef = theclef;      /* Useful for when a clef intrudes
465                                    mid-beamgroup */
466   gint next_stem_directive = thestem_directive;
467 
468   if (theobjs==NULL)
469     return;
470 #if 0
471   {
472     static gint count = 0;
473     count++;
474     gint stem = *stem_directive;
475     g_debug ("Call calc %d #################################\n\
476           Stem directive %s\n\
477           Clef %d\n\
478           ------------------------------\n", count, stem == 2 ? "Neutral" : stem == 1 ? "Down" : "Up", next_clef);
479   }
480 #endif
481 
482   ticksperbeat = calcticksperbeat (thetime1, thetime2);
483   settickvalsinmeasure (theobjs);
484   beatendsat = ticksperbeat;
485 
486   for (curobjnode = theobjs; curobjnode; prevobj = theobj, curobjnode = curobjnode->next)
487     {
488       theobj = (DenemoObject *) curobjnode->data;
489       isbeambreak = (theobj->type == CHORD) && (!((chord *) theobj->object)->notes || ((chord *) theobj->object)->is_grace);
490       if (theobj->type != CHORD || isbeambreak)
491         {
492           /* A non-chord or rest always breaks up a beam group */
493           /* LilyPond directives can have their own behaviour,
494              starting with *not* forcing beam breaks */
495           /* if(theobj->type != LILYDIRECTIVE) */
496           {
497             theobj->isstart_beamgroup = TRUE;
498             theobj->isend_beamgroup = TRUE;
499           }
500 
501           switch (theobj->type)
502             {
503             case CLEF:
504               next_clef = ((clef *) theobj->object)->type;
505               break;
506             case STEMDIRECTIVE:
507               next_stem_directive = ((stemdirective *) theobj->object)->type;
508               break;
509             default:
510               break;
511             }
512         }
513       else
514         {
515           /* Determine whether this is the start or end of another
516            * beam group.  Quarter notes or longer automatically are. */
517           if (((chord *) theobj->object)->baseduration <= 2)
518             theobj->isstart_beamgroup = theobj->isend_beamgroup = TRUE;
519           else                  /* otherwise... */
520             {
521               if (prevobj)
522                 theobj->isstart_beamgroup = prevobj->isend_beamgroup;
523               else
524                 theobj->isstart_beamgroup = TRUE;
525 
526               /* Does this note occupy a beat boundary. i.e., it's dotted,
527                * syncopated, whatever? If so, then it's its own beamgroup. */
528               if (theobj->starttickofnextnote > beatendsat)
529                 theobj->isstart_beamgroup = theobj->isend_beamgroup = TRUE;
530               /* Does it end exactly on the beat? Then it's the end of
531                * the beamgroup */
532               else if (theobj->starttickofnextnote == beatendsat)
533                 theobj->isend_beamgroup = TRUE;
534               /* Is it the last note in the measure */
535               else if (!curobjnode->next)
536                 theobj->isend_beamgroup = TRUE;
537               /* Okay. So it's not the end of the beamgroup */
538               else
539                 theobj->isend_beamgroup = FALSE;
540             }                   /* End inner else */
541         }                       /* End outer else */
542 
543       /* Update beatendsat to reflect the bit of music that's just
544        * been tacked on */
545 
546       while (theobj->starttickofnextnote >= beatendsat)
547         beatendsat += ticksperbeat;
548 
549       /* Backtrack a little bit -- we may not have known that prevobj
550        * was the end of the preceding beamgroup until just now. If it
551        * is, set the stem direction and such for the preceding
552        * beamgroup. */
553       if (prevobj && !prevobj->isend_beamgroup && theobj->isstart_beamgroup)
554         {
555           prevobj->isend_beamgroup = TRUE;
556           setsdir (starter, curobjnode->prev, beamgroup_sum, beamgroup_number, beamgroup_highest, beamgroup_lowest, theclef, thestem_directive);
557         }
558 
559       /* Now that we've determined this note's status, what to actually
560        * do about it: */
561 
562       theclef = theobj->clef->type;
563       thestem_directive = theobj->stemdir->type;
564 
565       if (theobj->isstart_beamgroup)
566         {
567           starter = curobjnode;
568           beamgroup_sum = beamgroup_number = 0;
569           beamgroup_highest = G_MININT;
570           beamgroup_lowest = G_MAXINT;
571         }
572       if (theobj->type == CHORD)
573         {
574           chordval = *(chord *) theobj->object;
575           beamgroup_sum += chordval.sum_mid_c_offset;
576           beamgroup_number += g_list_length (chordval.notes);
577           beamgroup_highest = MAX (beamgroup_highest, chordval.highestpitch);
578           beamgroup_lowest = MIN (beamgroup_lowest, chordval.lowestpitch);
579         }
580       if (theobj->isend_beamgroup)
581         {
582           setsdir (starter, curobjnode, beamgroup_sum, beamgroup_number, beamgroup_highest, beamgroup_lowest, theclef, thestem_directive);
583         }
584     }                           /* End object loop */
585 }                               /* End function */
586 
587 
588 
589 
590 
591 #define ACCS_TOO_CLOSE 10
592 /**
593  * This function offsets accidentals that are near to each
594  * other on the same chord.
595  */
596 void
set_accidental_positions(DenemoObject * the_chord)597 set_accidental_positions (DenemoObject * the_chord)
598 {
599   GList *current;
600   note *current_note;
601   gint columns[ACCS_TOO_CLOSE];
602   gint column_widths[ACCS_TOO_CLOSE];
603   gint column_positions[ACCS_TOO_CLOSE];
604   gint i;
605   chord chordval = *(chord *) the_chord->object;
606   gint baseduration = chordval.baseduration;
607   if (g_list_length (chordval.notes) > ACCS_TOO_CLOSE)
608     return;
609 
610   baseduration = MAX (baseduration, 0);
611   gint additional_space = ((!chordval.is_stemup && chordval.is_reversealigned) ? headwidths[MIN (baseduration, 2)] : 0);
612 
613 
614   for (i = 0; i < ACCS_TOO_CLOSE; i++)
615     {
616       columns[i] = G_MAXINT;
617       column_widths[i] = 0;
618     }
619 
620   /* First pass through notes: assign accidentals to numerical
621      columns: 0 -> closest to noteheads, ACCS_TOO_CLOSE - 1 ->
622      furthest away.  Store this value in position_of_accidental, though
623      it will be replaced fairly quickly.  */
624 
625   for (current = g_list_last (chordval.notes); current; current = current->prev)
626     {
627       current_note = (note *) current->data;
628       if (current_note->showaccidental)
629         {
630           for (i = 0; columns[i] < current_note->mid_c_offset + ACCS_TOO_CLOSE; i++)
631             ;
632           current_note->position_of_accidental = i;
633           columns[i] = current_note->mid_c_offset;
634           column_widths[i] = MAX (column_widths[i], accwidths[current_note->enshift + 2]);
635         }
636     }
637 
638   /* Second pass: go through the notes again and replace
639      position_of_accidental with a more useful value.  */
640 
641   column_positions[0] = (column_widths[0] + additional_space + EXTRABACKOFF);
642   for (i = 1; i < ACCS_TOO_CLOSE; i++)
643     column_positions[i] = (column_positions[i - 1] + column_widths[i] + EXTRABACKOFF);
644   for (current = chordval.notes; current; current = current->next)
645     {
646       current_note = (note *) current->data;
647       if (current_note->showaccidental)
648         current_note->position_of_accidental = column_positions[current_note->position_of_accidental];
649     }
650 }
651 
652 
653 #define UNSET -3
654 #define CONTRADICTED 3
655 
656 /**
657  * Calculate which accidentials should be shown
658  * for each note of each chord of the measure whose list of objects is passed in
659  * It also changes minpixelsalloted value of keysginatures to cope with the varying size (dependent on previous keysignature) by calling draw_key in dry-run mode.
660  */
661 void
showwhichaccidentals(objnode * theobjs)662 showwhichaccidentals (objnode * theobjs)
663 {
664   if(theobjs==NULL) return;
665   gint curkey;
666   gint * initialaccs;
667   gint whatpersisted[7];
668   static gint initialaccsthischord[7] = { UNSET, UNSET, UNSET, UNSET, UNSET, UNSET, UNSET };
669   gint accsthischord[7];
670   gboolean freshthischord[7];
671   gboolean contradicted[7];
672   gint otn;                     /* offsettonumber */
673   objnode *curobjnode;
674   DenemoObject *theobj = (DenemoObject *) theobjs->data;;
675   GList *curtone;
676   note *thetone;
677   gint ret[7];
678   gint i;
679 
680   keysig *thekeysig = theobj->keysig;
681   curkey = thekeysig->number;
682   initialaccs = thekeysig->accs;
683 
684   memcpy (ret, initialaccs, SEVENGINTS);
685   memcpy (whatpersisted, initialaccs, SEVENGINTS);
686 
687   for (curobjnode = theobjs; curobjnode; curobjnode = curobjnode->next)
688     {
689       theobj = (DenemoObject *) curobjnode->data;
690 
691       if (theobj->type == CHORD)
692         {
693           ((chord *) theobj->object)->hasanacc = FALSE;
694           memcpy (accsthischord, initialaccsthischord, SEVENGINTS);
695           memset (freshthischord, 0, SEVENGINTS);
696           memset (contradicted, 0, SEVENGINTS);
697           /* First loop through chord - looks for conflicting values
698            * for the same note */
699           for (curtone = ((chord *) theobj->object)->notes; curtone; curtone = curtone->next)
700             {
701               thetone = (note *) curtone->data;
702               otn = offsettonumber (thetone->mid_c_offset);
703               if (thetone->enshift != whatpersisted[otn])
704                 {
705                   freshthischord[otn] = TRUE;
706                   whatpersisted[otn] = thetone->enshift;
707                 }
708               if (accsthischord[otn] == UNSET)
709                 accsthischord[otn] = thetone->enshift;
710               else if (accsthischord[otn] != thetone->enshift)
711                 {
712                   contradicted[otn] = TRUE;
713                   whatpersisted[otn] = CONTRADICTED;
714                 }
715             }                   /* End first loop through chord */
716           /* Now loop through the chord again, setting note->showaccidental
717            * appropriately */
718           for (curtone = ((chord *) theobj->object)->notes; curtone; curtone = curtone->next)
719             {
720               thetone = (note *) curtone->data;
721               otn = offsettonumber (thetone->mid_c_offset);
722               if (contradicted[otn])
723                 /* We've got conflicting accidentals for the same pitch */
724                 thetone->showaccidental = ((chord *) theobj->object)->hasanacc = TRUE;
725               else if (freshthischord[otn])
726                 /* A new accidental not present in the original chord */
727                 thetone->showaccidental = ((chord *) theobj->object)->hasanacc = TRUE;
728               else
729                 thetone->showaccidental = FALSE;
730 
731 
732               // FIXME - you should use a script to apply these directives & set hasnacc with that.
733               if (thetone->directives && ((DenemoDirective *) thetone->directives->data)->postfix && (*((DenemoDirective *) thetone->directives->data)->postfix->str == '!' || *((DenemoDirective *) thetone->directives->data)->postfix->str == '?'))
734                 thetone->showaccidental = ((chord *) theobj->object)->hasanacc = (*((DenemoDirective *) thetone->directives->data)->postfix->str == '?') ? DENEMO_CAUTIONARY : DENEMO_REMINDER;
735 
736             }                   /* End second loop through chord */
737           set_accidental_positions (theobj);
738           setpixelmin (theobj);
739         }                       /* End if chord */
740       else if (theobj->type == KEYSIG)
741         {
742           for (i = 0; i < 7; i++)
743             initialaccsthischord[i] = UNSET;
744             memcpy (ret, ((keysig *) theobj->object)->accs, SEVENGINTS);
745             memcpy (whatpersisted, ret, SEVENGINTS);
746             theobj->minpixelsalloted = draw_key (NULL, 0, 0, ((keysig *) theobj->object)->number, curkey, 0, FALSE, (keysig *) theobj->object);
747             curkey = ((keysig *) theobj->object)->number;
748         }
749 
750     }                           /* End object loop */
751   //memcpy (initialaccs, ret, SEVENGINTS);
752 
753 }
754 
755 /**
756  *  Force and accidental to be shown on the score.
757  *
758  * @param theobj the DenemoObject to force the accidential on
759  */
760 void
forceaccidentals(DenemoObject * theobj)761 forceaccidentals (DenemoObject * theobj)
762 {
763   GList *curtone;
764   note *thetone;
765 
766   for (curtone = ((chord *) theobj->object)->notes; curtone; curtone = curtone->next)
767     {
768       thetone = (note *) curtone->data;
769       thetone->showaccidental = TRUE;
770     }
771   ((chord *) theobj->object)->hasanacc = TRUE;
772   set_accidental_positions (theobj);
773   setpixelmin (theobj);
774   displayhelper (Denemo.project);
775   score_status(Denemo.project, TRUE);
776 }
777 
778 /**
779  * Return the first object node of the given measure
780  * @param mnode a measurenode
781  * @return the first object node of the measure
782  */
783 objnode *
measure_first_obj_node(measurenode * mnode)784 measure_first_obj_node (measurenode * mnode)
785 {
786   return mnode?(objnode *) ((DenemoMeasure*)mnode->data)->objects:NULL; //FIXME DANGER was expecting a node with NULL data for the first object in the case of an empty measure.
787 }
788 
789 /**
790  * Return the last object node of the given measure
791  * @param mnode a measurenode
792  * @return the last object node of the measure
793  */
794 objnode *
measure_last_obj_node(measurenode * mnode)795 measure_last_obj_node (measurenode * mnode)
796 {
797   return g_list_last ((objnode *) ((DenemoMeasure*)mnode->data)->objects);
798 }
799