1 /* Copyright (c) 2003 by Arkkra Enterprises. */
2 /* All rights reserved. */
4 /* This file contains parse-time functions related to TIMEDSSVs.
5 * These are used to specify mid-measure parameter changes,
13 /* Mid-measure SSV's eventually get attached to the BAR, but we need
14 * to point to the list temporarily while the BAR doesn't exist yet. */
15 static struct TIMEDSSV *Timedssv_p;
17 /* When there is more than one TIMEDSSV at the same moment in time,
18 * we use user input order, so we add items to the end of the list.
19 * This keeps track of where to put the next one.
21 static struct TIMEDSSV **Timed_tail_p_p = &Timedssv_p;
23 static struct TIMEDSSV *tssv_new P((int context));
26 /* Allocate and initalize a TIMEDSSV for each staff/voice being defined,
27 * and return pointer to the first one.
36 struct SVRANGELIST *svr_p; /* list of staffs/voices being entered */
37 struct RANGELIST *srange_p; /* list of staffs being entered */
38 struct RANGELIST *vrange_p; /* list of voices being entered */
39 struct TIMEDSSV *new_p;
40 struct TIMEDSSV *first_p = 0; /* first one created */
41 int s; /* staff number */
42 int v; /* voice number */
44 /* Create as many new TIMEDSSVs as needed, based on the current list
45 * of staffs/voices being defined,
46 * link them onto the temporary list for the current measure.
51 first_p = new_p = tssv_new(context);
55 for (svr_p = Svrangelist_p; svr_p != 0; svr_p = svr_p->next) {
56 for (srange_p = svr_p->stafflist_p; srange_p != 0;
57 srange_p = srange_p->next) {
58 for (s = srange_p->begin; s <= srange_p->end; s++) {
59 if (context == C_STAFF) {
60 new_p = tssv_new(context);
64 new_p->ssv.staffno = s;
67 for (vrange_p = svr_p->vnolist_p;
69 vrange_p = vrange_p->next) {
70 for (v = vrange_p->begin;
73 new_p = tssv_new(context);
77 new_p->ssv.staffno = s;
78 new_p->ssv.voiceno = v;
87 pfatal("invalid context %d when creating TIMEDSSV", context);
95 /* Create a single TIMEDSSV and link it onto the list */
97 static struct TIMEDSSV *
103 struct TIMEDSSV *curr_tssv_p;
105 CALLOC(TIMEDSSV, curr_tssv_p, 1);
106 zapssv( & (curr_tssv_p->ssv) );
107 curr_tssv_p->ssv.context = context;
108 curr_tssv_p->grpsyl_p = 0;
109 curr_tssv_p->time_off.n = -1;
110 curr_tssv_p->time_off.d = 1;
112 curr_tssv_p->next = 0;
113 *Timed_tail_p_p = curr_tssv_p;
114 Timed_tail_p_p = &(curr_tssv_p->next);
120 /* Save a parameter setting in the given TIMEDSSV. We only support a very
121 * limited list of parameters that can be changed mid-measure,
122 * so this checks for valid ones.
126 tssv_update(timedssv_p, param, value)
128 struct TIMEDSSV *timedssv_p;
133 /* Could be multiple staffs/voices, so do them all */
134 for ( ; timedssv_p != 0; timedssv_p = timedssv_p->next) {
137 timedssv_p->ssv.clef = value;
140 if (rangecheck(value, MINRELEASE, MAXRELEASE,
141 "mid-measure release change") == YES) {
142 timedssv_p->ssv.release = value;
146 if (rangecheck(value, MINOCTAVE, MAXOCTAVE,
147 "mid-measure defoct change") == YES) {
148 timedssv_p->ssv.defoct = value;
153 yyerror("only clef, defoct, and release parameters can be changed mid-measure");
156 if (timedssv_p->ssv.used[param] == YES) {
157 warning("multiple changes of the same parameter; last used");
159 timedssv_p->ssv.used[param] = YES;
164 /* Associate grpsyl with TIMEDSSV. This should be called at the end of
165 * parsing of a grpsyl, in case it has at least one timed ssv. */
173 struct TIMEDSSV *tssv_p;
175 /* User could input multiple << >> things, and each gets their
176 * own TIMEDSSV, so we need to associate this grpsyl with
177 * all that don't yet have one. */
178 for (tssv_p = Timedssv_p; tssv_p != 0; tssv_p = tssv_p->next) {
179 if (tssv_p->grpsyl_p == 0) {
180 tssv_p->grpsyl_p = gs_p;
182 /* Do some error checks */
183 if (tssv_p->ssv.used[CLEF] == YES) {
184 if (tssv_p->ssv.context == C_STAFF
185 && is_tab_staff(tssv_p->ssv.staffno)) {
186 yyerror("can't change clef of tab staff");
188 if (tssv_p->ssv.context == C_VOICE) {
189 yyerror("can't change clef in voice context");
198 /* Do processing on one input line worth of TIMEDSSVs.
204 struct TIMEDSSV *ts_p;
207 /* First we have to find the time offsets of each TIMEDSSV.
208 * We can't necessarily calculate them at the time
209 * they were added to the list, since for tuplets
210 * we don't know fulltimes till we reach the end
211 * of the tuplet, and know how to adjust.
212 * So we just save the GRPSYL* at that point,
213 * and now we go through and find all the actual times.
215 for (ts_p = Timedssv_p; ts_p != 0; ts_p = ts_p->next) {
216 if (GE(ts_p->time_off, Zero)) {
217 /* already set from some previous line */
221 if (ts_p->grpsyl_p == 0) {
222 /* This could happen if there was a user input
223 * error, because we could have set up the TIMEDSSV
224 * and then not been able to parse the GRPSYL that
225 * was intended to go with it. Set time offset to
226 * a safe value, and skip the rest of the loop,
227 * so we don't try to dereference the null ptr. */
228 ts_p->time_off = Zero;
232 /* Count up the time before the group where the timed
233 * SSV was specified. */
234 for (ts_p->time_off = Zero, gs_p = ts_p->grpsyl_p->prev;
235 gs_p != 0; gs_p = gs_p->prev) {
236 /* Alt groups have not yet had their time adjusted,
237 * so we have to compensate for that. */
238 if (gs_p->slash_alt < 0 || (gs_p->prev != 0
239 && gs_p->prev->slash_alt < 0) ) {
240 ts_p->time_off = radd(ts_p->time_off,
241 rdiv(gs_p->fulltime, Two));
243 else if (gs_p->grpvalue != GV_ZERO) {
244 ts_p->time_off = radd(ts_p->time_off,
252 /* Sort the current TIMEDSSV list by time and return pointer to the head
253 * of the sorted list. The sorting is done by time. When there is a tie
254 * things are put in user input order. Also re-inits for the next measure.
261 struct TIMEDSSV *ret; /* return value is pointer to sorted list */
262 short moved; /* YES if something was moved during sort */
264 /* Most of the time, the list will be empty. */
265 if (Timedssv_p == 0) {
269 /* Sort in time order.
270 * The list is almost certain to be very short,
271 * so sort needn't be very efficient. So we check pairs
272 * and swap ones that are backwards. */
274 struct TIMEDSSV **ts_p_p;
275 struct TIMEDSSV *tmp_ts_p;
278 for (ts_p_p = &Timedssv_p; (*ts_p_p)->next != 0;
279 ts_p_p = &((*ts_p_p)->next) ) {
280 if ( GT( (*ts_p_p)->time_off, (*ts_p_p)->next->time_off ) ) {
281 /* Wrong order. Swap them */
282 tmp_ts_p = (*ts_p_p)->next;
283 (*ts_p_p)->next = (*ts_p_p)->next->next;
284 tmp_ts_p->next = *ts_p_p;
290 } while (moved == YES);
293 /* re-init for next measure */
295 Timed_tail_p_p = &(Timedssv_p);