Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add the sample quality API #267

Merged
merged 3 commits into from
Jun 14, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions src/sfizz.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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.
*
Expand Down
33 changes: 33 additions & 0 deletions src/sfizz.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,14 @@ class SFIZZ_EXPORTED_API Sfizz
Sfizz();
~Sfizz();

/**
* @brief Processing mode
*/
enum ProcessMode {
ProcessLive,
ProcessFreewheeling,
};

/**
* @brief Empties the current regions and load a new SFZ file into the synth.
*
Expand Down Expand Up @@ -174,6 +182,31 @@ class SFIZZ_EXPORTED_API Sfizz
*/
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.
*/
Expand Down
1 change: 1 addition & 0 deletions src/sfizz/Defaults.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
5 changes: 4 additions & 1 deletion src/sfizz/Region.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion src/sfizz/Region.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions src/sfizz/Resources.h
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -21,6 +22,7 @@ class WavetableMulti;

struct Resources
{
SynthConfig synthConfig;
BufferPool bufferPool;
MidiState midiState;
Logger logger;
Expand Down
41 changes: 36 additions & 5 deletions src/sfizz/Synth.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 };
Expand Down Expand Up @@ -1112,6 +1112,37 @@ 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)
{
CHECK(quality >= 1 && quality <= 10);
quality = clamp(quality, 1, 10);

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;
Expand Down Expand Up @@ -1200,15 +1231,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");
}
}
Expand Down
25 changes: 24 additions & 1 deletion src/sfizz/Synth.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,15 @@ class Synth final : public Voice::StateListener, public Parser::Listener {
* @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.
*
Expand Down Expand Up @@ -255,6 +264,21 @@ class Synth final : public Voice::StateListener, public Parser::Listener {
* @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.
*
Expand Down Expand Up @@ -669,7 +693,6 @@ class Synth final : public Voice::StateListener, public Parser::Listener {
std::uniform_real_distribution<float> randNoteDistribution { 0, 1 };

std::mutex callbackGuard;
bool freeWheeling { false };

// Singletons passed as references to the voices
Resources resources;
Expand Down
24 changes: 24 additions & 0 deletions src/sfizz/SynthConfig.h
Original file line number Diff line number Diff line change
@@ -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;
}
};
}
8 changes: 7 additions & 1 deletion src/sfizz/Voice.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,12 @@ void sfz::Voice::startVoice(Region* region, int delay, int number, float value,
egEnvelope.reset(region->amplitudeEG, *region, resources.midiState, delay, value, sampleRate);
}

int sfz::Voice::getCurrentSampleQuality() const noexcept
{
return (region && region->sampleQuality) ?
*region->sampleQuality : resources.synthConfig.currentSampleQuality();
}

bool sfz::Voice::isFree() const noexcept
{
return (state == State::idle);
Expand Down Expand Up @@ -511,7 +517,7 @@ void sfz::Voice::fillWithData(AudioSpan<float> buffer) noexcept
}
}

const int quality = region->sampleQuality;
const int quality = getCurrentSampleQuality();

switch (quality) {
default:
Expand Down
7 changes: 7 additions & 0 deletions src/sfizz/Voice.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,13 @@ class Voice {
*/
void startVoice(Region* region, int delay, int number, float value, TriggerType triggerType) noexcept;

/**
* @brief Get the sample quality determined by the active region.
*
* @return int
*/
int getCurrentSampleQuality() const noexcept;

/**
* @brief Register a note-off event; this may trigger a release.
*
Expand Down
10 changes: 10 additions & 0 deletions src/sfizz/sfizz.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
12 changes: 12 additions & 0 deletions src/sfizz/sfizz_wrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Loading