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