Add the sample quality API

This commit is contained in:
Jean Pierre Cimalando 2020-06-11 13:51:37 +02:00
parent 3994089233
commit 336a435773
12 changed files with 180 additions and 9 deletions

View file

@ -40,6 +40,13 @@ typedef enum {
SFIZZ_OVERSAMPLING_X4 = 4,
SFIZZ_OVERSAMPLING_X8 = 8
} sfizz_oversampling_factor_t;
/**
* @brief Processing mode
*/
typedef enum {
SFIZZ_PROCESS_LIVE,
SFIZZ_PROCESS_FREEWHEELING,
} sfizz_process_mode_t;
/**
* @brief Creates a sfizz synth. This object has to be freed by the caller
@ -366,6 +373,33 @@ SFIZZ_EXPORTED_API sfizz_oversampling_factor_t sfizz_get_oversampling_factor(sfi
*/
SFIZZ_EXPORTED_API bool sfizz_set_oversampling_factor(sfizz_synth_t* synth, sfizz_oversampling_factor_t oversampling);
/**
* @brief Get the default resampling quality. This is the quality setting
* which the engine uses when the instrument does not use the
* opcode `sample_quality`. The engine uses distinct default quality
* settings for live mode and freewheeling mode, which both can be
* accessed by the means of this function.
*
* @param synth The synth.
* @param[in] mode The processing mode.
*
* @return The sample quality for the given mode, in the range 1 to 10.
*/
SFIZZ_EXPORTED_API int sfizz_get_sample_quality(sfizz_synth_t* synth, sfizz_process_mode_t mode);
/**
* @brief Set the default resampling quality. This is the quality setting
* which the engine uses when the instrument does not use the
* opcode `sample_quality`. The engine uses distinct default quality
* settings for live mode and freewheeling mode, which both can be
* accessed by the means of this function.
*
* @param synth The synth.
* @param[in] mode The processing mode.
* @param[in] quality The desired sample quality, in the range 1 to 10.
*/
SFIZZ_EXPORTED_API void sfizz_set_sample_quality(sfizz_synth_t* synth, sfizz_process_mode_t mode, int quality);
/**
* @brief Set the global instrument volume.
*

View file

@ -43,6 +43,14 @@ public:
Sfizz();
~Sfizz();
/**
* @brief Processing mode
*/
enum ProcessMode {
ProcessLive,
ProcessFreewheeling,
};
/**
* @brief Empties the current regions and load a new SFZ file into the synth.
*
@ -174,6 +182,31 @@ public:
*/
void setSampleRate(float sampleRate) noexcept;
/**
* @brief Get the default resampling quality. This is the quality setting
* which the engine uses when the instrument does not use the
* opcode `sample_quality`. The engine uses distinct default quality
* settings for live mode and freewheeling mode, which both can be
* accessed by the means of this function.
*
* @param[in] mode The processing mode.
*
* @return The sample quality for the given mode, in the range 1 to 10.
*/
int getSampleQuality(ProcessMode mode);
/**
* @brief Set the default resampling quality. This is the quality setting
* which the engine uses when the instrument does not use the
* opcode `sample_quality`. The engine uses distinct default quality
* settings for live mode and freewheeling mode, which both can be
* accessed by the means of this function.
*
* @param[in] mode The processing mode.
* @param[in] quality The desired sample quality, in the range 1 to 10.
*/
void setSampleQuality(ProcessMode mode, int quality);
/**
* @brief Return the current value for the volume, in dB.
*/

View file

@ -222,6 +222,7 @@ namespace Default
// ***** SFZ v2 ********
constexpr int sampleQuality { 2 };
constexpr int sampleQualityInFreewheelingMode { 10 }; // for future use, possibly excessive
constexpr Range<int> sampleQualityRange { 1, 10 }; // sample_quality
constexpr bool checkSustain { true }; // sustain_sw

View file

@ -62,7 +62,10 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode)
break;
case hash("sample_quality"):
{
setValueFromOpcode(opcode, sampleQuality, Default::sampleQualityRange);
if (opcode.value == "-1")
sampleQuality.reset();
else
setValueFromOpcode(opcode, sampleQuality, Default::sampleQualityRange);
break;
}
break;

View file

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

View file

