1 //=========================================================
2 // MusE
3 // Linux Music Editor
4 //
5 // time_stretch.cpp
6 // Copyright (C) 2010-2020 Tim E. Real (terminator356 on users dot sourceforge dot net)
7 //
8 // This program is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU General Public License
10 // as published by the Free Software Foundation; version 2 of
11 // the License, or (at your option) any later version.
12 //
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU General Public License for more details.
17 //
18 // You should have received a copy of the GNU General Public License
19 // along with this program; if not, write to the Free Software
20 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 //
22 //=========================================================
23
24 #include <stdio.h>
25 #include "muse_math.h"
26
27 #include "time_stretch.h"
28 #include "xml.h"
29
30 // For debugging output: Uncomment the fprintf section.
31 #define ERROR_TIMESTRETCH(dev, format, args...) fprintf(dev, format, ##args)
32 #define INFO_TIMESTRETCH(dev, format, args...) // fprintf(dev, format, ##args)
33 #define DEBUG_TIMESTRETCH(dev, format, args...) // fprintf(dev, format, ##args)
34
35 namespace MusECore {
36
37 //---------------------------------------------------------
38 // StretchList
39 //---------------------------------------------------------
40
StretchList()41 StretchList::StretchList()
42 {
43 _isStretched = false;
44 _isResampled = false;
45 _isPitchShifted = false;
46 _startFrame = 0;
47 _endFrame = 0;
48 _stretchedEndFrame = 0;
49 _squishedEndFrame = 0;
50 _stretchRatio = 1.0;
51 _samplerateRatio = 1.0;
52 _pitchRatio = 1.0;
53
54 // Ensure that there is always an item at frame zero.
55 insert(std::pair<const MuseFrame_t, StretchListItem>
56 (0, StretchListItem(1.0, 1.0, 1.0,
57 StretchListItem::StretchEvent |
58 StretchListItem::SamplerateEvent |
59 StretchListItem::PitchEvent)));
60
61 // Technically it is normalized now, since StretchListItem
62 // constructor fills in zeros for the frame values.
63 _isNormalized = true;
64 }
65
~StretchList()66 StretchList::~StretchList()
67 {
68 }
69
add(StretchListItem::StretchEventType type,MuseFrame_t frame,double value,bool do_normalize)70 void StretchList::add(StretchListItem::StretchEventType type, MuseFrame_t frame, double value, bool do_normalize)
71 {
72 // Some '1.0' values will be filled in if neccessary by normalize() below.
73 double str = 1.0;
74 double srr = 1.0;
75 double psr = 1.0;
76 switch(type)
77 {
78 case StretchListItem::StretchEvent:
79 str = value;
80 break;
81
82 case StretchListItem::SamplerateEvent:
83 srr = value;
84 break;
85
86 case StretchListItem::PitchEvent:
87 psr = value;
88 break;
89 }
90
91 std::pair<iStretchListItem, bool> res =
92 insert(std::pair<const MuseFrame_t, StretchListItem>
93 (frame, StretchListItem(str, srr, psr, type)));
94
95 // Item already exists? Assign.
96 if(!res.second)
97 {
98 // Set the type's value. But leave the others alone.
99 switch(type)
100 {
101 case StretchListItem::StretchEvent:
102 res.first->second._stretchRatio = value;
103 break;
104
105 case StretchListItem::SamplerateEvent:
106 res.first->second._samplerateRatio = value;
107 break;
108
109 case StretchListItem::PitchEvent:
110 res.first->second._pitchRatio = value;
111 break;
112 }
113
114 // Combine the type.
115 res.first->second._type |= type;
116 }
117
118 // Mark as invalidated, normalization is required.
119 _isNormalized = false;
120
121 if(do_normalize)
122 normalizeListFrames();
123 }
124
add(MuseFrame_t frame,const StretchListItem & e,bool do_normalize)125 void StretchList::add(MuseFrame_t frame, const StretchListItem& e, bool do_normalize)
126 {
127 std::pair<iStretchListItem, bool> res = insert(std::pair<const MuseFrame_t, StretchListItem> (frame, e));
128
129 // Item already exists? Assign.
130 if(!res.second)
131 {
132 //res.first->second = e;
133 res.first->second._stretchRatio = e._stretchRatio;
134 res.first->second._samplerateRatio = e._samplerateRatio;
135 res.first->second._pitchRatio = e._pitchRatio;
136 }
137
138 // Mark as invalidated, normalization is required.
139 _isNormalized = false;
140
141 if(do_normalize)
142 normalizeListFrames();
143 }
144
del(int types,MuseFrame_t frame,bool do_normalize)145 void StretchList::del(int types, MuseFrame_t frame, bool do_normalize)
146 {
147 // Do not delete the item at zeroth frame.
148 if(frame == 0)
149 return;
150
151 iStretchListItem e = find(frame);
152 if(e == end())
153 {
154 ERROR_TIMESTRETCH(stderr, "StretchList::del(%ld): not found\n", frame);
155 return;
156 }
157
158 del(types, e, do_normalize);
159 }
160
del(int types,iStretchListItem item,bool do_normalize)161 void StretchList::del(int types, iStretchListItem item, bool do_normalize)
162 {
163 // Do not delete the item at zeroth frame.
164 if(item->first == 0)
165 return;
166
167 // We must restore any previous event's ratio to 1.0.
168 // This is crucial so that when the last user marker is finally removed, the special zeroth marker (non-user)
169 // will be set to 1.0 ratio and the converters are not required anymore and can be deleted.
170 if(types & StretchListItem::StretchEvent)
171 {
172 iStretchListItem prevStretchTyped = previousEvent(StretchListItem::StretchEvent, item);
173 if(prevStretchTyped != end())
174 prevStretchTyped->second._stretchRatio = 1.0;
175 }
176 if(types & StretchListItem::SamplerateEvent)
177 {
178 iStretchListItem prevSamplerateTyped = previousEvent(StretchListItem::SamplerateEvent, item);
179 if(prevSamplerateTyped != end())
180 prevSamplerateTyped->second._samplerateRatio = 1.0;
181 }
182 if(types & StretchListItem::PitchEvent)
183 {
184 iStretchListItem prevPitchTyped = previousEvent(StretchListItem::PitchEvent, item);
185 if(prevPitchTyped != end())
186 prevPitchTyped->second._stretchRatio = 1.0;
187 }
188
189 item->second._type &= ~types;
190
191 if(item->second._type == 0)
192 erase(item);
193
194 // Mark as invalidated, normalization is required.
195 _isNormalized = false;
196
197 if(do_normalize)
198 normalizeListFrames();
199 }
200
201
normalizeFrames()202 void StretchList::normalizeFrames()
203 {
204 _stretchedEndFrame = stretch(_endFrame);
205 _squishedEndFrame = squish(_endFrame);
206 }
207
normalizeRatios()208 void StretchList::normalizeRatios()
209 {
210
211 }
212
normalizeListFrames()213 void StretchList::normalizeListFrames()
214 {
215 double dtime;
216 double factor;
217 double duntime;
218 MuseFrame_t dframe;
219
220 MuseFrame_t thisFrame, prevFrame;
221 double prevNewFrame;
222 double prevNewUnFrame;
223 double prevNewStretchFrame;
224 double prevNewUnStretchFrame;
225 double prevNewSamplerateFrame;
226 double prevNewUnSamplerateFrame;
227
228 double prevStretch;
229 double prevSamplerate;
230 double prevPitch;
231
232 // If any intrinsic value has a stretch or samplerate other than 1.0,
233 // the map is stretched, a stretcher or samplerate converter must be engaged.
234 _isStretched = (_stretchRatio != 1.0);
235 _isResampled = (_samplerateRatio != 1.0);
236 _isPitchShifted = (_pitchRatio != 1.0);
237 for(iterator ise = begin(); ise != end(); ++ise)
238 {
239 thisFrame = ise->first;
240 StretchListItem& se = ise->second;
241
242 // The policy is such that if there are user items (non zeroth item) of a given type,
243 // the list is said to be in that state (stretched, resampled, shifted etc), even if all
244 // the items' ratios are 1.0.
245 // Ignore the special zeroth frame.
246 // If the zeroth frame is the only item, its ratios must (should) all be at 1.0 right now
247 // so they will be ignored.
248 if(thisFrame != 0)
249 {
250 if(((se._type & StretchListItem::StretchEvent))) //&& se._stretchRatio != 1.0))
251 _isStretched = true;
252 if(((se._type & StretchListItem::SamplerateEvent))) //&& se._samplerateRatio != 1.0))
253 _isResampled = true;
254 if(((se._type & StretchListItem::PitchEvent))) //&& se._pitchRatio != 1.0))
255 _isPitchShifted = true;
256 }
257
258 if(ise == begin())
259 {
260 prevFrame = prevNewUnFrame = prevNewFrame =
261 prevNewStretchFrame = prevNewUnStretchFrame =
262 prevNewSamplerateFrame = prevNewUnSamplerateFrame =
263 se._finSquishedFrame = se._finStretchedFrame =
264 se._stretchStretchedFrame = se._stretchSquishedFrame =
265 se._samplerateStretchedFrame = se._samplerateSquishedFrame = thisFrame;
266
267 prevStretch = se._stretchRatio;
268 prevSamplerate = se._samplerateRatio;
269 prevPitch = se._pitchRatio;
270 }
271 else
272 {
273 dframe = thisFrame - prevFrame;
274
275 factor = (_samplerateRatio * prevSamplerate) / (_stretchRatio * prevStretch);
276 dtime = double(dframe) * factor;
277 se._finStretchedFrame = prevNewFrame + dtime;
278 prevNewFrame = se._finStretchedFrame;
279
280 duntime = double(dframe) / factor;
281 se._finSquishedFrame = prevNewUnFrame + duntime;
282 prevNewUnFrame = se._finSquishedFrame;
283
284
285 factor = 1.0 / (_stretchRatio * prevStretch);
286 dtime = double(dframe) * factor;
287 se._stretchStretchedFrame = prevNewStretchFrame + dtime;
288 prevNewStretchFrame = se._stretchStretchedFrame;
289
290 duntime = double(dframe) / factor;
291 se._stretchSquishedFrame = prevNewUnStretchFrame + duntime;
292 prevNewUnStretchFrame = se._stretchSquishedFrame;
293
294
295
296 factor = (_samplerateRatio * prevSamplerate);
297 dtime = double(dframe) * factor;
298 se._samplerateStretchedFrame = prevNewSamplerateFrame + dtime;
299 prevNewSamplerateFrame = se._samplerateStretchedFrame;
300
301 duntime = double(dframe) / factor;
302 se._samplerateSquishedFrame = prevNewUnSamplerateFrame + duntime;
303 prevNewUnSamplerateFrame = se._samplerateSquishedFrame;
304
305
306 prevFrame = thisFrame;
307
308 if(se._type & StretchListItem::StretchEvent)
309 prevStretch = se._stretchRatio;
310 else
311 se._stretchRatio = prevStretch;
312
313 if(se._type & StretchListItem::SamplerateEvent)
314 prevSamplerate = se._samplerateRatio;
315 else
316 se._samplerateRatio = prevSamplerate;
317
318 if(se._type & StretchListItem::PitchEvent)
319 prevPitch = se._pitchRatio;
320 else
321 se._pitchRatio = prevPitch;
322 }
323 }
324
325 // TODO
326 normalizeFrames();
327
328 // Mark as validated, normalization is done.
329 _isNormalized = true;
330
331 #ifdef DEBUG_TIMESTRETCH
332 dump();
333 #endif
334 }
335
normalizeListRatios()336 void StretchList::normalizeListRatios()
337 {
338
339 }
340
341 //---------------------------------------------------------
342 // clear
343 //---------------------------------------------------------
344
clear()345 void StretchList::clear()
346 {
347 StretchList_t::clear();
348
349 // Ensure that there is always an item at frame zero.
350 insert(std::pair<const MuseFrame_t, StretchListItem>
351 (0, StretchListItem(1.0, 1.0, 1.0,
352 StretchListItem::StretchEvent |
353 StretchListItem::SamplerateEvent |
354 StretchListItem::PitchEvent)));
355
356 // Technically it is normalized now, since StretchListItem
357 // constructor fills in zeros for the frame values.
358 _isNormalized = true;
359 }
360
361 //---------------------------------------------------------
362 // eraseRange
363 //---------------------------------------------------------
364
eraseRange(int types,MuseFrame_t sframe,MuseFrame_t eframe)365 void StretchList::eraseRange(int types, MuseFrame_t sframe, MuseFrame_t eframe)
366 {
367 if(sframe >= eframe)
368 return;
369 iStretchListItem se = lower_bound(sframe);
370 if(se == end())
371 return;
372 iStretchListItem ee = upper_bound(eframe);
373
374 for(iStretchListItem ise = se; ise != ee; )
375 {
376 // Do not delete the item at zeroth frame.
377 if(ise->first == 0)
378 {
379 ++ise;
380 continue;
381 }
382
383 ise->second._type &= ~types;
384 if(ise->second._type == 0)
385 {
386 iStretchListItem ise_save = ise;
387 erase(ise);
388 ise = ise_save;
389 }
390 else
391 ++ise;
392 }
393
394 // Mark as invalidated, normalization is required.
395 _isNormalized = false;
396
397 normalizeListFrames();
398 }
399
400 //---------------------------------------------------------
401 // read
402 //---------------------------------------------------------
403
read(Xml & xml)404 void StretchList::read(Xml& xml)
405 {
406 bool ok;
407 for (;;) {
408 Xml::Token token = xml.parse();
409 const QString& tag = xml.s1();
410 switch (token) {
411 case Xml::Error:
412 case Xml::End:
413 return;
414 case Xml::Attribut:
415 ERROR_TIMESTRETCH(stderr, "stretchlist unknown tag %s\n", tag.toLatin1().constData());
416 break;
417 case Xml::Text:
418 {
419 int len = tag.length();
420 int i = 0;
421 for(;;)
422 {
423 while(i < len && (tag[i] == ',' || tag[i] == ' ' || tag[i] == '\n'))
424 ++i;
425 if(i == len)
426 break;
427
428 QString fs;
429 while(i < len && tag[i] != ' ')
430 {
431 fs.append(tag[i]);
432 ++i;
433 }
434 if(i == len)
435 break;
436
437 MuseFrame_t frame = fs.toLong(&ok);
438 if(!ok)
439 {
440 ERROR_TIMESTRETCH(stderr, "StretchList::read failed reading frame string: %s\n", fs.toLatin1().constData());
441 break;
442 }
443
444
445 while(i < len && (tag[i] == ' ' || tag[i] == '\n'))
446 ++i;
447 if(i == len)
448 break;
449 QString stretchStr;
450 while(i < len && tag[i] != ' ' && tag[i] != ',')
451 {
452 stretchStr.append(tag[i]);
453 ++i;
454 }
455 double stretchVal = stretchStr.toDouble(&ok);
456 if(!ok)
457 {
458 ERROR_TIMESTRETCH(stderr, "StretchList::read failed reading stretch ratio string: %s\n", stretchStr.toLatin1().constData());
459 break;
460 }
461
462
463 while(i < len && (tag[i] == ' ' || tag[i] == '\n'))
464 ++i;
465 if(i == len)
466 break;
467 QString SRStr;
468 while(i < len && tag[i] != ' ' && tag[i] != ',')
469 {
470 SRStr.append(tag[i]);
471 ++i;
472 }
473 double SRVal = SRStr.toDouble(&ok);
474 if(!ok)
475 {
476 ERROR_TIMESTRETCH(stderr, "StretchList::read failed reading samplerate ratio string: %s\n", SRStr.toLatin1().constData());
477 break;
478 }
479
480 while(i < len && (tag[i] == ' ' || tag[i] == '\n'))
481 ++i;
482 if(i == len)
483 break;
484 QString pitchStr;
485 while(i < len && tag[i] != ' ' && tag[i] != ',')
486 {
487 pitchStr.append(tag[i]);
488 ++i;
489 }
490 double pitchVal = pitchStr.toDouble(&ok);
491 if(!ok)
492 {
493 ERROR_TIMESTRETCH(stderr, "StretchList::read failed reading pitch ratio string: %s\n", pitchStr.toLatin1().constData());
494 break;
495 }
496
497
498 while(i < len && (tag[i] == ' ' || tag[i] == '\n'))
499 ++i;
500 if(i == len)
501 break;
502 QString typeStr;
503 while(i < len && tag[i] != ' ' && tag[i] != ',')
504 {
505 typeStr.append(tag[i]);
506 ++i;
507 }
508 int typeVal = typeStr.toInt(&ok);
509 if(!ok)
510 {
511 ERROR_TIMESTRETCH(stderr, "StretchList::read failed reading type string: %s\n", typeStr.toLatin1().constData());
512 break;
513 }
514
515 // Defer normalize until tag end.
516 add(frame, StretchListItem(stretchVal, SRVal, pitchVal, typeVal), false);
517
518 if(i == len)
519 break;
520 }
521 }
522 break;
523 case Xml::TagEnd:
524 if (tag == "stretchlist")
525 {
526 normalizeListFrames();
527 return;
528 }
529 default:
530 break;
531 }
532 }
533
534 }
535
536 //---------------------------------------------------------
537 // write
538 //---------------------------------------------------------
539
write(int level,Xml & xml) const540 void StretchList::write(int level, Xml& xml) const
541 {
542 if(empty())
543 return;
544
545 xml.tag(level++, "stretchlist");
546 int i = 0;
547 QString seStr("%1 %2 %3 %4 %5, ");
548 for (const_iterator ise = cbegin(); ise != cend(); ++ise) {
549 xml.nput(level,
550 seStr.arg(ise->first)
551 .arg(ise->second._stretchRatio)
552 .arg(ise->second._samplerateRatio)
553 .arg(ise->second._pitchRatio)
554 .arg(ise->second._type)
555 .toLatin1().constData());
556 ++i;
557 if (i >= 3) {
558 xml.put(level, "");
559 i = 0;
560 }
561 }
562 if (i)
563 xml.put(level, "");
564 xml.etag(level--, "stretchlist");
565 }
566
567 //---------------------------------------------------------
568 // dump
569 //---------------------------------------------------------
570
dump() const571 void StretchList::dump() const
572 {
573 INFO_TIMESTRETCH(stderr, "\nStretchList: isNormalized:%d\n", _isNormalized);
574 for(const_iterator i = cbegin(); i != cend(); ++i)
575 {
576 INFO_TIMESTRETCH(stderr, "frame:%6ld StretchRatio:%f SamplerateRatio:%f PitchRatio:%f "
577 "stretchedFrame:%f squishedFrame:%f\n",
578 i->first, i->second._stretchRatio, i->second._samplerateRatio, i->second._pitchRatio,
579 i->second._finStretchedFrame, i->second._finSquishedFrame);
580 }
581 }
582
583 // ------------------------------------------
584 // Intrinsic functions:
585 //-------------------------------------------
586
setStartFrame(MuseFrame_t frame,bool do_normalize)587 void StretchList::setStartFrame(MuseFrame_t frame, bool do_normalize)
588 {
589 _startFrame = frame;
590
591 // Mark as invalidated, normalization is required.
592 _isNormalized = false;
593
594 if(do_normalize)
595 normalizeListFrames();
596 }
597
setEndFrame(MuseFrame_t frame,bool do_normalize)598 void StretchList::setEndFrame(MuseFrame_t frame, bool do_normalize)
599 {
600 _endFrame = frame;
601
602 // Mark as invalidated, normalization is required.
603 _isNormalized = false;
604
605 if(do_normalize)
606 normalizeListFrames();
607 }
608
setStretchedEndFrame(MuseFrame_t frame,bool do_normalize)609 void StretchList::setStretchedEndFrame(MuseFrame_t frame, bool do_normalize)
610 {
611 _stretchedEndFrame = frame;
612
613 // Mark as invalidated, normalization is required.
614 _isNormalized = false;
615
616 if(do_normalize)
617 normalizeListFrames();
618 }
619
setSquishedEndFrame(MuseFrame_t frame,bool do_normalize)620 void StretchList::setSquishedEndFrame(MuseFrame_t frame, bool do_normalize)
621 {
622 _squishedEndFrame = frame;
623
624 // Mark as invalidated, normalization is required.
625 _isNormalized = false;
626
627 if(do_normalize)
628 normalizeListFrames();
629 }
630
ratio(StretchListItem::StretchEventType type) const631 double StretchList::ratio(StretchListItem::StretchEventType type) const
632 {
633 switch(type)
634 {
635 case StretchListItem::StretchEvent:
636 return _stretchRatio;
637 break;
638
639 case StretchListItem::SamplerateEvent:
640 return _samplerateRatio;
641 break;
642
643 case StretchListItem::PitchEvent:
644 return _pitchRatio;
645 break;
646 }
647 return 1.0;
648 }
649
setRatio(StretchListItem::StretchEventType type,double ratio,bool do_normalize)650 void StretchList::setRatio(StretchListItem::StretchEventType type, double ratio, bool do_normalize)
651 {
652 switch(type)
653 {
654 case StretchListItem::StretchEvent:
655 _stretchRatio = ratio;
656 break;
657
658 case StretchListItem::SamplerateEvent:
659 _samplerateRatio = ratio;
660 break;
661
662 case StretchListItem::PitchEvent:
663 _pitchRatio = ratio;
664 break;
665 }
666
667 // Mark as invalidated, normalization is required.
668 _isNormalized = false;
669
670 if(do_normalize)
671 normalizeListFrames();
672 }
673
674 // ------------------------------------------
675 // List functions:
676 //-------------------------------------------
677
findEvent(int types,MuseFrame_t frame)678 iStretchListItem StretchList::findEvent(int types, MuseFrame_t frame)
679 {
680 iStretchListItemPair res = equal_range(frame);
681 for(iStretchListItem ise = res.first; ise != res.second; ++ise)
682 {
683 if(ise->second._type & types)
684 return ise;
685 }
686 return end();
687 }
688
cFindEvent(int types,MuseFrame_t frame) const689 ciStretchListItem StretchList::cFindEvent(int types, MuseFrame_t frame) const
690 {
691 const StretchList* sl = this;
692 ciStretchListItemPair res = sl->equal_range(frame); // FIXME Calls non-const version unless cast ??
693 for(ciStretchListItem ise = res.first; ise != res.second; ++ise)
694 {
695 if(ise->second._type & types)
696 return ise;
697 }
698 return sl->end();
699 }
700
previousEvent(int types,iStretchListItem item)701 iStretchListItem StretchList::previousEvent(int types, iStretchListItem item)
702 {
703 iStretchListItem i = item;
704 while(i != begin())
705 {
706 --i;
707 if(i->second._type & types)
708 return i;
709 }
710 return end();
711 }
712
cPreviousEvent(int types,ciStretchListItem item) const713 ciStretchListItem StretchList::cPreviousEvent(int types, ciStretchListItem item) const
714 {
715 ciStretchListItem i = item;
716 while(i != cbegin())
717 {
718 --i;
719 if(i->second._type & types)
720 return i;
721 }
722 return cend();
723 }
724
nextEvent(int types,iStretchListItem item)725 iStretchListItem StretchList::nextEvent(int types, iStretchListItem item)
726 {
727 iStretchListItem i = item;
728 while(i != end())
729 {
730 ++i;
731 if(i->second._type & types)
732 return i;
733 }
734 return end();
735 }
736
cNextEvent(int types,ciStretchListItem item) const737 ciStretchListItem StretchList::cNextEvent(int types, ciStretchListItem item) const
738 {
739 const StretchList* sl = this;
740 ciStretchListItem i = item;
741 while(i != sl->end())
742 {
743 ++i;
744 if(i->second._type & types)
745 return i;
746 }
747 return sl->end();
748 }
749
750
751
752 //---------------------------------------------------------
753 // ratioAt
754 //---------------------------------------------------------
755
ratioAt(StretchListItem::StretchEventType type,MuseFrame_t frame) const756 double StretchList::ratioAt(StretchListItem::StretchEventType type, MuseFrame_t frame) const
757 {
758 // If the zeroth frame is the only item, its ratios must (should) all be at 1.0 right now
759 // so they will be ignored.
760 if(size() == 1)
761 return 1.0;
762
763 const_iterator i = upper_bound(frame);
764 if(i == cbegin())
765 return 1.0;
766 --i;
767
768 switch(type)
769 {
770 case StretchListItem::StretchEvent:
771 return i->second._stretchRatio;
772 break;
773
774 case StretchListItem::SamplerateEvent:
775 return i->second._samplerateRatio;
776 break;
777
778 case StretchListItem::PitchEvent:
779 return i->second._pitchRatio;
780 break;
781 }
782
783 return 1.0;
784 }
785
786 //---------------------------------------------------------
787 // setRatioAt
788 //---------------------------------------------------------
789
setRatioAt(StretchListItem::StretchEventType type,MuseFrame_t frame,double ratio,bool do_normalize)790 void StretchList::setRatioAt(StretchListItem::StretchEventType type, MuseFrame_t frame, double ratio, bool do_normalize)
791 {
792 add(type, frame, ratio, do_normalize);
793 }
794
setRatioAt(StretchListItem::StretchEventType type,iStretchListItem item,double ratio,bool do_normalize)795 void StretchList::setRatioAt(StretchListItem::StretchEventType type, iStretchListItem item, double ratio, bool do_normalize)
796 {
797 item->second._type |= type;
798 switch(type)
799 {
800 case StretchListItem::StretchEvent:
801 item->second._stretchRatio = ratio;
802 break;
803
804 case StretchListItem::SamplerateEvent:
805 item->second._samplerateRatio = ratio;
806 break;
807
808 case StretchListItem::PitchEvent:
809 item->second._pitchRatio = ratio;
810 break;
811 }
812
813 // Mark as invalidated, normalization is required.
814 _isNormalized = false;
815
816 if(do_normalize)
817 normalizeListFrames();
818 }
819
addRatioAt(StretchListItem::StretchEventType type,MuseFrame_t frame,double ratio,bool do_normalize)820 void StretchList::addRatioAt(StretchListItem::StretchEventType type, MuseFrame_t frame, double ratio, bool do_normalize)
821 {
822 add(type, frame, ratio, do_normalize);
823 }
824
delRatioAt(int types,MuseFrame_t frame,bool do_normalize)825 void StretchList::delRatioAt(int types, MuseFrame_t frame, bool do_normalize)
826 {
827 del(types, frame, do_normalize);
828 }
829
830 //---------------------------------------------------------
831 // stretch
832 //---------------------------------------------------------
833
stretch(MuseFrame_t frame,int type) const834 double StretchList::stretch(MuseFrame_t frame, int type) const
835 {
836 MuseFrame_t prevFrame;
837 double prevNewFrame = frame;
838 double prevStretch;
839 double prevSamplerate;
840 double dtime = 0.0;
841
842 const_iterator i = upper_bound(frame);
843 if(i == cbegin())
844 return frame;
845
846 --i;
847 prevFrame = i->first;
848 prevStretch = i->second._stretchRatio;
849 prevSamplerate = i->second._samplerateRatio;
850 const MuseFrame_t dframe = frame - prevFrame;
851
852 // Full conversion requested.
853 if((type & StretchListItem::StretchEvent) && (type & StretchListItem::SamplerateEvent))
854 {
855 prevNewFrame = i->second._finStretchedFrame;
856 dtime = double(dframe) * (_samplerateRatio * prevSamplerate) / (_stretchRatio * prevStretch);
857 }
858 // Stretch only.
859 else if(type & StretchListItem::StretchEvent)
860 {
861 prevNewFrame = i->second._stretchStretchedFrame;
862 dtime = double(dframe) / (_stretchRatio * prevStretch);
863 }
864 // Samplerate only.
865 else if(type & StretchListItem::SamplerateEvent)
866 {
867 prevNewFrame = i->second._samplerateStretchedFrame;
868 dtime = double(dframe) * _samplerateRatio * prevSamplerate;
869 }
870
871 return prevNewFrame + dtime;
872 }
873
stretch(double frame,int type) const874 double StretchList::stretch(double frame, int type) const
875 {
876 MuseFrame_t prevFrame;
877 double prevNewFrame = frame;
878 double prevStretch;
879 double prevSamplerate;
880 double dtime = 0.0;
881
882 const_iterator i = upper_bound(frame);
883 if(i == cbegin())
884 return frame;
885
886 --i;
887 prevFrame = i->first;
888 prevStretch = i->second._stretchRatio;
889 prevSamplerate = i->second._samplerateRatio;
890 const double dframe = frame - (double)prevFrame;
891
892 // Full conversion requested.
893 if((type & StretchListItem::StretchEvent) && (type & StretchListItem::SamplerateEvent))
894 {
895 prevNewFrame = i->second._finStretchedFrame;
896 dtime = dframe * (_samplerateRatio * prevSamplerate) / (_stretchRatio * prevStretch);
897 }
898 // Stretch only.
899 else if(type & StretchListItem::StretchEvent)
900 {
901 prevNewFrame = i->second._stretchStretchedFrame;
902 dtime = dframe / (_stretchRatio * prevStretch);
903 }
904 // Samplerate only.
905 else if(type & StretchListItem::SamplerateEvent)
906 {
907 prevNewFrame = i->second._samplerateStretchedFrame;
908 dtime = dframe * _samplerateRatio * prevSamplerate;
909 }
910
911 return prevNewFrame + dtime;
912 }
913
squish(MuseFrame_t frame,int type) const914 double StretchList::squish(MuseFrame_t frame, int type) const
915 {
916 MuseFrame_t prevFrame;
917 double prevNewUnFrame = frame;
918 double prevStretch;
919 double prevSamplerate;
920 double dtime = 0.0;
921
922 const_iterator i = upper_bound(frame);
923 if(i == cbegin())
924 return frame;
925
926 --i;
927 prevFrame = i->first;
928 prevStretch = i->second._stretchRatio;
929 prevSamplerate = i->second._samplerateRatio;
930 const MuseFrame_t dframe = frame - prevFrame;
931
932 // Full conversion requested.
933 if((type & StretchListItem::StretchEvent) && (type & StretchListItem::SamplerateEvent))
934 {
935 prevNewUnFrame = i->second._finSquishedFrame;
936 dtime = double(dframe) * (_stretchRatio * prevStretch) / (_samplerateRatio * prevSamplerate);
937 }
938 // Stretch only.
939 else if(type & StretchListItem::StretchEvent)
940 {
941 prevNewUnFrame = i->second._stretchSquishedFrame;
942 dtime = double(dframe) * (_stretchRatio * prevStretch);
943 }
944 // Samplerate only.
945 else if(type & StretchListItem::SamplerateEvent)
946 {
947 prevNewUnFrame = i->second._samplerateSquishedFrame;
948 dtime = double(dframe) / (_samplerateRatio * prevSamplerate);
949 }
950
951 return prevNewUnFrame + dtime;
952 }
953
squish(double frame,int type) const954 double StretchList::squish(double frame, int type) const
955 {
956 MuseFrame_t prevFrame;
957 double prevNewUnFrame = frame;
958 double prevStretch;
959 double prevSamplerate;
960 double dtime = 0.0;
961
962 const_iterator i = upper_bound(frame);
963 if(i == cbegin())
964 return frame;
965
966 --i;
967 prevFrame = i->first;
968 prevStretch = i->second._stretchRatio;
969 prevSamplerate = i->second._samplerateRatio;
970 const double dframe = frame - (double)prevFrame;
971
972 // Full conversion requested.
973 if((type & StretchListItem::StretchEvent) && (type & StretchListItem::SamplerateEvent))
974 {
975 prevNewUnFrame = i->second._finSquishedFrame;
976 dtime = dframe * (_stretchRatio * prevStretch) / (_samplerateRatio * prevSamplerate);
977 }
978 // Stretch only.
979 else if(type & StretchListItem::StretchEvent)
980 {
981 prevNewUnFrame = i->second._stretchSquishedFrame;
982 dtime = dframe * (_stretchRatio * prevStretch);
983 }
984 // Samplerate only.
985 else if(type & StretchListItem::SamplerateEvent)
986 {
987 prevNewUnFrame = i->second._samplerateSquishedFrame;
988 dtime = dframe / (_samplerateRatio * prevSamplerate);
989 }
990
991 return prevNewUnFrame + dtime;
992 }
993
994 //---------------------------------------------------------
995 // unStretch
996 //---------------------------------------------------------
997
unStretch(double frame,int type) const998 MuseFrame_t StretchList::unStretch(double frame, int type) const
999 {
1000 if(empty())
1001 return frame;
1002
1003 MuseFrame_t prevFrame;
1004 double prevNewFrame = frame;
1005 double prevStretch;
1006 double prevSamplerate;
1007 double factor = 1.0;
1008
1009 const_iterator e;
1010 for(e = cbegin(); e != cend(); ++e)
1011 {
1012 if((type & StretchListItem::StretchEvent) && // Full conversion requested.
1013 (type & StretchListItem::SamplerateEvent))
1014 {
1015 if(frame < e->second._finStretchedFrame)
1016 break;
1017 else
1018 continue;
1019 }
1020 else if(type & StretchListItem::StretchEvent) // Only stretch conversion requested.
1021 {
1022 if(frame < e->second._stretchStretchedFrame)
1023 break;
1024 else
1025 continue;
1026 }
1027 else if(type & StretchListItem::SamplerateEvent) // Only samplerate conversion requested.
1028 {
1029 if(frame < e->second._samplerateStretchedFrame)
1030 break;
1031 else
1032 continue;
1033 }
1034 }
1035
1036 if(e == cbegin())
1037 return frame;
1038
1039 --e;
1040 prevFrame = e->first;
1041 prevStretch = e->second._stretchRatio;
1042 prevSamplerate = e->second._samplerateRatio;
1043
1044
1045 // Full conversion requested.
1046 if((type & StretchListItem::StretchEvent) && (type & StretchListItem::SamplerateEvent))
1047 {
1048 prevNewFrame = e->second._finStretchedFrame;
1049 factor = (_stretchRatio * prevStretch) / (_samplerateRatio * prevSamplerate);
1050 }
1051 // Stretch only.
1052 else if(type & StretchListItem::StretchEvent)
1053 {
1054 prevNewFrame = e->second._stretchStretchedFrame;
1055 factor = (_stretchRatio * prevStretch);
1056 }
1057 // Samplerate only.
1058 else if(type & StretchListItem::SamplerateEvent)
1059 {
1060 prevNewFrame = e->second._samplerateStretchedFrame;
1061 factor = 1.0 / (_samplerateRatio * prevSamplerate);
1062 }
1063
1064 return prevFrame + lrint((frame - prevNewFrame) * factor);
1065 }
1066
1067 //---------------------------------------------------------
1068 // unStretch
1069 //---------------------------------------------------------
1070
unSquish(double frame,int type) const1071 MuseFrame_t StretchList::unSquish(double frame, int type) const
1072 {
1073 if(empty())
1074 return frame;
1075
1076 MuseFrame_t prevFrame;
1077 double prevNewUnFrame = frame;
1078 double prevStretch;
1079 double prevSamplerate;
1080 double factor = 1.0;
1081
1082 const_iterator e;
1083 for(e = cbegin(); e != cend(); ++e)
1084 {
1085 if((type & StretchListItem::StretchEvent) && // Full conversion requested.
1086 (type & StretchListItem::SamplerateEvent))
1087 {
1088 if(frame < e->second._finSquishedFrame)
1089 break;
1090 else
1091 continue;
1092 }
1093 else if(type & StretchListItem::StretchEvent) // Only stretch conversion requested.
1094 {
1095 if(frame < e->second._stretchSquishedFrame)
1096 break;
1097 else
1098 continue;
1099 }
1100 else if(type & StretchListItem::SamplerateEvent) // Only samplerate conversion requested.
1101 {
1102 if(frame < e->second._samplerateSquishedFrame)
1103 break;
1104 else
1105 continue;
1106 }
1107 }
1108
1109 if(e == cbegin())
1110 return frame;
1111
1112 --e;
1113 prevFrame = e->first;
1114 prevStretch = e->second._stretchRatio;
1115 prevSamplerate = e->second._samplerateRatio;
1116
1117 // Full conversion requested.
1118 if((type & StretchListItem::StretchEvent) && (type & StretchListItem::SamplerateEvent))
1119 {
1120 prevNewUnFrame = e->second._finSquishedFrame;
1121 factor = (_samplerateRatio * prevSamplerate) / (_stretchRatio * prevStretch);
1122 }
1123 // Stretch only.
1124 else if(type & StretchListItem::StretchEvent)
1125 {
1126 prevNewUnFrame = e->second._stretchSquishedFrame;
1127 factor = 1.0 / (_stretchRatio * prevStretch);
1128 }
1129 // Samplerate only.
1130 else if(type & StretchListItem::SamplerateEvent)
1131 {
1132 prevNewUnFrame = e->second._samplerateSquishedFrame;
1133 factor = (_samplerateRatio * prevSamplerate);
1134 }
1135
1136 // FIXME: Hm, lrint? Try returning double.
1137 return prevFrame + lrint((frame - prevNewUnFrame) * factor);
1138 }
1139
testDelListOperation(int types,MuseFrame_t frame) const1140 StretchListInfo StretchList::testDelListOperation(int types, MuseFrame_t frame) const
1141 {
1142 // The policy is such that if (after deletion) there are still user items (non zeroth item) of a given type,
1143 // the list is said to still be in that state (stretched, resampled, shifted etc),
1144 // even if all the items' ratios are 1.0.
1145 StretchListInfo info;
1146 MuseFrame_t fr;
1147 // If any intrinsic value has a stretch or samplerate other than 1.0,
1148 // the map is stretched, a stretcher or samplerate converter must be engaged.
1149 info._isStretched = (_stretchRatio != 1.0);
1150 info._isResampled = (_samplerateRatio != 1.0);
1151 info._isPitchShifted = (_pitchRatio != 1.0);
1152 for(const_iterator ise = cbegin(); ise != cend(); ++ise)
1153 {
1154 fr = ise->first;
1155 // Ignore the special zeroth frame.
1156 // If the zeroth frame is the only item, its ratios must (should) all be at 1.0 right now
1157 // so they will be ignored.
1158 if(fr == 0)
1159 continue;
1160
1161 const StretchListItem& se = ise->second;
1162 if(((se._type & StretchListItem::StretchEvent) &&
1163 //(types & StretchListItem::StretchEvent) &&
1164 (!(types & StretchListItem::StretchEvent) ||
1165 fr != frame))) //&&
1166 //se._stretchRatio != 1.0))
1167 info._isStretched = true;
1168
1169 if(((se._type & StretchListItem::SamplerateEvent) &&
1170 //(types & StretchListItem::SamplerateEvent) &&
1171 (!(types & StretchListItem::SamplerateEvent) ||
1172 fr != frame))) //&&
1173 //se._samplerateRatio != 1.0))
1174 info._isResampled = true;
1175
1176 if(((se._type & StretchListItem::PitchEvent) &&
1177 //(types & StretchListItem::PitchEvent) &&
1178 (!(types & StretchListItem::PitchEvent) ||
1179 fr != frame))) //&&
1180 //se._pitchRatio != 1.0))
1181 info._isPitchShifted = true;
1182 }
1183 return info;
1184 }
1185
1186 } // namespace MusECore
1187