Add the opcode sample_quality and default value to 2

This commit is contained in:
Jean Pierre Cimalando 2020-05-16 16:16:52 +02:00
parent 51502eaed3
commit 4ff54b3158
6 changed files with 72 additions and 20 deletions

View file

@ -246,7 +246,7 @@ public:
* @param channelIndex the channel
* @return absl::Span<const Type>
*/
absl::Span<const Type> getConstSpan(size_t channelIndex)
absl::Span<const Type> getConstSpan(size_t channelIndex) const
{
ASSERT(channelIndex < numChannels);
if (channelIndex < numChannels)
@ -382,7 +382,7 @@ public:
*
* @returns size_type the number of frames in the AudioSpan
*/
size_type getNumFrames()
size_type getNumFrames() const
{
return numFrames;
}
@ -392,7 +392,7 @@ public:
*
* @returns size_type the number of channels in the AudioSpan
*/
size_t getNumChannels()
size_t getNumChannels() const
{
return numChannels;
}

View file

@ -221,6 +221,9 @@ namespace Default
constexpr Range<float> egOnCCPercentRange { -100.0, 100.0 };
// ***** SFZ v2 ********
constexpr int sampleQuality { 2 };
constexpr Range<int> sampleQualityRange { 1, 10 }; // sample_quality
constexpr bool checkSustain { true }; // sustain_sw
constexpr bool checkSostenuto { true }; // sostenuto_sw
constexpr Range<int> octaveOffsetRange { -10, 10 }; // octave_offset

View file

@ -60,6 +60,12 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode)
sampleId = FileId(std::move(filename), sampleId.isReverse());
}
break;
case hash("sample_quality"):
{
setValueFromOpcode(opcode, sampleQuality, Default::sampleQualityRange);
break;
}
break;
case hash("direction"):
sampleId = sampleId.reversed(opcode.value == "reverse");
break;

View file

@ -240,6 +240,7 @@ struct Region {
// Sound source: sample playback
FileId sampleId {}; // Sample
int sampleQuality { Default::sampleQuality };
float delay { Default::delay }; // delay
float delayRandom { Default::delayRandom }; // delay_random
int64_t offset { Default::offset }; // offset

View file

@ -506,23 +506,25 @@ void sfz::Voice::fillWithData(AudioSpan<float> buffer) noexcept
}
}
auto ind = indices->data();
auto coeff = coeffs->data();
auto leftSource = source.getConstSpan(0);
auto left = buffer.getChannel(0);
if (source.getNumChannels() == 1) {
while (ind < indices->end()) {
*left = interpolate<kInterpolatorBspline3>(&leftSource[*ind], *coeff);
incrementAll(ind, left, coeff);
}
} else {
auto right = buffer.getChannel(1);
auto rightSource = source.getConstSpan(1);
while (ind < indices->end()) {
*left = interpolate<kInterpolatorBspline3>(&leftSource[*ind], *coeff);
*right = interpolate<kInterpolatorBspline3>(&rightSource[*ind], *coeff);
incrementAll(ind, left, right, coeff);
}
const int quality = region->sampleQuality;
switch (quality) {
default:
if (quality > 2)
goto high; // TODO sinc, not implemented
// fall through
case 1:
fillInterpolated<kInterpolatorLinear>(source, buffer, *indices, *coeffs);
break;
case 2: high:
#if 1
// B-spline response has faster decay of aliasing, but not zero-crossings at integer positions
fillInterpolated<kInterpolatorBspline3>(source, buffer, *indices, *coeffs);
#else
// Hermite polynomial
fillInterpolated<kInterpolatorHermite3>(source, buffer, *indices, *coeffs);
#endif
break;
}
sourcePosition = indices->back();
@ -536,6 +538,31 @@ void sfz::Voice::fillWithData(AudioSpan<float> buffer) noexcept
#endif
}
template <sfz::InterpolatorModel M>
void sfz::Voice::fillInterpolated(
const sfz::AudioSpan<const float>& source, sfz::AudioSpan<float>& dest,
absl::Span<const int> indices, absl::Span<const float> coeffs)
{
auto ind = indices.data();
auto coeff = coeffs.data();
auto leftSource = source.getConstSpan(0);
auto left = dest.getChannel(0);
if (source.getNumChannels() == 1) {
while (ind < indices.end()) {
*left = sfz::interpolate<M>(&leftSource[*ind], *coeff);
incrementAll(ind, left, coeff);
}
} else {
auto right = dest.getChannel(1);
auto rightSource = source.getConstSpan(1);
while (ind < indices.end()) {
*left = sfz::interpolate<M>(&leftSource[*ind], *coeff);
*right = sfz::interpolate<M>(&rightSource[*ind], *coeff);
incrementAll(ind, left, right, coeff);
}
}
}
void sfz::Voice::fillWithGenerator(AudioSpan<float> buffer) noexcept
{
const auto leftSpan = buffer.getSpan(0);

View file

@ -19,6 +19,7 @@
#include <random>
namespace sfz {
enum InterpolatorModel : int;
/**
* @brief The SFZ voice are the polyphony holders. They get activated by the synth
* and tasked to play a given region until the end, stopping on note-offs, off-groups
@ -242,6 +243,20 @@ private:
* @param buffer
*/
void fillWithGenerator(AudioSpan<float> buffer) noexcept;
/**
* @brief Fill a destination with an interpolated source.
*
* @param source the source sample
* @param dest the destination buffer
* @param indices the integral parts of the source positions
* @param coeffs the fractional parts of the source positions
*/
template <sfz::InterpolatorModel M>
static void fillInterpolated(
const sfz::AudioSpan<const float>& source, sfz::AudioSpan<float>& dest,
absl::Span<const int> indices, absl::Span<const float> coeffs);
void amplitudeEnvelope(absl::Span<float> modulationSpan) noexcept;
void ampStageMono(AudioSpan<float> buffer) noexcept;
void ampStageStereo(AudioSpan<float> buffer) noexcept;