Add R3 support to plugins
This commit is contained in:
646
ladspa-lv2/RubberBandR3PitchShifter.cpp
Normal file
646
ladspa-lv2/RubberBandR3PitchShifter.cpp
Normal file
@@ -0,0 +1,646 @@
|
|||||||
|
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
||||||
|
|
||||||
|
/*
|
||||||
|
Rubber Band Library
|
||||||
|
An audio time-stretching and pitch-shifting library.
|
||||||
|
Copyright 2007-2022 Particular Programs Ltd.
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License as
|
||||||
|
published by the Free Software Foundation; either version 2 of the
|
||||||
|
License, or (at your option) any later version. See the file
|
||||||
|
COPYING included with this distribution for more information.
|
||||||
|
|
||||||
|
Alternatively, if you have a valid commercial licence for the
|
||||||
|
Rubber Band Library obtained by agreement with the copyright
|
||||||
|
holders, you may redistribute and/or modify it under the terms
|
||||||
|
described in that licence.
|
||||||
|
|
||||||
|
If you wish to distribute code using the Rubber Band Library
|
||||||
|
under terms other than those of the GNU General Public License,
|
||||||
|
you must obtain a valid commercial licence before doing so.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "RubberBandR3PitchShifter.h"
|
||||||
|
|
||||||
|
#include "RubberBandStretcher.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
using namespace RubberBand;
|
||||||
|
|
||||||
|
using std::cout;
|
||||||
|
using std::cerr;
|
||||||
|
using std::endl;
|
||||||
|
using std::min;
|
||||||
|
|
||||||
|
#ifdef RB_PLUGIN_LADSPA
|
||||||
|
|
||||||
|
const char *const
|
||||||
|
RubberBandR3PitchShifter::portNamesMono[PortCountMono] =
|
||||||
|
{
|
||||||
|
"latency",
|
||||||
|
"Cents",
|
||||||
|
"Semitones",
|
||||||
|
"Octaves",
|
||||||
|
"Formant Preserving",
|
||||||
|
"Wet-Dry Mix",
|
||||||
|
"Input",
|
||||||
|
"Output"
|
||||||
|
};
|
||||||
|
|
||||||
|
const char *const
|
||||||
|
RubberBandR3PitchShifter::portNamesStereo[PortCountStereo] =
|
||||||
|
{
|
||||||
|
"latency",
|
||||||
|
"Cents",
|
||||||
|
"Semitones",
|
||||||
|
"Octaves",
|
||||||
|
"Formant Preserving",
|
||||||
|
"Wet-Dry Mix",
|
||||||
|
"Input L",
|
||||||
|
"Output L",
|
||||||
|
"Input R",
|
||||||
|
"Output R"
|
||||||
|
};
|
||||||
|
|
||||||
|
const LADSPA_PortDescriptor
|
||||||
|
RubberBandR3PitchShifter::portsMono[PortCountMono] =
|
||||||
|
{
|
||||||
|
LADSPA_PORT_OUTPUT | LADSPA_PORT_CONTROL,
|
||||||
|
LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL,
|
||||||
|
LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL,
|
||||||
|
LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL,
|
||||||
|
LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL,
|
||||||
|
LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL,
|
||||||
|
LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO,
|
||||||
|
LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO
|
||||||
|
};
|
||||||
|
|
||||||
|
const LADSPA_PortDescriptor
|
||||||
|
RubberBandR3PitchShifter::portsStereo[PortCountStereo] =
|
||||||
|
{
|
||||||
|
LADSPA_PORT_OUTPUT | LADSPA_PORT_CONTROL,
|
||||||
|
LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL,
|
||||||
|
LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL,
|
||||||
|
LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL,
|
||||||
|
LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL,
|
||||||
|
LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL,
|
||||||
|
LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO,
|
||||||
|
LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO,
|
||||||
|
LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO,
|
||||||
|
LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO
|
||||||
|
};
|
||||||
|
|
||||||
|
const LADSPA_PortRangeHint
|
||||||
|
RubberBandR3PitchShifter::hintsMono[PortCountMono] =
|
||||||
|
{
|
||||||
|
{ 0, 0, 0 }, // latency
|
||||||
|
{ LADSPA_HINT_DEFAULT_0 | // cents
|
||||||
|
LADSPA_HINT_BOUNDED_BELOW |
|
||||||
|
LADSPA_HINT_BOUNDED_ABOVE,
|
||||||
|
-100.0, 100.0 },
|
||||||
|
{ LADSPA_HINT_DEFAULT_0 | // semitones
|
||||||
|
LADSPA_HINT_BOUNDED_BELOW |
|
||||||
|
LADSPA_HINT_BOUNDED_ABOVE |
|
||||||
|
LADSPA_HINT_INTEGER,
|
||||||
|
-12.0, 12.0 },
|
||||||
|
{ LADSPA_HINT_DEFAULT_0 | // octaves
|
||||||
|
LADSPA_HINT_BOUNDED_BELOW |
|
||||||
|
LADSPA_HINT_BOUNDED_ABOVE |
|
||||||
|
LADSPA_HINT_INTEGER,
|
||||||
|
-2.0, 2.0 },
|
||||||
|
{ LADSPA_HINT_DEFAULT_0 | // formant preserving
|
||||||
|
LADSPA_HINT_BOUNDED_BELOW |
|
||||||
|
LADSPA_HINT_BOUNDED_ABOVE |
|
||||||
|
LADSPA_HINT_TOGGLED,
|
||||||
|
0.0, 1.0 },
|
||||||
|
{ LADSPA_HINT_DEFAULT_0 | // wet-dry mix
|
||||||
|
LADSPA_HINT_BOUNDED_BELOW |
|
||||||
|
LADSPA_HINT_BOUNDED_ABOVE,
|
||||||
|
0.0, 1.0 },
|
||||||
|
{ 0, 0, 0 },
|
||||||
|
{ 0, 0, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
const LADSPA_PortRangeHint
|
||||||
|
RubberBandR3PitchShifter::hintsStereo[PortCountStereo] =
|
||||||
|
{
|
||||||
|
{ 0, 0, 0 }, // latency
|
||||||
|
{ LADSPA_HINT_DEFAULT_0 | // cents
|
||||||
|
LADSPA_HINT_BOUNDED_BELOW |
|
||||||
|
LADSPA_HINT_BOUNDED_ABOVE,
|
||||||
|
-100.0, 100.0 },
|
||||||
|
{ LADSPA_HINT_DEFAULT_0 | // semitones
|
||||||
|
LADSPA_HINT_BOUNDED_BELOW |
|
||||||
|
LADSPA_HINT_BOUNDED_ABOVE |
|
||||||
|
LADSPA_HINT_INTEGER,
|
||||||
|
-12.0, 12.0 },
|
||||||
|
{ LADSPA_HINT_DEFAULT_0 | // octaves
|
||||||
|
LADSPA_HINT_BOUNDED_BELOW |
|
||||||
|
LADSPA_HINT_BOUNDED_ABOVE |
|
||||||
|
LADSPA_HINT_INTEGER,
|
||||||
|
-2.0, 2.0 },
|
||||||
|
{ LADSPA_HINT_DEFAULT_0 | // formant preserving
|
||||||
|
LADSPA_HINT_BOUNDED_BELOW |
|
||||||
|
LADSPA_HINT_BOUNDED_ABOVE |
|
||||||
|
LADSPA_HINT_TOGGLED,
|
||||||
|
0.0, 1.0 },
|
||||||
|
{ LADSPA_HINT_DEFAULT_0 | // wet-dry mix
|
||||||
|
LADSPA_HINT_BOUNDED_BELOW |
|
||||||
|
LADSPA_HINT_BOUNDED_ABOVE,
|
||||||
|
0.0, 1.0 },
|
||||||
|
{ 0, 0, 0 },
|
||||||
|
{ 0, 0, 0 },
|
||||||
|
{ 0, 0, 0 },
|
||||||
|
{ 0, 0, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
const LADSPA_Properties
|
||||||
|
RubberBandR3PitchShifter::properties = LADSPA_PROPERTY_HARD_RT_CAPABLE;
|
||||||
|
|
||||||
|
const LADSPA_Descriptor
|
||||||
|
RubberBandR3PitchShifter::ladspaDescriptorMono =
|
||||||
|
{
|
||||||
|
29790, // "Unique" ID
|
||||||
|
"rubberband-r3-pitchshifter-mono", // Label
|
||||||
|
properties,
|
||||||
|
"Rubber Band R3 Mono Pitch Shifter", // Name
|
||||||
|
"Breakfast Quay",
|
||||||
|
"GPL",
|
||||||
|
PortCountMono,
|
||||||
|
portsMono,
|
||||||
|
portNamesMono,
|
||||||
|
hintsMono,
|
||||||
|
nullptr, // Implementation data
|
||||||
|
instantiate,
|
||||||
|
connectPort,
|
||||||
|
activate,
|
||||||
|
run,
|
||||||
|
nullptr, // Run adding
|
||||||
|
nullptr, // Set run adding gain
|
||||||
|
deactivate,
|
||||||
|
cleanup
|
||||||
|
};
|
||||||
|
|
||||||
|
const LADSPA_Descriptor
|
||||||
|
RubberBandR3PitchShifter::ladspaDescriptorStereo =
|
||||||
|
{
|
||||||
|
97920, // "Unique" ID
|
||||||
|
"rubberband-r3-pitchshifter-stereo", // Label
|
||||||
|
properties,
|
||||||
|
"Rubber Band R3 Stereo Pitch Shifter", // Name
|
||||||
|
"Breakfast Quay",
|
||||||
|
"GPL",
|
||||||
|
PortCountStereo,
|
||||||
|
portsStereo,
|
||||||
|
portNamesStereo,
|
||||||
|
hintsStereo,
|
||||||
|
nullptr, // Implementation data
|
||||||
|
instantiate,
|
||||||
|
connectPort,
|
||||||
|
activate,
|
||||||
|
run,
|
||||||
|
nullptr, // Run adding
|
||||||
|
nullptr, // Set run adding gain
|
||||||
|
deactivate,
|
||||||
|
cleanup
|
||||||
|
};
|
||||||
|
|
||||||
|
const LADSPA_Descriptor *
|
||||||
|
RubberBandR3PitchShifter::getDescriptor(unsigned long index)
|
||||||
|
{
|
||||||
|
if (index == 0) return &ladspaDescriptorMono;
|
||||||
|
if (index == 1) return &ladspaDescriptorStereo;
|
||||||
|
else return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
const LV2_Descriptor
|
||||||
|
RubberBandR3PitchShifter::lv2DescriptorMono =
|
||||||
|
{
|
||||||
|
"http://breakfastquay.com/rdf/lv2-rubberband-r3#mono",
|
||||||
|
instantiate,
|
||||||
|
connectPort,
|
||||||
|
activate,
|
||||||
|
run,
|
||||||
|
deactivate,
|
||||||
|
cleanup,
|
||||||
|
nullptr
|
||||||
|
};
|
||||||
|
|
||||||
|
const LV2_Descriptor
|
||||||
|
RubberBandR3PitchShifter::lv2DescriptorStereo =
|
||||||
|
{
|
||||||
|
"http://breakfastquay.com/rdf/lv2-rubberband-r3#stereo",
|
||||||
|
instantiate,
|
||||||
|
connectPort,
|
||||||
|
activate,
|
||||||
|
run,
|
||||||
|
deactivate,
|
||||||
|
cleanup,
|
||||||
|
nullptr
|
||||||
|
};
|
||||||
|
|
||||||
|
const LV2_Descriptor *
|
||||||
|
RubberBandR3PitchShifter::getDescriptor(uint32_t index)
|
||||||
|
{
|
||||||
|
if (index == 0) return &lv2DescriptorMono;
|
||||||
|
if (index == 1) return &lv2DescriptorStereo;
|
||||||
|
else return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
RubberBandR3PitchShifter::RubberBandR3PitchShifter(int sampleRate, size_t channels) :
|
||||||
|
m_latency(nullptr),
|
||||||
|
m_cents(nullptr),
|
||||||
|
m_semitones(nullptr),
|
||||||
|
m_octaves(nullptr),
|
||||||
|
m_formant(nullptr),
|
||||||
|
m_wetDry(nullptr),
|
||||||
|
m_ratio(1.0),
|
||||||
|
m_prevRatio(1.0),
|
||||||
|
m_currentFormant(false),
|
||||||
|
m_blockSize(1024),
|
||||||
|
m_reserve(8192),
|
||||||
|
m_bufsize(0),
|
||||||
|
m_minfill(0),
|
||||||
|
m_stretcher(new RubberBandStretcher
|
||||||
|
(sampleRate, channels,
|
||||||
|
RubberBandStretcher::OptionProcessRealTime |
|
||||||
|
RubberBandStretcher::OptionEngineFiner)),
|
||||||
|
m_sampleRate(sampleRate),
|
||||||
|
m_channels(channels)
|
||||||
|
{
|
||||||
|
m_input = new float *[m_channels];
|
||||||
|
m_output = new float *[m_channels];
|
||||||
|
|
||||||
|
m_outputBuffer = new RingBuffer<float> *[m_channels];
|
||||||
|
m_delayMixBuffer = new RingBuffer<float> *[m_channels];
|
||||||
|
m_scratch = new float *[m_channels];
|
||||||
|
m_inptrs = new float *[m_channels];
|
||||||
|
|
||||||
|
m_bufsize = m_blockSize + m_reserve + 8192;
|
||||||
|
|
||||||
|
for (size_t c = 0; c < m_channels; ++c) {
|
||||||
|
|
||||||
|
m_input[c] = 0;
|
||||||
|
m_output[c] = 0;
|
||||||
|
|
||||||
|
m_outputBuffer[c] = new RingBuffer<float>(m_bufsize);
|
||||||
|
m_delayMixBuffer[c] = new RingBuffer<float>(m_bufsize);
|
||||||
|
|
||||||
|
m_scratch[c] = new float[m_bufsize];
|
||||||
|
for (size_t i = 0; i < m_bufsize; ++i) {
|
||||||
|
m_scratch[c][i] = 0.f;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_inptrs[c] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
activateImpl();
|
||||||
|
}
|
||||||
|
|
||||||
|
RubberBandR3PitchShifter::~RubberBandR3PitchShifter()
|
||||||
|
{
|
||||||
|
delete m_stretcher;
|
||||||
|
for (size_t c = 0; c < m_channels; ++c) {
|
||||||
|
delete m_outputBuffer[c];
|
||||||
|
delete m_delayMixBuffer[c];
|
||||||
|
delete[] m_scratch[c];
|
||||||
|
}
|
||||||
|
delete[] m_outputBuffer;
|
||||||
|
delete[] m_delayMixBuffer;
|
||||||
|
delete[] m_inptrs;
|
||||||
|
delete[] m_scratch;
|
||||||
|
delete[] m_output;
|
||||||
|
delete[] m_input;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef RB_PLUGIN_LADSPA
|
||||||
|
|
||||||
|
LADSPA_Handle
|
||||||
|
RubberBandR3PitchShifter::instantiate(const LADSPA_Descriptor *desc, unsigned long rate)
|
||||||
|
{
|
||||||
|
if (desc->PortCount == ladspaDescriptorMono.PortCount) {
|
||||||
|
return new RubberBandR3PitchShifter(rate, 1);
|
||||||
|
} else if (desc->PortCount == ladspaDescriptorStereo.PortCount) {
|
||||||
|
return new RubberBandR3PitchShifter(rate, 2);
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
LV2_Handle
|
||||||
|
RubberBandR3PitchShifter::instantiate(const LV2_Descriptor *desc, double rate,
|
||||||
|
const char *, const LV2_Feature *const *)
|
||||||
|
{
|
||||||
|
if (rate < 1.0) {
|
||||||
|
std::cerr << "RubberBandR3PitchShifter::instantiate: invalid sample rate "
|
||||||
|
<< rate << " provided" << std::endl;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
size_t srate = size_t(round(rate));
|
||||||
|
if (std::string(desc->URI) == lv2DescriptorMono.URI) {
|
||||||
|
return new RubberBandR3PitchShifter(srate, 1);
|
||||||
|
} else if (std::string(desc->URI) == lv2DescriptorStereo.URI) {
|
||||||
|
return new RubberBandR3PitchShifter(srate, 2);
|
||||||
|
} else {
|
||||||
|
std::cerr << "RubberBandR3PitchShifter::instantiate: unrecognised URI "
|
||||||
|
<< desc->URI << " requested" << std::endl;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef RB_PLUGIN_LADSPA
|
||||||
|
void
|
||||||
|
RubberBandR3PitchShifter::connectPort(LADSPA_Handle handle,
|
||||||
|
unsigned long port, LADSPA_Data *location)
|
||||||
|
#else
|
||||||
|
void
|
||||||
|
RubberBandR3PitchShifter::connectPort(LV2_Handle handle,
|
||||||
|
uint32_t port, void *location)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
RubberBandR3PitchShifter *shifter = (RubberBandR3PitchShifter *)handle;
|
||||||
|
|
||||||
|
float **ports[PortCountStereo] = {
|
||||||
|
&shifter->m_latency,
|
||||||
|
&shifter->m_cents,
|
||||||
|
&shifter->m_semitones,
|
||||||
|
&shifter->m_octaves,
|
||||||
|
&shifter->m_formant,
|
||||||
|
&shifter->m_wetDry,
|
||||||
|
&shifter->m_input[0],
|
||||||
|
&shifter->m_output[0],
|
||||||
|
&shifter->m_input[1],
|
||||||
|
&shifter->m_output[1]
|
||||||
|
};
|
||||||
|
|
||||||
|
if (shifter->m_channels == 1) {
|
||||||
|
if (port >= PortCountMono) return;
|
||||||
|
} else {
|
||||||
|
if (port >= PortCountStereo) return;
|
||||||
|
}
|
||||||
|
|
||||||
|
*ports[port] = (float *)location;
|
||||||
|
|
||||||
|
if (shifter->m_latency) {
|
||||||
|
*(shifter->m_latency) = shifter->getLatency();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef RB_PLUGIN_LADSPA
|
||||||
|
void
|
||||||
|
RubberBandR3PitchShifter::activate(LADSPA_Handle handle)
|
||||||
|
#else
|
||||||
|
void
|
||||||
|
RubberBandR3PitchShifter::activate(LV2_Handle handle)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
RubberBandR3PitchShifter *shifter = (RubberBandR3PitchShifter *)handle;
|
||||||
|
shifter->activateImpl();
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef RB_PLUGIN_LADSPA
|
||||||
|
void
|
||||||
|
RubberBandR3PitchShifter::run(LADSPA_Handle handle, unsigned long samples)
|
||||||
|
#else
|
||||||
|
void
|
||||||
|
RubberBandR3PitchShifter::run(LV2_Handle handle, uint32_t samples)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
RubberBandR3PitchShifter *shifter = (RubberBandR3PitchShifter *)handle;
|
||||||
|
shifter->runImpl(samples);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef RB_PLUGIN_LADSPA
|
||||||
|
void
|
||||||
|
RubberBandR3PitchShifter::deactivate(LADSPA_Handle handle)
|
||||||
|
#else
|
||||||
|
void
|
||||||
|
RubberBandR3PitchShifter::deactivate(LV2_Handle handle)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
activate(handle); // both functions just reset the plugin
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef RB_PLUGIN_LADSPA
|
||||||
|
void
|
||||||
|
RubberBandR3PitchShifter::cleanup(LADSPA_Handle handle)
|
||||||
|
#else
|
||||||
|
void
|
||||||
|
RubberBandR3PitchShifter::cleanup(LV2_Handle handle)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
delete (RubberBandR3PitchShifter *)handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
RubberBandR3PitchShifter::getLatency() const
|
||||||
|
{
|
||||||
|
return m_reserve;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
RubberBandR3PitchShifter::activateImpl()
|
||||||
|
{
|
||||||
|
updateRatio();
|
||||||
|
m_prevRatio = m_ratio;
|
||||||
|
m_stretcher->reset();
|
||||||
|
m_stretcher->setPitchScale(m_ratio);
|
||||||
|
|
||||||
|
for (size_t c = 0; c < m_channels; ++c) {
|
||||||
|
m_outputBuffer[c]->reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t c = 0; c < m_channels; ++c) {
|
||||||
|
m_delayMixBuffer[c]->reset();
|
||||||
|
m_delayMixBuffer[c]->zero(getLatency());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t c = 0; c < m_channels; ++c) {
|
||||||
|
for (size_t i = 0; i < m_bufsize; ++i) {
|
||||||
|
m_scratch[c][i] = 0.f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_minfill = 0;
|
||||||
|
|
||||||
|
m_stretcher->process(m_scratch, m_reserve, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
RubberBandR3PitchShifter::updateRatio()
|
||||||
|
{
|
||||||
|
// The octaves, semitones, and cents parameters are supposed to be
|
||||||
|
// integral: we want to enforce that, just to avoid
|
||||||
|
// inconsistencies between hosts if some respect the hints more
|
||||||
|
// than others
|
||||||
|
|
||||||
|
#ifdef RB_PLUGIN_LADSPA
|
||||||
|
|
||||||
|
// But we don't want to change the long-standing behaviour of the
|
||||||
|
// LADSPA plugin, so let's leave this as-is and only do "the right
|
||||||
|
// thing" for LV2
|
||||||
|
double oct = (m_octaves ? *m_octaves : 0.0);
|
||||||
|
oct += (m_semitones ? *m_semitones : 0.0) / 12;
|
||||||
|
oct += (m_cents ? *m_cents : 0.0) / 1200;
|
||||||
|
m_ratio = pow(2.0, oct);
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
// LV2
|
||||||
|
|
||||||
|
double octaves = round(m_octaves ? *m_octaves : 0.0);
|
||||||
|
if (octaves < -2.0) octaves = -2.0;
|
||||||
|
if (octaves > 2.0) octaves = 2.0;
|
||||||
|
|
||||||
|
double semitones = round(m_semitones ? *m_semitones : 0.0);
|
||||||
|
if (semitones < -12.0) semitones = -12.0;
|
||||||
|
if (semitones > 12.0) semitones = 12.0;
|
||||||
|
|
||||||
|
double cents = round(m_cents ? *m_cents : 0.0);
|
||||||
|
if (cents < -100.0) cents = -100.0;
|
||||||
|
if (cents > 100.0) cents = 100.0;
|
||||||
|
|
||||||
|
m_ratio = pow(2.0,
|
||||||
|
octaves +
|
||||||
|
semitones / 12.0 +
|
||||||
|
cents / 1200.0);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
RubberBandR3PitchShifter::updateFormant()
|
||||||
|
{
|
||||||
|
if (!m_formant) return;
|
||||||
|
|
||||||
|
bool f = (*m_formant > 0.5f);
|
||||||
|
if (f == m_currentFormant) return;
|
||||||
|
|
||||||
|
RubberBandStretcher *s = m_stretcher;
|
||||||
|
|
||||||
|
s->setFormantOption(f ?
|
||||||
|
RubberBandStretcher::OptionFormantPreserved :
|
||||||
|
RubberBandStretcher::OptionFormantShifted);
|
||||||
|
|
||||||
|
m_currentFormant = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
RubberBandR3PitchShifter::runImpl(uint32_t insamples)
|
||||||
|
{
|
||||||
|
for (size_t c = 0; c < m_channels; ++c) {
|
||||||
|
m_delayMixBuffer[c]->write(m_input[c], insamples);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t offset = 0;
|
||||||
|
|
||||||
|
// We have to break up the input into chunks like this because
|
||||||
|
// insamples could be arbitrarily large and our output buffer is
|
||||||
|
// of limited size
|
||||||
|
|
||||||
|
while (offset < insamples) {
|
||||||
|
|
||||||
|
size_t block = m_blockSize;
|
||||||
|
if (offset + block > insamples) {
|
||||||
|
block = insamples - offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
runImpl(block, offset);
|
||||||
|
|
||||||
|
offset += block;
|
||||||
|
}
|
||||||
|
|
||||||
|
float mix = 0.0;
|
||||||
|
if (m_wetDry) mix = *m_wetDry;
|
||||||
|
|
||||||
|
for (size_t c = 0; c < m_channels; ++c) {
|
||||||
|
if (mix > 0.0) {
|
||||||
|
for (size_t i = 0; i < insamples; ++i) {
|
||||||
|
float dry = m_delayMixBuffer[c]->readOne();
|
||||||
|
m_output[c][i] *= (1.0 - mix);
|
||||||
|
m_output[c][i] += dry * mix;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
m_delayMixBuffer[c]->skip(insamples);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
RubberBandR3PitchShifter::runImpl(uint32_t insamples, uint32_t offset)
|
||||||
|
{
|
||||||
|
updateRatio();
|
||||||
|
if (m_ratio != m_prevRatio) {
|
||||||
|
m_stretcher->setPitchScale(m_ratio);
|
||||||
|
m_prevRatio = m_ratio;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_latency) {
|
||||||
|
*m_latency = getLatency();
|
||||||
|
}
|
||||||
|
|
||||||
|
updateFormant();
|
||||||
|
|
||||||
|
const int samples = insamples;
|
||||||
|
int processed = 0;
|
||||||
|
size_t outTotal = 0;
|
||||||
|
|
||||||
|
while (processed < samples) {
|
||||||
|
|
||||||
|
// never feed more than the minimum necessary number of
|
||||||
|
// samples at a time; ensures nothing will overflow internally
|
||||||
|
// and we don't need to call setMaxProcessSize
|
||||||
|
|
||||||
|
int toCauseProcessing = m_stretcher->getSamplesRequired();
|
||||||
|
int inchunk = min(samples - processed, toCauseProcessing);
|
||||||
|
|
||||||
|
for (size_t c = 0; c < m_channels; ++c) {
|
||||||
|
m_inptrs[c] = &(m_input[c][offset + processed]);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_stretcher->process(m_inptrs, inchunk, false);
|
||||||
|
|
||||||
|
processed += inchunk;
|
||||||
|
|
||||||
|
int avail = m_stretcher->available();
|
||||||
|
int writable = m_outputBuffer[0]->getWriteSpace();
|
||||||
|
|
||||||
|
int outchunk = avail;
|
||||||
|
if (outchunk > writable) {
|
||||||
|
cerr << "RubberBandR3PitchShifter::runImpl: buffer is not large enough: size = " << m_outputBuffer[0]->getSize() << ", chunk = " << outchunk << ", space = " << writable << " (buffer contains " << m_outputBuffer[0]->getReadSpace() << " unread)" << endl;
|
||||||
|
outchunk = writable;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t actual = m_stretcher->retrieve(m_scratch, outchunk);
|
||||||
|
outTotal += actual;
|
||||||
|
|
||||||
|
for (size_t c = 0; c < m_channels; ++c) {
|
||||||
|
m_outputBuffer[c]->write(m_scratch[c], actual);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t c = 0; c < m_channels; ++c) {
|
||||||
|
int toRead = m_outputBuffer[c]->getReadSpace();
|
||||||
|
if (toRead < samples && c == 0) {
|
||||||
|
cerr << "RubberBandR3PitchShifter::runImpl: buffer underrun: required = " << samples << ", available = " << toRead << endl;
|
||||||
|
}
|
||||||
|
int chunk = min(toRead, samples);
|
||||||
|
m_outputBuffer[c]->read(&(m_output[c][offset]), chunk);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t fill = m_outputBuffer[0]->getReadSpace();
|
||||||
|
if (fill < m_minfill || m_minfill == 0) {
|
||||||
|
m_minfill = fill;
|
||||||
|
// cerr << "minfill = " << m_minfill << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
149
ladspa-lv2/RubberBandR3PitchShifter.h
Normal file
149
ladspa-lv2/RubberBandR3PitchShifter.h
Normal file
@@ -0,0 +1,149 @@
|
|||||||
|
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
||||||
|
|
||||||
|
/*
|
||||||
|
Rubber Band Library
|
||||||
|
An audio time-stretching and pitch-shifting library.
|
||||||
|
Copyright 2007-2022 Particular Programs Ltd.
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License as
|
||||||
|
published by the Free Software Foundation; either version 2 of the
|
||||||
|
License, or (at your option) any later version. See the file
|
||||||
|
COPYING included with this distribution for more information.
|
||||||
|
|
||||||
|
Alternatively, if you have a valid commercial licence for the
|
||||||
|
Rubber Band Library obtained by agreement with the copyright
|
||||||
|
holders, you may redistribute and/or modify it under the terms
|
||||||
|
described in that licence.
|
||||||
|
|
||||||
|
If you wish to distribute code using the Rubber Band Library
|
||||||
|
under terms other than those of the GNU General Public License,
|
||||||
|
you must obtain a valid commercial licence before doing so.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef RUBBERBAND_R3_PITCH_SHIFTER_H
|
||||||
|
#define RUBBERBAND_R3_PITCH_SHIFTER_H
|
||||||
|
|
||||||
|
#ifdef RB_PLUGIN_LADSPA
|
||||||
|
#ifdef RB_PLUGIN_LV2
|
||||||
|
#error "Only one of RB_PLUGIN_LADSPA and RB_PLUGIN_LV2 may be defined at once"
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#ifndef RB_PLUGIN_LV2
|
||||||
|
#error "Including code must define either RB_PLUGIN_LADSPA or RB_PLUGIN_LV2"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef RB_PLUGIN_LADSPA
|
||||||
|
#include <ladspa.h>
|
||||||
|
#else
|
||||||
|
#include <lv2.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "common/RingBuffer.h"
|
||||||
|
|
||||||
|
namespace RubberBand {
|
||||||
|
class RubberBandStretcher;
|
||||||
|
}
|
||||||
|
|
||||||
|
class RubberBandR3PitchShifter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
#ifdef RB_PLUGIN_LADSPA
|
||||||
|
static const LADSPA_Descriptor *getDescriptor(unsigned long index);
|
||||||
|
#else
|
||||||
|
static const LV2_Descriptor *getDescriptor(uint32_t index);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
protected:
|
||||||
|
RubberBandR3PitchShifter(int sampleRate, size_t channels);
|
||||||
|
~RubberBandR3PitchShifter();
|
||||||
|
|
||||||
|
enum {
|
||||||
|
LatencyPort = 0,
|
||||||
|
CentsPort = 1,
|
||||||
|
SemitonesPort = 2,
|
||||||
|
OctavesPort = 3,
|
||||||
|
FormantPort = 4,
|
||||||
|
WetDryPort = 5,
|
||||||
|
InputPort1 = 6,
|
||||||
|
OutputPort1 = 7,
|
||||||
|
PortCountMono = OutputPort1 + 1,
|
||||||
|
InputPort2 = 8,
|
||||||
|
OutputPort2 = 9,
|
||||||
|
PortCountStereo = OutputPort2 + 1
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef RB_PLUGIN_LADSPA
|
||||||
|
static const char *const portNamesMono[PortCountMono];
|
||||||
|
static const LADSPA_PortDescriptor portsMono[PortCountMono];
|
||||||
|
static const LADSPA_PortRangeHint hintsMono[PortCountMono];
|
||||||
|
|
||||||
|
static const char *const portNamesStereo[PortCountStereo];
|
||||||
|
static const LADSPA_PortDescriptor portsStereo[PortCountStereo];
|
||||||
|
static const LADSPA_PortRangeHint hintsStereo[PortCountStereo];
|
||||||
|
|
||||||
|
static const LADSPA_Properties properties;
|
||||||
|
|
||||||
|
static const LADSPA_Descriptor ladspaDescriptorMono;
|
||||||
|
static const LADSPA_Descriptor ladspaDescriptorStereo;
|
||||||
|
|
||||||
|
static LADSPA_Handle instantiate(const LADSPA_Descriptor *, unsigned long);
|
||||||
|
static void connectPort(LADSPA_Handle, unsigned long, LADSPA_Data *);
|
||||||
|
static void activate(LADSPA_Handle);
|
||||||
|
static void run(LADSPA_Handle, unsigned long);
|
||||||
|
static void deactivate(LADSPA_Handle);
|
||||||
|
static void cleanup(LADSPA_Handle);
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
static const LV2_Descriptor lv2DescriptorMono;
|
||||||
|
static const LV2_Descriptor lv2DescriptorStereo;
|
||||||
|
|
||||||
|
static LV2_Handle instantiate(const LV2_Descriptor *, double,
|
||||||
|
const char *, const LV2_Feature *const *);
|
||||||
|
static void connectPort(LV2_Handle, uint32_t, void *);
|
||||||
|
static void activate(LV2_Handle);
|
||||||
|
static void run(LV2_Handle, uint32_t);
|
||||||
|
static void deactivate(LV2_Handle);
|
||||||
|
static void cleanup(LV2_Handle);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void activateImpl();
|
||||||
|
void runImpl(uint32_t count);
|
||||||
|
void runImpl(uint32_t count, uint32_t offset);
|
||||||
|
void updateRatio();
|
||||||
|
void updateFormant();
|
||||||
|
|
||||||
|
int getLatency() const;
|
||||||
|
|
||||||
|
float **m_input;
|
||||||
|
float **m_output;
|
||||||
|
float *m_latency;
|
||||||
|
float *m_cents;
|
||||||
|
float *m_semitones;
|
||||||
|
float *m_octaves;
|
||||||
|
float *m_formant;
|
||||||
|
float *m_wetDry;
|
||||||
|
double m_ratio;
|
||||||
|
double m_prevRatio;
|
||||||
|
bool m_currentFormant;
|
||||||
|
|
||||||
|
size_t m_blockSize;
|
||||||
|
size_t m_reserve;
|
||||||
|
size_t m_bufsize;
|
||||||
|
size_t m_minfill;
|
||||||
|
|
||||||
|
RubberBand::RubberBandStretcher *m_stretcher;
|
||||||
|
RubberBand::RingBuffer<float> **m_outputBuffer;
|
||||||
|
RubberBand::RingBuffer<float> **m_delayMixBuffer;
|
||||||
|
float **m_scratch;
|
||||||
|
float **m_inptrs;
|
||||||
|
|
||||||
|
int m_sampleRate;
|
||||||
|
size_t m_channels;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,2 +1,4 @@
|
|||||||
ladspa:ladspa-rubberband:rubberband-pitchshifter-mono::Frequency > Pitch shifters
|
ladspa:ladspa-rubberband:rubberband-pitchshifter-mono::Frequency > Pitch shifters
|
||||||
ladspa:ladspa-rubberband:rubberband-pitchshifter-stereo::Frequency > Pitch shifters
|
ladspa:ladspa-rubberband:rubberband-pitchshifter-stereo::Frequency > Pitch shifters
|
||||||
|
ladspa:ladspa-rubberband:rubberband-r3-pitchshifter-mono::Frequency > Pitch shifters
|
||||||
|
ladspa:ladspa-rubberband:rubberband-r3-pitchshifter-stereo::Frequency > Pitch shifters
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
#define RB_PLUGIN_LADSPA 1
|
#define RB_PLUGIN_LADSPA 1
|
||||||
#undef RB_PLUGIN_LV2
|
#undef RB_PLUGIN_LV2
|
||||||
#include "RubberBandPitchShifter.cpp"
|
#include "RubberBandPitchShifter.cpp"
|
||||||
|
#include "RubberBandR3PitchShifter.cpp"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
@@ -31,7 +32,11 @@ extern "C" {
|
|||||||
|
|
||||||
const LADSPA_Descriptor *ladspa_descriptor(unsigned long index)
|
const LADSPA_Descriptor *ladspa_descriptor(unsigned long index)
|
||||||
{
|
{
|
||||||
return RubberBandPitchShifter::getDescriptor(index);
|
if (index < 2) {
|
||||||
|
return RubberBandPitchShifter::getDescriptor(index);
|
||||||
|
} else {
|
||||||
|
return RubberBandR3PitchShifter::getDescriptor(index - 2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
#define RB_PLUGIN_LV2 1
|
#define RB_PLUGIN_LV2 1
|
||||||
#undef RB_PLUGIN_LADSPA
|
#undef RB_PLUGIN_LADSPA
|
||||||
#include "RubberBandPitchShifter.cpp"
|
#include "RubberBandPitchShifter.cpp"
|
||||||
|
#include "RubberBandR3PitchShifter.cpp"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
@@ -32,7 +33,11 @@ extern "C" {
|
|||||||
LV2_SYMBOL_EXPORT
|
LV2_SYMBOL_EXPORT
|
||||||
const LV2_Descriptor *lv2_descriptor(uint32_t index)
|
const LV2_Descriptor *lv2_descriptor(uint32_t index)
|
||||||
{
|
{
|
||||||
return RubberBandPitchShifter::getDescriptor(index);
|
if (index < 2) {
|
||||||
|
return RubberBandPitchShifter::getDescriptor(index);
|
||||||
|
} else {
|
||||||
|
return RubberBandR3PitchShifter::getDescriptor(index - 2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -78,6 +78,16 @@
|
|||||||
lv2:maximum 1 ;
|
lv2:maximum 1 ;
|
||||||
lv2:portProperty lv2:integer, lv2:toggled .
|
lv2:portProperty lv2:integer, lv2:toggled .
|
||||||
|
|
||||||
|
:formantPortR3
|
||||||
|
a lv2:ControlPort, lv2:InputPort ;
|
||||||
|
lv2:index 4 ;
|
||||||
|
lv2:symbol "formant" ;
|
||||||
|
lv2:name "Formant Preserving" ;
|
||||||
|
lv2:default 0 ;
|
||||||
|
lv2:minimum 0 ;
|
||||||
|
lv2:maximum 1 ;
|
||||||
|
lv2:portProperty lv2:integer, lv2:toggled .
|
||||||
|
|
||||||
:wetDryPort
|
:wetDryPort
|
||||||
a lv2:ControlPort, lv2:InputPort ;
|
a lv2:ControlPort, lv2:InputPort ;
|
||||||
lv2:index 6 ;
|
lv2:index 6 ;
|
||||||
@@ -87,6 +97,15 @@
|
|||||||
lv2:minimum 0 ;
|
lv2:minimum 0 ;
|
||||||
lv2:maximum 1 .
|
lv2:maximum 1 .
|
||||||
|
|
||||||
|
:wetDryPortR3
|
||||||
|
a lv2:ControlPort, lv2:InputPort ;
|
||||||
|
lv2:index 5 ;
|
||||||
|
lv2:symbol "wetdry" ;
|
||||||
|
lv2:name "Wet-Dry Mix" ;
|
||||||
|
lv2:default 0 ;
|
||||||
|
lv2:minimum 0 ;
|
||||||
|
lv2:maximum 1 .
|
||||||
|
|
||||||
rubberband:mono_in_group
|
rubberband:mono_in_group
|
||||||
a pg:MonoGroup, pg:InputGroup ;
|
a pg:MonoGroup, pg:InputGroup ;
|
||||||
lv2:symbol "mono_in" ;
|
lv2:symbol "mono_in" ;
|
||||||
@@ -146,6 +165,44 @@ rubberband:mono
|
|||||||
lv2:designation pg:center ;
|
lv2:designation pg:center ;
|
||||||
] .
|
] .
|
||||||
|
|
||||||
|
rubberband:r3mono
|
||||||
|
a doap:Project, lv2:Plugin, lv2:PitchPlugin ;
|
||||||
|
doap:name "Rubber Band R3 Mono Pitch Shifter" ;
|
||||||
|
doap:license <http://usefulinc.com/doap/licenses/gpl> ;
|
||||||
|
foaf:maker :maker ;
|
||||||
|
doap:developer :maker ;
|
||||||
|
doap:maintainer :maker ;
|
||||||
|
# Minor version will be 2x the Rubber Band API minor version,
|
||||||
|
# but this is an initial test release, so 0
|
||||||
|
lv2:minorVersion 0 ;
|
||||||
|
lv2:microVersion 0 ;
|
||||||
|
lv2:optionalFeature lv2:hardRTCapable ;
|
||||||
|
pg:mainInput rubberband:mono_in_group ;
|
||||||
|
pg:mainOutput rubberband:mono_out_group ;
|
||||||
|
dc:replaces <urn:ladspa:29790> ;
|
||||||
|
lv2:port :latencyPort ,
|
||||||
|
:centsPort ,
|
||||||
|
:semitonesPort ,
|
||||||
|
:octavesPort ,
|
||||||
|
:formantPortR3 ,
|
||||||
|
:wetDryPortR3 ,
|
||||||
|
[ a lv2:AudioPort, lv2:InputPort ;
|
||||||
|
lv2:index 6 ;
|
||||||
|
lv2:symbol "input" ;
|
||||||
|
lv2:name "Input" ;
|
||||||
|
lv2:shortName "Input" ;
|
||||||
|
pg:group rubberband:mono_in_group ;
|
||||||
|
lv2:designation pg:center ;
|
||||||
|
], [
|
||||||
|
a lv2:AudioPort, lv2:OutputPort ;
|
||||||
|
lv2:index 7 ;
|
||||||
|
lv2:symbol "output" ;
|
||||||
|
lv2:name "Output" ;
|
||||||
|
lv2:shortName "Output" ;
|
||||||
|
pg:group rubberband:mono_out_group ;
|
||||||
|
lv2:designation pg:center ;
|
||||||
|
] .
|
||||||
|
|
||||||
rubberband:stereo
|
rubberband:stereo
|
||||||
a doap:Project, lv2:Plugin, lv2:PitchPlugin ;
|
a doap:Project, lv2:Plugin, lv2:PitchPlugin ;
|
||||||
doap:name "Rubber Band Stereo Pitch Shifter" ;
|
doap:name "Rubber Band Stereo Pitch Shifter" ;
|
||||||
@@ -200,3 +257,56 @@ rubberband:stereo
|
|||||||
lv2:designation pg:right ;
|
lv2:designation pg:right ;
|
||||||
] .
|
] .
|
||||||
|
|
||||||
|
rubberband:r3stereo
|
||||||
|
a doap:Project, lv2:Plugin, lv2:PitchPlugin ;
|
||||||
|
doap:name "Rubber Band R3 Stereo Pitch Shifter" ;
|
||||||
|
doap:license <http://usefulinc.com/doap/licenses/gpl> ;
|
||||||
|
foaf:maker :maker ;
|
||||||
|
doap:developer :maker ;
|
||||||
|
doap:maintainer :maker ;
|
||||||
|
# Minor version will be 2x the Rubber Band API minor version,
|
||||||
|
# but this is an initial test release, so 0
|
||||||
|
lv2:minorVersion 0 ;
|
||||||
|
lv2:microVersion 0 ;
|
||||||
|
lv2:optionalFeature lv2:hardRTCapable ;
|
||||||
|
pg:mainInput rubberband:stereo_in_group ;
|
||||||
|
pg:mainOutput rubberband:stereo_out_group ;
|
||||||
|
dc:replaces <urn:ladspa:97920> ;
|
||||||
|
lv2:port :latencyPort ,
|
||||||
|
:centsPort ,
|
||||||
|
:semitonesPort ,
|
||||||
|
:octavesPort ,
|
||||||
|
:formantPortR3 ,
|
||||||
|
:wetDryPortR3 ,
|
||||||
|
[ a lv2:AudioPort, lv2:InputPort ;
|
||||||
|
lv2:index 6 ;
|
||||||
|
lv2:symbol "input_l" ;
|
||||||
|
lv2:name "Input L" ;
|
||||||
|
lv2:shortName "Input L" ;
|
||||||
|
pg:group rubberband:stereo_in_group ;
|
||||||
|
lv2:designation pg:left ;
|
||||||
|
], [
|
||||||
|
a lv2:AudioPort, lv2:OutputPort ;
|
||||||
|
lv2:index 7 ;
|
||||||
|
lv2:symbol "output_l" ;
|
||||||
|
lv2:name "Output L" ;
|
||||||
|
lv2:shortName "Output L" ;
|
||||||
|
pg:group rubberband:stereo_out_group ;
|
||||||
|
lv2:designation pg:left ;
|
||||||
|
], [ a lv2:AudioPort, lv2:InputPort ;
|
||||||
|
lv2:index 8 ;
|
||||||
|
lv2:symbol "input_r" ;
|
||||||
|
lv2:name "Input R" ;
|
||||||
|
lv2:shortName "Input R" ;
|
||||||
|
pg:group rubberband:stereo_in_group ;
|
||||||
|
lv2:designation pg:right ;
|
||||||
|
], [
|
||||||
|
a lv2:AudioPort, lv2:OutputPort ;
|
||||||
|
lv2:index 9 ;
|
||||||
|
lv2:symbol "output_r" ;
|
||||||
|
lv2:name "Output R" ;
|
||||||
|
lv2:shortName "Output R" ;
|
||||||
|
pg:group rubberband:stereo_out_group ;
|
||||||
|
lv2:designation pg:right ;
|
||||||
|
] .
|
||||||
|
|
||||||
|
|||||||
@@ -7,8 +7,18 @@ rubberband:mono
|
|||||||
lv2:binary <lv2-rubberband.so> ;
|
lv2:binary <lv2-rubberband.so> ;
|
||||||
rdfs:seeAlso <lv2-rubberband.ttl> .
|
rdfs:seeAlso <lv2-rubberband.ttl> .
|
||||||
|
|
||||||
|
rubberband:r3mono
|
||||||
|
a lv2:Plugin ;
|
||||||
|
lv2:binary <lv2-rubberband.so> ;
|
||||||
|
rdfs:seeAlso <lv2-rubberband.ttl> .
|
||||||
|
|
||||||
rubberband:stereo
|
rubberband:stereo
|
||||||
a lv2:Plugin ;
|
a lv2:Plugin ;
|
||||||
lv2:binary <lv2-rubberband.so> ;
|
lv2:binary <lv2-rubberband.so> ;
|
||||||
rdfs:seeAlso <lv2-rubberband.ttl> .
|
rdfs:seeAlso <lv2-rubberband.ttl> .
|
||||||
|
|
||||||
|
rubberband:r3stereo
|
||||||
|
a lv2:Plugin ;
|
||||||
|
lv2:binary <lv2-rubberband.so> ;
|
||||||
|
rdfs:seeAlso <lv2-rubberband.ttl> .
|
||||||
|
|
||||||
|
|||||||
@@ -190,6 +190,7 @@ R3StretcherImpl::setFormantOption(RubberBandStretcher::Options options)
|
|||||||
m_parameters.options |= options;
|
m_parameters.options |= options;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//!!! unused?
|
||||||
void
|
void
|
||||||
R3StretcherImpl::setPitchOption(RubberBandStretcher::Options options)
|
R3StretcherImpl::setPitchOption(RubberBandStretcher::Options options)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user