Added a C++ opaque API for the shared lib
This commit is contained in:
parent
6bf3d78778
commit
aef8352cfc
8 changed files with 437 additions and 12 deletions
|
|
@ -21,7 +21,7 @@
|
|||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include "sfizz.hpp"
|
||||
#include "sfizz/Synth.h"
|
||||
#include <absl/flags/parse.h>
|
||||
#include <absl/flags/flag.h>
|
||||
#include <absl/types/span.h>
|
||||
|
|
|
|||
|
|
@ -37,12 +37,12 @@ add_library (sfizz::sfizz ALIAS sfizz_static)
|
|||
# Shared library and installation target
|
||||
if (SFIZZ_SHARED)
|
||||
add_library (sfizz_shared SHARED)
|
||||
target_sources(sfizz_shared PRIVATE ${SFIZZ_SOURCES} sfizz/sfizz_wrapper.cpp)
|
||||
target_sources(sfizz_shared PRIVATE ${SFIZZ_SOURCES} sfizz/sfizz_wrapper.cpp sfizz/sfizz.cpp)
|
||||
target_include_directories (sfizz_shared PRIVATE .)
|
||||
target_include_directories (sfizz_static PRIVATE external)
|
||||
target_link_libraries (sfizz_shared PRIVATE absl::strings absl::span sfizz_parser absl::flat_hash_map Threads::Threads)
|
||||
target_compile_definitions(sfizz_shared PRIVATE SFIZZ_EXPORT_SYMBOLS)
|
||||
set_target_properties (sfizz_shared PROPERTIES OUTPUT_NAME sfizz PUBLIC_HEADER sfizz.h)
|
||||
set_target_properties (sfizz_shared PROPERTIES OUTPUT_NAME sfizz PUBLIC_HEADER "sfizz.h;sfizz.hpp")
|
||||
sfizz_link_libsndfile(sfizz_shared)
|
||||
sfizz_enable_lto_if_needed(sfizz_shared)
|
||||
configure_file (${PROJECT_SOURCE_DIR}/scripts/sfizz.pc.in sfizz.pc @ONLY)
|
||||
|
|
|
|||
251
src/sfizz.hpp
251
src/sfizz.hpp
|
|
@ -1,2 +1,249 @@
|
|||
#include "sfizz/AudioSpan.h"
|
||||
#include "sfizz/Synth.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
#if defined SFIZZ_EXPORT_SYMBOLS
|
||||
#if defined _WIN32
|
||||
#define SFIZZ_EXPORTED_API __declspec(dllexport)
|
||||
#else
|
||||
#define SFIZZ_EXPORTED_API __attribute__ ((visibility ("default")))
|
||||
#endif
|
||||
#else
|
||||
#define SFIZZ_EXPORTED_API
|
||||
#endif
|
||||
|
||||
namespace sfz
|
||||
{
|
||||
class Synth;
|
||||
class SFIZZ_EXPORTED_API Sfizz
|
||||
{
|
||||
public:
|
||||
Sfizz();
|
||||
~Sfizz();
|
||||
/**
|
||||
* @brief Empties the current regions and load a new SFZ file into the synth.
|
||||
*
|
||||
* This function will disable all callbacks so it is safe to call from a
|
||||
* UI thread for example, although it may generate a click. However it is
|
||||
* not reentrant, so you should not call it from concurrent threads.
|
||||
*
|
||||
* @param file
|
||||
* @return true
|
||||
* @return false if the file was not found or no regions were loaded.
|
||||
*/
|
||||
bool loadSfzFile(const std::string& path);
|
||||
/**
|
||||
* @brief Get the current number of regions loaded
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
int getNumRegions() const noexcept;
|
||||
/**
|
||||
* @brief Get the current number of groups loaded
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
int getNumGroups() const noexcept;
|
||||
/**
|
||||
* @brief Get the current number of masters loaded
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
int getNumMasters() const noexcept;
|
||||
/**
|
||||
* @brief Get the current number of curves loaded
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
int getNumCurves() const noexcept;
|
||||
const std::vector<std::string>& getUnknownOpcodes() const noexcept;
|
||||
/**
|
||||
* @brief Get the number of preloaded samples in the synth
|
||||
*
|
||||
* @return size_t
|
||||
*/
|
||||
size_t getNumPreloadedSamples() const noexcept;
|
||||
/**
|
||||
* @brief Set the maximum size of the blocks for the callback. The actual
|
||||
* size can be lower in each callback but should not be larger
|
||||
* than this value.
|
||||
*
|
||||
* @param samplesPerBlock
|
||||
*/
|
||||
void setSamplesPerBlock(int samplesPerBlock) noexcept;
|
||||
/**
|
||||
* @brief Set the sample rate. If you do not call it it is initialized
|
||||
* to sfz::config::defaultSampleRate.
|
||||
*
|
||||
* @param sampleRate
|
||||
*/
|
||||
void setSampleRate(float sampleRate) noexcept;
|
||||
/**
|
||||
* @brief Get the current value for the volume, in dB.
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
float getVolume() const noexcept;
|
||||
/**
|
||||
* @brief Set the value for the volume. This value will be
|
||||
* clamped within sfz::default::volumeRange.
|
||||
*
|
||||
* @param volume
|
||||
*/
|
||||
void setVolume(float volume) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Send a note on event to the synth
|
||||
*
|
||||
* @param delay the delay at which the event occurs; this should be lower
|
||||
* than the size of the block in the next call to renderBlock().
|
||||
* @param noteNumber the midi note number
|
||||
* @param velocity the midi note velocity
|
||||
*/
|
||||
void noteOn(int delay, int noteNumber, uint8_t velocity) noexcept;
|
||||
/**
|
||||
* @brief Send a note off event to the synth
|
||||
*
|
||||
* @param delay the delay at which the event occurs; this should be lower
|
||||
* than the size of the block in the next call to renderBlock().
|
||||
* @param noteNumber the midi note number
|
||||
* @param velocity the midi note velocity
|
||||
*/
|
||||
void noteOff(int delay, int noteNumber, uint8_t velocity) noexcept;
|
||||
/**
|
||||
* @brief Send a CC event to the synth
|
||||
*
|
||||
* @param delay the delay at which the event occurs; this should be lower than the size of
|
||||
* the block in the next call to renderBlock().
|
||||
* @param ccNumber the cc number
|
||||
* @param ccValue the cc value
|
||||
*/
|
||||
void cc(int delay, int ccNumber, uint8_t ccValue) noexcept;
|
||||
/**
|
||||
* @brief Send a pitch bend event to the synth
|
||||
*
|
||||
* @param delay the delay at which the event occurs; this should be lower
|
||||
* than the size of the block in the next call to
|
||||
* renderBlock().
|
||||
* @param pitch the pitch value centered between -8192 and 8192
|
||||
*/
|
||||
void pitchWheel(int delay, int pitch) noexcept;
|
||||
/**
|
||||
* @brief Send a aftertouch event to the synth
|
||||
*
|
||||
* @param delay the delay at which the event occurs; this should be lower than the size of
|
||||
* the block in the next call to renderBlock().
|
||||
* @param aftertouch the aftertouch value
|
||||
*/
|
||||
void aftertouch(int delay, uint8_t aftertouch) noexcept;
|
||||
/**
|
||||
* @brief Send a tempo event to the synth
|
||||
*
|
||||
* @param delay the delay at which the event occurs; this should be lower than the size of
|
||||
* the block in the next call to renderBlock().
|
||||
* @param secondsPerQuarter the new period of the quarter note
|
||||
*/
|
||||
void tempo(int delay, float secondsPerQuarter) noexcept;
|
||||
/**
|
||||
* @brief Render an block of audio data in the buffer. This call will reset
|
||||
* the synth in its waiting state for the next batch of events. The size of
|
||||
* the block is integrated in the AudioSpan object. You can build an
|
||||
* AudioSpan implicitely from a large number of source objects; check the
|
||||
* AudioSpan reference for more precision.
|
||||
*
|
||||
* @param buffer the buffer to write the next block into
|
||||
* @param numSamples the number of samples
|
||||
*/
|
||||
void renderBlock(float** buffers, size_t numSamples, int numOutputs) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Get the number of active voices
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
int getNumActiveVoices() const noexcept;
|
||||
/**
|
||||
* @brief Get the total number of voices in the synth (the polyphony)
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
int getNumVoices() const noexcept;
|
||||
/**
|
||||
* @brief Change the number of voices (the polyphony)
|
||||
*
|
||||
* @param numVoices
|
||||
*/
|
||||
void setNumVoices(int numVoices) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Set the oversampling factor to a new value. This will disable all callbacks
|
||||
* kill all the voices, and trigger a reloading of every file in the FilePool under
|
||||
* the new oversampling.
|
||||
*
|
||||
* @param factor
|
||||
* @return true if the factor did indeed change
|
||||
*/
|
||||
bool setOversamplingFactor(int factor) noexcept;
|
||||
|
||||
/**
|
||||
* @brief get the current oversampling factor
|
||||
*
|
||||
* @return Oversampling
|
||||
*/
|
||||
int getOversamplingFactor() const noexcept;
|
||||
|
||||
/**
|
||||
* @brief Set the preloaded file size. This will disable the callback.
|
||||
*
|
||||
* @param factor
|
||||
*/
|
||||
void setPreloadSize(uint32_t preloadSize) noexcept;
|
||||
|
||||
/**
|
||||
* @brief get the current preloaded file size
|
||||
*
|
||||
* @return Oversampling
|
||||
*/
|
||||
uint32_t getPreloadSize() const noexcept;
|
||||
|
||||
/**
|
||||
* @brief Gets the number of allocated buffers.
|
||||
*
|
||||
* @return The allocated buffers.
|
||||
*/
|
||||
int getAllocatedBuffers() const noexcept;
|
||||
|
||||
/**
|
||||
* @brief Gets the number of bytes allocated through the buffers
|
||||
*
|
||||
* @return The allocated bytes.
|
||||
*/
|
||||
int getAllocatedBytes() const noexcept;
|
||||
|
||||
/**
|
||||
* @brief Enable freewheeling on the synth. This will wait for background
|
||||
* loaded files to finish loading before each render callback to ensure that
|
||||
* there will be no dropouts.
|
||||
*
|
||||
*/
|
||||
void enableFreeWheeling() noexcept;
|
||||
/**
|
||||
* @brief Disable freewheeling on the synth. You should disable freewheeling
|
||||
* before live use of the plugin otherwise the audio thread will lock.
|
||||
*
|
||||
*/
|
||||
void disableFreeWheeling() noexcept;
|
||||
/**
|
||||
* @brief Check if the SFZ should be reloaded.
|
||||
*
|
||||
* Depending on the platform this can create file descriptors.
|
||||
*
|
||||
* @return true if any included files (including the root file) have
|
||||
* been modified since the sfz file was loaded.
|
||||
* @return false
|
||||
*/
|
||||
bool shouldReloadFile();
|
||||
private:
|
||||
std::unique_ptr<sfz::Synth> synth;
|
||||
};
|
||||
}
|
||||
|
|
@ -105,7 +105,7 @@ void sfz::Synth::buildRegion(const std::vector<Opcode>& regionOpcodes)
|
|||
}
|
||||
|
||||
if (!lastRegion->parseOpcode(opcode))
|
||||
unknownOpcodes.insert(opcode.opcode);
|
||||
unknownOpcodes.emplace_back(opcode.opcode);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -556,7 +556,7 @@ const sfz::Voice* sfz::Synth::getVoiceView(int idx) const noexcept
|
|||
return (size_t)idx < voices.size() ? voices[idx].get() : nullptr;
|
||||
}
|
||||
|
||||
std::set<absl::string_view> sfz::Synth::getUnknownOpcodes() const noexcept
|
||||
const std::vector<std::string>& sfz::Synth::getUnknownOpcodes() const noexcept
|
||||
{
|
||||
return unknownOpcodes;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -154,7 +154,7 @@ public:
|
|||
*
|
||||
* @return std::set<absl::string_view>
|
||||
*/
|
||||
std::set<absl::string_view> getUnknownOpcodes() const noexcept;
|
||||
const std::vector<std::string>& getUnknownOpcodes() const noexcept;
|
||||
/**
|
||||
* @brief Get the number of preloaded samples in the synth
|
||||
*
|
||||
|
|
@ -432,7 +432,7 @@ private:
|
|||
std::vector<CCNamePair> ccNames;
|
||||
// Default active switch if multiple keyswitchable regions are present
|
||||
absl::optional<uint8_t> defaultSwitch;
|
||||
std::set<absl::string_view> unknownOpcodes;
|
||||
std::vector<std::string> unknownOpcodes;
|
||||
using RegionPtrVector = std::vector<Region*>;
|
||||
using VoicePtrVector = std::vector<Voice*>;
|
||||
std::vector<std::unique_ptr<Region>> regions;
|
||||
|
|
|
|||
180
src/sfizz/sfizz.cpp
Normal file
180
src/sfizz/sfizz.cpp
Normal file
|
|
@ -0,0 +1,180 @@
|
|||
#include "Synth.h"
|
||||
#include "sfizz.hpp"
|
||||
|
||||
sfz::Sfizz::Sfizz()
|
||||
{
|
||||
synth = std::make_unique<sfz::Synth>();
|
||||
}
|
||||
|
||||
sfz::Sfizz::~Sfizz()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool sfz::Sfizz::loadSfzFile(const std::string& path)
|
||||
{
|
||||
return synth->loadSfzFile(path);
|
||||
}
|
||||
|
||||
int sfz::Sfizz::getNumRegions() const noexcept
|
||||
{
|
||||
return synth->getNumRegions();
|
||||
}
|
||||
|
||||
int sfz::Sfizz::getNumGroups() const noexcept
|
||||
{
|
||||
return synth->getNumGroups();
|
||||
}
|
||||
|
||||
int sfz::Sfizz::getNumMasters() const noexcept
|
||||
{
|
||||
return synth->getNumMasters();
|
||||
}
|
||||
|
||||
int sfz::Sfizz::getNumCurves() const noexcept
|
||||
{
|
||||
return synth->getNumCurves();
|
||||
}
|
||||
|
||||
const std::vector<std::string>& sfz::Sfizz::getUnknownOpcodes() const noexcept
|
||||
{
|
||||
return synth->getUnknownOpcodes();
|
||||
}
|
||||
|
||||
size_t sfz::Sfizz::getNumPreloadedSamples() const noexcept
|
||||
{
|
||||
return synth->getNumPreloadedSamples();
|
||||
}
|
||||
|
||||
void sfz::Sfizz::setSamplesPerBlock(int samplesPerBlock) noexcept
|
||||
{
|
||||
synth->setSamplesPerBlock(samplesPerBlock);
|
||||
}
|
||||
|
||||
void sfz::Sfizz::setSampleRate(float sampleRate) noexcept
|
||||
{
|
||||
synth->setSampleRate(sampleRate);
|
||||
}
|
||||
|
||||
float sfz::Sfizz::getVolume() const noexcept
|
||||
{
|
||||
return synth->getVolume();
|
||||
}
|
||||
|
||||
void sfz::Sfizz::setVolume(float volume) noexcept
|
||||
{
|
||||
synth->setVolume(volume);
|
||||
}
|
||||
|
||||
void sfz::Sfizz::noteOn(int delay, int noteNumber, uint8_t velocity) noexcept
|
||||
{
|
||||
synth->noteOn(delay, noteNumber, velocity);
|
||||
}
|
||||
|
||||
void sfz::Sfizz::noteOff(int delay, int noteNumber, uint8_t velocity) noexcept
|
||||
{
|
||||
synth->noteOff(delay, noteNumber, velocity);
|
||||
}
|
||||
|
||||
void sfz::Sfizz::cc(int delay, int ccNumber, uint8_t ccValue) noexcept
|
||||
{
|
||||
synth->cc(delay, ccNumber, ccValue);
|
||||
}
|
||||
|
||||
void sfz::Sfizz::pitchWheel(int delay, int pitch) noexcept
|
||||
{
|
||||
synth->pitchWheel(delay, pitch);
|
||||
}
|
||||
|
||||
void sfz::Sfizz::aftertouch(int delay, uint8_t aftertouch) noexcept
|
||||
{
|
||||
synth->aftertouch(delay, aftertouch);
|
||||
}
|
||||
|
||||
void sfz::Sfizz::tempo(int delay, float secondsPerQuarter) noexcept
|
||||
{
|
||||
synth->tempo(delay, secondsPerQuarter);
|
||||
}
|
||||
|
||||
void sfz::Sfizz::renderBlock(float** buffers, size_t numSamples, int /*numOutputs*/) noexcept
|
||||
{
|
||||
synth->renderBlock({{buffers[0], buffers[1]}, numSamples});
|
||||
}
|
||||
|
||||
int sfz::Sfizz::getNumActiveVoices() const noexcept
|
||||
{
|
||||
return synth->getNumActiveVoices();
|
||||
}
|
||||
|
||||
int sfz::Sfizz::getNumVoices() const noexcept
|
||||
{
|
||||
return synth->getNumVoices();
|
||||
}
|
||||
|
||||
void sfz::Sfizz::setNumVoices(int numVoices) noexcept
|
||||
{
|
||||
synth->setNumVoices(numVoices);
|
||||
}
|
||||
|
||||
bool sfz::Sfizz::setOversamplingFactor(int factor) noexcept
|
||||
{
|
||||
using sfz::Oversampling;
|
||||
switch(factor)
|
||||
{
|
||||
case 1:
|
||||
synth->setOversamplingFactor(sfz::Oversampling::x1);
|
||||
return true;
|
||||
case 2:
|
||||
synth->setOversamplingFactor(sfz::Oversampling::x2);
|
||||
return true;
|
||||
case 4:
|
||||
synth->setOversamplingFactor(sfz::Oversampling::x4);
|
||||
return true;
|
||||
case 8:
|
||||
synth->setOversamplingFactor(sfz::Oversampling::x8);
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int sfz::Sfizz::getOversamplingFactor() const noexcept
|
||||
{
|
||||
return static_cast<int>(synth->getOversamplingFactor());
|
||||
}
|
||||
|
||||
void sfz::Sfizz::setPreloadSize(uint32_t preloadSize) noexcept
|
||||
{
|
||||
synth->setPreloadSize(preloadSize);
|
||||
}
|
||||
|
||||
uint32_t sfz::Sfizz::getPreloadSize() const noexcept
|
||||
{
|
||||
return synth->getPreloadSize();
|
||||
}
|
||||
|
||||
int sfz::Sfizz::getAllocatedBuffers() const noexcept
|
||||
{
|
||||
return synth->getAllocatedBuffers();
|
||||
}
|
||||
|
||||
int sfz::Sfizz::getAllocatedBytes() const noexcept
|
||||
{
|
||||
return synth->getAllocatedBytes();
|
||||
}
|
||||
|
||||
void sfz::Sfizz::enableFreeWheeling() noexcept
|
||||
{
|
||||
synth->enableFreeWheeling();
|
||||
}
|
||||
|
||||
void sfz::Sfizz::disableFreeWheeling() noexcept
|
||||
{
|
||||
synth->disableFreeWheeling();
|
||||
}
|
||||
|
||||
bool sfz::Sfizz::shouldReloadFile()
|
||||
{
|
||||
return synth->shouldReloadFile();
|
||||
}
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
#include "sfizz/Parser.h"
|
||||
#include "sfizz/Opcode.h"
|
||||
|
|
@ -21,7 +21,7 @@
|
|||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include "sfizz.hpp"
|
||||
#include "sfizz/Synth.h"
|
||||
#include "catch2/catch.hpp"
|
||||
using namespace Catch::literals;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue