Mercurial > hg > sonic-visualiser
changeset 26:d88d117e0c34
* Add mono timestretch toggle button; some more work on getting blocksize etc
parameters through to plugins
author | Chris Cannam |
---|---|
date | Mon, 18 Sep 2006 16:43:17 +0000 (2006-09-18) |
parents | e74f508db18c |
children | 61259228d029 |
files | audioio/AudioCallbackPlaySource.cpp audioio/AudioCallbackPlaySource.h audioio/PhaseVocoderTimeStretcher.cpp audioio/PhaseVocoderTimeStretcher.h icons/mono.png icons/sharpen.png icons/stereo.png main/MainWindow.cpp main/MainWindow.h sonic-visualiser.qrc transform/FeatureExtractionPluginTransform.cpp transform/FeatureExtractionPluginTransform.h transform/RealTimePluginTransform.cpp transform/RealTimePluginTransform.h transform/TransformFactory.cpp transform/TransformFactory.h |
diffstat | 16 files changed, 154 insertions(+), 48 deletions(-) [+] |
line wrap: on
line diff
--- a/audioio/AudioCallbackPlaySource.cpp Fri Sep 15 15:35:06 2006 +0000 +++ b/audioio/AudioCallbackPlaySource.cpp Mon Sep 18 16:43:17 2006 +0000 @@ -588,34 +588,41 @@ } void -AudioCallbackPlaySource::setSlowdownFactor(float factor, bool sharpen) +AudioCallbackPlaySource::setTimeStretch(float factor, bool sharpen, bool mono) { // Avoid locks -- create, assign, mark old one for scavenging // later (as a call to getSourceSamples may still be using it) PhaseVocoderTimeStretcher *existingStretcher = m_timeStretcher; + size_t channels = getTargetChannelCount(); + if (mono) channels = 1; + if (existingStretcher && existingStretcher->getRatio() == factor && - existingStretcher->getSharpening() == sharpen) { + existingStretcher->getSharpening() == sharpen && + existingStretcher->getChannelCount() == channels) { return; } if (factor != 1) { if (existingStretcher && - existingStretcher->getSharpening() == sharpen) { + existingStretcher->getSharpening() == sharpen && + existingStretcher->getChannelCount() == channels) { existingStretcher->setRatio(factor); return; } PhaseVocoderTimeStretcher *newStretcher = new PhaseVocoderTimeStretcher (getTargetSampleRate(), - getTargetChannelCount(), + channels, factor, sharpen, lrintf(getTargetBlockSize() / factor)); + m_timeStretcher = newStretcher; + } else { m_timeStretcher = 0; } @@ -624,7 +631,7 @@ m_timeStretcherScavenger.claim(existingStretcher); } } - + size_t AudioCallbackPlaySource::getSourceSamples(size_t count, float **buffer) { @@ -676,6 +683,9 @@ // std::cout << "ratio = " << ratio << std::endl; + size_t channels = getTargetChannelCount(); + bool mix = (channels > 1 && ts->getChannelCount() == 1); + size_t available; while ((available = ts->getAvailableOutputSamples()) < count) { @@ -684,18 +694,30 @@ reqd = std::max(reqd, ts->getRequiredInputSamples()); if (reqd == 0) reqd = 1; - size_t channels = getTargetChannelCount(); - float *ib[channels]; size_t got = reqd; - for (size_t c = 0; c < channels; ++c) { - ib[c] = new float[reqd]; //!!! fix -- this is a rt function - RingBuffer<float> *rb = getReadRingBuffer(c); - if (rb) { - size_t gotHere = rb->read(ib[c], got); - if (gotHere < got) got = gotHere; + if (mix) { + for (size_t c = 0; c < channels; ++c) { + if (c == 0) ib[c] = new float[reqd]; //!!! fix -- this is a rt function + else ib[c] = 0; + RingBuffer<float> *rb = getReadRingBuffer(c); + if (rb) { + size_t gotHere; + if (c > 0) gotHere = rb->readAdding(ib[0], got); + else gotHere = rb->read(ib[0], got); + if (gotHere < got) got = gotHere; + } + } + } else { + for (size_t c = 0; c < channels; ++c) { + ib[c] = new float[reqd]; //!!! fix -- this is a rt function + RingBuffer<float> *rb = getReadRingBuffer(c); + if (rb) { + size_t gotHere = rb->read(ib[c], got); + if (gotHere < got) got = gotHere; + } } } @@ -720,6 +742,17 @@ ts->getOutput(buffer, count); + if (mix) { + for (size_t c = 1; c < channels; ++c) { + for (size_t i = 0; i < count; ++i) { + buffer[c][i] = buffer[0][i] / channels; + } + } + for (size_t i = 0; i < count; ++i) { + buffer[0][i] /= channels; + } + } + m_condition.wakeAll(); return count;
--- a/audioio/AudioCallbackPlaySource.h Fri Sep 15 15:35:06 2006 +0000 +++ b/audioio/AudioCallbackPlaySource.h Mon Sep 18 16:43:17 2006 +0000 @@ -177,7 +177,7 @@ */ size_t getSourceSamples(size_t count, float **buffer); - void setSlowdownFactor(float factor, bool sharpen); + void setTimeStretch(float factor, bool sharpen, bool mono); signals: void modelReplaced();
--- a/audioio/PhaseVocoderTimeStretcher.cpp Fri Sep 15 15:35:06 2006 +0000 +++ b/audioio/PhaseVocoderTimeStretcher.cpp Mon Sep 18 16:43:17 2006 +0000 @@ -39,11 +39,6 @@ { initialise(); - std::cerr << "PhaseVocoderTimeStretcher: channels = " << m_channels - << ", ratio = " << m_ratio - << ", n1 = " << m_n1 << ", n2 = " << m_n2 << ", wlen = " - << m_wlen << ", max = " << maxProcessInputBlockSize - << ", outbuflen = " << m_outbuf[0]->getSize() << std::endl; } PhaseVocoderTimeStretcher::~PhaseVocoderTimeStretcher() @@ -166,6 +161,17 @@ } m_transientThreshold = m_wlen / 4.5; + + m_totalCount = 0; + m_transientCount = 0; + m_n2sum = 0; + + + std::cerr << "PhaseVocoderTimeStretcher: channels = " << m_channels + << ", ratio = " << m_ratio + << ", n1 = " << m_n1 << ", n2 = " << m_n2 << ", wlen = " + << m_wlen << ", max = " << m_maxProcessInputBlockSize << std::endl; +// << ", outbuflen = " << m_outbuf[0]->getSize() << std::endl; } void @@ -516,10 +522,17 @@ bool isTransient = false; - if (count > m_transientThreshold && - count > m_prevTransientScore * 1.2) { +// if (count > m_transientThreshold && +// count > m_prevTransientScore * 1.2) { + if (count > m_prevTransientScore && + count > m_transientThreshold && + count - m_prevTransientScore > m_wlen / 20) { isTransient = true; - std::cerr << "isTransient (count = " << count << ", prev = " << m_prevTransientScore << ")" << std::endl; + + + std::cerr << "isTransient (count = " << count << ", prev = " << m_prevTransientScore << ", diff = " << count - m_prevTransientScore << ", ratio = " << (m_totalCount > 0 ? (float (m_n2sum) / float(m_totalCount * m_n1)) : 1.f) << ", ideal = " << m_ratio << ")" << std::endl; +// } else { +// std::cerr << " !transient (count = " << count << ", prev = " << m_prevTransientScore << ", diff = " << count - m_prevTransientScore << ")" << std::endl; } m_prevTransientScore = count;
--- a/audioio/PhaseVocoderTimeStretcher.h Fri Sep 15 15:35:06 2006 +0000 +++ b/audioio/PhaseVocoderTimeStretcher.h Mon Sep 18 16:43:17 2006 +0000 @@ -119,6 +119,11 @@ bool getSharpening() const { return m_sharpen; } /** + * Return the number of channels for this time stretcher. + */ + size_t getChannelCount() const { return m_channels; } + + /** * Get the latency added by the time stretcher, in sample frames. * This will be exact if transient sharpening is off, or approximate * if it is on.
--- a/main/MainWindow.cpp Fri Sep 15 15:35:06 2006 +0000 +++ b/main/MainWindow.cpp Mon Sep 18 16:43:17 2006 +0000 @@ -166,23 +166,38 @@ connect(m_playSpeed, SIGNAL(valueChanged(int)), this, SLOT(playSpeedChanged(int))); - m_playSharpen = new QCheckBox(frame); + m_playSharpen = new QPushButton(frame); m_playSharpen->setToolTip(tr("Sharpen percussive transients")); + m_playSharpen->setFixedSize(20, 20); +// m_playSharpen->setFlat(true); m_playSharpen->setEnabled(false); + m_playSharpen->setCheckable(true); + m_playSharpen->setChecked(false); + m_playSharpen->setIcon(QIcon(":icons/sharpen.png")); + connect(m_playSharpen, SIGNAL(clicked()), this, SLOT(playSharpenToggled())); + + m_playMono = new QPushButton(frame); + m_playMono->setToolTip(tr("Run time stretcher in mono only")); + m_playMono->setFixedSize(20, 20); +// m_playMono->setFlat(true); + m_playMono->setEnabled(false); + m_playMono->setCheckable(true); + m_playMono->setChecked(false); + m_playMono->setIcon(QIcon(":icons/mono.png")); + connect(m_playMono, SIGNAL(clicked()), this, SLOT(playMonoToggled())); QSettings settings; settings.beginGroup("MainWindow"); m_playSharpen->setChecked(settings.value("playsharpen", true).toBool()); + m_playMono->setChecked(settings.value("playmono", false).toBool()); settings.endGroup(); - connect(m_playSharpen, SIGNAL(clicked()), - this, SLOT(playSharpenToggled())); - - layout->addWidget(m_paneStack, 0, 0, 1, 4); + layout->addWidget(m_paneStack, 0, 0, 1, 5); layout->addWidget(m_panner, 1, 0); layout->addWidget(m_fader, 1, 1); layout->addWidget(m_playSpeed, 1, 2); layout->addWidget(m_playSharpen, 1, 3); + layout->addWidget(m_playMono, 1, 4); layout->setColumnStretch(0, 10); @@ -2870,11 +2885,6 @@ void MainWindow::playSpeedChanged(int speed) { -// static float factors[] = { -// 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]; - bool slow = false; bool something = false; float factor; @@ -2907,8 +2917,10 @@ .arg(pc)); m_playSharpen->setEnabled(something); + m_playMono->setEnabled(something); bool sharpen = (something && m_playSharpen->isChecked()); - m_playSource->setSlowdownFactor(factor, sharpen); + bool mono = (something && m_playMono->isChecked()); + m_playSource->setTimeStretch(factor, sharpen, mono); } void @@ -2923,6 +2935,17 @@ } void +MainWindow::playMonoToggled() +{ + QSettings settings; + settings.beginGroup("MainWindow"); + settings.setValue("playmono", m_playMono->isChecked()); + settings.endGroup(); + + playSpeedChanged(m_playSpeed->value()); +} + +void MainWindow::outputLevelsChanged(float left, float right) { m_fader->setPeakLeft(left);
--- a/main/MainWindow.h Fri Sep 15 15:35:06 2006 +0000 +++ b/main/MainWindow.h Mon Sep 18 16:43:17 2006 +0000 @@ -46,6 +46,7 @@ class QLabel; class QCheckBox; class PreferencesDialog; +class QPushButton; class MainWindow : public QMainWindow @@ -141,6 +142,7 @@ void playSelectionToggled(); void playSpeedChanged(int); void playSharpenToggled(); + void playMonoToggled(); void sampleRateMismatch(size_t, size_t, bool); void outputLevelsChanged(float, float); @@ -205,7 +207,8 @@ Panner *m_panner; Fader *m_fader; AudioDial *m_playSpeed; - QCheckBox *m_playSharpen; + QPushButton *m_playSharpen; + QPushButton *m_playMono; WaveformLayer *m_panLayer; Layer *m_timeRulerLayer;
--- a/sonic-visualiser.qrc Fri Sep 15 15:35:06 2006 +0000 +++ b/sonic-visualiser.qrc Mon Sep 18 16:43:17 2006 +0000 @@ -48,6 +48,9 @@ <file>icons/editcut.png</file> <file>icons/editcopy.png</file> <file>icons/editpaste.png</file> + <file>icons/mono.png</file> + <file>icons/stereo.png</file> + <file>icons/sharpen.png</file> <file>samples/bass.wav</file> <file>samples/beep.wav</file> <file>samples/bounce.wav</file>
--- a/transform/FeatureExtractionPluginTransform.cpp Fri Sep 15 15:35:06 2006 +0000 +++ b/transform/FeatureExtractionPluginTransform.cpp Mon Sep 18 16:43:17 2006 +0000 @@ -36,12 +36,16 @@ QString pluginId, int channel, QString configurationXml, - QString outputName) : + QString outputName, + size_t stepSize, + size_t blockSize, + WindowType windowType) : Transform(inputModel), m_plugin(0), m_channel(channel), m_stepSize(0), m_blockSize(0), + m_windowType(windowType), m_descriptor(0), m_outputFeatureNo(0) { @@ -68,11 +72,17 @@ PluginXml(m_plugin).setParametersFromXml(configurationXml); } - m_blockSize = m_plugin->getPreferredBlockSize(); - m_stepSize = m_plugin->getPreferredStepSize(); + if (m_blockSize == 0) m_blockSize = m_plugin->getPreferredBlockSize(); + if (m_stepSize == 0) m_stepSize = m_plugin->getPreferredStepSize(); - if (m_blockSize == 0) m_blockSize = 1024; //!!! todo: ask user - if (m_stepSize == 0) m_stepSize = m_blockSize; //!!! likewise + if (m_blockSize == 0) m_blockSize = 1024; + if (m_stepSize == 0) { + if (m_plugin->getInputDomain() == Vamp::Plugin::FrequencyDomain) { + m_stepSize = m_blockSize / 2; + } else { + m_stepSize = m_blockSize; + } + } DenseTimeValueModel *input = getInput(); if (!input) return; @@ -250,7 +260,7 @@ fftModels.push_back(new FFTModel (getInput(), channelCount == 1 ? m_channel : ch, - HanningWindow, + m_windowType, m_blockSize, m_stepSize, m_blockSize,
--- a/transform/FeatureExtractionPluginTransform.h Fri Sep 15 15:35:06 2006 +0000 +++ b/transform/FeatureExtractionPluginTransform.h Mon Sep 18 16:43:17 2006 +0000 @@ -18,6 +18,8 @@ #include "Transform.h" +#include "base/Window.h" + #include "vamp-sdk/Plugin.h" class DenseTimeValueModel; @@ -29,7 +31,10 @@ QString plugin, int channel, QString configurationXml = "", - QString outputName = ""); + QString outputName = "", + size_t stepSize = 0, + size_t blockSize = 0, + WindowType windowType = HanningWindow); virtual ~FeatureExtractionPluginTransform(); protected: @@ -39,6 +44,7 @@ int m_channel; size_t m_stepSize; size_t m_blockSize; + WindowType m_windowType; Vamp::Plugin::OutputDescriptor *m_descriptor; int m_outputFeatureNo;
--- a/transform/RealTimePluginTransform.cpp Fri Sep 15 15:35:06 2006 +0000 +++ b/transform/RealTimePluginTransform.cpp Mon Sep 18 16:43:17 2006 +0000 @@ -31,12 +31,16 @@ int channel, QString configurationXml, QString units, - int output) : + int output, + size_t blockSize) : Transform(inputModel), m_plugin(0), m_channel(channel), - m_outputNo(output) + m_outputNo(output), + m_blockSize(blockSize) { + if (!m_blockSize) m_blockSize = 1024; + std::cerr << "RealTimePluginTransform::RealTimePluginTransform: plugin " << pluginId.toStdString() << ", output " << output << std::endl; RealTimePluginFactory *factory = @@ -52,7 +56,7 @@ if (!input) return; m_plugin = factory->instantiatePlugin(pluginId, 0, 0, m_input->getSampleRate(), - 1024, //!!! wants to be configurable + m_blockSize, input->getChannelCount()); if (!m_plugin) { @@ -71,8 +75,7 @@ } SparseTimeValueModel *model = new SparseTimeValueModel - (input->getSampleRate(), 1024, //!!! - 0.0, 0.0, false); + (input->getSampleRate(), m_blockSize, 0.0, 0.0, false); if (units != "") model->setScaleUnits(units);
--- a/transform/RealTimePluginTransform.h Fri Sep 15 15:35:06 2006 +0000 +++ b/transform/RealTimePluginTransform.h Mon Sep 18 16:43:17 2006 +0000 @@ -29,7 +29,8 @@ int channel, QString configurationXml = "", QString units = "", - int output = 0); + int output = 0, + size_t blockSize = 0); virtual ~RealTimePluginTransform(); protected: @@ -38,6 +39,7 @@ RealTimePluginInstance *m_plugin; int m_channel; int m_outputNo; + size_t m_blockSize; // just casts DenseTimeValueModel *getInput();
--- a/transform/TransformFactory.cpp Fri Sep 15 15:35:06 2006 +0000 +++ b/transform/TransformFactory.cpp Mon Sep 18 16:43:17 2006 +0000 @@ -413,6 +413,10 @@ } configurationXml = PluginXml(plugin).toXmlString(); channel = dialog->getChannel(); + + //!!! where now for step size, block size, etc? +// dialog->getProcessingParameters(stepSize, blockSize, windowType); + delete dialog; delete plugin; }
--- a/transform/TransformFactory.h Fri Sep 15 15:35:06 2006 +0000 +++ b/transform/TransformFactory.h Mon Sep 18 16:43:17 2006 +0000 @@ -66,7 +66,8 @@ * asking the user, most likely). Returns true if the transform * is acceptable, false if the operation should be cancelled. */ - bool getConfigurationForTransform(TransformName name, Model *inputModel, + bool getConfigurationForTransform(TransformName name, + Model *inputModel, int &channel, QString &configurationXml);