1 /***************************************************************************
2  *  Copyright 1991, 1992, 1993, 1994, 1995, 1996, 2001, 2002               *
3  *    David R. Hill, Leonard Manzara, Craig Schock                         *
4  *                                                                         *
5  *  This program is free software: you can redistribute it and/or modify   *
6  *  it under the terms of the GNU General Public License as published by   *
7  *  the Free Software Foundation, either version 3 of the License, or      *
8  *  (at your option) any later version.                                    *
9  *                                                                         *
10  *  This program is distributed in the hope that it will be useful,        *
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of         *
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          *
13  *  GNU General Public License for more details.                           *
14  *                                                                         *
15  *  You should have received a copy of the GNU General Public License      *
16  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.  *
17  ***************************************************************************/
18 // 2014-09
19 // This file was copied from Gnuspeech and modified by Marcelo Y. Matuda.
20 
21 #include "EventList.h"
22 
23 #include <cstring>
24 #include <iomanip>
25 #include <sstream>
26 #include <vector>
27 
28 #include "Log.h"
29 
30 #define DIPHONE 2
31 #define TRIPHONE 3
32 #define TETRAPHONE 4
33 
34 #define INTONATION_CONFIG_FILE_NAME "/intonation"
35 
36 
37 
38 namespace GS {
39 namespace TRMControlModel {
40 
Event()41 Event::Event() : time(0), flag(0)
42 {
43 	for (int i = 0; i < EVENTS_SIZE; ++i) {
44 		events[i] = GS_EVENTLIST_INVALID_EVENT_VALUE;
45 	}
46 }
47 
EventList(const char * configDirPath,Model & model)48 EventList::EventList(const char* configDirPath, Model& model)
49 		: model_(model)
50 		, macroFlag_(0)
51 		, microFlag_(0)
52 		, driftFlag_(0)
53 		, smoothIntonation_(1)
54 		, globalTempo_(1.0)
55 		, tgParameters_(5)
56 		, useFixedIntonationParameters_(false)
57 		, randSrc_(randDev_())
58 {
59 	setUp();
60 
61 	list_.reserve(128);
62 
63 	initToneGroups(configDirPath);
64 
65 	for (int i = 0; i < 10; ++i) {
66 		fixedIntonationParameters_[i] = 0.0;
67 	}
68 	for (int i = 0; i < TRM::Tube::TOTAL_REGIONS; ++i) {
69 		radiusCoef[i] = 1.0;
70 	}
71 }
72 
~EventList()73 EventList::~EventList()
74 {
75 }
76 
77 void
setUp()78 EventList::setUp()
79 {
80 	list_.clear();
81 
82 	zeroRef_ = 0;
83 	zeroIndex_ = 0;
84 	duration_ = 0;
85 	timeQuantization_ = 4;
86 
87 	multiplier_ = 1.0;
88 	intonParms_ = nullptr;
89 
90 	postureData_.clear();
91 	postureData_.push_back(PostureData());
92 	postureTempo_.clear();
93 	postureTempo_.push_back(1.0);
94 	currentPosture_ = 0;
95 
96 	feet_.clear();
97 	feet_.push_back(Foot());
98 	currentFoot_ = 0;
99 
100 	toneGroups_.clear();
101 	toneGroups_.push_back(ToneGroup());
102 	currentToneGroup_ = 0;
103 
104 	ruleData_.clear();
105 	ruleData_.push_back(RuleData());
106 	currentRule_ = 0;
107 }
108 
109 void
setUpDriftGenerator(double deviation,double sampleRate,double lowpassCutoff)110 EventList::setUpDriftGenerator(double deviation, double sampleRate, double lowpassCutoff)
111 {
112 	driftGenerator_.setUp(deviation, sampleRate, lowpassCutoff);
113 }
114 
115 const Posture*
getPostureAtIndex(unsigned int index) const116 EventList::getPostureAtIndex(unsigned int index) const
117 {
118 	if (index > currentPosture_) {
119 		return nullptr;
120 	} else {
121 		return postureData_[index].posture;
122 	}
123 }
124 
125 const PostureData*
getPostureDataAtIndex(unsigned int index) const126 EventList::getPostureDataAtIndex(unsigned int index) const
127 {
128 	if (index > currentPosture_) {
129 		return nullptr;
130 	} else {
131 		return &postureData_[index];
132 	}
133 }
134 
135 const RuleData*
getRuleAtIndex(unsigned int index) const136 EventList::getRuleAtIndex(unsigned int index) const
137 {
138 	if (static_cast<int>(index) > currentRule_) {
139 		return nullptr;
140 	} else {
141 		return &ruleData_[index];
142 	}
143 }
144 
145 void
setFixedIntonationParameters(float notionalPitch,float pretonicRange,float pretonicLift,float tonicRange,float tonicMovement)146 EventList::setFixedIntonationParameters(float notionalPitch, float pretonicRange, float pretonicLift, float tonicRange, float tonicMovement)
147 {
148 	fixedIntonationParameters_[1] = notionalPitch;
149 	fixedIntonationParameters_[2] = pretonicRange;
150 	fixedIntonationParameters_[3] = pretonicLift;
151 	fixedIntonationParameters_[5] = tonicRange;
152 	fixedIntonationParameters_[6] = tonicMovement;
153 }
154 
155 void
setRadiusCoef(const double * values)156 EventList::setRadiusCoef(const double* values)
157 {
158 	for (int i = 0; i < TRM::Tube::TOTAL_REGIONS; ++i) {
159 		radiusCoef[i] = values[i];
160 	}
161 }
162 
163 void
parseGroups(int index,int number,FILE * fp)164 EventList::parseGroups(int index, int number, FILE* fp)
165 {
166 	char line[256];
167 	tgParameters_[index].resize(10 * number);
168 	for (int i = 0; i < number; ++i) {
169 		fgets(line, 256, fp);
170 		float* temp = &tgParameters_[index][i * 10];
171 		sscanf(line, " %f %f %f %f %f %f %f %f %f %f",
172 			&temp[0], &temp[1], &temp[2], &temp[3], &temp[4],
173 			&temp[5], &temp[6], &temp[7], &temp[8], &temp[9]);
174 	}
175 }
176 
177 void
initToneGroups(const char * configDirPath)178 EventList::initToneGroups(const char* configDirPath)
179 {
180 	FILE* fp;
181 	char line[256];
182 	int count = 0;
183 
184 	std::ostringstream path;
185 	path << configDirPath << INTONATION_CONFIG_FILE_NAME;
186 	fp = fopen(path.str().c_str(), "rb");
187 	if (fp == NULL) {
188 		THROW_EXCEPTION(IOException, "Could not open the file " << path.str().c_str() << '.');
189 	}
190 	while (fgets(line, 256, fp) != NULL) {
191 		if ((line[0] == '#') || (line[0] == ' ')) {
192 			// Skip.
193 		} else if (strncmp(line, "TG", 2) == 0) {
194 			sscanf(&line[2], " %d", &tgCount_[count]);
195 			parseGroups(count, tgCount_[count], fp);
196 			count++;
197 		} else if (strncmp(line, "RANDOM", 6) == 0) {
198 			sscanf(&line[6], " %f", &intonationRandom_);
199 		}
200 	}
201 	fclose(fp);
202 
203 	if (Log::debugEnabled) {
204 		printToneGroups();
205 	}
206 }
207 
208 void
printToneGroups()209 EventList::printToneGroups()
210 {
211 	printf("===== Intonation configuration:\n");
212 	printf("Intonation random = %f\n", intonationRandom_);
213 	printf("Tone groups: %d %d %d %d %d\n", tgCount_[0], tgCount_[1], tgCount_[2], tgCount_[3], tgCount_[4]);
214 
215 	for (int i = 0; i < 5; i++) {
216 		float* temp = &tgParameters_[i][0];
217 		printf("Temp [%d] = %p\n", i, temp);
218 		int j = 0;
219 		for (int k = 0; k < tgCount_[i]; k++) {
220 			printf("%f %f %f %f %f %f %f %f %f %f\n",
221 				temp[j]  , temp[j+1], temp[j+2], temp[j+3], temp[j+4],
222 				temp[j+5], temp[j+6], temp[j+7], temp[j+8], temp[j+9]);
223 			j += 10;
224 		}
225 	}
226 }
227 
228 double
getBeatAtIndex(int ruleIndex) const229 EventList::getBeatAtIndex(int ruleIndex) const
230 {
231 	if (ruleIndex > currentRule_) {
232 		return 0.0;
233 	} else {
234 		return ruleData_[ruleIndex].beat;
235 	}
236 }
237 
238 void
newPostureWithObject(const Posture & p)239 EventList::newPostureWithObject(const Posture& p)
240 {
241 	if (postureData_[currentPosture_].posture) {
242 		postureData_.push_back(PostureData());
243 		postureTempo_.push_back(1.0);
244 		currentPosture_++;
245 	}
246 	postureTempo_[currentPosture_] = 1.0;
247 	postureData_[currentPosture_].ruleTempo = 1.0;
248 	postureData_[currentPosture_].posture = &p;
249 }
250 
251 void
replaceCurrentPostureWith(const Posture & p)252 EventList::replaceCurrentPostureWith(const Posture& p)
253 {
254 	if (postureData_[currentPosture_].posture) {
255 		postureData_[currentPosture_].posture = &p;
256 	} else {
257 		postureData_[currentPosture_ - 1].posture = &p;
258 	}
259 }
260 
261 void
setCurrentToneGroupType(int type)262 EventList::setCurrentToneGroupType(int type)
263 {
264 	toneGroups_[currentToneGroup_].type = type;
265 }
266 
267 void
newFoot()268 EventList::newFoot()
269 {
270 	if (currentPosture_ == 0) {
271 		return;
272 	}
273 
274 	feet_[currentFoot_++].end = currentPosture_;
275 	newPosture();
276 
277 	feet_.push_back(Foot());
278 	feet_[currentFoot_].start = currentPosture_;
279 	feet_[currentFoot_].end = -1;
280 	feet_[currentFoot_].tempo = 1.0;
281 }
282 
283 void
setCurrentFootMarked()284 EventList::setCurrentFootMarked()
285 {
286 	feet_[currentFoot_].marked = 1;
287 }
288 
289 void
setCurrentFootLast()290 EventList::setCurrentFootLast()
291 {
292 	feet_[currentFoot_].last = 1;
293 }
294 
295 void
setCurrentFootTempo(double tempo)296 EventList::setCurrentFootTempo(double tempo)
297 {
298 	feet_[currentFoot_].tempo = tempo;
299 }
300 
301 void
setCurrentPostureTempo(double tempo)302 EventList::setCurrentPostureTempo(double tempo)
303 {
304 	postureTempo_[currentPosture_] = tempo;
305 }
306 
307 void
setCurrentPostureRuleTempo(float tempo)308 EventList::setCurrentPostureRuleTempo(float tempo)
309 {
310 	postureData_[currentPosture_].ruleTempo = tempo;
311 }
312 
313 void
newToneGroup()314 EventList::newToneGroup()
315 {
316 	if (currentFoot_ == 0) {
317 		return;
318 	}
319 
320 	toneGroups_[currentToneGroup_++].endFoot = currentFoot_;
321 	newFoot();
322 
323 	toneGroups_.push_back(ToneGroup());
324 	toneGroups_[currentToneGroup_].startFoot = currentFoot_;
325 	toneGroups_[currentToneGroup_].endFoot = -1;
326 }
327 
328 void
newPosture()329 EventList::newPosture()
330 {
331 	if (postureData_[currentPosture_].posture) {
332 		postureData_.push_back(PostureData());
333 		postureTempo_.push_back(1.0);
334 		currentPosture_++;
335 	}
336 	postureTempo_[currentPosture_] = 1.0;
337 }
338 
339 void
setCurrentPostureSyllable()340 EventList::setCurrentPostureSyllable()
341 {
342 	postureData_[currentPosture_].syllable = 1;
343 }
344 
345 Event*
insertEvent(int number,double time,double value)346 EventList::insertEvent(int number, double time, double value)
347 {
348 	time = time * multiplier_;
349 	if (time < 0.0) {
350 		return nullptr;
351 	}
352 	if (time > (double) (duration_ + timeQuantization_)) {
353 		return nullptr;
354 	}
355 
356 	int tempTime = zeroRef_ + (int) time;
357 	tempTime = (tempTime >> 2) << 2;
358 	//if ((tempTime % timeQuantization) != 0) {
359 	//	tempTime++;
360 	//}
361 
362 	if (list_.empty()) {
363 		std::unique_ptr<Event> tempEvent(new Event());
364 		tempEvent->time = tempTime;
365 		if (number >= 0) {
366 			tempEvent->setValue(value, number);
367 		}
368 		list_.push_back(std::move(tempEvent));
369 		return list_.back().get();
370 	}
371 
372 	int i;
373 	for (i = list_.size() - 1; i >= zeroIndex_; i--) {
374 		if (list_[i]->time == tempTime) {
375 			if (number >= 0) {
376 				list_[i]->setValue(value, number);
377 			}
378 			return list_[i].get();
379 		}
380 		if (list_[i]->time < tempTime) {
381 			std::unique_ptr<Event> tempEvent(new Event());
382 			tempEvent->time = tempTime;
383 			if (number >= 0) {
384 				tempEvent->setValue(value, number);
385 			}
386 			list_.insert(list_.begin() + (i + 1), std::move(tempEvent));
387 			return list_[i + 1].get();
388 		}
389 	}
390 
391 	std::unique_ptr<Event> tempEvent(new Event());
392 	tempEvent->time = tempTime;
393 	if (number >= 0) {
394 		tempEvent->setValue(value, number);
395 	}
396 	list_.insert(list_.begin() + (i + 1), std::move(tempEvent));
397 	return list_[i + 1].get();
398 }
399 
400 void
setZeroRef(int newValue)401 EventList::setZeroRef(int newValue)
402 {
403 	zeroRef_ = newValue;
404 	zeroIndex_ = 0;
405 
406 	if (list_.empty()) {
407 		return;
408 	}
409 
410 	for (int i = list_.size() - 1; i >= 0; i--) {
411 		if (list_[i]->time < newValue) {
412 			zeroIndex_ = i;
413 			return;
414 		}
415 	}
416 }
417 
418 double
createSlopeRatioEvents(const Transition::SlopeRatio & slopeRatio,double baseline,double parameterDelta,double min,double max,int eventIndex)419 EventList::createSlopeRatioEvents(
420 		const Transition::SlopeRatio& slopeRatio,
421 		double baseline, double parameterDelta, double min, double max, int eventIndex)
422 {
423 	double temp = 0.0, temp1 = 0.0, intervalTime = 0.0, sum = 0.0, factor = 0.0;
424 	double baseTime = 0.0, endTime = 0.0, totalTime = 0.0, delta = 0.0;
425 	double startValue;
426 	double pointTime, pointValue;
427 
428 	Transition::getPointData(*slopeRatio.pointList.front(), model_, pointTime, pointValue);
429 	baseTime = pointTime;
430 	startValue = pointValue;
431 
432 	Transition::getPointData(*slopeRatio.pointList.back(), model_, pointTime, pointValue);
433 	endTime = pointTime;
434 	delta = pointValue - startValue;
435 
436 	temp = slopeRatio.totalSlopeUnits();
437 	totalTime = endTime - baseTime;
438 
439 	int numSlopes = slopeRatio.slopeList.size();
440 	std::vector<double> newPointValues(numSlopes - 1);
441 	for (int i = 1; i < numSlopes + 1; i++) {
442 		temp1 = slopeRatio.slopeList[i - 1]->slope / temp; /* Calculate normal slope */
443 
444 		/* Calculate time interval */
445 		intervalTime = Transition::getPointTime(*slopeRatio.pointList[i], model_)
446 				- Transition::getPointTime(*slopeRatio.pointList[i - 1], model_);
447 
448 		/* Apply interval percentage to slope */
449 		temp1 = temp1 * (intervalTime / totalTime);
450 
451 		/* Multiply by delta and add to last point */
452 		temp1 = temp1 * delta;
453 		sum += temp1;
454 
455 		if (i < numSlopes) {
456 			newPointValues[i - 1] = temp1;
457 		}
458 	}
459 	factor = delta / sum;
460 	temp = startValue;
461 
462 	double value = 0.0;
463 	for (unsigned int i = 0, size = slopeRatio.pointList.size(); i < size; i++) {
464 		const Transition::Point& point = *slopeRatio.pointList[i];
465 
466 		if (i >= 1 && i < slopeRatio.pointList.size() - 1) {
467 			pointTime = Transition::getPointTime(point, model_);
468 
469 			pointValue = newPointValues[i - 1];
470 			pointValue *= factor;
471 			pointValue += temp;
472 			temp = pointValue;
473 		} else {
474 			Transition::getPointData(point, model_, pointTime, pointValue);
475 		}
476 
477 		value = baseline + ((pointValue / 100.0) * parameterDelta);
478 		if (value < min) {
479 			value = min;
480 		} else if (value > max) {
481 			value = max;
482 		}
483 		if (!point.isPhantom) {
484 			insertEvent(eventIndex, pointTime, value);
485 		}
486 	}
487 
488 	return value;
489 }
490 
491 // It is assumed that postureList.size() >= 2.
492 void
applyRule(const Rule & rule,const std::vector<const Posture * > & postureList,const double * tempos,int postureIndex)493 EventList::applyRule(const Rule& rule, const std::vector<const Posture*>& postureList, const double* tempos, int postureIndex)
494 {
495 	int cont;
496 	int currentType;
497 	double currentValueDelta, value, lastValue;
498 	double ruleSymbols[5] = {0.0, 0.0, 0.0, 0.0, 0.0};
499 	double tempTime;
500 	double targets[4];
501 	Event* tempEvent = nullptr;
502 
503 	rule.evaluateExpressionSymbols(tempos, postureList, model_, ruleSymbols);
504 
505 	multiplier_ = 1.0 / (double) (postureData_[postureIndex].ruleTempo);
506 
507 	int type = rule.numberOfExpressions();
508 	setDuration((int) (ruleSymbols[0] * multiplier_));
509 
510 	ruleData_[currentRule_].firstPosture = postureIndex;
511 	ruleData_[currentRule_].lastPosture = postureIndex + (type - 1);
512 	ruleData_[currentRule_].beat = (ruleSymbols[1] * multiplier_) + (double) zeroRef_;
513 	ruleData_[currentRule_++].duration = ruleSymbols[0] * multiplier_;
514 	ruleData_.push_back(RuleData());
515 
516 	switch (type) {
517 	/* Note: Case 4 should execute all of the below, case 3 the last two */
518 	case 4:
519 		if (postureList.size() == 4) {
520 			postureData_[postureIndex + 3].onset = (double) zeroRef_ + ruleSymbols[1];
521 			tempEvent = insertEvent(-1, ruleSymbols[3], 0.0);
522 			if (tempEvent) tempEvent->flag = 1;
523 		}
524 	case 3:
525 		if (postureList.size() >= 3) {
526 			postureData_[postureIndex + 2].onset = (double) zeroRef_ + ruleSymbols[1];
527 			tempEvent = insertEvent(-1, ruleSymbols[2], 0.0);
528 			if (tempEvent) tempEvent->flag = 1;
529 		}
530 	case 2:
531 		postureData_[postureIndex + 1].onset = (double) zeroRef_ + ruleSymbols[1];
532 		tempEvent = insertEvent(-1, 0.0, 0.0);
533 		if (tempEvent) tempEvent->flag = 1;
534 		break;
535 	}
536 
537 	//tempTargets = (List *) [rule parameterList];
538 
539 	/* Loop through the parameters */
540 	for (unsigned int i = 0, size = model_.parameterList().size(); i < size; ++i) {
541 		/* Get actual parameter target values */
542 		targets[0] = postureList[0]->getParameterTarget(i);
543 		targets[1] = postureList[1]->getParameterTarget(i);
544 		targets[2] = (postureList.size() >= 3) ? postureList[2]->getParameterTarget(i) : 0.0;
545 		targets[3] = (postureList.size() == 4) ? postureList[3]->getParameterTarget(i) : 0.0;
546 
547 		/* Optimization, Don't calculate if no changes occur */
548 		cont = 1;
549 		switch (type) {
550 		case DIPHONE:
551 			if (targets[0] == targets[1]) {
552 				cont = 0;
553 			}
554 			break;
555 		case TRIPHONE:
556 			if ((targets[0] == targets[1]) && (targets[0] == targets[2])) {
557 				cont = 0;
558 			}
559 			break;
560 		case TETRAPHONE:
561 			if ((targets[0] == targets[1]) && (targets[0] == targets[2]) && (targets[0] == targets[3])) {
562 				cont = 0;
563 			}
564 			break;
565 		}
566 
567 		insertEvent(i, 0.0, targets[0]);
568 
569 		if (cont) {
570 			currentType = DIPHONE;
571 			currentValueDelta = targets[1] - targets[0];
572 			lastValue = targets[0];
573 			//lastValue = 0.0;
574 
575 			const std::shared_ptr<Transition> transition = rule.getParamProfileTransition(i);
576 			if (!transition) {
577 				THROW_EXCEPTION(UnavailableResourceException, "Rule transition not found: " << i << '.');
578 			}
579 
580 			/* Apply lists to parameter */
581 			for (unsigned int j = 0; j < transition->pointOrSlopeList().size(); ++j) {
582 				const Transition::PointOrSlope& pointOrSlope = *transition->pointOrSlopeList()[j];
583 				if (pointOrSlope.isSlopeRatio()) {
584 					const auto& slopeRatio = dynamic_cast<const Transition::SlopeRatio&>(pointOrSlope);
585 
586 					if (slopeRatio.pointList[0]->type != currentType) { //TODO: check pointList.size() > 0
587 						currentType = slopeRatio.pointList[0]->type;
588 						targets[currentType - 2] = lastValue;
589 						currentValueDelta = targets[currentType - 1] - lastValue;
590 					}
591 					value = createSlopeRatioEvents(
592 							slopeRatio, targets[currentType - 2], currentValueDelta,
593 							min_[i], max_[i], i);
594 				} else {
595 					const auto& point = dynamic_cast<const Transition::Point&>(pointOrSlope);
596 
597 					if (point.type != currentType) {
598 						currentType = point.type;
599 						targets[currentType - 2] = lastValue;
600 						currentValueDelta = targets[currentType - 1] - lastValue;
601 					}
602 					double pointTime;
603 					Transition::getPointData(point, model_,
604 									targets[currentType - 2], currentValueDelta, min_[i], max_[i],
605 									pointTime, value);
606 					if (!point.isPhantom) {
607 						insertEvent(i, pointTime, value);
608 					}
609 				}
610 				lastValue = value;
611 			}
612 		}
613 		//else {
614 		//	insertEvent(i, 0.0, targets[0]);
615 		//}
616 	}
617 
618 	/* Special Event Profiles */
619 	for (unsigned int i = 0, size = model_.parameterList().size(); i < size; ++i) {
620 		const std::shared_ptr<Transition> specialTransition = rule.getSpecialProfileTransition(i);
621 		if (specialTransition) {
622 			for (unsigned int j = 0; j < specialTransition->pointOrSlopeList().size(); ++j) {
623 				const Transition::PointOrSlope& pointOrSlope = *specialTransition->pointOrSlopeList()[j];
624 				const auto& point = dynamic_cast<const Transition::Point&>(pointOrSlope);
625 
626 				/* calculate time of event */
627 				tempTime = Transition::getPointTime(point, model_);
628 
629 				/* Calculate value of event */
630 				value = ((point.value / 100.0) * (max_[i] - min_[i]));
631 				//maxValue = value;
632 
633 				/* insert event into event list */
634 				insertEvent(i + 16U, tempTime, value);
635 			}
636 		}
637 	}
638 
639 	setZeroRef((int) (ruleSymbols[0] * multiplier_) + zeroRef_);
640 	tempEvent = insertEvent(-1, 0.0, 0.0);
641 	if (tempEvent) tempEvent->flag = 1;
642 }
643 
644 void
generateEventList()645 EventList::generateEventList()
646 {
647 	for (unsigned int i = 0; i < 16; i++) { //TODO: replace hard-coded value
648 		const Parameter& param = model_.getParameter(i);
649 		min_[i] = (double) param.minimum();
650 		max_[i] = (double) param.maximum();
651 	}
652 
653 	/* Calculate Rhythm including regression */
654 	for (int i = 0; i < currentFoot_; i++) {
655 		int rus = feet_[i].end - feet_[i].start + 1;
656 		/* Apply rhythm model */
657 		double footTempo;
658 		if (feet_[i].marked) {
659 			double tempTempo = 117.7 - (19.36 * (double) rus);
660 			feet_[i].tempo -= tempTempo / 180.0;
661 			footTempo = globalTempo_ * feet_[i].tempo;
662 		} else {
663 			double tempTempo = 18.5 - (2.08 * (double) rus);
664 			feet_[i].tempo -= tempTempo / 140.0;
665 			footTempo = globalTempo_ * feet_[i].tempo;
666 		}
667 		for (int j = feet_[i].start; j < feet_[i].end + 1; j++) {
668 			postureTempo_[j] *= footTempo;
669 			if (postureTempo_[j] < 0.2) {
670 				postureTempo_[j] = 0.2;
671 			} else if (postureTempo_[j] > 2.0) {
672 				postureTempo_[j] = 2.0;
673 			}
674 		}
675 	}
676 
677 	unsigned int basePostureIndex = 0;
678 	std::vector<const Posture*> tempPostureList;
679 	while (basePostureIndex < currentPosture_) {
680 		tempPostureList.clear();
681 		for (unsigned int i = 0; i < 4; i++) {
682 			unsigned int postureIndex = basePostureIndex + i;
683 			if (postureIndex <= currentPosture_ && postureData_[postureIndex].posture) {
684 				tempPostureList.push_back(postureData_[postureIndex].posture);
685 			} else {
686 				break;
687 			}
688 		}
689 		if (tempPostureList.size() < 2) {
690 			break;
691 		}
692 		unsigned int ruleIndex = 0;
693 		const Rule* tempRule = model_.findFirstMatchingRule(tempPostureList, ruleIndex);
694 		if (tempRule == nullptr) {
695 			THROW_EXCEPTION(UnavailableResourceException, "Could not find a matching rule.");
696 		}
697 
698 		ruleData_[currentRule_].number = ruleIndex + 1U;
699 
700 		applyRule(*tempRule, tempPostureList, &postureTempo_[basePostureIndex], basePostureIndex);
701 
702 		basePostureIndex += tempRule->numberOfExpressions() - 1;
703 	}
704 
705 	//[dataPtr[numElements-1] setFlag:1];
706 }
707 
708 void
setFullTimeScale()709 EventList::setFullTimeScale()
710 {
711 	zeroRef_ = 0;
712 	zeroIndex_ = 0;
713 	duration_ = list_.back()->time + 100;
714 }
715 
716 void
applyIntonation()717 EventList::applyIntonation()
718 {
719 	int tgRandom;
720 	int firstFoot, endFoot;
721 	int ruleIndex = 0, postureIndex;
722 	int i, j, k;
723 	double startTime, endTime, pretonicDelta, offsetTime = 0.0;
724 	double randomSemitone, randomSlope;
725 
726 	zeroRef_ = 0;
727 	zeroIndex_ = 0;
728 	duration_ = list_.back()->time + 100;
729 
730 	intonationPoints_.clear();
731 
732 	std::shared_ptr<const Category> vocoidCategory = model_.findCategory("vocoid");
733 	if (!vocoidCategory) {
734 		THROW_EXCEPTION(UnavailableResourceException, "Could not find the category \"vocoid\".");
735 	}
736 
737 	std::uniform_int_distribution<> intRandDist0(0, tgCount_[0] > 0 ? tgCount_[0] - 1 : 0);
738 	std::uniform_int_distribution<> intRandDist1(0, tgCount_[1] > 0 ? tgCount_[1] - 1 : 0);
739 	std::uniform_int_distribution<> intRandDist2(0, tgCount_[2] > 0 ? tgCount_[2] - 1 : 0);
740 	std::uniform_int_distribution<> intRandDist3(0, tgCount_[3] > 0 ? tgCount_[3] - 1 : 0);
741 
742 	for (i = 0; i < currentToneGroup_; i++) {
743 		firstFoot = toneGroups_[i].startFoot;
744 		endFoot = toneGroups_[i].endFoot;
745 
746 		startTime = postureData_[feet_[firstFoot].start].onset;
747 		endTime = postureData_[feet_[endFoot].end].onset;
748 
749 		//printf("Tg: %d First: %d  end: %d  StartTime: %f  endTime: %f\n", i, firstFoot, endFoot, startTime, endTime);
750 
751 		if (useFixedIntonationParameters_) {
752 			intonParms_ = fixedIntonationParameters_;
753 		} else {
754 			switch (toneGroups_[i].type) {
755 			default:
756 			case TONE_GROUP_TYPE_STATEMENT:
757 				if (tgUseRandom_) {
758 					tgRandom = intRandDist0(randSrc_);
759 				} else {
760 					tgRandom = 0;
761 				}
762 				intonParms_ = &tgParameters_[0][tgRandom * 10];
763 				break;
764 			case TONE_GROUP_TYPE_EXCLAMATION:
765 				if (tgUseRandom_) {
766 					tgRandom = intRandDist0(randSrc_);
767 				} else {
768 					tgRandom = 0;
769 				}
770 				intonParms_ = &tgParameters_[0][tgRandom * 10];
771 				break;
772 			case TONE_GROUP_TYPE_QUESTION:
773 				if (tgUseRandom_) {
774 					tgRandom = intRandDist1(randSrc_);
775 				} else {
776 					tgRandom = 0;
777 				}
778 				intonParms_ = &tgParameters_[1][tgRandom * 10];
779 				break;
780 			case TONE_GROUP_TYPE_CONTINUATION:
781 				if (tgUseRandom_) {
782 					tgRandom = intRandDist2(randSrc_);
783 				} else {
784 					tgRandom = 0;
785 				}
786 				intonParms_ = &tgParameters_[2][tgRandom * 10];
787 				break;
788 			case TONE_GROUP_TYPE_SEMICOLON:
789 				if (tgUseRandom_) {
790 					tgRandom = intRandDist3(randSrc_);
791 				} else {
792 					tgRandom = 0;
793 				}
794 				intonParms_ = &tgParameters_[3][tgRandom * 10];
795 				break;
796 			}
797 		}
798 
799 		//printf("Intonation Parameters: Type : %d  random: %d\n", toneGroups[i].type, tgRandom);
800 		//for (j = 0; j<6; j++)
801 		//	printf("%f ", intonParms[j]);
802 		//printf("\n");
803 
804 		pretonicDelta = (intonParms_[1]) / (endTime - startTime);
805 		//printf("Pretonic Delta = %f time = %f\n", pretonicDelta, (endTime - startTime));
806 
807 		/* Set up intonation boundary variables */
808 		for (j = firstFoot; j <= endFoot; j++) {
809 			postureIndex = feet_[j].start;
810 			while (!postureData_[postureIndex].posture->isMemberOfCategory(*vocoidCategory)) {
811 				postureIndex++;
812 				//printf("Checking posture %s for vocoid\n", [posture[postureIndex].posture symbol]);
813 				if (postureIndex > feet_[j].end) {
814 					postureIndex = feet_[j].start;
815 					break;
816 				}
817 			}
818 
819 			if (!feet_[j].marked) {
820 				for (k = 0; k < currentRule_; k++) {
821 					if ((postureIndex >= ruleData_[k].firstPosture) && (postureIndex <= ruleData_[k].lastPosture)) {
822 						ruleIndex = k;
823 						break;
824 					}
825 				}
826 
827 				if (tgUseRandom_) {
828 					randomSemitone = randDist_(randSrc_) * intonParms_[3] - intonParms_[3] / 2.0;
829 					randomSlope = randDist_(randSrc_) * 0.015 + 0.01;
830 				} else {
831 					randomSemitone = 0.0;
832 					randomSlope = 0.02;
833 				}
834 
835 				//printf("postureIndex = %d onsetTime : %f Delta: %f\n", postureIndex,
836 				//	postures[postureIndex].onset-startTime,
837 				//	((postures[postureIndex].onset-startTime)*pretonicDelta) + intonParms[1] + randomSemitone);
838 
839 				addIntonationPoint((postureData_[postureIndex].onset - startTime) * pretonicDelta + intonParms_[1] + randomSemitone,
840 							offsetTime, randomSlope, ruleIndex);
841 			} else { /* Tonic */
842 				if (toneGroups_[i].type == 3) {
843 					randomSlope = 0.01;
844 				} else {
845 					randomSlope = 0.02;
846 				}
847 
848 				for (k = 0; k < currentRule_; k++) {
849 					if ((postureIndex >= ruleData_[k].firstPosture) && (postureIndex <= ruleData_[k].lastPosture)) {
850 						ruleIndex = k;
851 						break;
852 					}
853 				}
854 
855 				if (tgUseRandom_) {
856 					randomSemitone = randDist_(randSrc_) * intonParms_[6] - intonParms_[6] / 2.0;
857 					randomSlope += randDist_(randSrc_) * 0.03;
858 				} else {
859 					randomSemitone = 0.0;
860 					randomSlope += 0.03;
861 				}
862 				addIntonationPoint(intonParms_[2] + intonParms_[1] + randomSemitone,
863 							offsetTime, randomSlope, ruleIndex);
864 
865 				postureIndex = feet_[j].end;
866 				for (k = ruleIndex; k < currentRule_; k++) {
867 					if ((postureIndex >= ruleData_[k].firstPosture) && (postureIndex <= ruleData_[k].lastPosture)) {
868 						ruleIndex = k;
869 						break;
870 					}
871 				}
872 
873 				addIntonationPoint(intonParms_[2] + intonParms_[1] + intonParms_[5],
874 							0.0, 0.0, ruleIndex);
875 			}
876 			offsetTime = -40.0;
877 		}
878 	}
879 	addIntonationPoint(intonParms_[2] + intonParms_[1] + intonParms_[5],
880 				0.0, 0.0, currentRule_ - 1);
881 }
882 
883 void
applyIntonationSmooth()884 EventList::applyIntonationSmooth()
885 {
886 	setFullTimeScale();
887 	//tempPoint = [[IntonationPoint alloc] initWithEventList: self];
888 	//[tempPoint setSemitone: -20.0];
889 	//[tempPoint setSemitone: -20.0];
890 	//[tempPoint setRuleIndex: 0];
891 	//[tempPoint setOffsetTime: 10.0 - [self getBeatAtIndex:(int) 0]];
892 
893 	//[intonationPoints insertObject: tempPoint at:0];
894 
895 	for (unsigned int j = 0; j < intonationPoints_.size() - 1; j++) {
896 		const IntonationPoint& point1 = intonationPoints_[j];
897 		const IntonationPoint& point2 = intonationPoints_[j + 1];
898 
899 		double x1 = point1.absoluteTime() / 4.0;
900 		double y1 = point1.semitone() + 20.0;
901 		double m1 = point1.slope();
902 
903 		double x2 = point2.absoluteTime() / 4.0;
904 		double y2 = point2.semitone() + 20.0;
905 		double m2 = point2.slope();
906 
907 		double x12 = x1 * x1;
908 		double x13 = x12 * x1;
909 
910 		double x22 = x2 * x2;
911 		double x23 = x22 * x2;
912 
913 		double denominator = x2 - x1;
914 		denominator = denominator * denominator * denominator;
915 
916 //		double d = ( -(y2 * x13) + 3 * y2 * x12 * x2 + m2 * x13 * x2 + m1 * x12 * x22 - m2 * x12 * x22 - 3 * x1 * y1 * x22 - m1 * x1 * x23 + y1 * x23 )
917 //			/ denominator;
918 		double c = ( -(m2 * x13) - 6 * y2 * x1 * x2 - 2 * m1 * x12 * x2 - m2 * x12 * x2 + 6 * x1 * y1 * x2 + m1 * x1 * x22 + 2 * m2 * x1 * x22 + m1 * x23 )
919 			/ denominator;
920 		double b = ( 3 * y2 * x1 + m1 * x12 + 2 * m2 * x12 - 3 * x1 * y1 + 3 * x2 * y2 + m1 * x1 * x2 - m2 * x1 * x2 - 3 * y1 * x2 - 2 * m1 * x22 - m2 * x22 )
921 			/ denominator;
922 		double a = ( -2 * y2 - m1 * x1 - m2 * x1 + 2 * y1 + m1 * x2 + m2 * x2) / denominator;
923 
924 		insertEvent(32, point1.absoluteTime(), point1.semitone());
925 		//printf("Inserting Point %f\n", [point1 semitone]);
926 		double yTemp = (3.0 * a * x12) + (2.0 * b * x1) + c;
927 		insertEvent(33, point1.absoluteTime(), yTemp);
928 		yTemp = (6.0 * a * x1) + (2.0 * b);
929 		insertEvent(34, point1.absoluteTime(), yTemp);
930 		yTemp = 6.0 * a;
931 		insertEvent(35, point1.absoluteTime(), yTemp);
932 	}
933 	//[intonationPoints removeObjectAt:0];
934 
935 	//[self insertEvent:32 atTime: 0.0 withValue: -20.0]; /* A value of -20.0 in bin 32 should produce a
936 	//							    linear interp to -20.0 */
937 }
938 
939 void
addIntonationPoint(double semitone,double offsetTime,double slope,int ruleIndex)940 EventList::addIntonationPoint(double semitone, double offsetTime, double slope, int ruleIndex)
941 {
942 	if (ruleIndex > currentRule_) {
943 		return;
944 	}
945 
946 	IntonationPoint iPoint(this);
947 	iPoint.setRuleIndex(ruleIndex);
948 	iPoint.setOffsetTime(offsetTime);
949 	iPoint.setSemitone(semitone);
950 	iPoint.setSlope(slope);
951 
952 	double time = iPoint.absoluteTime();
953 	for (unsigned int i = 0; i < intonationPoints_.size(); i++) {
954 		if (time < intonationPoints_[i].absoluteTime()) {
955 			intonationPoints_.insert(intonationPoints_.begin() + i, iPoint);
956 			return;
957 		}
958 	}
959 
960 	intonationPoints_.push_back(iPoint);
961 }
962 
963 void
generateOutput(std::ostream & trmParamStream)964 EventList::generateOutput(std::ostream& trmParamStream)
965 {
966 	double currentValues[36];
967 	double currentDeltas[36];
968 	double temp;
969 	float table[16];
970 
971 	if (list_.empty()) {
972 		return;
973 	}
974 
975 	for (int i = 0; i < 16; i++) {
976 		unsigned int j = 1;
977 		while ((temp = list_[j]->getValue(i)) == GS_EVENTLIST_INVALID_EVENT_VALUE) {
978 			j++;
979 			if (j >= list_.size()) break;
980 		}
981 		currentValues[i] = list_[0]->getValue(i);
982 		if (j < list_.size()) {
983 			currentDeltas[i] = ((temp - currentValues[i]) / (double) (list_[j]->time)) * 4.0;
984 		} else {
985 			currentDeltas[i] = 0.0;
986 		}
987 	}
988 	for (int i = 16; i < 36; i++) {
989 		currentValues[i] = currentDeltas[i] = 0.0;
990 	}
991 
992 	if (smoothIntonation_) {
993 		unsigned int j = 0;
994 		while ((temp = list_[j]->getValue(32)) == GS_EVENTLIST_INVALID_EVENT_VALUE) {
995 			j++;
996 			if (j >= list_.size()) break;
997 		}
998 		if (j < list_.size()) {
999 			currentValues[32] = list_[j]->getValue(32);
1000 		} else {
1001 			currentValues[32] = 0.0;
1002 		}
1003 		currentDeltas[32] = 0.0;
1004 	} else {
1005 		unsigned int j = 1;
1006 		while ((temp = list_[j]->getValue(32)) == GS_EVENTLIST_INVALID_EVENT_VALUE) {
1007 			j++;
1008 			if (j >= list_.size()) break;
1009 		}
1010 		currentValues[32] = list_[0]->getValue(32);
1011 		if (j < list_.size()) {
1012 			currentDeltas[32] = ((temp - currentValues[32]) / (double) (list_[j]->time)) * 4.0;
1013 		} else {
1014 			currentDeltas[32] = 0.0;
1015 		}
1016 		currentValues[32] = -20.0;
1017 	}
1018 
1019 	unsigned int index = 1;
1020 	int currentTime = 0;
1021 	int nextTime = list_[1]->time;
1022 	while (index < list_.size()) {
1023 
1024 		for (int j = 0; j < 16; j++) {
1025 			table[j] = (float) currentValues[j] + (float) currentValues[j + 16];
1026 		}
1027 		if (!microFlag_) table[0] = 0.0;
1028 		if (driftFlag_)  table[0] += static_cast<float>(driftGenerator_.drift());
1029 		if (macroFlag_)  table[0] += static_cast<long>(currentValues[32]);
1030 
1031 		table[0] += static_cast<float>(pitchMean_);
1032 
1033 		trmParamStream << std::fixed << std::setprecision(3);
1034 		trmParamStream << table[0];
1035 		for (int k = 1; k < 7; ++k) {
1036 			trmParamStream << ' ' << table[k];
1037 		}
1038 		for (int k = 7; k < 15; ++k) { // R1 - R8
1039 			trmParamStream << ' ' << table[k] * radiusCoef[k - 7];
1040 		}
1041 		trmParamStream << ' ' << table[15];
1042 		trmParamStream << '\n';
1043 
1044 		for (int j = 0; j < 32; j++) {
1045 			if (currentDeltas[j]) {
1046 				currentValues[j] += currentDeltas[j];
1047 			}
1048 		}
1049 
1050 		if (smoothIntonation_) {
1051 			currentDeltas[34] += currentDeltas[35];
1052 			currentDeltas[33] += currentDeltas[34];
1053 			currentValues[32] += currentDeltas[33];
1054 		} else {
1055 			if (currentDeltas[32]) {
1056 				currentValues[32] += currentDeltas[32];
1057 			}
1058 		}
1059 		currentTime += 4;
1060 
1061 		if (currentTime >= nextTime) {
1062 			++index;
1063 			if (index == list_.size()) {
1064 				break;
1065 			}
1066 			nextTime = list_[index]->time;
1067 			for (int j = 0; j < 33; j++) { /* 32? 33? */
1068 				if (list_[index - 1]->getValue(j) != GS_EVENTLIST_INVALID_EVENT_VALUE) {
1069 					unsigned int k = index;
1070 					while ((temp = list_[k]->getValue(j)) == GS_EVENTLIST_INVALID_EVENT_VALUE) {
1071 						if (k >= list_.size() - 1U) {
1072 							currentDeltas[j] = 0.0;
1073 							break;
1074 						}
1075 						k++;
1076 					}
1077 					if (temp != GS_EVENTLIST_INVALID_EVENT_VALUE) {
1078 						currentDeltas[j] = (temp - currentValues[j]) /
1079 									(double) (list_[k]->time - currentTime) * 4.0;
1080 					}
1081 				}
1082 			}
1083 			if (smoothIntonation_) {
1084 				if (list_[index - 1]->getValue(33) != GS_EVENTLIST_INVALID_EVENT_VALUE) {
1085 					currentValues[32] = list_[index - 1]->getValue(32);
1086 					currentDeltas[32] = 0.0;
1087 					currentDeltas[33] = list_[index - 1]->getValue(33);
1088 					currentDeltas[34] = list_[index - 1]->getValue(34);
1089 					currentDeltas[35] = list_[index - 1]->getValue(35);
1090 				}
1091 			}
1092 		}
1093 	}
1094 
1095 	if (Log::debugEnabled) {
1096 		printDataStructures();
1097 	}
1098 }
1099 
1100 void
clearMacroIntonation()1101 EventList::clearMacroIntonation()
1102 {
1103 	for (unsigned int i = 0, size = list_.size(); i < size; ++i) {
1104 		auto& event = list_[i];
1105 		for (unsigned int j = 32; j < 36; ++j) {
1106 			event->setValue(GS_EVENTLIST_INVALID_EVENT_VALUE, j);
1107 		}
1108 	}
1109 }
1110 
1111 void
printDataStructures()1112 EventList::printDataStructures()
1113 {
1114 	printf("Tone Groups %d\n", currentToneGroup_);
1115 	for (int i = 0; i < currentToneGroup_; i++) {
1116 		printf("%d  start: %d  end: %d  type: %d\n", i, toneGroups_[i].startFoot, toneGroups_[i].endFoot,
1117 			toneGroups_[i].type);
1118 	}
1119 
1120 	printf("\nFeet %d\n", currentFoot_);
1121 	for (int i = 0; i < currentFoot_; i++) {
1122 		printf("%d  tempo: %f start: %d  end: %d  marked: %d last: %d onset1: %f onset2: %f\n", i, feet_[i].tempo,
1123 			feet_[i].start, feet_[i].end, feet_[i].marked, feet_[i].last, feet_[i].onset1, feet_[i].onset2);
1124 	}
1125 
1126 	printf("\nPostures %d\n", currentPosture_);
1127 	for (unsigned int i = 0; i < currentPosture_; i++) {
1128 		printf("%u  \"%s\" tempo: %f syllable: %d onset: %f ruleTempo: %f\n",
1129 			 i, postureData_[i].posture->name().c_str(), postureTempo_[i], postureData_[i].syllable, postureData_[i].onset, postureData_[i].ruleTempo);
1130 	}
1131 
1132 	printf("\nRules %d\n", currentRule_);
1133 	for (int i = 0; i < currentRule_; i++) {
1134 		printf("Number: %d  start: %d  end: %d  duration %f\n", ruleData_[i].number, ruleData_[i].firstPosture,
1135 			ruleData_[i].lastPosture, ruleData_[i].duration);
1136 	}
1137 #if 0
1138 	printf("\nEvents %lu\n", list_.size());
1139 	for (unsigned int i = 0; i < list_.size(); i++) {
1140 		const Event& event = *list_[i];
1141 		printf("  Event: time=%d flag=%d\n    Values: ", event.time, event.flag);
1142 
1143 		for (int j = 0; j < 16; j++) {
1144 			printf("%.3f ", event.getValue(j));
1145 		}
1146 		printf("\n            ");
1147 		for (int j = 16; j < 32; j++) {
1148 			printf("%.3f ", event.getValue(j));
1149 		}
1150 		printf("\n            ");
1151 		for (int j = 32; j < Event::EVENTS_SIZE; j++) {
1152 			printf("%.3f ", event.getValue(j));
1153 		}
1154 		printf("\n");
1155 	}
1156 #endif
1157 }
1158 
1159 } /* namespace TRMControlModel */
1160 } /* namespace GS */
1161