Skip to content

Commit

Permalink
- Fixed automation curve rescaling across multiple, more than just
Browse files Browse the repository at this point in the history
  one or two, tempo-map node changes. (EXPERIMENTAL)
  • Loading branch information
rncbc committed Nov 18, 2023
1 parent 25565d9 commit 08960fd
Show file tree
Hide file tree
Showing 12 changed files with 168 additions and 130 deletions.
3 changes: 3 additions & 0 deletions ChangeLog
Expand Up @@ -6,6 +6,9 @@ ChangeLog

GIT HEAD

- Fixed automation curve rescaling across multiple, more than just
one or two, tempo-map node changes. (EXPERIMENTAL)

- New MIDI Tool Resize / Legato duration option added. (EXPERIMENTAL)

- MIDI Clip Editor (aka. piano-roll) thumb-view now taking tempo-map
Expand Down
73 changes: 53 additions & 20 deletions src/qtractorTimeScaleCommand.cpp
Expand Up @@ -87,12 +87,19 @@ bool qtractorTimeScaleNodeCommand::addNode (void)
if (bPlaying)
pSession->seek(0, false);

qtractorTimeScale::Node *pNext = pNode->next();
const unsigned long iFrameStart = m_iFrame;
const unsigned long iFrameEnd
= (pNext ? pNext->frame : pSession->sessionEnd());

const float fOldTempo = pNode->tempo;
const float fNewTempo = m_fTempo;

