# HG changeset patch # User Chris Cannam # Date 1158250103 0 # Node ID 7da85e0b85e98c2c5c5bc7677712797ad273c91f # Parent e125f0dde7a39af7185720c8750eb9d309bf9ec2 * Add some internal feedback to the time stretcher to try to make it maintain tempo within variable timestretching situations -- not ideal but perhaps better than nothing. * Better tooltip text for play speeed control; make play sharpening control remember its last state diff -r e125f0dde7a3 -r 7da85e0b85e9 audioio/PhaseVocoderTimeStretcher.cpp --- a/audioio/PhaseVocoderTimeStretcher.cpp Thu Sep 14 13:41:56 2006 +0000 +++ b/audioio/PhaseVocoderTimeStretcher.cpp Thu Sep 14 16:08:23 2006 +0000 @@ -26,10 +26,17 @@ size_t maxProcessInputBlockSize) : m_channels(channels), m_ratio(ratio), - m_sharpen(sharpen) + m_sharpen(sharpen), + m_totalCount(0), + m_transientCount(0), + m_n2sum(0) { m_wlen = 1024; + //!!! In transient sharpening mode, we need to pick the window + //length so as to be more or less fixed in audio duration (i.e. we + //need to know the sample rate) + if (ratio < 1) { if (ratio < 0.4) { m_n1 = 1024; @@ -40,7 +47,6 @@ m_n1 = 256; } if (m_sharpen) { -// m_n1 /= 2; m_wlen = 2048; } m_n2 = m_n1 * ratio; @@ -55,7 +61,6 @@ m_n2 = 256; } if (m_sharpen) { -// m_n2 /= 2; if (m_wlen < 2048) m_wlen = 2048; } m_n1 = m_n2 / ratio; @@ -68,7 +73,7 @@ m_prevAdjustedPhase = new float *[m_channels]; m_prevTransientMag = (float *)fftwf_malloc(sizeof(float) * (m_wlen / 2 + 1)); - m_prevTransientCount = 0; + m_prevTransientScore = 0; m_prevTransient = false; m_tempbuf = (float *)fftwf_malloc(sizeof(float) * m_wlen); @@ -249,6 +254,29 @@ n2 = m_n1; } + ++m_totalCount; + if (transient) ++m_transientCount; + m_n2sum += n2; + +// std::cerr << "ratio for last 10: " < 50 && m_transientCount < m_totalCount) { + + int fixed = lrintf(m_transientCount * m_n1); + int squashy = m_n2sum - fixed; + + int idealTotal = lrintf(m_totalCount * m_n1 * m_ratio); + int idealSquashy = idealTotal - fixed; + + int squashyCount = m_totalCount - m_transientCount; + + n2 = lrintf(idealSquashy / squashyCount); + + if (n2 != m_n2) { + std::cerr << m_n2 << " -> " << n2 << std::endl; + } + } + for (size_t c = 0; c < m_channels; ++c) { synthesiseBlock(c, m_mashbuf[c], @@ -287,6 +315,8 @@ for (size_t i = m_wlen - n2; i < m_wlen; ++i) { m_modulationbuf[i] = 0.0f; } + + if (!transient) m_n2 = n2; } @@ -298,6 +328,9 @@ #ifdef DEBUG_PHASE_VOCODER_TIME_STRETCHER std::cerr << "PhaseVocoderTimeStretcher::putInput returning" << std::endl; #endif + +// std::cerr << "ratio: nominal: " << getRatio() << " actual: " +// << m_total2 << "/" << m_total1 << " = " << float(m_total2) / float(m_total1) << " ideal: " << m_ratio << std::endl; } size_t @@ -385,12 +418,12 @@ bool isTransient = false; if (count > m_wlen / 4.5 && //!!! - count > m_prevTransientCount * 1.2) { + count > m_prevTransientScore * 1.2) { isTransient = true; - std::cerr << "isTransient (count = " << count << ", prev = " << m_prevTransientCount << ")" << std::endl; + std::cerr << "isTransient (count = " << count << ", prev = " << m_prevTransientScore << ")" << std::endl; } - m_prevTransientCount = count; + m_prevTransientScore = count; return isTransient; } diff -r e125f0dde7a3 -r 7da85e0b85e9 audioio/PhaseVocoderTimeStretcher.h --- a/audioio/PhaseVocoderTimeStretcher.h Thu Sep 14 13:41:56 2006 +0000 +++ b/audioio/PhaseVocoderTimeStretcher.h Thu Sep 14 16:08:23 2006 +0000 @@ -140,11 +140,15 @@ Window *m_analysisWindow; Window *m_synthesisWindow; + int m_totalCount; + int m_transientCount; + int m_n2sum; + float **m_prevPhase; float **m_prevAdjustedPhase; float *m_prevTransientMag; - int m_prevTransientCount; + int m_prevTransientScore; bool m_prevTransient; float *m_tempbuf; diff -r e125f0dde7a3 -r 7da85e0b85e9 main/MainWindow.cpp --- a/main/MainWindow.cpp Thu Sep 14 13:41:56 2006 +0000 +++ b/main/MainWindow.cpp Thu Sep 14 16:08:23 2006 +0000 @@ -169,7 +169,12 @@ m_playSharpen = new QCheckBox(frame); m_playSharpen->setToolTip(tr("Sharpen percussive transients")); m_playSharpen->setEnabled(false); - m_playSharpen->setChecked(false); + + QSettings settings; + settings.beginGroup("MainWindow"); + m_playSharpen->setChecked(settings.value("playsharpen", false).toBool()); + settings.endGroup(); + connect(m_playSharpen, SIGNAL(clicked()), this, SLOT(playSharpenToggled())); @@ -2869,19 +2874,19 @@ 1.0, 1.1, 1.2, 1.3, 1.5, 1.7, 2.0, 3.0, 4.0, 6.0, 10.0 }; float factor = factors[speed >= 10 ? speed - 10 : 10 - speed]; -// int factor = 11 - speed; - if (speed > 10) factor = 1.0 / factor; + + int pc = lrintf((factor - 1.0) * 100); + + if (speed > 10) { + factor = 1.0 / factor; + } + std::cerr << "factor = " << factor << std::endl; -/* - int iinc = 128; - int oinc = lrintf(iinc * factor); - factor = (float(oinc) + 0.01) / iinc; - std::cerr << "corrected factor = " << factor << std::endl; -*/ - m_playSpeed->setToolTip(tr("Playback speed: %1") - .arg(factor != 1 ? - QString("1/%1").arg(factor) : - tr("Full"))); + + m_playSpeed->setToolTip(tr("Playback speed: %1%2%") + .arg(speed >= 10 ? "+" : "-") + .arg(pc)); + m_playSharpen->setEnabled(speed != 10); bool sharpen = (speed != 10 && m_playSharpen->isChecked()); m_playSource->setSlowdownFactor(factor, sharpen); @@ -2890,6 +2895,11 @@ void MainWindow::playSharpenToggled() { + QSettings settings; + settings.beginGroup("MainWindow"); + settings.setValue("playsharpen", m_playSharpen->isChecked()); + settings.endGroup(); + playSpeedChanged(m_playSpeed->value()); }