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

View file

@ -221,6 +221,9 @@ namespace Default
constexpr Range<float> egOnCCPercentRange { -100.0, 100.0 }; constexpr Range<float> egOnCCPercentRange { -100.0, 100.0 };
// ***** SFZ v2 ******** // ***** SFZ v2 ********
constexpr int sampleQuality { 2 };
constexpr Range<int> sampleQualityRange { 1, 10 }; // sample_quality
constexpr bool checkSustain { true }; // sustain_sw constexpr bool checkSustain { true }; // sustain_sw
constexpr bool checkSostenuto { true }; // sostenuto_sw constexpr bool checkSostenuto { true }; // sostenuto_sw
constexpr Range<int> octaveOffsetRange { -10, 10 }; // octave_offset 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()); sampleId = FileId(std::move(filename), sampleId.isReverse());
} }
break; break;
case hash("sample_quality"):
{
setValueFromOpcode(opcode, sampleQuality, Default::sampleQualityRange);
break;
}
break;
case hash("direction"): case hash("direction"):
sampleId = sampleId.reversed(opcode.value == "reverse"); sampleId = sampleId.reversed(opcode.value == "reverse");
break; break;

View file

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

View file

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

View file

@ -19,6 +19,7 @@
#include <random> #include <random>
namespace sfz { namespace sfz {
enum InterpolatorModel : int;
/** /**
* @brief The SFZ voice are the polyphony holders. They get activated by the synth * @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 * and tasked to play a given region until the end, stopping on note-offs, off-groups
@ -242,6 +243,20 @@ private:
* @param buffer * @param buffer
*/ */
void fillWithGenerator(AudioSpan<float> buffer) noexcept; 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 amplitudeEnvelope(absl::Span<float> modulationSpan) noexcept;
void ampStageMono(AudioSpan<float> buffer) noexcept; void ampStageMono(AudioSpan<float> buffer) noexcept;
void ampStageStereo(AudioSpan<float> buffer) noexcept; void ampStageStereo(AudioSpan<float> buffer) noexcept;