const bool bRedoClipCommand = (m_pClipCommand == nullptr);
if (bRedoClipCommand)
m_pClipCommand = createClipCommand(pNode, fNewTempo, fOldTempo);
if (bRedoClipCommand) {
m_pClipCommand = createClipCommand(
iFrameStart, iFrameEnd, fNewTempo, fOldTempo);
}
else
if (m_pClipCommand) {
m_pClipCommand->undo();
Expand All @@ -107,7 +114,7 @@ bool qtractorTimeScaleNodeCommand::addNode (void)

const bool bRedoCurveEditCommands = m_curveEditCommands.isEmpty();
if (bRedoCurveEditCommands) {
addCurveEditCommands(pNode->frame, fNewTempo, fOldTempo);
addCurveEditCommands(iFrameStart, iFrameEnd, fNewTempo, fOldTempo);
} else {
QListIterator<qtractorCurveEditCommand *> undos(m_curveEditCommands);
while (undos.hasNext())
Expand Down Expand Up @@ -175,12 +182,19 @@ bool qtractorTimeScaleNodeCommand::updateNode (void)
const unsigned short iBeatsPerBar = pNode->beatsPerBar;
const unsigned short iBeatDivisor = pNode->beatDivisor;

qtractorTimeScale::Node *pNext = pNode->next();
const unsigned long iFrameStart = pNode->frame;
const unsigned long iFrameEnd
= (pNext ? pNext->frame : pSession->sessionEnd());

const float fOldTempo = pNode->tempo;
const float fNewTempo = m_fTempo;

const bool bRedoClipCommand = (m_pClipCommand == nullptr);
if (bRedoClipCommand)
m_pClipCommand = createClipCommand(pNode, fNewTempo, fOldTempo);
if (bRedoClipCommand) {
m_pClipCommand = createClipCommand(
iFrameStart, iFrameEnd, fNewTempo, fOldTempo);
}
else
if (m_pClipCommand) {
m_pClipCommand->undo();
Expand All @@ -190,7 +204,7 @@ bool qtractorTimeScaleNodeCommand::updateNode (void)

const bool bRedoCurveEditCommands = m_curveEditCommands.isEmpty();
if (bRedoCurveEditCommands) {
addCurveEditCommands(pNode->frame, fNewTempo, fOldTempo);
addCurveEditCommands(iFrameStart, iFrameEnd, fNewTempo, fOldTempo);
} else {
QListIterator<qtractorCurveEditCommand *> undos(m_curveEditCommands);
while (undos.hasNext())
Expand Down Expand Up @@ -265,13 +279,20 @@ bool qtractorTimeScaleNodeCommand::removeNode (void)
if (bPlaying)
pSession->seek(0, false);

qtractorTimeScale::Node *pNext = pNode->next();
const unsigned long iFrameStart = pNode->frame;
const unsigned long iFrameEnd
= (pNext ? pNext->frame : pSession->sessionEnd());

qtractorTimeScale::Node *pPrev = pNode->prev();
const float fOldTempo = pNode->tempo;
const float fNewTempo = (pPrev ? pPrev->tempo : m_pTimeScale->tempo());

const bool bRedoClipCommand = (m_pClipCommand == nullptr);
if (bRedoClipCommand)
m_pClipCommand = createClipCommand(pNode, fNewTempo, fOldTempo);
if (bRedoClipCommand) {
m_pClipCommand = createClipCommand(
iFrameStart, iFrameEnd, fNewTempo, fOldTempo);
}
else
if (m_pClipCommand) {
m_pClipCommand->undo();
Expand All @@ -281,7 +302,7 @@ bool qtractorTimeScaleNodeCommand::removeNode (void)

const bool bRedoCurveEditCommands = m_curveEditCommands.isEmpty();
if (bRedoCurveEditCommands) {
addCurveEditCommands(pNode->frame, fNewTempo, fOldTempo);
addCurveEditCommands(iFrameStart, iFrameEnd, fNewTempo, fOldTempo);
} else {
QListIterator<qtractorCurveEditCommand *> undos(m_curveEditCommands);
while (undos.hasNext())
Expand Down Expand Up @@ -330,21 +351,18 @@ bool qtractorTimeScaleNodeCommand::removeNode (void)

// Make it automatic clip time-stretching command (static).
qtractorClipCommand *qtractorTimeScaleNodeCommand::createClipCommand (
qtractorTimeScale::Node *pNode, float fNewTempo, float fOldTempo )
unsigned long iFrameStart, unsigned long iFrameEnd,
float fNewTempo, float fOldTempo )
{
if (pNode == nullptr)
if (iFrameStart >= iFrameEnd)
return nullptr;
if (fNewTempo == fOldTempo)
if (qAbs(fNewTempo - fOldTempo) < 0.1f)
return nullptr;

qtractorSession *pSession = qtractorSession::getInstance();
if (pSession == nullptr)
return nullptr;

qtractorTimeScale::Node *pNext = pNode->next();
const unsigned long iFrameStart = pNode->frame;
const unsigned long iFrameEnd = (pNext ? pNext->frame : pSession->sessionEnd());

qtractorClipCommand *pClipCommand = nullptr;

for (qtractorTrack *pTrack = pSession->tracks().first();
Expand Down Expand Up @@ -384,19 +402,25 @@ qtractorClipCommand *qtractorTimeScaleNodeCommand::createClipCommand (

// Automation curve time-stretching command (static).
void qtractorTimeScaleNodeCommand::addCurveEditCommands (
unsigned long iFrame, float fNewTempo, float fOldTempo )
unsigned long iFrameStart, unsigned long iFrameEnd,
float fNewTempo, float fOldTempo )
{
if (qAbs(fNewTempo - fOldTempo) < 0.01f)
if (iFrameStart >= iFrameEnd)
return;
if (qAbs(fNewTempo - fOldTempo) < 0.1f)
return;

qtractorSession *pSession = qtractorSession::getInstance();
if (pSession == nullptr)
return;

const unsigned long iFrameStart = iFrame;
const float fFactor = (fOldTempo / fNewTempo);
const bool bReverse = (fOldTempo > fNewTempo);

const long iFrameDelta
= long(iFrameStart) - long(iFrameEnd)
+ long(float(iFrameEnd - iFrameStart) * fFactor);

for (qtractorTrack *pTrack = pSession->tracks().first();
pTrack; pTrack = pTrack->next()) {
qtractorCurveList *pCurveList = pTrack->curveList();
Expand All @@ -410,13 +434,22 @@ void qtractorTimeScaleNodeCommand::addCurveEditCommands (
qtractorCurve::Node *pCurveNode = (bReverse
? pCurve->nodes().last() : pCurve->seek(iFrameStart));
while (pCurveNode) {
if (pCurveNode->frame >= iFrameEnd) {
const unsigned long iFrame = pCurveNode->frame + iFrameDelta;
const float fValue = pCurveNode->value;
pCurveEditCommand->moveNode(pCurveNode, iFrame, fValue);
++iCurveEditUpdate;
}
else
if (pCurveNode->frame >= iFrameStart) {
const unsigned long iFrame = iFrameStart + (unsigned long)
(float(pCurveNode->frame - iFrameStart) * fFactor);
const float fValue = pCurveNode->value;
pCurveEditCommand->moveNode(pCurveNode, iFrame, fValue);
++iCurveEditUpdate;
} else if (bReverse)
}
else
if (bReverse)
break;
if (bReverse)
pCurveNode = pCurveNode->prev();
Expand Down
6 changes: 4 additions & 2 deletions src/qtractorTimeScaleCommand.h
Expand Up @@ -76,11 +76,13 @@ class qtractorTimeScaleNodeCommand : public qtractorCommand

// Make it automatic clip time-stretching command (static).
qtractorClipCommand *createClipCommand(
qtractorTimeScale::Node *pNode, float fOldTempo, float fNewTempo);
unsigned long iFrameStart, unsigned long iFrameEnd,
float fOldTempo, float fNewTempo);

// Automation curve time-stretching command (static).
void addCurveEditCommands(
unsigned long iFrame, float fOldTempo, float fNewTempo);
unsigned long iFrameStart, unsigned long iFrameEnd,
float fOldTempo, float fNewTempo);

private:

Expand Down
24 changes: 12 additions & 12 deletions src/translations/qtractor_cs.ts
Expand Up @@ -560,62 +560,62 @@ Stopa: &quot;%1&quot; Vstup: &quot;%2&quot; Výstup: &quot;%3&quot;</translation
<translation>%1 (%2)</translation>
</message>
<message>
<location filename="../qtractorTimeScaleCommand.cpp" line="448"/>
<location filename="../qtractorTimeScaleCommand.cpp" line="479"/>
<source>add tempo node</source>
<translation>Přidat uzel s tempem</translation>
</message>
<message>
<location filename="../qtractorTimeScaleCommand.cpp" line="468"/>
<location filename="../qtractorTimeScaleCommand.cpp" line="499"/>
<source>update tempo node</source>
<translation>Obnovit uzel s tempem</translation>
</message>
<message>
<location filename="../qtractorTimeScaleCommand.cpp" line="486"/>
<location filename="../qtractorTimeScaleCommand.cpp" line="517"/>
<source>remove tempo node</source>
<translation>Odstranit uzel s tempem</translation>
</message>
<message>
<location filename="../qtractorTimeScaleCommand.cpp" line="503"/>
<location filename="../qtractorTimeScaleCommand.cpp" line="534"/>
<source>move tempo node</source>
<translation>Přesunout uzel s tempem</translation>
</message>
<message>
<location filename="../qtractorTimeScaleCommand.cpp" line="679"/>
<location filename="../qtractorTimeScaleCommand.cpp" line="710"/>
<source>add marker</source>
<translation>Přidat značku</translation>
</message>
<message>
<location filename="../qtractorTimeScaleCommand.cpp" line="698"/>
<location filename="../qtractorTimeScaleCommand.cpp" line="729"/>
<source>update marker</source>
<translation>Obnovit značku</translation>
</message>
<message>
<location filename="../qtractorTimeScaleCommand.cpp" line="716"/>
<location filename="../qtractorTimeScaleCommand.cpp" line="747"/>
<source>remove marker</source>
<translation>Odstranit značku</translation>
</message>
<message>
<location filename="../qtractorTimeScaleCommand.cpp" line="735"/>
<location filename="../qtractorTimeScaleCommand.cpp" line="766"/>
<source>add key signature</source>
<translation>Přidat předznamenání</translation>
</message>
<message>
<location filename="../qtractorTimeScaleCommand.cpp" line="754"/>
<location filename="../qtractorTimeScaleCommand.cpp" line="785"/>
<source>update key signature</source>
<translation>Aktualizovat předznamenání</translation>
</message>
<message>
<location filename="../qtractorTimeScaleCommand.cpp" line="772"/>
<location filename="../qtractorTimeScaleCommand.cpp" line="803"/>
<source>remove key signature</source>
<translation>Odstranit předznamenání</translation>
</message>
<message>
<location filename="../qtractorTimeScaleCommand.cpp" line="789"/>
<location filename="../qtractorTimeScaleCommand.cpp" line="820"/>
<source>move marker</source>
<translation>Přesunout značku</translation>
</message>
<message>
<location filename="../qtractorTimeScaleCommand.cpp" line="923"/>
<location filename="../qtractorTimeScaleCommand.cpp" line="954"/>
<source>change time-sig.</source>
<translation>Změnit taktové označení</translation>
</message>
Expand Down
24 changes: 12 additions & 12 deletions src/translations/qtractor_de.ts
Expand Up @@ -575,62 +575,62 @@ MIDI: </translation>
<translation>Taktschlag</translation>
</message>
<message>
<location filename="../qtractorTimeScaleCommand.cpp" line="448"/>
<location filename="../qtractorTimeScaleCommand.cpp" line="479"/>
<source>add tempo node</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qtractorTimeScaleCommand.cpp" line="468"/>
<location filename="../qtractorTimeScaleCommand.cpp" line="499"/>
<source>update tempo node</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qtractorTimeScaleCommand.cpp" line="486"/>
<location filename="../qtractorTimeScaleCommand.cpp" line="517"/>
<source>remove tempo node</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qtractorTimeScaleCommand.cpp" line="503"/>
<location filename="../qtractorTimeScaleCommand.cpp" line="534"/>
<source>move tempo node</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qtractorTimeScaleCommand.cpp" line="679"/>
<location filename="../qtractorTimeScaleCommand.cpp" line="710"/>
<source>add marker</source>
<translation>Markierung hinzufügen</translation>
</message>
<message>
<location filename="../qtractorTimeScaleCommand.cpp" line="698"/>
<location filename="../qtractorTimeScaleCommand.cpp" line="729"/>
<source>update marker</source>
<translation>Markierung aktualisieren</translation>
</message>
<message>
<location filename="../qtractorTimeScaleCommand.cpp" line="716"/>
<location filename="../qtractorTimeScaleCommand.cpp" line="747"/>
<source>remove marker</source>
<translation>Markierung entfernen</translation>
</message>
<message>
<location filename="../qtractorTimeScaleCommand.cpp" line="735"/>
<location filename="../qtractorTimeScaleCommand.cpp" line="766"/>
<source>add key signature</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qtractorTimeScaleCommand.cpp" line="754"/>
<location filename="../qtractorTimeScaleCommand.cpp" line="785"/>
<source>update key signature</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qtractorTimeScaleCommand.cpp" line="772"/>
<location filename="../qtractorTimeScaleCommand.cpp" line="803"/>
<source>remove key signature</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qtractorTimeScaleCommand.cpp" line="789"/>
<location filename="../qtractorTimeScaleCommand.cpp" line="820"/>
<source>move marker</source>
<translation>Markierung verschieben</translation>
</message>
<message>
<location filename="../qtractorTimeScaleCommand.cpp" line="923"/>
<location filename="../qtractorTimeScaleCommand.cpp" line="954"/>
<source>change time-sig.</source>
<translation type="unfinished"></translation>
</message>
Expand Down

0 comments on commit 08960fd

Please sign in to comment.