Merge branch 'master' into develop
This commit is contained in:
commit
b946170b7b
9 changed files with 133 additions and 25 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -16,5 +16,7 @@ compile_commands.json
|
|||
*.a
|
||||
*.txt.user
|
||||
|
||||
.DS_Store
|
||||
|
||||
clients/sfizz_jack
|
||||
clients/sfzprint
|
||||
|
|
|
|||
|
|
@ -14,8 +14,8 @@ matrix:
|
|||
env:
|
||||
- MATRIX_EVAL="CC=gcc-8 && CXX=g++-8"
|
||||
|
||||
- os: osx
|
||||
osx_image: xcode10.1
|
||||
# - os: osx
|
||||
# osx_image: xcode10.1
|
||||
|
||||
before_install:
|
||||
- sh ${TRAVIS_BUILD_DIR}/.travis/before_install.sh
|
||||
|
|
|
|||
|
|
@ -7,10 +7,10 @@ if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
|||
gcc -v && g++ -v && cmake --version && /usr/local/bin/cmake --version && $SHELL --version
|
||||
|
||||
mkdir build && cd build
|
||||
/usr/local/bin/cmake -D CMAKE_BUILD_TYPE=Release -D SFIZZ_CLIENTS=ON ..
|
||||
/usr/local/bin/cmake -D CMAKE_BUILD_TYPE=Debug -D SFIZZ_CLIENTS=ON ..
|
||||
make -j$(nproc)
|
||||
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
||||
mkdir build && cd build
|
||||
cmake -D CMAKE_BUILD_TYPE=Release -D SFIZZ_CLIENTS=ON -G Xcode ..
|
||||
xcodebuild -project sfizz.xcodeproj -alltargets -configuration Release build
|
||||
cmake -D SFIZZ_CLIENTS=OFF -G Xcode .. # FIXME: client build
|
||||
xcodebuild -project sfizz.xcodeproj -alltargets -configuration Debug build
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -1,7 +1,10 @@
|
|||
cmake_minimum_required(VERSION 3.13)
|
||||
project(sfizz VERSION 1.0.0 LANGUAGES CXX)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 14)
|
||||
# Do not override if set to more than 14
|
||||
if (NOT CMAKE_CXX_STANDARD OR CMAKE_CXX_STANDARD LESS 14)
|
||||
set(CMAKE_CXX_STANDARD 14)
|
||||
endif()
|
||||
|
||||
# Enable LTO
|
||||
set(CMAKE_POLICY_DEFAULT_CMP0069 NEW) # To override the policy in abseil and benchmark
|
||||
|
|
@ -67,10 +70,13 @@ if (WIN32)
|
|||
set_target_properties(sndfile PROPERTIES LINKER_LANGUAGE CXX)
|
||||
file(COPY "${WIN_SNDFILE_PATH}/bin/libsndfile-1.dll" DESTINATION ${CMAKE_BINARY_DIR})
|
||||
target_include_directories(sndfile INTERFACE "${WIN_SNDFILE_PATH}/include")
|
||||
elseif (APPLE)
|
||||
add_library(sndfile STATIC IMPORTED)
|
||||
set_target_properties(sndfile PROPERTIES LINKER_LANGUAGE CXX)
|
||||
target_include_directories(sndfile INTERFACE "usr/local/include")
|
||||
elseif(APPLE)
|
||||
find_path(SNDFILE_INCLUDE_DIR NAMES sndfile.hh PATHS "/usr/local/include")
|
||||
find_library(SNDFILE_LIBRARY NAMES sndfile PATHS "/usr/local/lib")
|
||||
message(STATUS "include dir: " ${SNDFILE_INCLUDE_DIR} " lib: " ${SNDFILE_LIBRARY})
|
||||
add_library(sndfile SHARED IMPORTED GLOBAL)
|
||||
target_include_directories(sndfile INTERFACE ${SNDFILE_INCLUDE_DIR})
|
||||
target_link_libraries(sndfile INTERFACE ${SNDFILE_LIBRARY})
|
||||
endif()
|
||||
|
||||
add_subdirectory(sfizz)
|
||||
|
|
|
|||
|
|
@ -6,5 +6,14 @@ target_link_libraries(sfzprint sfizz::parser absl::flags_parse)
|
|||
|
||||
###############################
|
||||
# Basic command line program
|
||||
if(APPLE)
|
||||
find_path(JACK_INCLUDE_DIR NAMES jack.h PATHS "/usr/local/include/jack")
|
||||
find_library(JACK_LIBRARY NAMES jack PATHS "/usr/local/lib")
|
||||
message(STATUS "include dir: " ${JACK_INCLUDE_DIR} " lib: " ${JACK_LIBRARY})
|
||||
add_library(jack SHARED IMPORTED GLOBAL)
|
||||
target_include_directories(jack INTERFACE ${JACK_INCLUDE_DIR})
|
||||
target_link_libraries(jack INTERFACE ${JACK_LIBRARY})
|
||||
endif()
|
||||
|
||||
add_executable(sfizz_jack jack_client.cpp)
|
||||
target_link_libraries(sfizz_jack sfizz::sfizz jack absl::flags_parse)
|
||||
|
|
|
|||
60
sfizz/AtomicGuard.h
Normal file
60
sfizz/AtomicGuard.h
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
// Copyright (c) 2019, Paul Ferrand
|
||||
// All rights reserved.
|
||||
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (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 <atomic>
|
||||
|
||||
namespace sfz
|
||||
{
|
||||
class AtomicGuard
|
||||
{
|
||||
public:
|
||||
AtomicGuard() = delete;
|
||||
AtomicGuard(std::atomic<bool>& guard)
|
||||
: guard(guard)
|
||||
{
|
||||
guard = true;
|
||||
}
|
||||
~AtomicGuard()
|
||||
{
|
||||
guard = false;
|
||||
}
|
||||
private:
|
||||
std::atomic<bool>& guard;
|
||||
};
|
||||
class AtomicDisabler
|
||||
{
|
||||
public:
|
||||
AtomicDisabler() = delete;
|
||||
AtomicDisabler(std::atomic<bool>& allowed)
|
||||
: allowed(allowed)
|
||||
{
|
||||
allowed = false;
|
||||
}
|
||||
~AtomicDisabler()
|
||||
{
|
||||
allowed = true;
|
||||
}
|
||||
private:
|
||||
std::atomic<bool>& allowed;
|
||||
};
|
||||
}
|
||||
|
|
@ -160,4 +160,5 @@ private:
|
|||
pointer _alignedEnd { nullptr };
|
||||
LEAK_DETECTOR(Buffer);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
@ -14,7 +14,9 @@ set(SFIZZ_SOURCES
|
|||
include(CheckIncludeFiles)
|
||||
CHECK_INCLUDE_FILES(x86intrin.h HAVE_X86INTRIN_H)
|
||||
CHECK_INCLUDE_FILES(intrin.h HAVE_INTRIN_H)
|
||||
CHECK_INCLUDE_FILES(arm_neon.h HAVE_ARM_NEON_H)
|
||||
if (!APPLE)
|
||||
CHECK_INCLUDE_FILES(arm_neon.h HAVE_ARM_NEON_H)
|
||||
endif()
|
||||
|
||||
# SIMD checks
|
||||
if (HAVE_X86INTRIN_H AND UNIX)
|
||||
|
|
@ -71,4 +73,4 @@ target_link_libraries(sfizz PUBLIC absl::strings)
|
|||
target_link_libraries(sfizz PRIVATE sndfile absl::flat_hash_map)
|
||||
|
||||
add_library(sfizz::parser ALIAS sfizz_parser)
|
||||
add_library(sfizz::sfizz ALIAS sfizz)
|
||||
add_library(sfizz::sfizz ALIAS sfizz)
|
||||
|
|
|
|||
|
|
@ -22,9 +22,10 @@
|
|||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include "Synth.h"
|
||||
#include "MidiState.h"
|
||||
#include "AtomicGuard.h"
|
||||
#include "Config.h"
|
||||
#include "Debug.h"
|
||||
#include "MidiState.h"
|
||||
#include "ScopedFTZ.h"
|
||||
#include "StringViewHelpers.h"
|
||||
#include "absl/algorithm/container.h"
|
||||
|
|
@ -139,17 +140,20 @@ void sfz::Synth::handleControlOpcodes(const std::vector<Opcode>& members)
|
|||
{
|
||||
for (auto& member : members) {
|
||||
switch (hash(member.opcode)) {
|
||||
case hash("Set_cc"): [[fallthrough]];
|
||||
case hash("Set_cc"):
|
||||
[[fallthrough]];
|
||||
case hash("set_cc"):
|
||||
if (member.parameter && Default::ccRange.containsWithEnd(*member.parameter))
|
||||
setValueFromOpcode(member, midiState.cc[*member.parameter], Default::ccRange);
|
||||
break;
|
||||
case hash("Label_cc"): [[fallthrough]];
|
||||
case hash("Label_cc"):
|
||||
[[fallthrough]];
|
||||
case hash("label_cc"):
|
||||
if (member.parameter && Default::ccRange.containsWithEnd(*member.parameter))
|
||||
ccNames.emplace_back(*member.parameter, member.value);
|
||||
break;
|
||||
case hash("Default_path"): [[fallthrough]];
|
||||
case hash("Default_path"):
|
||||
[[fallthrough]];
|
||||
case hash("default_path"): {
|
||||
auto stringPath = std::string(member.value.begin(), member.value.end());
|
||||
auto newPath = fs::path(stringPath);
|
||||
|
|
@ -184,7 +188,7 @@ void addEndpointsToVelocityCurve(sfz::Region& region)
|
|||
|
||||
bool sfz::Synth::loadSfzFile(const fs::path& filename)
|
||||
{
|
||||
canEnterCallback = false;
|
||||
AtomicDisabler callbackDisabler { canEnterCallback };
|
||||
while (inCallback) {
|
||||
std::this_thread::sleep_for(1ms);
|
||||
}
|
||||
|
|
@ -247,8 +251,7 @@ bool sfz::Synth::loadSfzFile(const fs::path& filename)
|
|||
|
||||
DBG("Removed " << regions.size() - std::distance(regions.begin(), lastRegion) - 1 << " out of " << regions.size() << " regions.");
|
||||
regions.resize(std::distance(regions.begin(), lastRegion) + 1);
|
||||
|
||||
canEnterCallback = true;
|
||||
|
||||
return parserReturned;
|
||||
}
|
||||
|
||||
|
|
@ -261,12 +264,12 @@ sfz::Voice* sfz::Synth::findFreeVoice() noexcept
|
|||
// Find voices that can be stolen
|
||||
DBG("No free voice, trying to steal");
|
||||
voiceViewArray.clear();
|
||||
for (auto& voice: voices)
|
||||
for (auto& voice : voices)
|
||||
if (voice->canBeStolen())
|
||||
voiceViewArray.push_back(voice.get());
|
||||
absl::c_sort(voices, [](const auto& lhs, const auto& rhs) { return lhs->getSourcePosition() > rhs->getSourcePosition(); });
|
||||
|
||||
for (auto* voice: voiceViewArray) {
|
||||
for (auto* voice : voiceViewArray) {
|
||||
DBG("Average voice power: " << voice->getMeanSquaredAverage());
|
||||
if (voice->getMeanSquaredAverage() < config::voiceStealingThreshold) {
|
||||
DBG("Stealing voice...");
|
||||
|
|
@ -297,6 +300,11 @@ void sfz::Synth::garbageCollect() noexcept
|
|||
|
||||
void sfz::Synth::setSamplesPerBlock(int samplesPerBlock) noexcept
|
||||
{
|
||||
AtomicDisabler callbackDisabler { canEnterCallback };
|
||||
while (inCallback) {
|
||||
std::this_thread::sleep_for(1ms);
|
||||
}
|
||||
|
||||
this->samplesPerBlock = samplesPerBlock;
|
||||
this->tempBuffer.resize(samplesPerBlock);
|
||||
for (auto& voice : voices)
|
||||
|
|
@ -305,6 +313,11 @@ void sfz::Synth::setSamplesPerBlock(int samplesPerBlock) noexcept
|
|||
|
||||
void sfz::Synth::setSampleRate(float sampleRate) noexcept
|
||||
{
|
||||
AtomicDisabler callbackDisabler { canEnterCallback };
|
||||
while (inCallback) {
|
||||
std::this_thread::sleep_for(1ms);
|
||||
}
|
||||
|
||||
this->sampleRate = sampleRate;
|
||||
for (auto& voice : voices)
|
||||
voice->setSampleRate(sampleRate);
|
||||
|
|
@ -314,18 +327,17 @@ void sfz::Synth::renderBlock(AudioSpan<float> buffer) noexcept
|
|||
{
|
||||
ScopedFTZ ftz;
|
||||
buffer.fill(0.0f);
|
||||
|
||||
if (!canEnterCallback)
|
||||
return;
|
||||
|
||||
inCallback = true;
|
||||
AtomicGuard callbackGuard { inCallback };
|
||||
|
||||
auto tempSpan = AudioSpan<float>(tempBuffer).first(buffer.getNumFrames());
|
||||
for (auto& voice : voices) {
|
||||
voice->renderBlock(tempSpan);
|
||||
buffer.add(tempSpan);
|
||||
}
|
||||
|
||||
inCallback = false;
|
||||
}
|
||||
|
||||
void sfz::Synth::noteOn(int delay, int channel, int noteNumber, uint8_t velocity) noexcept
|
||||
|
|
@ -334,6 +346,12 @@ void sfz::Synth::noteOn(int delay, int channel, int noteNumber, uint8_t velocity
|
|||
ASSERT(noteNumber >= 0);
|
||||
|
||||
midiState.noteOn(noteNumber, velocity);
|
||||
|
||||
if (!canEnterCallback)
|
||||
return;
|
||||
|
||||
AtomicGuard callbackGuard { inCallback };
|
||||
|
||||
auto randValue = randNoteDistribution(Random::randomGenerator);
|
||||
|
||||
for (auto& region : noteActivationLists[noteNumber]) {
|
||||
|
|
@ -361,7 +379,12 @@ void sfz::Synth::noteOff(int delay, int channel, int noteNumber, uint8_t velocit
|
|||
ASSERT(noteNumber < 128);
|
||||
ASSERT(noteNumber >= 0);
|
||||
|
||||
// FIXME: Some keyboards (e.g. Casio PX5S) can send a real note-off velocity. In this case, do we have a
|
||||
if (!canEnterCallback)
|
||||
return;
|
||||
|
||||
AtomicGuard callbackGuard { inCallback };
|
||||
|
||||
// FIXME: Some keyboards (e.g. Casio PX5S) can send a real note-off velocity. In this case, do we have a
|
||||
// way in sfz to specify that a release trigger should NOT use the note-on velocity?
|
||||
// auto replacedVelocity = (velocity == 0 ? sfz::getNoteVelocity(noteNumber) : velocity);
|
||||
auto replacedVelocity = midiState.getNoteVelocity(noteNumber);
|
||||
|
|
@ -389,6 +412,11 @@ void sfz::Synth::cc(int delay, int channel, int ccNumber, uint8_t ccValue) noexc
|
|||
ASSERT(ccNumber < 128);
|
||||
ASSERT(ccNumber >= 0);
|
||||
|
||||
if (!canEnterCallback)
|
||||
return;
|
||||
|
||||
AtomicGuard callbackGuard { inCallback };
|
||||
|
||||
for (auto& voice : voices)
|
||||
voice->registerCC(delay, channel, ccNumber, ccValue);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue