* Add library API version to headers
* Add phase reset on silence (doesn't appear to make much difference) * Fix mistake in LRDF file
This commit is contained in:
@@ -55,6 +55,7 @@ LIBRARY_INCLUDES := \
|
|||||||
src/Resampler.h \
|
src/Resampler.h \
|
||||||
src/RingBuffer.h \
|
src/RingBuffer.h \
|
||||||
src/Scavenger.h \
|
src/Scavenger.h \
|
||||||
|
src/SilentAudioCurve.h \
|
||||||
src/SpectralDifferenceAudioCurve.h \
|
src/SpectralDifferenceAudioCurve.h \
|
||||||
src/StretchCalculator.h \
|
src/StretchCalculator.h \
|
||||||
src/StretcherImpl.h \
|
src/StretcherImpl.h \
|
||||||
@@ -73,6 +74,7 @@ LIBRARY_SOURCES := \
|
|||||||
src/Resampler.cpp \
|
src/Resampler.cpp \
|
||||||
src/rubberband-c.cpp \
|
src/rubberband-c.cpp \
|
||||||
src/RubberBandStretcher.cpp \
|
src/RubberBandStretcher.cpp \
|
||||||
|
src/SilentAudioCurve.cpp \
|
||||||
src/SpectralDifferenceAudioCurve.cpp \
|
src/SpectralDifferenceAudioCurve.cpp \
|
||||||
src/StretchCalculator.cpp \
|
src/StretchCalculator.cpp \
|
||||||
src/StretcherImpl.cpp \
|
src/StretcherImpl.cpp \
|
||||||
|
|||||||
@@ -14,6 +14,9 @@
|
|||||||
|
|
||||||
#ifndef _RUBBERBANDSTRETCHER_H_
|
#ifndef _RUBBERBANDSTRETCHER_H_
|
||||||
#define _RUBBERBANDSTRETCHER_H_
|
#define _RUBBERBANDSTRETCHER_H_
|
||||||
|
|
||||||
|
#define RUBBERBAND_API_MAJOR_VERSION 2
|
||||||
|
#define RUBBERBAND_API_MINOR_VERSION 0
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,9 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define RUBBERBAND_API_MAJOR_VERSION 2
|
||||||
|
#define RUBBERBAND_API_MINOR_VERSION 0
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is a C-linkage interface to the Rubber Band time stretcher.
|
* This is a C-linkage interface to the Rubber Band time stretcher.
|
||||||
*
|
*
|
||||||
|
|||||||
69
src/SilentAudioCurve.cpp
Normal file
69
src/SilentAudioCurve.cpp
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
||||||
|
|
||||||
|
/*
|
||||||
|
Rubber Band
|
||||||
|
An audio time-stretching and pitch-shifting library.
|
||||||
|
Copyright 2007-2008 Chris Cannam.
|
||||||
|
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "SilentAudioCurve.h"
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
namespace RubberBand
|
||||||
|
{
|
||||||
|
|
||||||
|
SilentAudioCurve::SilentAudioCurve(size_t sampleRate, size_t windowSize) :
|
||||||
|
AudioCurve(sampleRate, windowSize)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
SilentAudioCurve::~SilentAudioCurve()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SilentAudioCurve::reset()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SilentAudioCurve::setWindowSize(size_t newSize)
|
||||||
|
{
|
||||||
|
m_windowSize = newSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
float
|
||||||
|
SilentAudioCurve::process(const float *R__ mag, size_t)
|
||||||
|
{
|
||||||
|
const int hs = m_windowSize / 2;
|
||||||
|
static float threshold = powf(10.f, -6);
|
||||||
|
|
||||||
|
for (int i = 0; i <= hs; ++i) {
|
||||||
|
if (mag[i] > threshold) return 0.f;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1.f;
|
||||||
|
}
|
||||||
|
|
||||||
|
float
|
||||||
|
SilentAudioCurve::process(const double *R__ mag, size_t)
|
||||||
|
{
|
||||||
|
const int hs = m_windowSize / 2;
|
||||||
|
static double threshold = pow(10.0, -6);
|
||||||
|
|
||||||
|
for (int i = 0; i <= hs; ++i) {
|
||||||
|
if (mag[i] > threshold) return 0.f;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1.f;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
38
src/SilentAudioCurve.h
Normal file
38
src/SilentAudioCurve.h
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
||||||
|
|
||||||
|
/*
|
||||||
|
Rubber Band
|
||||||
|
An audio time-stretching and pitch-shifting library.
|
||||||
|
Copyright 2007-2008 Chris Cannam.
|
||||||
|
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _SILENT_AUDIO_CURVE_H_
|
||||||
|
#define _SILENT_AUDIO_CURVE_H_
|
||||||
|
|
||||||
|
#include "AudioCurve.h"
|
||||||
|
|
||||||
|
namespace RubberBand
|
||||||
|
{
|
||||||
|
|
||||||
|
class SilentAudioCurve : public AudioCurve
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SilentAudioCurve(size_t sampleRate, size_t windowSize);
|
||||||
|
virtual ~SilentAudioCurve();
|
||||||
|
|
||||||
|
virtual void setWindowSize(size_t newSize);
|
||||||
|
|
||||||
|
virtual float process(const float *R__ mag, size_t increment);
|
||||||
|
virtual float process(const double *R__ mag, size_t increment);
|
||||||
|
virtual void reset();
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -16,6 +16,7 @@
|
|||||||
#include "PercussiveAudioCurve.h"
|
#include "PercussiveAudioCurve.h"
|
||||||
#include "HighFrequencyAudioCurve.h"
|
#include "HighFrequencyAudioCurve.h"
|
||||||
#include "SpectralDifferenceAudioCurve.h"
|
#include "SpectralDifferenceAudioCurve.h"
|
||||||
|
#include "SilentAudioCurve.h"
|
||||||
#include "ConstantAudioCurve.h"
|
#include "ConstantAudioCurve.h"
|
||||||
#include "StretchCalculator.h"
|
#include "StretchCalculator.h"
|
||||||
#include "StretcherChannelData.h"
|
#include "StretcherChannelData.h"
|
||||||
@@ -72,6 +73,7 @@ RubberBandStretcher::Impl::Impl(size_t sampleRate,
|
|||||||
m_studyFFT(0),
|
m_studyFFT(0),
|
||||||
m_spaceAvailable("space"),
|
m_spaceAvailable("space"),
|
||||||
m_inputDuration(0),
|
m_inputDuration(0),
|
||||||
|
m_silentHistory(0),
|
||||||
m_lastProcessOutputIncrements(16),
|
m_lastProcessOutputIncrements(16),
|
||||||
m_lastProcessPhaseResetDf(16),
|
m_lastProcessPhaseResetDf(16),
|
||||||
m_phaseResetAudioCurve(0),
|
m_phaseResetAudioCurve(0),
|
||||||
@@ -163,6 +165,7 @@ RubberBandStretcher::Impl::~Impl()
|
|||||||
|
|
||||||
delete m_phaseResetAudioCurve;
|
delete m_phaseResetAudioCurve;
|
||||||
delete m_stretchAudioCurve;
|
delete m_stretchAudioCurve;
|
||||||
|
delete m_silentAudioCurve;
|
||||||
delete m_stretchCalculator;
|
delete m_stretchCalculator;
|
||||||
delete m_studyFFT;
|
delete m_studyFFT;
|
||||||
|
|
||||||
@@ -196,7 +199,9 @@ RubberBandStretcher::Impl::reset()
|
|||||||
m_mode = JustCreated;
|
m_mode = JustCreated;
|
||||||
if (m_phaseResetAudioCurve) m_phaseResetAudioCurve->reset();
|
if (m_phaseResetAudioCurve) m_phaseResetAudioCurve->reset();
|
||||||
if (m_stretchAudioCurve) m_stretchAudioCurve->reset();
|
if (m_stretchAudioCurve) m_stretchAudioCurve->reset();
|
||||||
|
if (m_silentAudioCurve) m_silentAudioCurve->reset();
|
||||||
m_inputDuration = 0;
|
m_inputDuration = 0;
|
||||||
|
m_silentHistory = 0;
|
||||||
|
|
||||||
if (m_threaded) m_threadSetMutex.unlock();
|
if (m_threaded) m_threadSetMutex.unlock();
|
||||||
|
|
||||||
@@ -361,8 +366,8 @@ RubberBandStretcher::Impl::calculateSizes()
|
|||||||
outputIncrement /= 2;
|
outputIncrement /= 2;
|
||||||
inputIncrement = int(outputIncrement / r);
|
inputIncrement = int(outputIncrement / r);
|
||||||
}
|
}
|
||||||
size_t minwin = roundUp(lrint(outputIncrement * windowIncrRatio));
|
size_t minwin = roundUp(lrint(outputIncrement * windowIncrRatio));
|
||||||
if (windowSize < minwin) windowSize = minwin;
|
if (windowSize < minwin) windowSize = minwin;
|
||||||
|
|
||||||
if (rsb) {
|
if (rsb) {
|
||||||
// cerr << "adjusting window size from " << windowSize;
|
// cerr << "adjusting window size from " << windowSize;
|
||||||
@@ -546,12 +551,17 @@ RubberBandStretcher::Impl::configure()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
delete m_phaseResetAudioCurve;
|
// stretchAudioCurve is unused in RT mode; phaseResetAudioCurve,
|
||||||
m_phaseResetAudioCurve = new PercussiveAudioCurve(m_sampleRate,
|
// silentAudioCurve and stretchCalculator however are used in all
|
||||||
m_windowSize);
|
// modes
|
||||||
|
|
||||||
// stretchAudioCurve unused in RT mode; phaseResetAudioCurve and
|
delete m_phaseResetAudioCurve;
|
||||||
// stretchCalculator however are used in all modes
|
m_phaseResetAudioCurve = new PercussiveAudioCurve
|
||||||
|
(m_sampleRate, m_windowSize);
|
||||||
|
|
||||||
|
delete m_silentAudioCurve;
|
||||||
|
m_silentAudioCurve = new SilentAudioCurve
|
||||||
|
(m_sampleRate, m_windowSize);
|
||||||
|
|
||||||
if (!m_realtime) {
|
if (!m_realtime) {
|
||||||
delete m_stretchAudioCurve;
|
delete m_stretchAudioCurve;
|
||||||
@@ -602,6 +612,7 @@ RubberBandStretcher::Impl::reconfigure()
|
|||||||
calculateStretch();
|
calculateStretch();
|
||||||
m_phaseResetDf.clear();
|
m_phaseResetDf.clear();
|
||||||
m_stretchDf.clear();
|
m_stretchDf.clear();
|
||||||
|
m_silence.clear();
|
||||||
m_inputDuration = 0;
|
m_inputDuration = 0;
|
||||||
}
|
}
|
||||||
configure();
|
configure();
|
||||||
@@ -782,8 +793,8 @@ RubberBandStretcher::Impl::study(const float *const *input, size_t samples, bool
|
|||||||
consumed += writable;
|
consumed += writable;
|
||||||
}
|
}
|
||||||
|
|
||||||
while ((inbuf.getReadSpace() >= m_windowSize) ||
|
while ((inbuf.getReadSpace() >= int(m_windowSize)) ||
|
||||||
(final && (inbuf.getReadSpace() >= m_windowSize/2))) {
|
(final && (inbuf.getReadSpace() >= int(m_windowSize/2)))) {
|
||||||
|
|
||||||
// We know we have at least m_windowSize samples available
|
// We know we have at least m_windowSize samples available
|
||||||
// in m_inbuf. We need to peek m_windowSize of them for
|
// in m_inbuf. We need to peek m_windowSize of them for
|
||||||
@@ -811,6 +822,11 @@ RubberBandStretcher::Impl::study(const float *const *input, size_t samples, bool
|
|||||||
df = m_stretchAudioCurve->process(cd.fltbuf, m_increment);
|
df = m_stretchAudioCurve->process(cd.fltbuf, m_increment);
|
||||||
m_stretchDf.push_back(df);
|
m_stretchDf.push_back(df);
|
||||||
|
|
||||||
|
df = m_silentAudioCurve->process(cd.fltbuf, m_increment);
|
||||||
|
bool silent = (df > 0.f);
|
||||||
|
if (silent) cerr << "silence found at " << m_inputDuration << endl;
|
||||||
|
m_silence.push_back(silent);
|
||||||
|
|
||||||
// cout << df << endl;
|
// cout << df << endl;
|
||||||
|
|
||||||
// We have augmented the input by m_windowSize/2 so
|
// We have augmented the input by m_windowSize/2 so
|
||||||
@@ -892,6 +908,20 @@ RubberBandStretcher::Impl::calculateStretch()
|
|||||||
m_phaseResetDf,
|
m_phaseResetDf,
|
||||||
m_stretchDf);
|
m_stretchDf);
|
||||||
|
|
||||||
|
int history = 0;
|
||||||
|
for (size_t i = 0; i < increments.size(); ++i) {
|
||||||
|
if (i >= m_silence.size()) break;
|
||||||
|
if (m_silence[i]) ++history;
|
||||||
|
else history = 0;
|
||||||
|
if (history >= (m_windowSize / m_increment) && increments[i] >= 0) {
|
||||||
|
increments[i] = -increments[i];
|
||||||
|
// if (m_debugLevel > 1) {
|
||||||
|
std::cerr << "phase reset on silence (silent history == "
|
||||||
|
<< history << ")" << std::endl;
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (m_outputIncrements.empty()) m_outputIncrements = increments;
|
if (m_outputIncrements.empty()) m_outputIncrements = increments;
|
||||||
else {
|
else {
|
||||||
for (size_t i = 0; i < increments.size(); ++i) {
|
for (size_t i = 0; i < increments.size(); ++i) {
|
||||||
@@ -1055,7 +1085,7 @@ RubberBandStretcher::Impl::process(const float *const *input, size_t samples, bo
|
|||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!allConsumed) cerr << "process looping" << endl;
|
// if (!allConsumed) cerr << "process looping" << endl;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -166,6 +166,8 @@ protected:
|
|||||||
size_t m_inputDuration;
|
size_t m_inputDuration;
|
||||||
std::vector<float> m_phaseResetDf;
|
std::vector<float> m_phaseResetDf;
|
||||||
std::vector<float> m_stretchDf;
|
std::vector<float> m_stretchDf;
|
||||||
|
std::vector<bool> m_silence;
|
||||||
|
int m_silentHistory;
|
||||||
|
|
||||||
class ChannelData;
|
class ChannelData;
|
||||||
std::vector<ChannelData *> m_channelData;
|
std::vector<ChannelData *> m_channelData;
|
||||||
@@ -177,6 +179,7 @@ protected:
|
|||||||
|
|
||||||
AudioCurve *m_phaseResetAudioCurve;
|
AudioCurve *m_phaseResetAudioCurve;
|
||||||
AudioCurve *m_stretchAudioCurve;
|
AudioCurve *m_stretchAudioCurve;
|
||||||
|
AudioCurve *m_silentAudioCurve;
|
||||||
StretchCalculator *m_stretchCalculator;
|
StretchCalculator *m_stretchCalculator;
|
||||||
|
|
||||||
float m_freq0;
|
float m_freq0;
|
||||||
|
|||||||
@@ -147,8 +147,6 @@ RubberBandStretcher::Impl::consumeChannel(size_t c, const float *input,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// std::cerr << "resampling on INPUT" << std::endl;
|
|
||||||
|
|
||||||
toWrite = cd.resampler->resample(&input,
|
toWrite = cd.resampler->resample(&input,
|
||||||
&cd.resamplebuf,
|
&cd.resamplebuf,
|
||||||
samples,
|
samples,
|
||||||
@@ -445,10 +443,12 @@ RubberBandStretcher::Impl::calculateIncrements(size_t &phaseIncrementRtn,
|
|||||||
// be apparent.
|
// be apparent.
|
||||||
|
|
||||||
float df = 0.f;
|
float df = 0.f;
|
||||||
|
bool silent = false;
|
||||||
|
|
||||||
if (m_channels == 1) {
|
if (m_channels == 1) {
|
||||||
|
|
||||||
df = m_phaseResetAudioCurve->process(cd.mag, m_increment);
|
df = m_phaseResetAudioCurve->process(cd.mag, m_increment);
|
||||||
|
silent = (m_silentAudioCurve->process(cd.mag, m_increment) > 0.f);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
@@ -464,7 +464,8 @@ RubberBandStretcher::Impl::calculateIncrements(size_t &phaseIncrementRtn,
|
|||||||
}
|
}
|
||||||
|
|
||||||
df = m_phaseResetAudioCurve->process(tmp, m_increment);
|
df = m_phaseResetAudioCurve->process(tmp, m_increment);
|
||||||
}
|
silent = (m_silentAudioCurve->process(tmp, m_increment) > 0.f);
|
||||||
|
}
|
||||||
|
|
||||||
int incr = m_stretchCalculator->calculateSingle
|
int incr = m_stretchCalculator->calculateSingle
|
||||||
(getEffectiveRatio(), df, m_increment);
|
(getEffectiveRatio(), df, m_increment);
|
||||||
@@ -499,6 +500,17 @@ RubberBandStretcher::Impl::calculateIncrements(size_t &phaseIncrementRtn,
|
|||||||
}
|
}
|
||||||
|
|
||||||
cd.prevIncrement = shiftIncrementRtn;
|
cd.prevIncrement = shiftIncrementRtn;
|
||||||
|
|
||||||
|
if (silent) ++m_silentHistory;
|
||||||
|
else m_silentHistory = 0;
|
||||||
|
|
||||||
|
if (m_silentHistory >= (m_windowSize / m_increment) && !phaseReset) {
|
||||||
|
phaseReset = true;
|
||||||
|
if (m_debugLevel > 1) {
|
||||||
|
std::cerr << "calculateIncrements: phase reset on silence (silent history == "
|
||||||
|
<< m_silentHistory << ")" << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
@@ -852,12 +864,9 @@ RubberBandStretcher::Impl::formantShiftChunk(size_t channel)
|
|||||||
dblbuf[i] /= denom;
|
dblbuf[i] /= denom;
|
||||||
}
|
}
|
||||||
|
|
||||||
//!!! calculate this value -- the divisor should be the highest fundamental frequency we expect to find, plus a bit
|
|
||||||
const int cutoff = m_sampleRate / 700;
|
const int cutoff = m_sampleRate / 700;
|
||||||
// const int cutoff = 1000;
|
|
||||||
// const int cutoff = 20;
|
|
||||||
|
|
||||||
// cerr <<"cutoff = "<< cutoff << ", m_sampleRate/cutoff = " << m_sampleRate/cutoff << ", m_sampleRate/700 = " << m_sampleRate/700 << endl;
|
// cerr <<"cutoff = "<< cutoff << ", m_sampleRate/cutoff = " << m_sampleRate/cutoff << endl;
|
||||||
|
|
||||||
dblbuf[0] /= 2;
|
dblbuf[0] /= 2;
|
||||||
dblbuf[cutoff-1] /= 2;
|
dblbuf[cutoff-1] /= 2;
|
||||||
@@ -880,7 +889,7 @@ RubberBandStretcher::Impl::formantShiftChunk(size_t channel)
|
|||||||
// scaling up, we want a new envelope that is lower by the pitch factor
|
// scaling up, we want a new envelope that is lower by the pitch factor
|
||||||
for (int target = 0; target <= hs; ++target) {
|
for (int target = 0; target <= hs; ++target) {
|
||||||
int source = lrint(target * m_pitchScale);
|
int source = lrint(target * m_pitchScale);
|
||||||
if (source > m_windowSize) {
|
if (source > int(m_windowSize)) {
|
||||||
envelope[target] = 0.0;
|
envelope[target] = 0.0;
|
||||||
} else {
|
} else {
|
||||||
envelope[target] = envelope[source];
|
envelope[target] = envelope[source];
|
||||||
@@ -897,7 +906,6 @@ RubberBandStretcher::Impl::formantShiftChunk(size_t channel)
|
|||||||
|
|
||||||
for (int i = 0; i <= hs; ++i) {
|
for (int i = 0; i <= hs; ++i) {
|
||||||
mag[i] *= envelope[i];
|
mag[i] *= envelope[i];
|
||||||
// mag[i] = envelope[i];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cd.unchanged = false;
|
cd.unchanged = false;
|
||||||
@@ -957,10 +965,8 @@ RubberBandStretcher::Impl::synthesiseChunk(size_t channel)
|
|||||||
|
|
||||||
// our ffts produced unscaled results
|
// our ffts produced unscaled results
|
||||||
for (i = 0; i < sz; ++i) {
|
for (i = 0; i < sz; ++i) {
|
||||||
fltbuf[i] = fltbuf[i] / float(sz * cd.oversample);
|
fltbuf[i] = fltbuf[i] / denom;
|
||||||
}
|
}
|
||||||
// } else {
|
|
||||||
// cerr << "unchanged on channel " << channel << endl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_window->cut(fltbuf);
|
m_window->cut(fltbuf);
|
||||||
@@ -1030,8 +1036,6 @@ RubberBandStretcher::Impl::writeChunk(size_t channel, size_t shiftIncrement, boo
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// std::cerr << "resampling on OUTPUT" << std::endl;
|
|
||||||
|
|
||||||
size_t outframes = cd.resampler->resample(&cd.accumulator,
|
size_t outframes = cd.resampler->resample(&cd.accumulator,
|
||||||
&cd.resamplebuf,
|
&cd.resamplebuf,
|
||||||
si,
|
si,
|
||||||
|
|||||||
@@ -10,3 +10,5 @@
|
|||||||
<ladspa:PitchPlugin rdf:about="&ladspa;2979"/>
|
<ladspa:PitchPlugin rdf:about="&ladspa;2979"/>
|
||||||
<ladspa:PitchPlugin rdf:about="&ladspa;9792"/>
|
<ladspa:PitchPlugin rdf:about="&ladspa;9792"/>
|
||||||
|
|
||||||
|
</rdf:RDF>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user