@ -5,6 +5,7 @@
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
#pragma once
#include "SynthConfig.h"
#include "FilePool.h"
#include "BufferPool.h"
#include "FilterPool.h"
@ -21,6 +22,7 @@ class WavetableMulti;
struct Resources
{
SynthConfig synthConfig;
BufferPool bufferPool;
MidiState midiState;
Logger logger;

View file

@ -667,7 +667,7 @@ void sfz::Synth::renderBlock(AudioSpan<float> buffer) noexcept
buffer.fill(0.0f);
}
if (freeWheeling)
if (resources.synthConfig.freeWheeling)
resources.filePool.waitForBackgroundLoading();
const std::unique_lock<std::mutex> lock { callbackGuard, std::try_to_lock };
@ -1112,6 +1112,34 @@ size_t sfz::Synth::getNumPreloadedSamples() const noexcept
return resources.filePool.getNumPreloadedSamples();
}
int sfz::Synth::getSampleQuality(ProcessMode mode)
{
switch (mode) {
case ProcessLive:
return resources.synthConfig.liveSampleQuality;
case ProcessFreewheeling:
return resources.synthConfig.freeWheelingSampleQuality;
default:
CHECK(false);
return 0;
}
}
void sfz::Synth::setSampleQuality(ProcessMode mode, int quality)
{
switch (mode) {
case ProcessLive:
resources.synthConfig.liveSampleQuality = quality;
break;
case ProcessFreewheeling:
resources.synthConfig.freeWheelingSampleQuality = quality;
break;
default:
CHECK(false);
break;
}
}
float sfz::Synth::getVolume() const noexcept
{
return volume;
@ -1200,15 +1228,15 @@ uint32_t sfz::Synth::getPreloadSize() const noexcept
void sfz::Synth::enableFreeWheeling() noexcept
{
if (!freeWheeling) {
freeWheeling = true;
if (!resources.synthConfig.freeWheeling) {
resources.synthConfig.freeWheeling = true;
DBG("Enabling freewheeling");
}
}
void sfz::Synth::disableFreeWheeling() noexcept
{
if (freeWheeling) {
freeWheeling = false;
if (resources.synthConfig.freeWheeling) {
resources.synthConfig.freeWheeling = false;
DBG("Disabling freewheeling");
}
}

View file

@ -78,6 +78,15 @@ public:
* @param numVoices
*/
Synth(int numVoices);
/**
* @brief Processing mode
*/
enum ProcessMode {
ProcessLive,
ProcessFreewheeling,
};
/**
* @brief Empties the current regions and load a new SFZ file into the synth.
*
@ -255,6 +264,21 @@ public:
* @param sampleRate
*/
void setSampleRate(float sampleRate) noexcept;
/**
* @brief Get the default resampling quality for the given mode.
*
* @param mode the processing mode
*
* @return the quality setting
*/
int getSampleQuality(ProcessMode mode);
/**
* @brief Set the default resampling quality for the given mode.
*
* @param mode the processing mode
* @param quality the quality setting
*/
void setSampleQuality(ProcessMode mode, int quality);
/**
* @brief Get the current value for the volume, in dB.
*
@ -669,7 +693,6 @@ private:
std::uniform_real_distribution<float> randNoteDistribution { 0, 1 };
std::mutex callbackGuard;
bool freeWheeling { false };
// Singletons passed as references to the voices
Resources resources;

24
src/sfizz/SynthConfig.h Normal file
View file

@ -0,0 +1,24 @@
// SPDX-License-Identifier: BSD-2-Clause
// This code is part of the sfizz library and is licensed under a BSD 2-clause
// license. You should have receive a LICENSE.md file along with the code.
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
#pragma once
#include "Defaults.h"
namespace sfz
{
struct SynthConfig
{
bool freeWheeling { false };
int liveSampleQuality { sfz::Default::sampleQuality };
int freeWheelingSampleQuality { sfz::Default::sampleQualityInFreewheelingMode };
int currentSampleQuality() const noexcept
{
return freeWheeling ? freeWheelingSampleQuality : liveSampleQuality;
}
};
}

View file

@ -511,7 +511,8 @@ void sfz::Voice::fillWithData(AudioSpan<float> buffer) noexcept
}
}
const int quality = region->sampleQuality;
const int quality = region->sampleQuality ?
*region->sampleQuality : resources.synthConfig.currentSampleQuality();
switch (quality) {
default:

View file

@ -103,6 +103,16 @@ void sfz::Sfizz::setSampleRate(float sampleRate) noexcept
synth->setSampleRate(sampleRate);
}
int sfz::Sfizz::getSampleQuality(ProcessMode mode)
{
return synth->getSampleQuality(static_cast<sfz::Synth::ProcessMode>(mode));
}
void sfz::Sfizz::setSampleQuality(ProcessMode mode, int quality)
{
synth->setSampleQuality(static_cast<sfz::Synth::ProcessMode>(mode), quality);
}
float sfz::Sfizz::getVolume() const noexcept
{
return synth->getVolume();

View file

@ -210,6 +210,18 @@ bool sfizz_set_oversampling_factor(sfizz_synth_t* synth, sfizz_oversampling_fact
}
}
int sfizz_get_sample_quality(sfizz_synth_t* synth, sfizz_process_mode_t mode)
{
auto self = reinterpret_cast<sfz::Synth*>(synth);
return self->getSampleQuality(static_cast<sfz::Synth::ProcessMode>(mode));
}
void sfizz_set_sample_quality(sfizz_synth_t* synth, sfizz_process_mode_t mode, int quality)
{
auto self = reinterpret_cast<sfz::Synth*>(synth);
return self->setSampleQuality(static_cast<sfz::Synth::ProcessMode>(mode), quality);
}
void sfizz_set_volume(sfizz_synth_t* synth, float volume)
{
auto self = reinterpret_cast<sfz::Synth*>(synth);