commit
b0c84ad99a
9 changed files with 2128 additions and 102 deletions
11
scripts/generate_re2c.sh
Executable file
11
scripts/generate_re2c.sh
Executable file
|
|
@ -0,0 +1,11 @@
|
|||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
if ! test -d "src"; then
|
||||
echo "Please run this in the project root directory."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
for src in src/sfizz/OpcodeCleanup.re; do
|
||||
re2c -o "${src%.re}.cpp" "$src"
|
||||
done
|
||||
|
|
@ -45,7 +45,7 @@ sfizz_add_simd_sources (SFIZZ_SOURCES ".")
|
|||
# Parser core library
|
||||
add_library (sfizz_parser STATIC)
|
||||
target_sources (sfizz_parser PRIVATE
|
||||
sfizz/Parser.cpp sfizz/Opcode.cpp sfizz/SfzHelpers.cpp
|
||||
sfizz/Parser.cpp sfizz/Opcode.cpp sfizz/OpcodeCleanup.cpp sfizz/SfzHelpers.cpp
|
||||
sfizz/parser/Parser.cpp sfizz/parser/ParserPrivate.cpp)
|
||||
target_include_directories (sfizz_parser PUBLIC sfizz)
|
||||
target_include_directories (sfizz_parser PUBLIC external)
|
||||
|
|
|
|||
|
|
@ -36,6 +36,18 @@ enum OpcodeCategory {
|
|||
kOpcodeSmoothCcN,
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A scope where an opcode may appear.
|
||||
*/
|
||||
enum OpcodeScope {
|
||||
//! unknown scope or other
|
||||
kOpcodeScopeGeneric,
|
||||
//! region scope
|
||||
kOpcodeScopeRegion,
|
||||
//! effect scope
|
||||
kOpcodeScopeEffect,
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Opcode description class. The class parses the parameters
|
||||
* of the opcode on construction.
|
||||
|
|
@ -51,6 +63,15 @@ struct Opcode {
|
|||
std::vector<uint16_t> parameters;
|
||||
OpcodeCategory category;
|
||||
|
||||
/*
|
||||
* @brief Normalize in order to make the ampersand-name unique, and
|
||||
* facilitate subsequent processing.
|
||||
*
|
||||
* @param scope scope where this opcode appears
|
||||
* @return normalized opcode
|
||||
*/
|
||||
Opcode cleanUp(OpcodeScope scope) const;
|
||||
|
||||
/*
|
||||
* @brief Get the derived opcode name to convert it to another category.
|
||||
*
|
||||
|
|
|
|||
1797
src/sfizz/OpcodeCleanup.cpp
Normal file
1797
src/sfizz/OpcodeCleanup.cpp
Normal file
File diff suppressed because it is too large
Load diff
172
src/sfizz/OpcodeCleanup.re
Normal file
172
src/sfizz/OpcodeCleanup.re
Normal file
|
|
@ -0,0 +1,172 @@
|
|||
/* -*- mode: c++; -*- */
|
||||
// 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
|
||||
|
||||
#include "Opcode.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "absl/strings/str_cat.h"
|
||||
#include <string>
|
||||
|
||||
namespace sfz {
|
||||
|
||||
static std::string cleanUpOpcodeName(absl::string_view rawOpcode, OpcodeScope scope)
|
||||
{
|
||||
std::string opcode { rawOpcode };
|
||||
|
||||
/*!re2c
|
||||
re2c:flags:posix-captures = 1;
|
||||
re2c:define:YYCTYPE = char;
|
||||
re2c:yyfill:enable = 0;
|
||||
*/
|
||||
/*!maxnmatch:re2c*/
|
||||
|
||||
const char* YYCURSOR;
|
||||
const char* YYMARKER;
|
||||
const char* yypmatch[2 * YYMAXNMATCH];
|
||||
size_t yynmatch;
|
||||
|
||||
/*!stags:re2c format = "const char* @@; "; */
|
||||
|
||||
auto group = [&yypmatch](size_t i) -> absl::string_view {
|
||||
const char *beg = yypmatch[2 * i];
|
||||
const char *end = yypmatch[2 * i + 1];
|
||||
return absl::string_view(beg, end - beg);
|
||||
};
|
||||
|
||||
/*!re2c
|
||||
digit = [0-9];
|
||||
number = digit+;
|
||||
any = [^\x00]*;
|
||||
END = [\x00];
|
||||
*/
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
YYCURSOR = opcode.c_str();
|
||||
|
||||
/*!re2c
|
||||
|
||||
(any) "_cc" (number) END {
|
||||
opcode = absl::StrCat(group(1), "_oncc", group(2));
|
||||
goto end_generic;
|
||||
}
|
||||
|
||||
* {
|
||||
goto end_generic;
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
end_generic:
|
||||
/* end */;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
if (scope == kOpcodeScopeRegion) {
|
||||
|
||||
YYCURSOR = opcode.c_str();
|
||||
|
||||
/*!re2c
|
||||
|
||||
lfoV1 = "amplfo"|"fillfo"|"pitchlfo";
|
||||
egV1 = "ampeg"|"fileg"|"pitcheg";
|
||||
eqV1 = "eq" number;
|
||||
lfoV2 = "lfo" number;
|
||||
|
||||
(lfoV1) "_" ("depth"|"freq"|"fade") "cc" (number) END {
|
||||
opcode = absl::StrCat(group(1), "_", group(2), "_oncc", group(3));
|
||||
goto end_region;
|
||||
}
|
||||
(egV1) "_" ("delay"|"start"|"attack"|"hold"|"decay"|"sustain"|"release") "cc" (number) END {
|
||||
opcode = absl::StrCat(group(1), "_", group(2), "_oncc", group(3));
|
||||
goto end_region;
|
||||
}
|
||||
(eqV1) "_" ("bw"|"freq"|"gain") "cc" (number) END {
|
||||
opcode = absl::StrCat(group(1), "_", group(2), "_oncc", group(3));
|
||||
goto end_region;
|
||||
}
|
||||
(lfoV2) "_" ("wave"|"offset"|"ratio"|"scale") END {
|
||||
opcode = absl::StrCat(group(1), "_", group(2), "1");
|
||||
goto end_region;
|
||||
}
|
||||
|
||||
"loop" ("mode"|"start"|"end") END {
|
||||
opcode = absl::StrCat("loop_", group(1));
|
||||
goto end_region;
|
||||
}
|
||||
"off" ("by"|"mode") END {
|
||||
opcode = absl::StrCat("off_", group(1));
|
||||
goto end_region;
|
||||
}
|
||||
"bend" ("up"|"down") END {
|
||||
opcode = absl::StrCat("bend_", group(1));
|
||||
goto end_region;
|
||||
}
|
||||
"filtype" END {
|
||||
opcode = absl::StrCat("fil1_type");
|
||||
goto end_region;
|
||||
}
|
||||
"fil" (number) "type" END {
|
||||
opcode = absl::StrCat("fil", group(1), "_type");
|
||||
goto end_region;
|
||||
}
|
||||
|
||||
"polyphony_group" END {
|
||||
opcode = "group";
|
||||
goto end_region;
|
||||
}
|
||||
|
||||
"gain" ("_" any)? END {
|
||||
opcode = absl::StrCat("volume", group(1));
|
||||
goto end_region;
|
||||
}
|
||||
"tune" ("_" any)? END {
|
||||
opcode = absl::StrCat("pitch", group(1));
|
||||
goto end_region;
|
||||
}
|
||||
|
||||
"on_" ("hi"|"lo") "cc" (number) END {
|
||||
opcode = absl::StrCat("start_", group(1), "cc", group(2));
|
||||
goto end_region;
|
||||
}
|
||||
|
||||
"fil_" (any) END {
|
||||
opcode = absl::StrCat("fil1_", group(1));
|
||||
goto end_region;
|
||||
}
|
||||
"cutoff" ("_" any)? END {
|
||||
opcode = absl::StrCat("cutoff1", group(1));
|
||||
goto end_region;
|
||||
}
|
||||
"resonance" ("_" any)? END {
|
||||
opcode = absl::StrCat("resonance1", group(1));
|
||||
goto end_region;
|
||||
}
|
||||
|
||||
* {
|
||||
goto end_region;
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
end_region:
|
||||
/* end */;
|
||||
|
||||
} // scope == kOpcodeScopeRegion
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
#undef YYMAXNMATCH
|
||||
|
||||
return opcode;
|
||||
}
|
||||
|
||||
Opcode Opcode::cleanUp(OpcodeScope scope) const
|
||||
{
|
||||
return Opcode(cleanUpOpcodeName(opcode, scope), value);
|
||||
}
|
||||
|
||||
} // namespace sfz
|
||||
|
|
@ -31,8 +31,10 @@ bool extendIfNecessary(std::vector<T>& vec, unsigned size, unsigned defaultCapac
|
|||
return true;
|
||||
}
|
||||
|
||||
bool sfz::Region::parseOpcode(const Opcode& opcode)
|
||||
bool sfz::Region::parseOpcode(const Opcode& rawOpcode)
|
||||
{
|
||||
const Opcode opcode = rawOpcode.cleanUp(kOpcodeScopeRegion);
|
||||
|
||||
switch (opcode.lettersOnlyHash) {
|
||||
// Sound source: sample playback
|
||||
case hash("sample"):
|
||||
|
|
@ -65,7 +67,7 @@ bool sfz::Region::parseOpcode(const Opcode& opcode)
|
|||
case hash("offset_random"):
|
||||
setValueFromOpcode(opcode, offsetRandom, Default::offsetRange);
|
||||
break;
|
||||
case hash("offset_cc&"):
|
||||
case hash("offset_oncc&"): // also offset_cc&
|
||||
if (opcode.parameters.back() > config::numCCs)
|
||||
return false;
|
||||
if (auto value = readOpcode(opcode.value, Default::offsetCCRange))
|
||||
|
|
@ -77,8 +79,7 @@ bool sfz::Region::parseOpcode(const Opcode& opcode)
|
|||
case hash("count"):
|
||||
setValueFromOpcode(opcode, sampleCount, Default::sampleCountRange);
|
||||
break;
|
||||
case hash("loopmode"): // fallthrough
|
||||
case hash("loop_mode"):
|
||||
case hash("loop_mode"): // also loopmode
|
||||
switch (hash(opcode.value)) {
|
||||
case hash("no_loop"):
|
||||
loopMode = SfzLoopMode::no_loop;
|
||||
|
|
@ -96,12 +97,10 @@ bool sfz::Region::parseOpcode(const Opcode& opcode)
|
|||
DBG("Unkown loop mode:" << std::string(opcode.value));
|
||||
}
|
||||
break;
|
||||
case hash("loopend"): // fallthrough
|
||||
case hash("loop_end"):
|
||||
case hash("loop_end"): // also loopend
|
||||
setRangeEndFromOpcode(opcode, loopRange, Default::loopRange);
|
||||
break;
|
||||
case hash("loopstart"): // fallthrough
|
||||
case hash("loop_start"):
|
||||
case hash("loop_start"): // also loopstart
|
||||
setRangeStartFromOpcode(opcode, loopRange, Default::loopRange);
|
||||
break;
|
||||
|
||||
|
|
@ -121,15 +120,13 @@ bool sfz::Region::parseOpcode(const Opcode& opcode)
|
|||
break;
|
||||
|
||||
// Instrument settings: voice lifecycle
|
||||
case hash("group"): // fallthrough
|
||||
case hash("polyphony_group"):
|
||||
case hash("group"): // also polyphony_group
|
||||
setValueFromOpcode(opcode, group, Default::groupRange);
|
||||
break;
|
||||
case hash("offby"): // fallthrough
|
||||
case hash("off_by"):
|
||||
case hash("off_by"): // also offby
|
||||
setValueFromOpcode(opcode, offBy, Default::groupRange);
|
||||
break;
|
||||
case hash("off_mode"):
|
||||
case hash("off_mode"): // also offmode
|
||||
switch (hash(opcode.value)) {
|
||||
case hash("fast"):
|
||||
offMode = SfzOffMode::fast;
|
||||
|
|
@ -292,15 +289,13 @@ bool sfz::Region::parseOpcode(const Opcode& opcode)
|
|||
DBG("Unknown trigger mode: " << std::string(opcode.value));
|
||||
}
|
||||
break;
|
||||
case hash("on_locc&"): // fallthrough
|
||||
case hash("start_locc&"):
|
||||
case hash("start_locc&"): // also on_locc&
|
||||
if (opcode.parameters.back() >= config::numCCs)
|
||||
return false;
|
||||
if (auto value = readOpcode(opcode.value, Default::midi7Range))
|
||||
ccTriggers[opcode.parameters.back()].setStart(normalizeCC(*value));
|
||||
break;
|
||||
case hash("on_hicc&"): // fallthrough
|
||||
case hash("start_hicc&"):
|
||||
case hash("start_hicc&"): // also on_hicc&
|
||||
if (opcode.parameters.back() >= config::numCCs)
|
||||
return false;
|
||||
if (auto value = readOpcode(opcode.value, Default::midi7Range))
|
||||
|
|
@ -308,30 +303,28 @@ bool sfz::Region::parseOpcode(const Opcode& opcode)
|
|||
break;
|
||||
|
||||
// Performance parameters: amplifier
|
||||
case hash("volume"):
|
||||
case hash("volume"): // also gain
|
||||
setValueFromOpcode(opcode, volume, Default::volumeRange);
|
||||
break;
|
||||
case hash("volume_curvecc&"):
|
||||
case hash("volume_curvecc&"): // also gain_curvecc&
|
||||
if (opcode.parameters.back() >= config::numCCs)
|
||||
return false;
|
||||
if (auto value = readOpcode(opcode.value, Default::curveCCRange))
|
||||
volumeCC[opcode.parameters.back()].curve = *value;
|
||||
break;
|
||||
case hash("volume_stepcc&"):
|
||||
case hash("volume_stepcc&"): // also gain_stepcc&
|
||||
if (opcode.parameters.back() >= config::numCCs)
|
||||
return false;
|
||||
if (auto value = readOpcode(opcode.value, Default::volumeStepRange))
|
||||
volumeCC[opcode.parameters.back()].step = *value;
|
||||
break;
|
||||
case hash("volume_smoothcc&"):
|
||||
case hash("volume_smoothcc&"): // also gain_smoothcc&
|
||||
if (opcode.parameters.back() >= config::numCCs)
|
||||
return false;
|
||||
if (auto value = readOpcode(opcode.value, Default::smoothCCRange))
|
||||
volumeCC[opcode.parameters.back()].smooth = *value;
|
||||
break;
|
||||
case hash("gain_cc&"):
|
||||
case hash("gain_oncc&"): // fallthrough
|
||||
case hash("volume_oncc&"):
|
||||
case hash("volume_oncc&"): // also gain_oncc&
|
||||
if (opcode.parameters.back() >= config::numCCs)
|
||||
return false;
|
||||
if (auto value = readOpcode(opcode.value, Default::volumeCCRange))
|
||||
|
|
@ -359,8 +352,7 @@ bool sfz::Region::parseOpcode(const Opcode& opcode)
|
|||
if (auto value = readOpcode(opcode.value, Default::smoothCCRange))
|
||||
amplitudeCC[opcode.parameters.back()].smooth = *value;
|
||||
break;
|
||||
case hash("amplitude_cc&"): // fallthrough
|
||||
case hash("amplitude_oncc&"):
|
||||
case hash("amplitude_oncc&"): // also amplitude_cc&
|
||||
if (opcode.parameters.back() >= config::numCCs)
|
||||
return false;
|
||||
if (auto value = readOpcode(opcode.value, Default::amplitudeRange))
|
||||
|
|
@ -388,8 +380,7 @@ bool sfz::Region::parseOpcode(const Opcode& opcode)
|
|||
if (auto value = readOpcode(opcode.value, Default::smoothCCRange))
|
||||
panCC[opcode.parameters.back()].smooth = *value;
|
||||
break;
|
||||
case hash("pan_cc&"):
|
||||
case hash("pan_oncc&"):
|
||||
case hash("pan_oncc&"): // also pan_cc&
|
||||
if (opcode.parameters.back() >= config::numCCs)
|
||||
return false;
|
||||
if (auto value = readOpcode(opcode.value, Default::panCCRange))
|
||||
|
|
@ -417,8 +408,7 @@ bool sfz::Region::parseOpcode(const Opcode& opcode)
|
|||
if (auto value = readOpcode(opcode.value, Default::smoothCCRange))
|
||||
positionCC[opcode.parameters.back()].smooth = *value;
|
||||
break;
|
||||
case hash("position_cc&"): // fallthrough
|
||||
case hash("position_oncc&"):
|
||||
case hash("position_oncc&"): // also position_cc&
|
||||
if (opcode.parameters.back() >= config::numCCs)
|
||||
return false;
|
||||
if (auto value = readOpcode(opcode.value, Default::positionCCRange))
|
||||
|
|
@ -567,8 +557,7 @@ bool sfz::Region::parseOpcode(const Opcode& opcode)
|
|||
break;
|
||||
|
||||
// Performance parameters: filters
|
||||
case hash("cutoff"): // fallthrough
|
||||
case hash("cutoff&"):
|
||||
case hash("cutoff&"): // also cutoff
|
||||
{
|
||||
const auto filterIndex = opcode.parameters.empty() ? 0 : (opcode.parameters.back() - 1);
|
||||
if (!extendIfNecessary(filters, filterIndex + 1, Default::numFilters))
|
||||
|
|
@ -576,8 +565,7 @@ bool sfz::Region::parseOpcode(const Opcode& opcode)
|
|||
setValueFromOpcode(opcode, filters[filterIndex].cutoff, Default::filterCutoffRange);
|
||||
}
|
||||
break;
|
||||
case hash("resonance"): // fallthrough
|
||||
case hash("resonance&"):
|
||||
case hash("resonance&"): // also resonance
|
||||
{
|
||||
const auto filterIndex = opcode.parameters.empty() ? 0 : (opcode.parameters.back() - 1);
|
||||
if (!extendIfNecessary(filters, filterIndex + 1, Default::numFilters))
|
||||
|
|
@ -585,12 +573,9 @@ bool sfz::Region::parseOpcode(const Opcode& opcode)
|
|||
setValueFromOpcode(opcode, filters[filterIndex].resonance, Default::filterResonanceRange);
|
||||
}
|
||||
break;
|
||||
case hash("cutoff_oncc&"):
|
||||
case hash("cutoff_cc&"):
|
||||
case hash("cutoff&_oncc&"): // fallthrough
|
||||
case hash("cutoff&_cc&"):
|
||||
case hash("cutoff&_oncc&"): // also cutoff_oncc&, cutoff_cc&, cutoff&_cc&
|
||||
{
|
||||
const auto filterIndex = opcode.parameters.size() == 1 ? 0 : (opcode.parameters.front() - 1);
|
||||
const auto filterIndex = opcode.parameters.front() - 1;
|
||||
if (!extendIfNecessary(filters, filterIndex + 1, Default::numFilters))
|
||||
return false;
|
||||
|
||||
|
|
@ -601,12 +586,9 @@ bool sfz::Region::parseOpcode(const Opcode& opcode)
|
|||
);
|
||||
}
|
||||
break;
|
||||
case hash("resonance&_oncc&"):
|
||||
case hash("resonance&_cc&"):
|
||||
case hash("resonance_oncc&"): // fallthrough
|
||||
case hash("resonance_cc&"):
|
||||
case hash("resonance&_oncc&"): // also resonance_oncc&, resonance_cc&, resonance&_cc&
|
||||
{
|
||||
const auto filterIndex = opcode.parameters.size() == 1 ? 0 : (opcode.parameters.front() - 1);
|
||||
const auto filterIndex = opcode.parameters.front() - 1;
|
||||
if (!extendIfNecessary(filters, filterIndex + 1, Default::numFilters))
|
||||
return false;
|
||||
|
||||
|
|
@ -617,60 +599,54 @@ bool sfz::Region::parseOpcode(const Opcode& opcode)
|
|||
);
|
||||
}
|
||||
break;
|
||||
case hash("fil_keytrack"): // fallthrough
|
||||
case hash("fil&_keytrack"):
|
||||
case hash("fil&_keytrack"): // also fil_keytrack
|
||||
{
|
||||
const auto filterIndex = opcode.parameters.empty() ? 0 : (opcode.parameters.front() - 1);
|
||||
const auto filterIndex = opcode.parameters.front() - 1;
|
||||
if (!extendIfNecessary(filters, filterIndex + 1, Default::numFilters))
|
||||
return false;
|
||||
|
||||
setValueFromOpcode(opcode, filters[filterIndex].keytrack, Default::filterKeytrackRange);
|
||||
}
|
||||
break;
|
||||
case hash("fil_keycenter"): // fallthrough
|
||||
case hash("fil&_keycenter"):
|
||||
case hash("fil&_keycenter"): // also fil_keycenter
|
||||
{
|
||||
const auto filterIndex = opcode.parameters.empty() ? 0 : (opcode.parameters.front() - 1);
|
||||
const auto filterIndex = opcode.parameters.front() - 1;
|
||||
if (!extendIfNecessary(filters, filterIndex + 1, Default::numFilters))
|
||||
return false;
|
||||
|
||||
setValueFromOpcode(opcode, filters[filterIndex].keycenter, Default::keyRange);
|
||||
}
|
||||
break;
|
||||
case hash("fil_veltrack"): // fallthrough
|
||||
case hash("fil&_veltrack"):
|
||||
case hash("fil&_veltrack"): // also fil_veltrack
|
||||
{
|
||||
const auto filterIndex = opcode.parameters.empty() ? 0 : (opcode.parameters.front() - 1);
|
||||
const auto filterIndex = opcode.parameters.front() - 1;
|
||||
if (!extendIfNecessary(filters, filterIndex + 1, Default::numFilters))
|
||||
return false;
|
||||
|
||||
setValueFromOpcode(opcode, filters[filterIndex].veltrack, Default::filterVeltrackRange);
|
||||
}
|
||||
break;
|
||||
case hash("fil_random"): // fallthrough
|
||||
case hash("fil&_random"):
|
||||
case hash("fil&_random"): // also fil_random
|
||||
{
|
||||
const auto filterIndex = opcode.parameters.empty() ? 0 : (opcode.parameters.front() - 1);
|
||||
const auto filterIndex = opcode.parameters.front() - 1;
|
||||
if (!extendIfNecessary(filters, filterIndex + 1, Default::numFilters))
|
||||
return false;
|
||||
|
||||
setValueFromOpcode(opcode, filters[filterIndex].random, Default::filterRandomRange);
|
||||
}
|
||||
break;
|
||||
case hash("fil_gain"): // fallthrough
|
||||
case hash("fil&_gain"):
|
||||
case hash("fil&_gain"): // also fil_gain
|
||||
{
|
||||
const auto filterIndex = opcode.parameters.empty() ? 0 : (opcode.parameters.front() - 1);
|
||||
const auto filterIndex = opcode.parameters.front() - 1;
|
||||
if (!extendIfNecessary(filters, filterIndex + 1, Default::numFilters))
|
||||
return false;
|
||||
|
||||
setValueFromOpcode(opcode, filters[filterIndex].gain, Default::filterGainRange);
|
||||
}
|
||||
break;
|
||||
case hash("fil_gaincc&"): // fallthrough
|
||||
case hash("fil&_gaincc&"):
|
||||
case hash("fil&_gain_oncc&"): // also fil_gain_oncc&
|
||||
{
|
||||
const auto filterIndex = opcode.parameters.size() == 1 ? 0 : (opcode.parameters.front() - 1);
|
||||
const auto filterIndex = opcode.parameters.front() - 1;
|
||||
if (!extendIfNecessary(filters, filterIndex + 1, Default::numFilters))
|
||||
return false;
|
||||
|
||||
|
|
@ -681,10 +657,9 @@ bool sfz::Region::parseOpcode(const Opcode& opcode)
|
|||
);
|
||||
}
|
||||
break;
|
||||
case hash("fil_type"): // fallthrough
|
||||
case hash("fil&_type"):
|
||||
case hash("fil&_type"): // also fil_type, filtype
|
||||
{
|
||||
const auto filterIndex = opcode.parameters.empty() ? 0 : (opcode.parameters.front() - 1);
|
||||
const auto filterIndex = opcode.parameters.front() - 1;
|
||||
if (!extendIfNecessary(filters, filterIndex + 1, Default::numFilters))
|
||||
return false;
|
||||
|
||||
|
|
@ -710,8 +685,7 @@ bool sfz::Region::parseOpcode(const Opcode& opcode)
|
|||
setValueFromOpcode(opcode, equalizers[eqNumber - 1].bandwidth, Default::eqBandwidthRange);
|
||||
}
|
||||
break;
|
||||
case hash("eq&_bw_oncc&"): // fallthrough
|
||||
case hash("eq&_bwcc&"):
|
||||
case hash("eq&_bw_oncc&"): // also eq&_bwcc&
|
||||
{
|
||||
const auto eqNumber = opcode.parameters.front();
|
||||
if (eqNumber == 0)
|
||||
|
|
@ -732,8 +706,7 @@ bool sfz::Region::parseOpcode(const Opcode& opcode)
|
|||
setValueFromOpcode(opcode, equalizers[eqNumber - 1].frequency, Default::eqFrequencyRange);
|
||||
}
|
||||
break;
|
||||
case hash("eq&_freq_oncc&"): // fallthrough
|
||||
case hash("eq&_freqcc&"):
|
||||
case hash("eq&_freq_oncc&"): // also eq&_freqcc&
|
||||
{
|
||||
const auto eqNumber = opcode.parameters.front();
|
||||
if (eqNumber == 0)
|
||||
|
|
@ -767,8 +740,7 @@ bool sfz::Region::parseOpcode(const Opcode& opcode)
|
|||
setValueFromOpcode(opcode, equalizers[eqNumber - 1].gain, Default::eqGainRange);
|
||||
}
|
||||
break;
|
||||
case hash("eq&_gain_oncc&"): // fallthrough
|
||||
case hash("eq&_gaincc&"):
|
||||
case hash("eq&_gain_oncc&"): // also eq&_gaincc&
|
||||
{
|
||||
const auto eqNumber = opcode.parameters.front();
|
||||
if (eqNumber == 0)
|
||||
|
|
@ -827,44 +799,37 @@ bool sfz::Region::parseOpcode(const Opcode& opcode)
|
|||
case hash("transpose"):
|
||||
setValueFromOpcode(opcode, transpose, Default::transposeRange);
|
||||
break;
|
||||
case hash("tune"): // fallthrough
|
||||
case hash("pitch"):
|
||||
case hash("pitch"): // also tune
|
||||
setValueFromOpcode(opcode, tune, Default::tuneRange);
|
||||
break;
|
||||
case hash("pitch_curvecc&"): // fallthrough
|
||||
case hash("tune_curvecc&"):
|
||||
case hash("pitch_curvecc&"): // also tune_curvecc&
|
||||
if (opcode.parameters.back() >= config::numCCs)
|
||||
return false;
|
||||
if (auto value = readOpcode(opcode.value, Default::curveCCRange))
|
||||
tuneCC[opcode.parameters.back()].curve = *value;
|
||||
break;
|
||||
case hash("pitch_stepcc&"): // fallthrough
|
||||
case hash("tune_stepcc&"):
|
||||
case hash("pitch_stepcc&"): // also tune_stepcc&
|
||||
if (opcode.parameters.back() >= config::numCCs)
|
||||
return false;
|
||||
if (auto value = readOpcode(opcode.value, Default::tuneStepRange))
|
||||
tuneCC[opcode.parameters.back()].step = *value;
|
||||
break;
|
||||
case hash("pitch_smoothcc&"): // fallthrough
|
||||
case hash("tune_smoothcc&"):
|
||||
case hash("pitch_smoothcc&"): // also tune_smoothcc&
|
||||
if (opcode.parameters.back() >= config::numCCs)
|
||||
return false;
|
||||
if (auto value = readOpcode(opcode.value, Default::smoothCCRange))
|
||||
tuneCC[opcode.parameters.back()].smooth = *value;
|
||||
break;
|
||||
case hash("tune_cc&"):
|
||||
case hash("tune_oncc&"):
|
||||
case hash("pitch_cc&"):
|
||||
case hash("pitch_oncc&"):
|
||||
case hash("pitch_oncc&"): // also pitch_cc&, tune_cc&, tune_oncc&
|
||||
if (opcode.parameters.back() >= config::numCCs)
|
||||
return false;
|
||||
if (auto value = readOpcode(opcode.value, Default::tuneCCRange))
|
||||
tuneCC[opcode.parameters.back()].value = *value;
|
||||
break;
|
||||
case hash("bend_up"):
|
||||
case hash("bend_up"): // also bendup
|
||||
setValueFromOpcode(opcode, bendUp, Default::bendBoundRange);
|
||||
break;
|
||||
case hash("bend_down"):
|
||||
case hash("bend_down"): // also benddown
|
||||
setValueFromOpcode(opcode, bendDown, Default::bendBoundRange);
|
||||
break;
|
||||
case hash("bend_step"):
|
||||
|
|
@ -923,32 +888,25 @@ bool sfz::Region::parseOpcode(const Opcode& opcode)
|
|||
return false; // Was not vel2...
|
||||
setValueFromOpcode(opcode, amplitudeEG.vel2sustain, Default::egOnCCPercentRange);
|
||||
break;
|
||||
case hash("ampeg_attackcc&"): // fallthrough
|
||||
case hash("ampeg_attack_oncc&"):
|
||||
case hash("ampeg_attack_oncc&"): // also ampeg_attackcc&
|
||||
setCCPairFromOpcode(opcode, amplitudeEG.ccAttack, Default::egOnCCTimeRange);
|
||||
break;
|
||||
case hash("ampeg_decaycc&"): // fallthrough
|
||||
case hash("ampeg_decay_oncc&"):
|
||||
case hash("ampeg_decay_oncc&"): // also ampeg_decaycc&
|
||||
setCCPairFromOpcode(opcode, amplitudeEG.ccDecay, Default::egOnCCTimeRange);
|
||||
break;
|
||||
case hash("ampeg_delaycc&"): // fallthrough
|
||||
case hash("ampeg_delay_oncc&"):
|
||||
case hash("ampeg_delay_oncc&"): // also ampeg_delaycc&
|
||||
setCCPairFromOpcode(opcode, amplitudeEG.ccDelay, Default::egOnCCTimeRange);
|
||||
break;
|
||||
case hash("ampeg_holdcc&"): // fallthrough
|
||||
case hash("ampeg_hold_oncc&"):
|
||||
case hash("ampeg_hold_oncc&"): // also ampeg_holdcc&
|
||||
setCCPairFromOpcode(opcode, amplitudeEG.ccHold, Default::egOnCCTimeRange);
|
||||
break;
|
||||
case hash("ampeg_releasecc&"): // fallthrough
|
||||
case hash("ampeg_release_oncc&"):
|
||||
case hash("ampeg_release_oncc&"): // also ampeg_releasecc&
|
||||
setCCPairFromOpcode(opcode, amplitudeEG.ccRelease, Default::egOnCCTimeRange);
|
||||
break;
|
||||
case hash("ampeg_startcc&"): // fallthrough
|
||||
case hash("ampeg_start_oncc&"):
|
||||
case hash("ampeg_start_oncc&"): // also ampeg_startcc&
|
||||
setCCPairFromOpcode(opcode, amplitudeEG.ccStart, Default::egOnCCPercentRange);
|
||||
break;
|
||||
case hash("ampeg_sustaincc&"): // fallthrough
|
||||
case hash("ampeg_sustain_oncc&"):
|
||||
case hash("ampeg_sustain_oncc&"): // also ampeg_sustaincc&
|
||||
setCCPairFromOpcode(opcode, amplitudeEG.ccSustain, Default::egOnCCPercentRange);
|
||||
break;
|
||||
|
||||
|
|
|
|||
|
|
@ -236,7 +236,7 @@ void sfz::Synth::handleControlOpcodes(const std::vector<Opcode>& members)
|
|||
}
|
||||
}
|
||||
|
||||
void sfz::Synth::handleEffectOpcodes(const std::vector<Opcode>& members)
|
||||
void sfz::Synth::handleEffectOpcodes(const std::vector<Opcode>& rawMembers)
|
||||
{
|
||||
absl::string_view busName = "main";
|
||||
|
||||
|
|
@ -252,6 +252,11 @@ void sfz::Synth::handleEffectOpcodes(const std::vector<Opcode>& members)
|
|||
return *bus;
|
||||
};
|
||||
|
||||
std::vector<Opcode> members;
|
||||
members.reserve(rawMembers.size());
|
||||
for (const Opcode& opcode : rawMembers)
|
||||
members.push_back(opcode.cleanUp(kOpcodeScopeEffect));
|
||||
|
||||
for (const Opcode& opcode : members) {
|
||||
switch (opcode.lettersOnlyHash) {
|
||||
case hash("bus"):
|
||||
|
|
|
|||
|
|
@ -158,3 +158,65 @@ TEST_CASE("[Opcode] Derived names")
|
|||
REQUIRE(sfz::Opcode("noise_level_smoothcc55", "").getDerivedName(sfz::kOpcodeStepCcN) == "noise_level_stepcc55");
|
||||
REQUIRE(sfz::Opcode("sample", "").getDerivedName(sfz::kOpcodeSmoothCcN, 66) == "sample_smoothcc66");
|
||||
}
|
||||
|
||||
TEST_CASE("[Opcode] Normalization")
|
||||
{
|
||||
REQUIRE(sfz::Opcode("foo_cc7", "").cleanUp(sfz::kOpcodeScopeGeneric).opcode == "foo_oncc7");
|
||||
REQUIRE(sfz::Opcode("foo_cc7", "").cleanUp(sfz::kOpcodeScopeRegion).opcode == "foo_oncc7");
|
||||
|
||||
static const std::pair<absl::string_view, absl::string_view> regionSpecific[] = {
|
||||
// LFO SFZv1
|
||||
{"amplfo_depthcc1", "amplfo_depth_oncc1"},
|
||||
{"fillfo_freqcc2", "fillfo_freq_oncc2"},
|
||||
{"pitchlfo_fadecc3", "pitchlfo_fade_oncc3"},
|
||||
// EG SFZv1
|
||||
{"ampeg_delaycc4", "ampeg_delay_oncc4"},
|
||||
{"fileg_startcc5", "fileg_start_oncc5"},
|
||||
{"pitcheg_attackcc6", "pitcheg_attack_oncc6"},
|
||||
{"ampeg_holdcc7", "ampeg_hold_oncc7"},
|
||||
{"fileg_decaycc8", "fileg_decay_oncc8"},
|
||||
{"pitcheg_sustaincc9", "pitcheg_sustain_oncc9"},
|
||||
{"ampeg_releasecc10", "ampeg_release_oncc10"},
|
||||
// EQ SFZv1
|
||||
{"eq11_bwcc12", "eq11_bw_oncc12"},
|
||||
{"eq13_freqcc14", "eq13_freq_oncc14"},
|
||||
{"eq15_gaincc16", "eq15_gain_oncc16"},
|
||||
// LFO SFZv2
|
||||
{"lfo17_wave", "lfo17_wave1"},
|
||||
{"lfo18_offset", "lfo18_offset1"},
|
||||
{"lfo19_ratio", "lfo19_ratio1"},
|
||||
{"lfo20_scale", "lfo20_scale1"},
|
||||
// LinuxSampler aliases
|
||||
{"loopmode", "loop_mode"},
|
||||
{"loopstart", "loop_start"},
|
||||
{"loopend", "loop_end"},
|
||||
{"offby", "off_by"},
|
||||
{"offmode", "off_mode"},
|
||||
{"bendup", "bend_up"},
|
||||
{"benddown", "bend_down"},
|
||||
{"filtype", "fil1_type"},
|
||||
{"fil21type", "fil21_type"},
|
||||
// ARIA aliases
|
||||
{"polyphony_group", "group"},
|
||||
{"gain", "volume"},
|
||||
{"gain_foobar", "volume_foobar"},
|
||||
{"tune", "pitch"},
|
||||
{"tune_foobar", "pitch_foobar"},
|
||||
// SFZv2 aliases
|
||||
{"on_hicc22", "start_hicc22"},
|
||||
{"on_locc23", "start_locc23"},
|
||||
// Filter SFZv1
|
||||
{"fil_foobar", "fil1_foobar"},
|
||||
{"cutoff", "cutoff1"},
|
||||
{"cutoff_foobar", "cutoff1_foobar"},
|
||||
{"resonance", "resonance1"},
|
||||
{"resonance_foobar", "resonance1_foobar"},
|
||||
};
|
||||
|
||||
for (auto pair : regionSpecific) {
|
||||
absl::string_view input = pair.first;
|
||||
absl::string_view expected = pair.second;
|
||||
REQUIRE(sfz::Opcode(input, "").cleanUp(sfz::kOpcodeScopeRegion).opcode == expected);
|
||||
REQUIRE(sfz::Opcode(input, "").cleanUp(sfz::kOpcodeScopeGeneric).opcode == input);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1199,7 +1199,7 @@ TEST_CASE("[Region] Parsing opcodes")
|
|||
region.parseOpcode({ "resonance3_cc24", "10" });
|
||||
REQUIRE(region.filters[2].resonanceCC.contains(24));
|
||||
REQUIRE(region.filters[2].resonanceCC[24] == 10);
|
||||
region.parseOpcode({ "fil2_gaincc12", "-50" });
|
||||
region.parseOpcode({ "fil2_gain_oncc12", "-50" });
|
||||
REQUIRE(region.filters[1].gainCC.contains(12));
|
||||
REQUIRE(region.filters[1].gainCC[12] == -50.0f);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue