diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..c59153c --- /dev/null +++ b/.clang-format @@ -0,0 +1,212 @@ +--- +# BasedOnStyle: Google +AccessModifierOffset: -1 +AlignAfterOpenBracket: Align +AlignArrayOfStructures: None +AlignConsecutiveMacros: None +AlignConsecutiveAssignments: None +AlignConsecutiveBitFields: None +AlignConsecutiveDeclarations: None +AlignEscapedNewlines: Left +AlignOperands: Align +AlignTrailingComments: true +AllowAllArgumentsOnNextLine: true +AllowAllConstructorInitializersOnNextLine: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortEnumsOnASingleLine: true +AllowShortBlocksOnASingleLine: Never +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: All +AllowShortLambdasOnASingleLine: All +AllowShortIfStatementsOnASingleLine: WithoutElse +AllowShortLoopsOnASingleLine: true +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: true +AlwaysBreakTemplateDeclarations: Yes +AttributeMacros: + - __capability +BinPackArguments: true +BinPackParameters: true +BraceWrapping: + AfterCaseLabel: false + AfterClass: false + AfterControlStatement: Never + AfterEnum: false + AfterFunction: false + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + AfterExternBlock: false + BeforeCatch: false + BeforeElse: false + BeforeLambdaBody: false + BeforeWhile: false + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BreakBeforeBinaryOperators: None +BreakBeforeConceptDeclarations: true +BreakBeforeBraces: Attach +BreakBeforeInheritanceComma: false +BreakInheritanceList: BeforeColon +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: false +BreakConstructorInitializers: BeforeColon +BreakAfterJavaFieldAnnotations: false +BreakStringLiterals: true +ColumnLimit: 80 +CommentPragmas: "^ IWYU pragma:" +CompactNamespaces: false +ConstructorInitializerAllOnOneLineOrOnePerLine: true +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DeriveLineEnding: true +DerivePointerAlignment: true +DisableFormat: false +EmptyLineAfterAccessModifier: Never +EmptyLineBeforeAccessModifier: LogicalBlock +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IfMacros: + - KJ_IF_MAYBE +IncludeBlocks: Regroup +IncludeCategories: + - Regex: '^' + Priority: 2 + SortPriority: 0 + CaseSensitive: false + - Regex: '^<.*\.h>' + Priority: 1 + SortPriority: 0 + CaseSensitive: false + - Regex: "^<.*" + Priority: 2 + SortPriority: 0 + CaseSensitive: false + - Regex: ".*" + Priority: 3 + SortPriority: 0 + CaseSensitive: false +IncludeIsMainRegex: "([-_](test|unittest))?$" +IncludeIsMainSourceRegex: "" +IndentAccessModifiers: false +IndentCaseLabels: true +IndentCaseBlocks: false +IndentGotoLabels: true +IndentPPDirectives: None +IndentExternBlock: AfterExternBlock +IndentRequires: false +IndentWidth: 2 +IndentWrappedFunctionNames: false +InsertTrailingCommas: None +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: false +LambdaBodyIndentation: Signature +MacroBlockBegin: "" +MacroBlockEnd: "" +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBinPackProtocolList: Never +ObjCBlockIndentWidth: 2 +ObjCBreakBeforeNestedBlockParam: true +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 1 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyBreakTemplateDeclaration: 10 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 200 +PenaltyIndentedWhitespace: 0 +PointerAlignment: Left +PPIndentWidth: -1 +RawStringFormats: + - Language: Cpp + Delimiters: + - cc + - CC + - cpp + - Cpp + - CPP + - "c++" + - "C++" + - "cs" + CanonicalDelimiter: "" + BasedOnStyle: google + - Language: TextProto + Delimiters: + - pb + - PB + - proto + - PROTO + EnclosingFunctions: + - EqualsProto + - EquivToProto + - PARSE_PARTIAL_TEXT_PROTO + - PARSE_TEST_PROTO + - PARSE_TEXT_PROTO + - ParseTextOrDie + - ParseTextProtoOrDie + - ParseTestProto + - ParsePartialTestProto + CanonicalDelimiter: pb + BasedOnStyle: google +ReferenceAlignment: Pointer +ReflowComments: true +ShortNamespaceLines: 1 +SortIncludes: CaseSensitive +SortJavaStaticImport: Before +SortUsingDeclarations: true +SpaceAfterCStyleCast: false +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: true +SpaceBeforeAssignmentOperators: true +SpaceBeforeCaseColon: false +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: ControlStatements +SpaceAroundPointerQualifiers: Default +SpaceBeforeRangeBasedForLoopColon: true +SpaceInEmptyBlock: false +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 2 +SpacesInAngles: Never +SpacesInConditionalStatement: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInLineCommentPrefix: + Minimum: 1 + Maximum: -1 +SpacesInParentheses: false +SpacesInSquareBrackets: false +SpaceBeforeSquareBrackets: false +BitFieldColonSpacing: Both +Standard: Auto +StatementAttributeLikeMacros: + - Q_EMIT +StatementMacros: + - Q_UNUSED + - QT_REQUIRE_VERSION +TabWidth: 8 +UseCRLF: false +UseTab: Never +WhitespaceSensitiveMacros: + - STRINGIZE + - PP_STRINGIZE + - BOOST_PP_STRINGIZE + - NS_SWIFT_NAME + - CF_SWIFT_NAME +--- + diff --git a/README.md b/README.md index 8b46efe..777edb4 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,9 @@ This is a fork of the [original SFZero by Steve Folta](https://github.com/stevefolta/SFZero), with the following changes: -* has been converted to a Juce module, so you can easily consume it from your own projects (you still get the sample player plugin, but it now includes that module) -* requires Juce 4.1 or higher -* supports Juce 4.1 module format +* has been converted to a Juce USER module, so you can easily consume it from your own projects (you still get the sample player plugin, but it now includes that module) +* requires Juce 7 or higher +* supports Juce 7 module format * now also supports new Juce 4.2 module format (thanks to Loki Davison) * conveniently sits within its own `sfzero::` namespace * has a tidied-up code base, so it now builds with as few warnings as possible on all platforms and on both 32/64 bit architectures. I also simplified logging, added support for synchronous sample loading, and fixed a few bugs. diff --git a/SFZero.cpp b/SFZero.cpp index c687f92..817a0a5 100644 --- a/SFZero.cpp +++ b/SFZero.cpp @@ -1,18 +1,19 @@ -// Your project must contain an AppConfig.h file with your project-specific settings in it, -// and your header search path must make it accessible to the module's files. +// Your project must contain an AppConfig.h file with your project-specific +// settings in it, and your header search path must make it accessible to the +// module's files. -//#include "AppConfig.h" #include "SFZero.h" -#include "sfzero/RIFF.cpp" -#include "sfzero/SF2.cpp" -#include "sfzero/SF2Generator.cpp" -#include "sfzero/SF2Reader.cpp" -#include "sfzero/SF2Sound.cpp" -#include "sfzero/SFZDebug.cpp" -#include "sfzero/SFZEG.cpp" -#include "sfzero/SFZReader.cpp" -#include "sfzero/SFZRegion.cpp" -#include "sfzero/SFZSample.cpp" -#include "sfzero/SFZSound.cpp" -#include "sfzero/SFZSynth.cpp" -#include "sfzero/SFZVoice.cpp" + +#include "sfzero/RIFF.cpp" +#include "sfzero/SF2.cpp" +#include "sfzero/SF2Generator.cpp" +#include "sfzero/SF2Reader.cpp" +#include "sfzero/SF2Sound.cpp" +#include "sfzero/SFZDebug.cpp" +#include "sfzero/SFZEG.cpp" +#include "sfzero/SFZReader.cpp" +#include "sfzero/SFZRegion.cpp" +#include "sfzero/SFZSample.cpp" +#include "sfzero/SFZSound.cpp" +#include "sfzero/SFZSynth.cpp" +#include "sfzero/SFZVoice.cpp" diff --git a/SFZero.h b/SFZero.h index 01ad118..47c48b1 100644 --- a/SFZero.h +++ b/SFZero.h @@ -1,16 +1,29 @@ -/* -BEGIN_JUCE_MODULE_DECLARATION - ID: SFZero - vendor: altalogix - version: 2.0.2 - name: SFZero sfz player - description: SFZero .szf/.sf2 soundfont player; forked from https://github.com/stevefolta/SFZero and converted to Juce module by Leo Olivers - website: https://github.com/altalogix/SFZero - dependencies: juce_gui_basics, juce_audio_basics, juce_audio_processors - license: MIT -END_JUCE_MODULE_DECLARATION -*/ +/******************************************************************************* + The block below describes the properties of this module, and is read by + the Projucer to automatically generate project code that uses it. + For details about the syntax and how to create or use a module, see the + JUCE Module Format.md file. + + BEGIN_JUCE_MODULE_DECLARATION + + ID: SFZero + vendor: altalogix + version: 2.0.3 + name: SFZero sfz player + description: SFZero .szf/.sf2 soundfont player; forked from +https://github.com/stevefolta/SFZero and converted to Juce module by Leo Olivers + website: https://github.com/altalogix/SFZeroModule + license: MIT + minimumCppStandard: 17 + + dependencies: juce_gui_basics, juce_audio_basics, juce_audio_processors + + END_JUCE_MODULE_DECLARATION + +*******************************************************************************/ + +#pragma once #ifndef INCLUDED_SFZERO_H #define INCLUDED_SFZERO_H @@ -30,6 +43,4 @@ END_JUCE_MODULE_DECLARATION #include "sfzero/SFZSynth.h" #include "sfzero/SFZVoice.h" - -#endif // INCLUDED_SFZERO_H - +#endif // INCLUDED_SFZERO_H diff --git a/SFZero.mm b/SFZero.mm new file mode 100644 index 0000000..e24b901 --- /dev/null +++ b/SFZero.mm @@ -0,0 +1,26 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2022 - Raw Material Software Limited + + JUCE is an open source library subject to commercial or open-source + licensing. + + By using JUCE, you agree to the terms of both the JUCE 7 End-User License + Agreement and JUCE Privacy Policy. + + End User License Agreement: www.juce.com/juce-7-licence + Privacy Policy: www.juce.com/juce-privacy-policy + + Or: You may also use this code under the terms of the GPL v3 (see + www.gnu.org/licenses). + + JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER + EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE + DISCLAIMED. + + ============================================================================== +*/ + +#include "SFZero.cpp" diff --git a/format.sh b/format.sh new file mode 100644 index 0000000..fb554bb --- /dev/null +++ b/format.sh @@ -0,0 +1,8 @@ +find . -regex '.*\.\(hh\)' -exec clang-format -style=file -i {} \; +find . -regex '.*\.\(cc\)' -exec clang-format -style=file -i {} \; +find . -regex '.*\.\(mm\)' -exec clang-format -style=file -i {} \; +find . -regex '.*\.\(h\)' -exec clang-format -style=file -i {} \; +find . -regex '.*\.\(c\)' -exec clang-format -style=file -i {} \; +find . -regex '.*\.\(m\)' -exec clang-format -style=file -i {} \; +find . -regex '.*\.\(hpp\)' -exec clang-format -style=file -i {} \; +find . -regex '.*\.\(cpp\)' -exec clang-format -style=file -i {} \; diff --git a/juce_module_info b/juce_module_info deleted file mode 100644 index 8406d57..0000000 --- a/juce_module_info +++ /dev/null @@ -1,29 +0,0 @@ -{ - "id": "SFZero", - "name": "SFZero soundfont player", - "version": "2.0.2", - "description": "SFZero .szf/.sf2 soundfont player; forked from https://github.com/stevefolta/SFZero and converted to Juce module by Leo Olivers", - "website": "https://github.com/altalogix/SFZero", - "license": "MIT", - - "dependencies": [ - { - "id": "juce_gui_basics", - "version": "4.1.0" - }, - { - "id": "juce_audio_basics", - "version": "4.1.0" - }, - { - "id": "juce_audio_processors", - "version": "4.1.0" - } - ], - - "include": "SFZero.h", - - "compile": [ { "file": "SFZero.cpp" } ], - - "browse": [ "sfzero/*" ] -} diff --git a/sfzero/RIFF.cpp b/sfzero/RIFF.cpp index 5576917..01f30f0 100644 --- a/sfzero/RIFF.cpp +++ b/sfzero/RIFF.cpp @@ -2,50 +2,44 @@ * Original code copyright (C) 2012 Steve Folta * Converted to Juce module (C) 2016 Leo Olivers * Forked from https://github.com/stevefolta/SFZero - * For license info please see the LICENSE file distributed with this source code + * For license info please see the LICENSE file distributed with this source + *code *************************************************************************************/ #include "RIFF.h" -void sfzero::RIFFChunk::readFrom(juce::InputStream *file) -{ +void sfzero::RIFFChunk::readFrom(juce::InputStream *file) { file->read(&id, sizeof(sfzero::fourcc)); size = static_cast(file->readInt()); start = file->getPosition(); - if (FourCCEquals(id, "RIFF")) - { + if (FourCCEquals(id, "RIFF")) { type = RIFF; file->read(&id, sizeof(sfzero::fourcc)); start += sizeof(sfzero::fourcc); size -= sizeof(sfzero::fourcc); - } - else if (FourCCEquals(id, "LIST")) - { + } else if (FourCCEquals(id, "LIST")) { type = LIST; file->read(&id, sizeof(sfzero::fourcc)); start += sizeof(sfzero::fourcc); size -= sizeof(sfzero::fourcc); - } - else - { + } else { type = Custom; } } -void sfzero::RIFFChunk::seek(juce::InputStream *file) { file->setPosition(start); } -void sfzero::RIFFChunk::seekAfter(juce::InputStream *file) -{ +void sfzero::RIFFChunk::seek(juce::InputStream *file) { + file->setPosition(start); +} +void sfzero::RIFFChunk::seekAfter(juce::InputStream *file) { juce::int64 next = start + size; - if (next % 2 != 0) - { + if (next % 2 != 0) { next += 1; } file->setPosition(next); } -juce::String sfzero::RIFFChunk::readString(juce::InputStream *file) -{ +juce::String sfzero::RIFFChunk::readString(juce::InputStream *file) { juce::MemoryBlock memoryBlock(size); file->read(memoryBlock.getData(), static_cast(memoryBlock.getSize())); return memoryBlock.toString(); diff --git a/sfzero/RIFF.h b/sfzero/RIFF.h index 39c4709..23443e8 100644 --- a/sfzero/RIFF.h +++ b/sfzero/RIFF.h @@ -2,24 +2,18 @@ * Original code copyright (C) 2012 Steve Folta * Converted to Juce module (C) 2016 Leo Olivers * Forked from https://github.com/stevefolta/SFZero - * For license info please see the LICENSE file distributed with this source code + * For license info please see the LICENSE file distributed with this source + *code *************************************************************************************/ #ifndef RIFF_H_INCLUDED #define RIFF_H_INCLUDED #include "SF2WinTypes.h" -namespace sfzero -{ +namespace sfzero { -struct RIFFChunk -{ - enum Type - { - RIFF, - LIST, - Custom - }; +struct RIFFChunk { + enum Type { RIFF, LIST, Custom }; fourcc id; dword size; @@ -33,6 +27,6 @@ struct RIFFChunk juce::int64 end() { return (start + size); } juce::String readString(juce::InputStream *file); }; -} +} // namespace sfzero -#endif // RIFF_H_INCLUDED +#endif // RIFF_H_INCLUDED diff --git a/sfzero/SF2.cpp b/sfzero/SF2.cpp index c720295..2ceb292 100644 --- a/sfzero/SF2.cpp +++ b/sfzero/SF2.cpp @@ -2,9 +2,11 @@ * Original code copyright (C) 2012 Steve Folta * Converted to Juce module (C) 2016 Leo Olivers * Forked from https://github.com/stevefolta/SFZero - * For license info please see the LICENSE file distributed with this source code + * For license info please see the LICENSE file distributed with this source + *code *************************************************************************************/ #include "SF2.h" + #include "RIFF.h" #define readAbyte(name, file) name = (byte)file->readByte(); @@ -17,64 +19,67 @@ #define SF2Field(type, name) readA##type(name, file) -void sfzero::SF2::iver::readFrom(juce::InputStream *file) -{ +void sfzero::SF2::iver::readFrom(juce::InputStream *file) { #include "sf2-chunks/iver.h" } -void sfzero::SF2::phdr::readFrom(juce::InputStream *file) -{ +void sfzero::SF2::phdr::readFrom(juce::InputStream *file) { #include "sf2-chunks/phdr.h" } -void sfzero::SF2::pbag::readFrom(juce::InputStream *file) -{ +void sfzero::SF2::pbag::readFrom(juce::InputStream *file) { #include "sf2-chunks/pbag.h" } -void sfzero::SF2::pmod::readFrom(juce::InputStream *file) -{ +void sfzero::SF2::pmod::readFrom(juce::InputStream *file) { #include "sf2-chunks/pmod.h" } -void sfzero::SF2::pgen::readFrom(juce::InputStream *file) -{ +void sfzero::SF2::pgen::readFrom(juce::InputStream *file) { #include "sf2-chunks/pgen.h" } -void sfzero::SF2::inst::readFrom(juce::InputStream *file) -{ +void sfzero::SF2::inst::readFrom(juce::InputStream *file) { #include "sf2-chunks/inst.h" } -void sfzero::SF2::ibag::readFrom(juce::InputStream *file) -{ +void sfzero::SF2::ibag::readFrom(juce::InputStream *file) { #include "sf2-chunks/ibag.h" } -void sfzero::SF2::imod::readFrom(juce::InputStream *file) -{ +void sfzero::SF2::imod::readFrom(juce::InputStream *file) { #include "sf2-chunks/imod.h" } -void sfzero::SF2::igen::readFrom(juce::InputStream *file) -{ +void sfzero::SF2::igen::readFrom(juce::InputStream *file) { #include "sf2-chunks/igen.h" } -void sfzero::SF2::shdr::readFrom(juce::InputStream *file) -{ +void sfzero::SF2::shdr::readFrom(juce::InputStream *file){ #include "sf2-chunks/shdr.h" } sfzero::SF2::Hydra::Hydra() - : phdrItems(nullptr), pbagItems(nullptr), pmodItems(nullptr), pgenItems(nullptr), instItems(nullptr), ibagItems(nullptr), - imodItems(nullptr), igenItems(nullptr), shdrItems(nullptr), phdrNumItems(0), pbagNumItems(0), pmodNumItems(0), pgenNumItems(0), - instNumItems(0), ibagNumItems(0), imodNumItems(0), igenNumItems(0), shdrNumItems(0) - { + : phdrItems(nullptr), + pbagItems(nullptr), + pmodItems(nullptr), + pgenItems(nullptr), + instItems(nullptr), + ibagItems(nullptr), + imodItems(nullptr), + igenItems(nullptr), + shdrItems(nullptr), + phdrNumItems(0), + pbagNumItems(0), + pmodNumItems(0), + pgenNumItems(0), + instNumItems(0), + ibagNumItems(0), + imodNumItems(0), + igenNumItems(0), + shdrNumItems(0) { } -sfzero::SF2::Hydra::~Hydra() -{ +sfzero::SF2::Hydra::~Hydra() { delete phdrItems; delete pbagItems; delete pmodItems; @@ -86,37 +91,32 @@ sfzero::SF2::Hydra::~Hydra() delete shdrItems; } -void sfzero::SF2::Hydra::readFrom(juce::InputStream *file, juce::int64 pdtaChunkEnd) -{ +void sfzero::SF2::Hydra::readFrom(juce::InputStream *file, + juce::int64 pdtaChunkEnd) { int i, numItems; -#define HandleChunk(chunkName) \ - if (FourCCEquals(chunk.id, #chunkName)) \ - { \ - numItems = chunk.size / SF2::chunkName::sizeInFile; \ - chunkName##NumItems = numItems; \ - chunkName##Items = new SF2::chunkName[numItems]; \ - for (i = 0; i < numItems; ++i) \ - { \ - chunkName##Items[i].readFrom(file); \ - } \ - } \ - else - - while (file->getPosition() < pdtaChunkEnd) - { +#define HandleChunk(chunkName) \ + if (FourCCEquals(chunk.id, #chunkName)) { \ + numItems = std::trunc(chunk.size / SF2::chunkName::sizeInFile); \ + chunkName##NumItems = numItems; \ + chunkName##Items = new SF2::chunkName[numItems]; \ + for (i = 0; i < numItems; ++i) { \ + chunkName##Items[i].readFrom(file); \ + } \ + } else + + while (file->getPosition() < pdtaChunkEnd) { sfzero::RIFFChunk chunk; chunk.readFrom(file); - HandleChunk(phdr) HandleChunk(pbag) HandleChunk(pmod) HandleChunk(pgen) HandleChunk(inst) HandleChunk(ibag) HandleChunk(imod) - HandleChunk(igen) HandleChunk(shdr) - { - } + HandleChunk(phdr) HandleChunk(pbag) HandleChunk(pmod) HandleChunk(pgen) + HandleChunk(inst) HandleChunk(ibag) HandleChunk(imod) HandleChunk(igen) + HandleChunk(shdr) {} chunk.seekAfter(file); } } -bool sfzero::SF2::Hydra::isComplete() -{ - return phdrItems && pbagItems && pmodItems && pgenItems && instItems && ibagItems && imodItems && igenItems && shdrItems; +bool sfzero::SF2::Hydra::isComplete() { + return phdrItems && pbagItems && pmodItems && pgenItems && instItems && + ibagItems && imodItems && igenItems && shdrItems; } diff --git a/sfzero/SF2.h b/sfzero/SF2.h index 856149f..9830d4a 100644 --- a/sfzero/SF2.h +++ b/sfzero/SF2.h @@ -2,7 +2,8 @@ * Original code copyright (C) 2012 Steve Folta * Converted to Juce module (C) 2016 Leo Olivers * Forked from https://github.com/stevefolta/SFZero - * For license info please see the LICENSE file distributed with this source code + * For license info please see the LICENSE file distributed with this source + *code *************************************************************************************/ #ifndef SF2_H_INCLUDED #define SF2_H_INCLUDED @@ -11,14 +12,11 @@ #define SF2Field(type, name) type name; -namespace sfzero -{ +namespace sfzero { -namespace SF2 -{ +namespace SF2 { -struct rangesType -{ +struct rangesType { byte lo, hi; }; @@ -28,86 +26,75 @@ union genAmountType { word wordAmount; }; -struct iver -{ +struct iver { #include "sf2-chunks/iver.h" void readFrom(juce::InputStream *file); }; -struct phdr -{ +struct phdr { #include "sf2-chunks/phdr.h" void readFrom(juce::InputStream *file); static const int sizeInFile = 38; }; -struct pbag -{ +struct pbag { #include "sf2-chunks/pbag.h" void readFrom(juce::InputStream *file); static const int sizeInFile = 4; }; -struct pmod -{ +struct pmod { #include "sf2-chunks/pmod.h" void readFrom(juce::InputStream *file); static const int sizeInFile = 10; }; -struct pgen -{ +struct pgen { #include "sf2-chunks/pgen.h" void readFrom(juce::InputStream *file); static const int sizeInFile = 4; }; -struct inst -{ +struct inst { #include "sf2-chunks/inst.h" void readFrom(juce::InputStream *file); static const int sizeInFile = 22; }; -struct ibag -{ +struct ibag { #include "sf2-chunks/ibag.h" void readFrom(juce::InputStream *file); static const int sizeInFile = 4; }; -struct imod -{ +struct imod { #include "sf2-chunks/imod.h" void readFrom(juce::InputStream *file); static const int sizeInFile = 10; }; -struct igen -{ +struct igen { #include "sf2-chunks/igen.h" void readFrom(juce::InputStream *file); static const int sizeInFile = 4; }; -struct shdr -{ +struct shdr { #include "sf2-chunks/shdr.h" void readFrom(juce::InputStream *file); static const int sizeInFile = 46; }; -struct Hydra -{ +struct Hydra { phdr *phdrItems; pbag *pbagItems; pmod *pmodItems; @@ -128,9 +115,9 @@ struct Hydra void readFrom(juce::InputStream *file, juce::int64 pdtaChunkEnd); bool isComplete(); }; -} -} +} // namespace SF2 +} // namespace sfzero #undef SF2Field -#endif // SF2_H_INCLUDED +#endif // SF2_H_INCLUDED diff --git a/sfzero/SF2Generator.cpp b/sfzero/SF2Generator.cpp index d236559..7f481ed 100644 --- a/sfzero/SF2Generator.cpp +++ b/sfzero/SF2Generator.cpp @@ -2,14 +2,13 @@ * Original code copyright (C) 2012 Steve Folta * Converted to Juce module (C) 2016 Leo Olivers * Forked from https://github.com/stevefolta/SFZero - * For license info please see the LICENSE file distributed with this source code + * For license info please see the LICENSE file distributed with this source + *code *************************************************************************************/ #include "SF2Generator.h" -#define SF2GeneratorValue(name, type) \ - { \ - #name, sfzero::SF2Generator::type \ - } +#define SF2GeneratorValue(name, type) \ + { #name, sfzero::SF2Generator::type } static const sfzero::SF2Generator generators[] = { @@ -19,12 +18,10 @@ static const sfzero::SF2Generator generators[] = { #undef SF2GeneratorValue -const sfzero::SF2Generator *sfzero::GeneratorFor(int index) -{ +const sfzero::SF2Generator *sfzero::GeneratorFor(int index) { static const int numGenerators = sizeof(generators) / sizeof(generators[0]); - if (index >= numGenerators) - { + if (index >= numGenerators) { return nullptr; } return &generators[index]; diff --git a/sfzero/SF2Generator.h b/sfzero/SF2Generator.h index bd837ff..2ad7b84 100644 --- a/sfzero/SF2Generator.h +++ b/sfzero/SF2Generator.h @@ -2,7 +2,8 @@ * Original code copyright (C) 2012 Steve Folta * Converted to Juce module (C) 2016 Leo Olivers * Forked from https://github.com/stevefolta/SFZero - * For license info please see the LICENSE file distributed with this source code + * For license info please see the LICENSE file distributed with this source + *code *************************************************************************************/ #ifndef SF2GENERATOR_H_INCLUDED #define SF2GENERATOR_H_INCLUDED @@ -11,23 +12,15 @@ #define SF2GeneratorValue(name, type) name -namespace sfzero -{ +namespace sfzero { -struct SF2Generator -{ - enum Type - { - Word, - Short, - Range - }; +struct SF2Generator { + enum Type { Word, Short, Range }; const char *name; Type type; - enum - { + enum { #include "sf2-chunks/generators.h" }; }; @@ -35,6 +28,6 @@ struct SF2Generator const SF2Generator *GeneratorFor(int index); #undef SF2GeneratorValue -} +} // namespace sfzero -#endif // SF2GENERATOR_H_INCLUDED +#endif // SF2GENERATOR_H_INCLUDED diff --git a/sfzero/SF2Reader.cpp b/sfzero/SF2Reader.cpp index 37ea84c..ba51942 100644 --- a/sfzero/SF2Reader.cpp +++ b/sfzero/SF2Reader.cpp @@ -2,25 +2,28 @@ * Original code copyright (C) 2012 Steve Folta * Converted to Juce module (C) 2016 Leo Olivers * Forked from https://github.com/stevefolta/SFZero - * For license info please see the LICENSE file distributed with this source code + * For license info please see the LICENSE file distributed with this source + *code *************************************************************************************/ #include "SF2Reader.h" + +#include + #include "RIFF.h" #include "SF2.h" #include "SF2Generator.h" #include "SF2Sound.h" -sfzero::SF2Reader::SF2Reader(sfzero::SF2Sound *soundIn, const juce::File &fileIn) : sound_(soundIn) -{ - file_ = fileIn.createInputStream(); +sfzero::SF2Reader::SF2Reader(sfzero::SF2Sound *soundIn, + const juce::File &fileIn) + : sound_(soundIn) { + file_ = fileIn.createInputStream().get(); } sfzero::SF2Reader::~SF2Reader() { delete file_; } -void sfzero::SF2Reader::read() -{ - if (file_ == nullptr) - { +void sfzero::SF2Reader::read() { + if (file_ == nullptr) { sound_->addError("Couldn't open file."); return; } @@ -30,51 +33,45 @@ void sfzero::SF2Reader::read() file_->setPosition(0); sfzero::RIFFChunk riffChunk; riffChunk.readFrom(file_); - while (file_->getPosition() < riffChunk.end()) - { + while (file_->getPosition() < riffChunk.end()) { sfzero::RIFFChunk chunk; chunk.readFrom(file_); - if (FourCCEquals(chunk.id, "pdta")) - { + if (FourCCEquals(chunk.id, "pdta")) { hydra.readFrom(file_, chunk.end()); break; } chunk.seekAfter(file_); } - if (!hydra.isComplete()) - { + if (!hydra.isComplete()) { sound_->addError("Invalid SF2 file (missing or incomplete hydra)."); return; } // Read each preset. - for (int whichPreset = 0; whichPreset < hydra.phdrNumItems - 1; ++whichPreset) - { + for (int whichPreset = 0; whichPreset < hydra.phdrNumItems - 1; + ++whichPreset) { sfzero::SF2::phdr *phdr = &hydra.phdrItems[whichPreset]; - sfzero::SF2Sound::Preset *preset = new sfzero::SF2Sound::Preset(phdr->presetName, phdr->bank, phdr->preset); + sfzero::SF2Sound::Preset *preset = new sfzero::SF2Sound::Preset( + phdr->presetName, phdr->bank, phdr->preset); sound_->addPreset(preset); // Zones. //*** TODO: Handle global zone (modulators only). int zoneEnd = phdr[1].presetBagNdx; - for (int whichZone = phdr->presetBagNdx; whichZone < zoneEnd; ++whichZone) - { + for (int whichZone = phdr->presetBagNdx; whichZone < zoneEnd; ++whichZone) { sfzero::SF2::pbag *pbag = &hydra.pbagItems[whichZone]; sfzero::Region presetRegion; presetRegion.clearForRelativeSF2(); // Generators. int genEnd = pbag[1].genNdx; - for (int whichGen = pbag->genNdx; whichGen < genEnd; ++whichGen) - { + for (int whichGen = pbag->genNdx; whichGen < genEnd; ++whichGen) { sfzero::SF2::pgen *pgen = &hydra.pgenItems[whichGen]; // Instrument. - if (pgen->genOper == sfzero::SF2Generator::instrument) - { + if (pgen->genOper == sfzero::SF2Generator::instrument) { sfzero::word whichInst = pgen->genAmount.wordAmount; - if (whichInst < hydra.instNumItems) - { + if (whichInst < hydra.instNumItems) { sfzero::Region instRegion; instRegion.clearForSF2(); // Preset generators are supposed to be "relative" modifications of @@ -89,19 +86,18 @@ void sfzero::SF2Reader::read() sfzero::SF2::inst *inst = &hydra.instItems[whichInst]; int firstZone = inst->instBagNdx; int zoneEnd2 = inst[1].instBagNdx; - for (int whichZone2 = firstZone; whichZone2 < zoneEnd2; ++whichZone2) - { + for (int whichZone2 = firstZone; whichZone2 < zoneEnd2; + ++whichZone2) { sfzero::SF2::ibag *ibag = &hydra.ibagItems[whichZone2]; // Generators. sfzero::Region zoneRegion = instRegion; bool hadSampleID = false; int genEnd2 = ibag[1].instGenNdx; - for (int whichGen2 = ibag->instGenNdx; whichGen2 < genEnd2; ++whichGen2) - { + for (int whichGen2 = ibag->instGenNdx; whichGen2 < genEnd2; + ++whichGen2) { sfzero::SF2::igen *igen = &hydra.igenItems[whichGen2]; - if (igen->genOper == sfzero::SF2Generator::sampleID) - { + if (igen->genOper == sfzero::SF2Generator::sampleID) { int whichSample = igen->genAmount.wordAmount; sfzero::SF2::shdr *shdr = &hydra.shdrItems[whichSample]; zoneRegion.addForSF2(&presetRegion); @@ -110,21 +106,19 @@ void sfzero::SF2Reader::read() zoneRegion.end += shdr->end; zoneRegion.loop_start += shdr->startLoop; zoneRegion.loop_end += shdr->endLoop; - if (shdr->endLoop > 0) - { + if (shdr->endLoop > 0) { zoneRegion.loop_end -= 1; } - if (zoneRegion.pitch_keycenter == -1) - { + if (zoneRegion.pitch_keycenter == -1) { zoneRegion.pitch_keycenter = shdr->originalPitch; } zoneRegion.tune += shdr->pitchCorrection; // Pin initialAttenuation to max +6dB. - if (zoneRegion.volume > 6.0) - { + if (zoneRegion.volume > 6.0) { zoneRegion.volume = 6.0; - sound_->addUnsupportedOpcode("extreme gain in initialAttenuation"); + sound_->addUnsupportedOpcode( + "extreme gain in initialAttenuation"); } sfzero::Region *newRegion = new sfzero::Region(); @@ -132,36 +126,30 @@ void sfzero::SF2Reader::read() newRegion->sample = sound_->sampleFor(shdr->sampleRate); preset->addRegion(newRegion); hadSampleID = true; - } - else - { - addGeneratorToRegion(igen->genOper, &igen->genAmount, &zoneRegion); + } else { + addGeneratorToRegion(igen->genOper, &igen->genAmount, + &zoneRegion); } } // Handle instrument's global zone. - if ((whichZone2 == firstZone) && !hadSampleID) - { + if ((whichZone2 == firstZone) && !hadSampleID) { instRegion = zoneRegion; } // Modulators. int modEnd = ibag[1].instModNdx; int whichMod = ibag->instModNdx; - if (whichMod < modEnd) - { + if (whichMod < modEnd) { sound_->addUnsupportedOpcode("any modulator"); } } - } - else - { + } else { sound_->addError("Instrument out of range."); } } // Other generators. - else - { + else { addGeneratorToRegion(pgen->genOper, &pgen->genAmount, &presetRegion); } } @@ -169,20 +157,18 @@ void sfzero::SF2Reader::read() // Modulators. int modEnd = pbag[1].modNdx; int whichMod = pbag->modNdx; - if (whichMod < modEnd) - { + if (whichMod < modEnd) { sound_->addUnsupportedOpcode("any modulator"); } } } } -juce::AudioSampleBuffer *sfzero::SF2Reader::readSamples(double *progressVar, juce::Thread *thread) -{ +juce::AudioSampleBuffer *sfzero::SF2Reader::readSamples(double *progressVar, + juce::Thread *thread) { static const int bufferSize = 32768; - if (file_ == nullptr) - { + if (file_ == nullptr) { sound_->addError("Couldn't open file."); return nullptr; } @@ -193,11 +179,9 @@ juce::AudioSampleBuffer *sfzero::SF2Reader::readSamples(double *progressVar, juc riffChunk.readFrom(file_); bool found = false; sfzero::RIFFChunk chunk; - while (file_->getPosition() < riffChunk.end()) - { + while (file_->getPosition() < riffChunk.end()) { chunk.readFrom(file_); - if (FourCCEquals(chunk.id, "sdta")) - { + if (FourCCEquals(chunk.id, "sdta")) { found = true; break; } @@ -205,36 +189,32 @@ juce::AudioSampleBuffer *sfzero::SF2Reader::readSamples(double *progressVar, juc } juce::int64 sdtaEnd = chunk.end(); found = false; - while (file_->getPosition() < sdtaEnd) - { + while (file_->getPosition() < sdtaEnd) { chunk.readFrom(file_); - if (FourCCEquals(chunk.id, "smpl")) - { + if (FourCCEquals(chunk.id, "smpl")) { found = true; break; } chunk.seekAfter(file_); } - if (!found) - { + if (!found) { sound_->addError("SF2 is missing its \"smpl\" chunk."); return nullptr; } // Allocate the AudioSampleBuffer. - int numSamples = chunk.size / sizeof(short); - juce::AudioSampleBuffer *sampleBuffer = new juce::AudioSampleBuffer(1, numSamples); + int numSamples = std::trunc(chunk.size / sizeof(short)); + juce::AudioSampleBuffer *sampleBuffer = + new juce::AudioSampleBuffer(1, numSamples); // Read and convert. short *buffer = new short[bufferSize]; int samplesLeft = numSamples; float *out = sampleBuffer->getWritePointer(0); - while (samplesLeft > 0) - { + while (samplesLeft > 0) { // Read the buffer. int samplesToRead = bufferSize; - if (samplesToRead > samplesLeft) - { + if (samplesToRead > samplesLeft) { samplesToRead = samplesLeft; } file_->read(buffer, samplesToRead * sizeof(short)); @@ -242,8 +222,7 @@ juce::AudioSampleBuffer *sfzero::SF2Reader::readSamples(double *progressVar, juc // Convert from signed 16-bit to float. int samplesToConvert = samplesToRead; short *in = buffer; - for (; samplesToConvert > 0; --samplesToConvert) - { + for (; samplesToConvert > 0; --samplesToConvert) { // If we ever need to compile for big-endian platforms, we'll need to // byte-swap here. *out++ = *in++ / 32767.0f; @@ -251,12 +230,10 @@ juce::AudioSampleBuffer *sfzero::SF2Reader::readSamples(double *progressVar, juc samplesLeft -= samplesToRead; - if (progressVar) - { + if (progressVar) { *progressVar = static_cast(numSamples - samplesLeft) / numSamples; } - if (thread && thread->threadShouldExit()) - { + if (thread && thread->threadShouldExit()) { delete[] buffer; delete sampleBuffer; return nullptr; @@ -264,169 +241,166 @@ juce::AudioSampleBuffer *sfzero::SF2Reader::readSamples(double *progressVar, juc } delete[] buffer; - if (progressVar) - { + if (progressVar) { *progressVar = 1.0; } return sampleBuffer; } -void sfzero::SF2Reader::addGeneratorToRegion(sfzero::word genOper, sfzero::SF2::genAmountType *amount, sfzero::Region *region) -{ - switch (genOper) - { - case sfzero::SF2Generator::startAddrsOffset: - region->offset += amount->shortAmount; - break; - - case sfzero::SF2Generator::endAddrsOffset: - region->end += amount->shortAmount; - break; - - case sfzero::SF2Generator::startloopAddrsOffset: - region->loop_start += amount->shortAmount; - break; - - case sfzero::SF2Generator::endloopAddrsOffset: - region->loop_end += amount->shortAmount; - break; - - case sfzero::SF2Generator::startAddrsCoarseOffset: - region->offset += amount->shortAmount * 32768; - break; - - case sfzero::SF2Generator::endAddrsCoarseOffset: - region->end += amount->shortAmount * 32768; - break; - - case sfzero::SF2Generator::pan: - region->pan = amount->shortAmount * (2.0f / 10.0f); - break; - - case sfzero::SF2Generator::delayVolEnv: - region->ampeg.delay = amount->shortAmount; - break; - - case sfzero::SF2Generator::attackVolEnv: - region->ampeg.attack = amount->shortAmount; - break; - - case sfzero::SF2Generator::holdVolEnv: - region->ampeg.hold = amount->shortAmount; - break; - - case sfzero::SF2Generator::decayVolEnv: - region->ampeg.decay = amount->shortAmount; - break; - - case sfzero::SF2Generator::sustainVolEnv: - region->ampeg.sustain = amount->shortAmount; - break; - - case sfzero::SF2Generator::releaseVolEnv: - region->ampeg.release = amount->shortAmount; - break; - - case sfzero::SF2Generator::keyRange: - region->lokey = amount->range.lo; - region->hikey = amount->range.hi; - break; - - case sfzero::SF2Generator::velRange: - region->lovel = amount->range.lo; - region->hivel = amount->range.hi; - break; - - case sfzero::SF2Generator::startloopAddrsCoarseOffset: - region->loop_start += amount->shortAmount * 32768; - break; - - case sfzero::SF2Generator::initialAttenuation: - // The spec says "initialAttenuation" is in centibels. But everyone - // seems to treat it as millibels. - region->volume += -amount->shortAmount / 100.0f; - break; - - case sfzero::SF2Generator::endloopAddrsCoarseOffset: - region->loop_end += amount->shortAmount * 32768; - break; - - case sfzero::SF2Generator::coarseTune: - region->transpose += amount->shortAmount; - break; - - case sfzero::SF2Generator::fineTune: - region->tune += amount->shortAmount; - break; - - case sfzero::SF2Generator::sampleModes: - { - sfzero::Region::LoopMode loopModes[] = {sfzero::Region::no_loop, sfzero::Region::loop_continuous, sfzero::Region::no_loop, - sfzero::Region::loop_sustain}; - region->loop_mode = loopModes[amount->wordAmount & 0x03]; - } - break; - - case sfzero::SF2Generator::scaleTuning: - region->pitch_keytrack = amount->shortAmount; - break; - - case sfzero::SF2Generator::exclusiveClass: - region->off_by = amount->wordAmount; - region->group = static_cast(region->off_by); - break; - - case sfzero::SF2Generator::overridingRootKey: - region->pitch_keycenter = amount->shortAmount; - break; - - case sfzero::SF2Generator::endOper: - // Ignore. - break; - - case sfzero::SF2Generator::modLfoToPitch: - case sfzero::SF2Generator::vibLfoToPitch: - case sfzero::SF2Generator::modEnvToPitch: - case sfzero::SF2Generator::initialFilterFc: - case sfzero::SF2Generator::initialFilterQ: - case sfzero::SF2Generator::modLfoToFilterFc: - case sfzero::SF2Generator::modEnvToFilterFc: - case sfzero::SF2Generator::modLfoToVolume: - case sfzero::SF2Generator::unused1: - case sfzero::SF2Generator::chorusEffectsSend: - case sfzero::SF2Generator::reverbEffectsSend: - case sfzero::SF2Generator::unused2: - case sfzero::SF2Generator::unused3: - case sfzero::SF2Generator::unused4: - case sfzero::SF2Generator::delayModLFO: - case sfzero::SF2Generator::freqModLFO: - case sfzero::SF2Generator::delayVibLFO: - case sfzero::SF2Generator::freqVibLFO: - case sfzero::SF2Generator::delayModEnv: - case sfzero::SF2Generator::attackModEnv: - case sfzero::SF2Generator::holdModEnv: - case sfzero::SF2Generator::decayModEnv: - case sfzero::SF2Generator::sustainModEnv: - case sfzero::SF2Generator::releaseModEnv: - case sfzero::SF2Generator::keynumToModEnvHold: - case sfzero::SF2Generator::keynumToModEnvDecay: - case sfzero::SF2Generator::keynumToVolEnvHold: - case sfzero::SF2Generator::keynumToVolEnvDecay: - case sfzero::SF2Generator::instrument: - // Only allowed in certain places, where we already special-case it. - case sfzero::SF2Generator::reserved1: - case sfzero::SF2Generator::keynum: - case sfzero::SF2Generator::velocity: - case sfzero::SF2Generator::reserved2: - case sfzero::SF2Generator::sampleID: - // Only allowed in certain places, where we already special-case it. - case sfzero::SF2Generator::reserved3: - case sfzero::SF2Generator::unused5: - { - const sfzero::SF2Generator *generator = sfzero::GeneratorFor(static_cast(genOper)); - sound_->addUnsupportedOpcode(generator->name); - } - break; +void sfzero::SF2Reader::addGeneratorToRegion(sfzero::word genOper, + sfzero::SF2::genAmountType *amount, + sfzero::Region *region) { + switch (genOper) { + case sfzero::SF2Generator::startAddrsOffset: + region->offset += amount->shortAmount; + break; + + case sfzero::SF2Generator::endAddrsOffset: + region->end += amount->shortAmount; + break; + + case sfzero::SF2Generator::startloopAddrsOffset: + region->loop_start += amount->shortAmount; + break; + + case sfzero::SF2Generator::endloopAddrsOffset: + region->loop_end += amount->shortAmount; + break; + + case sfzero::SF2Generator::startAddrsCoarseOffset: + region->offset += amount->shortAmount * 32768; + break; + + case sfzero::SF2Generator::endAddrsCoarseOffset: + region->end += amount->shortAmount * 32768; + break; + + case sfzero::SF2Generator::pan: + region->pan = amount->shortAmount * (2.0f / 10.0f); + break; + + case sfzero::SF2Generator::delayVolEnv: + region->ampeg.delay = amount->shortAmount; + break; + + case sfzero::SF2Generator::attackVolEnv: + region->ampeg.attack = amount->shortAmount; + break; + + case sfzero::SF2Generator::holdVolEnv: + region->ampeg.hold = amount->shortAmount; + break; + + case sfzero::SF2Generator::decayVolEnv: + region->ampeg.decay = amount->shortAmount; + break; + + case sfzero::SF2Generator::sustainVolEnv: + region->ampeg.sustain = amount->shortAmount; + break; + + case sfzero::SF2Generator::releaseVolEnv: + region->ampeg.release = amount->shortAmount; + break; + + case sfzero::SF2Generator::keyRange: + region->lokey = amount->range.lo; + region->hikey = amount->range.hi; + break; + + case sfzero::SF2Generator::velRange: + region->lovel = amount->range.lo; + region->hivel = amount->range.hi; + break; + + case sfzero::SF2Generator::startloopAddrsCoarseOffset: + region->loop_start += amount->shortAmount * 32768; + break; + + case sfzero::SF2Generator::initialAttenuation: + // The spec says "initialAttenuation" is in centibels. But everyone + // seems to treat it as millibels. + region->volume += -amount->shortAmount / 100.0f; + break; + + case sfzero::SF2Generator::endloopAddrsCoarseOffset: + region->loop_end += amount->shortAmount * 32768; + break; + + case sfzero::SF2Generator::coarseTune: + region->transpose += amount->shortAmount; + break; + + case sfzero::SF2Generator::fineTune: + region->tune += amount->shortAmount; + break; + + case sfzero::SF2Generator::sampleModes: { + sfzero::Region::LoopMode loopModes[] = { + sfzero::Region::no_loop, sfzero::Region::loop_continuous, + sfzero::Region::no_loop, sfzero::Region::loop_sustain}; + region->loop_mode = loopModes[amount->wordAmount & 0x03]; + } break; + + case sfzero::SF2Generator::scaleTuning: + region->pitch_keytrack = amount->shortAmount; + break; + + case sfzero::SF2Generator::exclusiveClass: + region->off_by = amount->wordAmount; + region->group = static_cast(region->off_by); + break; + + case sfzero::SF2Generator::overridingRootKey: + region->pitch_keycenter = amount->shortAmount; + break; + + case sfzero::SF2Generator::endOper: + // Ignore. + break; + + case sfzero::SF2Generator::modLfoToPitch: + case sfzero::SF2Generator::vibLfoToPitch: + case sfzero::SF2Generator::modEnvToPitch: + case sfzero::SF2Generator::initialFilterFc: + case sfzero::SF2Generator::initialFilterQ: + case sfzero::SF2Generator::modLfoToFilterFc: + case sfzero::SF2Generator::modEnvToFilterFc: + case sfzero::SF2Generator::modLfoToVolume: + case sfzero::SF2Generator::unused1: + case sfzero::SF2Generator::chorusEffectsSend: + case sfzero::SF2Generator::reverbEffectsSend: + case sfzero::SF2Generator::unused2: + case sfzero::SF2Generator::unused3: + case sfzero::SF2Generator::unused4: + case sfzero::SF2Generator::delayModLFO: + case sfzero::SF2Generator::freqModLFO: + case sfzero::SF2Generator::delayVibLFO: + case sfzero::SF2Generator::freqVibLFO: + case sfzero::SF2Generator::delayModEnv: + case sfzero::SF2Generator::attackModEnv: + case sfzero::SF2Generator::holdModEnv: + case sfzero::SF2Generator::decayModEnv: + case sfzero::SF2Generator::sustainModEnv: + case sfzero::SF2Generator::releaseModEnv: + case sfzero::SF2Generator::keynumToModEnvHold: + case sfzero::SF2Generator::keynumToModEnvDecay: + case sfzero::SF2Generator::keynumToVolEnvHold: + case sfzero::SF2Generator::keynumToVolEnvDecay: + case sfzero::SF2Generator::instrument: + // Only allowed in certain places, where we already special-case it. + case sfzero::SF2Generator::reserved1: + case sfzero::SF2Generator::keynum: + case sfzero::SF2Generator::velocity: + case sfzero::SF2Generator::reserved2: + case sfzero::SF2Generator::sampleID: + // Only allowed in certain places, where we already special-case it. + case sfzero::SF2Generator::reserved3: + case sfzero::SF2Generator::unused5: { + const sfzero::SF2Generator *generator = + sfzero::GeneratorFor(static_cast(genOper)); + sound_->addUnsupportedOpcode(generator->name); + } break; } } diff --git a/sfzero/SF2Reader.h b/sfzero/SF2Reader.h index 533e2c7..fc03414 100644 --- a/sfzero/SF2Reader.h +++ b/sfzero/SF2Reader.h @@ -2,36 +2,37 @@ * Original code copyright (C) 2012 Steve Folta * Converted to Juce module (C) 2016 Leo Olivers * Forked from https://github.com/stevefolta/SFZero - * For license info please see the LICENSE file distributed with this source code + * For license info please see the LICENSE file distributed with this source + *code *************************************************************************************/ #ifndef SF2READER_H_INCLUDED #define SF2READER_H_INCLUDED #include "SF2.h" -namespace sfzero -{ +namespace sfzero { class SF2Sound; class Sample; struct Region; -class SF2Reader -{ -public: +class SF2Reader { + public: SF2Reader(SF2Sound *sound, const juce::File &file); virtual ~SF2Reader(); void read(); - juce::AudioSampleBuffer *readSamples(double *progressVar = nullptr, juce::Thread *thread = nullptr); + juce::AudioSampleBuffer *readSamples(double *progressVar = nullptr, + juce::Thread *thread = nullptr); -private: + private: SF2Sound *sound_; juce::FileInputStream *file_; - void addGeneratorToRegion(word genOper, SF2::genAmountType *amount, Region *region); + void addGeneratorToRegion(word genOper, SF2::genAmountType *amount, + Region *region); JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(SF2Reader) }; -} +} // namespace sfzero -#endif // SF2READER_H_INCLUDED +#endif // SF2READER_H_INCLUDED diff --git a/sfzero/SF2Sound.cpp b/sfzero/SF2Sound.cpp index 5bc8015..6723ffb 100644 --- a/sfzero/SF2Sound.cpp +++ b/sfzero/SF2Sound.cpp @@ -2,16 +2,18 @@ * Original code copyright (C) 2012 Steve Folta * Converted to Juce module (C) 2016 Leo Olivers * Forked from https://github.com/stevefolta/SFZero - * For license info please see the LICENSE file distributed with this source code + * For license info please see the LICENSE file distributed with this source + *code *************************************************************************************/ #include "SF2Sound.h" + #include "SF2Reader.h" #include "SFZSample.h" -sfzero::SF2Sound::SF2Sound(const juce::File &file) : sfzero::Sound(file), selectedPreset_(0) {} +sfzero::SF2Sound::SF2Sound(const juce::File &file) + : sfzero::Sound(file), selectedPreset_(0) {} -sfzero::SF2Sound::~SF2Sound() -{ +sfzero::SF2Sound::~SF2Sound() { // "presets" owns the regions, so clear them out of "regions" so ~SFZSound() // doesn't try to delete them. getRegions().clear(); @@ -19,30 +21,27 @@ sfzero::SF2Sound::~SF2Sound() // The samples all share a single buffer, so make sure they don't all delete // it. juce::AudioSampleBuffer *buffer = nullptr; - for (juce::HashMap::Iterator i(samplesByRate_); i.next();) - { + for (juce::HashMap::Iterator i(samplesByRate_); + i.next();) { buffer = i.getValue()->detachBuffer(); } delete buffer; } -class PresetComparator -{ -public: - static int compareElements(const sfzero::SF2Sound::Preset *first, const sfzero::SF2Sound::Preset *second) - { +class PresetComparator { + public: + static int compareElements(const sfzero::SF2Sound::Preset *first, + const sfzero::SF2Sound::Preset *second) { int cmp = first->bank - second->bank; - if (cmp != 0) - { + if (cmp != 0) { return cmp; } return first->preset - second->preset; } }; -void sfzero::SF2Sound::loadRegions() -{ +void sfzero::SF2Sound::loadRegions() { sfzero::SF2Reader reader(this, getFile()); reader.read(); @@ -54,37 +53,35 @@ void sfzero::SF2Sound::loadRegions() useSubsound(0); } -void sfzero::SF2Sound::loadSamples(juce::AudioFormatManager * /*formatManager*/, double *progressVar, juce::Thread *thread) -{ +void sfzero::SF2Sound::loadSamples(juce::AudioFormatManager * /*formatManager*/, + double *progressVar, juce::Thread *thread) { sfzero::SF2Reader reader(this, getFile()); juce::AudioSampleBuffer *buffer = reader.readSamples(progressVar, thread); - if (buffer) - { + if (buffer) { // All the SFZSamples will share the buffer. - for (juce::HashMap::Iterator i(samplesByRate_); i.next();) - { + for (juce::HashMap::Iterator i(samplesByRate_); + i.next();) { i.getValue()->setBuffer(buffer); } } - if (progressVar) - { + if (progressVar) { *progressVar = 1.0; } } -void sfzero::SF2Sound::addPreset(sfzero::SF2Sound::Preset *preset) { presets_.add(preset); } +void sfzero::SF2Sound::addPreset(sfzero::SF2Sound::Preset *preset) { + presets_.add(preset); +} int sfzero::SF2Sound::numSubsounds() { return presets_.size(); } -juce::String sfzero::SF2Sound::subsoundName(int whichSubsound) -{ +juce::String sfzero::SF2Sound::subsoundName(int whichSubsound) { Preset *preset = presets_[whichSubsound]; juce::String result; - if (preset->bank != 0) - { + if (preset->bank != 0) { result += preset->bank; result += "/"; } @@ -94,8 +91,7 @@ juce::String sfzero::SF2Sound::subsoundName(int whichSubsound) return result; } -void sfzero::SF2Sound::useSubsound(int whichSubsound) -{ +void sfzero::SF2Sound::useSubsound(int whichSubsound) { selectedPreset_ = whichSubsound; getRegions().clear(); getRegions().addArray(presets_[whichSubsound]->regions); @@ -103,22 +99,19 @@ void sfzero::SF2Sound::useSubsound(int whichSubsound) int sfzero::SF2Sound::selectedSubsound() { return selectedPreset_; } -sfzero::Sample *sfzero::SF2Sound::sampleFor(double sampleRate) -{ +sfzero::Sample *sfzero::SF2Sound::sampleFor(double sampleRate) { sfzero::Sample *sample = samplesByRate_[static_cast(sampleRate)]; - if (sample == nullptr) - { + if (sample == nullptr) { sample = new sfzero::Sample(sampleRate); samplesByRate_.set(static_cast(sampleRate), sample); } return sample; } -void sfzero::SF2Sound::setSamplesBuffer(juce::AudioSampleBuffer *buffer) -{ - for (juce::HashMap::Iterator i(samplesByRate_); i.next();) - { +void sfzero::SF2Sound::setSamplesBuffer(juce::AudioSampleBuffer *buffer) { + for (juce::HashMap::Iterator i(samplesByRate_); + i.next();) { i.getValue()->setBuffer(buffer); } } diff --git a/sfzero/SF2Sound.h b/sfzero/SF2Sound.h index 70b00e2..7d2cf74 100644 --- a/sfzero/SF2Sound.h +++ b/sfzero/SF2Sound.h @@ -2,33 +2,34 @@ * Original code copyright (C) 2012 Steve Folta * Converted to Juce module (C) 2016 Leo Olivers * Forked from https://github.com/stevefolta/SFZero - * For license info please see the LICENSE file distributed with this source code + * For license info please see the LICENSE file distributed with this source + *code *************************************************************************************/ #ifndef SF2SOUND_H_INCLUDED #define SF2SOUND_H_INCLUDED #include "SFZSound.h" -namespace sfzero -{ +namespace sfzero { -class SF2Sound : public Sound -{ -public: +class SF2Sound : public Sound { + public: explicit SF2Sound(const juce::File &file); virtual ~SF2Sound(); void loadRegions() override; - void loadSamples(juce::AudioFormatManager *formatManager, double *progressVar = nullptr, juce::Thread *thread = nullptr) override; + void loadSamples(juce::AudioFormatManager *formatManager, + double *progressVar = nullptr, + juce::Thread *thread = nullptr) override; - struct Preset - { + struct Preset { juce::String name; int bank; int preset; juce::OwnedArray regions; - Preset(juce::String nameIn, int bankIn, int presetIn) : name(nameIn), bank(bankIn), preset(presetIn) {} + Preset(juce::String nameIn, int bankIn, int presetIn) + : name(nameIn), bank(bankIn), preset(presetIn) {} ~Preset() {} void addRegion(Region *region) { regions.add(region); } }; @@ -42,12 +43,12 @@ class SF2Sound : public Sound Sample *sampleFor(double sampleRate); void setSamplesBuffer(juce::AudioSampleBuffer *buffer); -private: + private: juce::OwnedArray presets_; juce::HashMap samplesByRate_; int selectedPreset_; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(SF2Sound) }; -} +} // namespace sfzero -#endif // SF2SOUND_H_INCLUDED +#endif // SF2SOUND_H_INCLUDED diff --git a/sfzero/SF2WinTypes.h b/sfzero/SF2WinTypes.h index 27d2be2..2e0faa3 100644 --- a/sfzero/SF2WinTypes.h +++ b/sfzero/SF2WinTypes.h @@ -2,20 +2,21 @@ * Original code copyright (C) 2012 Steve Folta * Converted to Juce module (C) 2016 Leo Olivers * Forked from https://github.com/stevefolta/SFZero - * For license info please see the LICENSE file distributed with this source code + * For license info please see the LICENSE file distributed with this source + *code *************************************************************************************/ #ifndef SF2WINTYPES_H_INCLUDED #define SF2WINTYPES_H_INCLUDED #include "SFZCommon.h" -#define FourCCEquals(value1, value2) \ - (value1[0] == value2[0] && value1[1] == value2[1] && value1[2] == value2[2] && value1[3] == value2[3]) +#define FourCCEquals(value1, value2) \ + (value1[0] == value2[0] && value1[1] == value2[1] && \ + value1[2] == value2[2] && value1[3] == value2[3]) // Useful in printfs: #define FourCCArgs(value) (value)[0], (value)[1], (value)[2], (value)[3] -namespace sfzero -{ +namespace sfzero { typedef char fourcc[4]; typedef unsigned char byte; typedef unsigned long dword; @@ -23,6 +24,6 @@ typedef unsigned short word; // Special types for SF2 fields. typedef char char20[20]; -} +} // namespace sfzero -#endif // SF2WINTYPES_H_INCLUDED +#endif // SF2WINTYPES_H_INCLUDED diff --git a/sfzero/SFZCommon.h b/sfzero/SFZCommon.h index 66faa30..2844490 100644 --- a/sfzero/SFZCommon.h +++ b/sfzero/SFZCommon.h @@ -2,16 +2,15 @@ * Original code copyright (C) 2012 Steve Folta * Converted to Juce module (C) 2016 Leo Olivers * Forked from https://github.com/stevefolta/SFZero - * For license info please see the LICENSE file distributed with this source code + * For license info please see the LICENSE file distributed with this source + *code *************************************************************************************/ #ifndef SFZCOMMON_H_INCLUDED #define SFZCOMMON_H_INCLUDED -#include "AppConfig.h" - #include #include #include #include -#endif // SFZCOMMON_H_INCLUDED +#endif // SFZCOMMON_H_INCLUDED diff --git a/sfzero/SFZDebug.cpp b/sfzero/SFZDebug.cpp index 64167b4..d5af6b9 100644 --- a/sfzero/SFZDebug.cpp +++ b/sfzero/SFZDebug.cpp @@ -2,15 +2,16 @@ * Original code copyright (C) 2012 Steve Folta * Converted to Juce module (C) 2016 Leo Olivers * Forked from https://github.com/stevefolta/SFZero - * For license info please see the LICENSE file distributed with this source code + * For license info please see the LICENSE file distributed with this source + *code *************************************************************************************/ #include "SFZDebug.h" + #include #ifdef JUCE_DEBUG -void sfzero::dbgprintf(const char *msg, ...) -{ +void sfzero::dbgprintf(const char *msg, ...) { va_list args; va_start(args, msg); @@ -21,4 +22,4 @@ void sfzero::dbgprintf(const char *msg, ...) va_end(args); } -#endif // JUCE_DEBUG +#endif // JUCE_DEBUG diff --git a/sfzero/SFZDebug.h b/sfzero/SFZDebug.h index dc35e33..dac26f9 100644 --- a/sfzero/SFZDebug.h +++ b/sfzero/SFZDebug.h @@ -2,7 +2,8 @@ * Original code copyright (C) 2012 Steve Folta * Converted to Juce module (C) 2016 Leo Olivers * Forked from https://github.com/stevefolta/SFZero - * For license info please see the LICENSE file distributed with this source code + * For license info please see the LICENSE file distributed with this source + *code *************************************************************************************/ #ifndef SFZDEBUG_H_INCLUDED #define SFZDEBUG_H_INCLUDED @@ -11,11 +12,10 @@ #ifdef JUCE_DEBUG -namespace sfzero -{ +namespace sfzero { void dbgprintf(const char *msg, ...); } #endif -#endif // SFZDEBUG_H_INCLUDED +#endif // SFZDEBUG_H_INCLUDED diff --git a/sfzero/SFZEG.cpp b/sfzero/SFZEG.cpp index 70cdf6c..0d47ba6 100644 --- a/sfzero/SFZEG.cpp +++ b/sfzero/SFZEG.cpp @@ -2,36 +2,39 @@ * Original code copyright (C) 2012 Steve Folta * Converted to Juce module (C) 2016 Leo Olivers * Forked from https://github.com/stevefolta/SFZero - * For license info please see the LICENSE file distributed with this source code + * For license info please see the LICENSE file distributed with this source + *code *************************************************************************************/ #include "SFZEG.h" static const float fastReleaseTime = 0.01f; sfzero::EG::EG() - : segment_(), sampleRate_(0), exponentialDecay_(false), level_(0), slope_(0), samplesUntilNextSegment_(0), segmentIsExponential_(false) -{ + : segment_(), + sampleRate_(0), + exponentialDecay_(false), + level_(0), + slope_(0), + samplesUntilNextSegment_(0), + segmentIsExponential_(false) {} + +void sfzero::EG::setExponentialDecay(bool newExponentialDecay) { + exponentialDecay_ = newExponentialDecay; } -void sfzero::EG::setExponentialDecay(bool newExponentialDecay) { exponentialDecay_ = newExponentialDecay; } - -void sfzero::EG::startNote(const EGParameters *newParameters, float floatVelocity, double newSampleRate, - const EGParameters *velMod) -{ +void sfzero::EG::startNote(const EGParameters *newParameters, + float floatVelocity, double newSampleRate, + const EGParameters *velMod) { parameters_ = *newParameters; - if (velMod) - { + if (velMod) { parameters_.delay += floatVelocity * velMod->delay; parameters_.attack += floatVelocity * velMod->attack; parameters_.hold += floatVelocity * velMod->hold; parameters_.decay += floatVelocity * velMod->decay; parameters_.sustain += floatVelocity * velMod->sustain; - if (parameters_.sustain < 0.0) - { + if (parameters_.sustain < 0.0) { parameters_.sustain = 0.0; - } - else if (parameters_.sustain > 100.0) - { + } else if (parameters_.sustain > 100.0) { parameters_.sustain = 100.0; } parameters_.release += floatVelocity * velMod->release; @@ -41,88 +44,75 @@ void sfzero::EG::startNote(const EGParameters *newParameters, float floatVelocit startDelay(); } -void sfzero::EG::nextSegment() -{ - switch (segment_) - { - case Delay: - startAttack(); - break; +void sfzero::EG::nextSegment() { + switch (segment_) { + case Delay: + startAttack(); + break; - case Attack: - startHold(); - break; + case Attack: + startHold(); + break; - case Hold: - startDecay(); - break; + case Hold: + startDecay(); + break; - case Decay: - startSustain(); - break; + case Decay: + startSustain(); + break; - case Sustain: - // Shouldn't be called. - break; + case Sustain: + // Shouldn't be called. + break; - case Release: - default: - segment_ = Done; - break; + case Release: + default: + segment_ = Done; + break; } } void sfzero::EG::noteOff() { startRelease(); } -void sfzero::EG::fastRelease() -{ +void sfzero::EG::fastRelease() { segment_ = Release; samplesUntilNextSegment_ = static_cast(fastReleaseTime * sampleRate_); slope_ = -level_ / samplesUntilNextSegment_; segmentIsExponential_ = false; } -void sfzero::EG::startDelay() -{ - if (parameters_.delay <= 0) - { +void sfzero::EG::startDelay() { + if (parameters_.delay <= 0) { startAttack(); - } - else - { + } else { segment_ = Delay; level_ = 0.0; slope_ = 0.0; - samplesUntilNextSegment_ = static_cast(parameters_.delay * sampleRate_); + samplesUntilNextSegment_ = + static_cast(parameters_.delay * sampleRate_); segmentIsExponential_ = false; } } -void sfzero::EG::startAttack() -{ - if (parameters_.attack <= 0) - { +void sfzero::EG::startAttack() { + if (parameters_.attack <= 0) { startHold(); - } - else - { + } else { segment_ = Attack; level_ = parameters_.start / 100.0f; - samplesUntilNextSegment_ = static_cast(parameters_.attack * sampleRate_); + samplesUntilNextSegment_ = + static_cast(parameters_.attack * sampleRate_); slope_ = 1.0f / samplesUntilNextSegment_; segmentIsExponential_ = false; } } -void sfzero::EG::startHold() -{ - if (parameters_.hold <= 0) - { +void sfzero::EG::startHold() { + if (parameters_.hold <= 0) { level_ = 1.0; startDecay(); - } - else - { + } else { segment_ = Hold; samplesUntilNextSegment_ = static_cast(parameters_.hold * sampleRate_); level_ = 1.0; @@ -131,53 +121,42 @@ void sfzero::EG::startHold() } } -void sfzero::EG::startDecay() -{ - if (parameters_.decay <= 0) - { +void sfzero::EG::startDecay() { + if (parameters_.decay <= 0) { startSustain(); - } - else - { + } else { segment_ = Decay; - samplesUntilNextSegment_ = static_cast(parameters_.decay * sampleRate_); + samplesUntilNextSegment_ = + static_cast(parameters_.decay * sampleRate_); level_ = 1.0; - if (exponentialDecay_) - { + if (exponentialDecay_) { // I don't truly understand this; just following what LinuxSampler does. float mysterySlope = -9.226f / samplesUntilNextSegment_; slope_ = exp(mysterySlope); segmentIsExponential_ = true; - if (parameters_.sustain > 0.0) - { + if (parameters_.sustain > 0.0) { // Again, this is following LinuxSampler's example, which is similar to // SF2-style decay, where "decay" specifies the time it would take to // get to zero, not to the sustain level. The SFZ spec is not that // specific about what "decay" means, so perhaps it's really supposed // to specify the time to reach the sustain level. - samplesUntilNextSegment_ = static_cast(log((parameters_.sustain / 100.0) / level_) / mysterySlope); - if (samplesUntilNextSegment_ <= 0) - { + samplesUntilNextSegment_ = static_cast( + log((parameters_.sustain / 100.0) / level_) / mysterySlope); + if (samplesUntilNextSegment_ <= 0) { startSustain(); } } - } - else - { + } else { slope_ = (parameters_.sustain / 100.0f - 1.0f) / samplesUntilNextSegment_; segmentIsExponential_ = false; } } } -void sfzero::EG::startSustain() -{ - if (parameters_.sustain <= 0) - { +void sfzero::EG::startSustain() { + if (parameters_.sustain <= 0) { startRelease(); - } - else - { + } else { segment_ = Sustain; level_ = parameters_.sustain / 100.0f; slope_ = 0.0; @@ -186,27 +165,22 @@ void sfzero::EG::startSustain() } } -void sfzero::EG::startRelease() -{ +void sfzero::EG::startRelease() { float release = parameters_.release; - if (release <= 0) - { + if (release <= 0) { // Enforce a short release, to prevent clicks. release = fastReleaseTime; } segment_ = Release; samplesUntilNextSegment_ = static_cast(release * sampleRate_); - if (exponentialDecay_) - { + if (exponentialDecay_) { // I don't truly understand this; just following what LinuxSampler does. float mysterySlope = -9.226f / samplesUntilNextSegment_; slope_ = exp(mysterySlope); segmentIsExponential_ = true; - } - else - { + } else { slope_ = -level_ / samplesUntilNextSegment_; segmentIsExponential_ = false; } diff --git a/sfzero/SFZEG.h b/sfzero/SFZEG.h index a274712..4fee6cb 100644 --- a/sfzero/SFZEG.h +++ b/sfzero/SFZEG.h @@ -2,23 +2,23 @@ * Original code copyright (C) 2012 Steve Folta * Converted to Juce module (C) 2016 Leo Olivers * Forked from https://github.com/stevefolta/SFZero - * For license info please see the LICENSE file distributed with this source code + * For license info please see the LICENSE file distributed with this source + *code *************************************************************************************/ #ifndef SFZEG_H_INCLUDED #define SFZEG_H_INCLUDED #include "SFZRegion.h" -namespace sfzero -{ -class EG -{ -public: +namespace sfzero { +class EG { + public: EG(); virtual ~EG() {} void setExponentialDecay(bool newExponentialDecay); - void startNote(const EGParameters *parameters, float floatVelocity, double sampleRate, const EGParameters *velMod = nullptr); + void startNote(const EGParameters *parameters, float floatVelocity, + double sampleRate, const EGParameters *velMod = nullptr); void nextSegment(); void noteOff(); void fastRelease(); @@ -34,17 +34,8 @@ class EG bool getSegmentIsExponential() const { return segmentIsExponential_; } void setSegmentIsExponential(bool v) { segmentIsExponential_ = v; } -private: - enum Segment - { - Delay, - Attack, - Hold, - Decay, - Sustain, - Release, - Done - }; + private: + enum Segment { Delay, Attack, Hold, Decay, Sustain, Release, Done }; void startDelay(); void startAttack(); @@ -64,6 +55,6 @@ class EG static const float BottomLevel; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(EG) }; -} +} // namespace sfzero -#endif // SFZEG_H_INCLUDED +#endif // SFZEG_H_INCLUDED diff --git a/sfzero/SFZReader.cpp b/sfzero/SFZReader.cpp index efb55bc..357241b 100644 --- a/sfzero/SFZReader.cpp +++ b/sfzero/SFZReader.cpp @@ -2,9 +2,14 @@ * Original code copyright (C) 2012 Steve Folta * Converted to Juce module (C) 2016 Leo Olivers * Forked from https://github.com/stevefolta/SFZero - * For license info please see the LICENSE file distributed with this source code + * For license info please see the LICENSE file distributed with this source + *code *************************************************************************************/ + #include "SFZReader.h" + +#include + #include "SFZRegion.h" #include "SFZSound.h" @@ -12,22 +17,20 @@ sfzero::Reader::Reader(sfzero::Sound *soundIn) : sound_(soundIn), line_(1) {} sfzero::Reader::~Reader() {} -void sfzero::Reader::read(const juce::File &file) -{ +void sfzero::Reader::read(const juce::File &file) { juce::MemoryBlock contents; bool ok = file.loadFileAsData(contents); - if (!ok) - { + if (!ok) { sound_->addError("Couldn't read \"" + file.getFullPathName() + "\""); return; } - read(static_cast(contents.getData()), static_cast(contents.getSize())); + read(static_cast(contents.getData()), + static_cast(contents.getSize())); } -void sfzero::Reader::read(const char *text, unsigned int length) -{ +void sfzero::Reader::read(const char *text, unsigned int length) { const char *p = text; const char *end = text + length; char c = 0; @@ -38,32 +41,25 @@ void sfzero::Reader::read(const char *text, unsigned int length) bool inControl = false; juce::String defaultPath; - while (p < end) - { + while (p < end) { // We're at the start of a line; skip any whitespace. - while (p < end) - { + while (p < end) { c = *p; - if ((c != ' ') && (c != '\t')) - { + if ((c != ' ') && (c != '\t')) { break; } p += 1; } - if (p >= end) - { + if (p >= end) { break; } // Check if it's a comment line. - if (c == '/') - { + if (c == '/') { // Skip to end of line. - while (p < end) - { + while (p < end) { c = *++p; - if ((c == '\n') || (c == '\r')) - { + if ((c == '\n') || (c == '\r')) { break; } } @@ -72,333 +68,219 @@ void sfzero::Reader::read(const char *text, unsigned int length) } // Check if it's a blank line. - if ((c == '\r') || (c == '\n')) - { + if ((c == '\r') || (c == '\n')) { p = handleLineEnd(p); continue; } // Handle elements on the line. - while (p < end) - { + while (p < end) { c = *p; // Tag. - if (c == '<') - { + if (c == '<') { p += 1; const char *tagStart = p; - while (p < end) - { + while (p < end) { c = *p++; - if ((c == '\n') || (c == '\r')) - { + if ((c == '\n') || (c == '\r')) { error("Unterminated tag"); goto fatalError; - } - else if (c == '>') - { + } else if (c == '>') { break; } } - if (p >= end) - { + if (p >= end) { error("Unterminated tag"); goto fatalError; } sfzero::StringSlice tag(tagStart, p - 1); - if (tag == "region") - { - if (buildingRegion && (buildingRegion == &curRegion)) - { + if (tag == "region") { + if (buildingRegion && (buildingRegion == &curRegion)) { finishRegion(&curRegion); } curRegion = curGroup; buildingRegion = &curRegion; inControl = false; - } - else if (tag == "group") - { - if (buildingRegion && (buildingRegion == &curRegion)) - { + } else if (tag == "group") { + if (buildingRegion && (buildingRegion == &curRegion)) { finishRegion(&curRegion); } curGroup.clear(); buildingRegion = &curGroup; inControl = false; - } - else if (tag == "control") - { - if (buildingRegion && (buildingRegion == &curRegion)) - { + } else if (tag == "control") { + if (buildingRegion && (buildingRegion == &curRegion)) { finishRegion(&curRegion); } curGroup.clear(); buildingRegion = nullptr; inControl = true; - } - else - { + } else { error("Illegal tag"); } } // Comment. - else if (c == '/') - { + else if (c == '/') { // Skip to end of line. - while (p < end) - { + while (p < end) { c = *p; - if ((c == '\r') || (c == '\n')) - { + if ((c == '\r') || (c == '\n')) { break; } p += 1; } } // Parameter. - else - { + else { // Get the parameter name. const char *parameterStart = p; - while (p < end) - { + while (p < end) { c = *p++; - if ((c == '=') || (c == ' ') || (c == '\t') || (c == '\r') || (c == '\n')) - { + if ((c == '=') || (c == ' ') || (c == '\t') || (c == '\r') || + (c == '\n')) { break; } } - if ((p >= end) || (c != '=')) - { + if ((p >= end) || (c != '=')) { error("Malformed parameter"); goto nextElement; } sfzero::StringSlice opcode(parameterStart, p - 1); - if (inControl) - { - if (opcode == "default_path") - { + if (inControl) { + if (opcode == "default_path") { p = readPathInto(&defaultPath, p, end); - } - else - { + } else { const char *valueStart = p; - while (p < end) - { + while (p < end) { c = *p; - if ((c == ' ') || (c == '\t') || (c == '\n') || (c == '\r')) - { + if ((c == ' ') || (c == '\t') || (c == '\n') || (c == '\r')) { break; } p++; } juce::String value(valueStart, p - valueStart); - juce::String fauxOpcode = juce::String(opcode.getStart(), opcode.length()) + " (in )"; + juce::String fauxOpcode = + juce::String(opcode.getStart(), opcode.length()) + + " (in )"; sound_->addUnsupportedOpcode(fauxOpcode); } - } - else if (opcode == "sample") - { + } else if (opcode == "sample") { juce::String path; p = readPathInto(&path, p, end); - if (!path.isEmpty()) - { - if (buildingRegion) - { + if (!path.isEmpty()) { + if (buildingRegion) { buildingRegion->sample = sound_->addSample(path, defaultPath); - } - else - { + } else { error("Adding sample outside a group or region"); } - } - else - { + } else { error("Empty sample path"); } - } - else - { + } else { const char *valueStart = p; - while (p < end) - { + while (p < end) { c = *p; - if ((c == ' ') || (c == '\t') || (c == '\n') || (c == '\r')) - { + if ((c == ' ') || (c == '\t') || (c == '\n') || (c == '\r')) { break; } p++; } juce::String value(valueStart, p - valueStart); - if (buildingRegion == nullptr) - { + if (buildingRegion == nullptr) { error("Setting a parameter outside a region or group"); - } - else if (opcode == "lokey") - { + } else if (opcode == "lokey") { buildingRegion->lokey = keyValue(value); - } - else if (opcode == "hikey") - { + } else if (opcode == "hikey") { buildingRegion->hikey = keyValue(value); - } - else if (opcode == "key") - { - buildingRegion->hikey = buildingRegion->lokey = buildingRegion->pitch_keycenter = keyValue(value); - } - else if (opcode == "lovel") - { + } else if (opcode == "key") { + buildingRegion->hikey = buildingRegion->lokey = + buildingRegion->pitch_keycenter = keyValue(value); + } else if (opcode == "lovel") { buildingRegion->lovel = value.getIntValue(); - } - else if (opcode == "hivel") - { + } else if (opcode == "hivel") { buildingRegion->hivel = value.getIntValue(); - } - else if (opcode == "trigger") - { - buildingRegion->trigger = static_cast(triggerValue(value)); - } - else if (opcode == "group") - { + } else if (opcode == "trigger") { + buildingRegion->trigger = + static_cast(triggerValue(value)); + } else if (opcode == "group") { buildingRegion->group = static_cast(value.getLargeIntValue()); - } - else if (opcode == "off_by") - { + } else if (opcode == "off_by") { buildingRegion->off_by = value.getLargeIntValue(); - } - else if (opcode == "offset") - { + } else if (opcode == "offset") { buildingRegion->offset = value.getLargeIntValue(); - } - else if (opcode == "end") - { + } else if (opcode == "end") { juce::int64 end2 = value.getLargeIntValue(); - if (end2 < 0) - { + if (end2 < 0) { buildingRegion->negative_end = true; - } - else - { + } else { buildingRegion->end = end2; } - } - else if (opcode == "loop_mode") - { - bool modeIsSupported = value == "no_loop" || value == "one_shot" || value == "loop_continuous"; - if (modeIsSupported) - { - buildingRegion->loop_mode = static_cast(loopModeValue(value)); - } - else - { - juce::String fauxOpcode = juce::String(opcode.getStart(), opcode.length()) + "=" + value; + } else if (opcode == "loop_mode") { + bool modeIsSupported = value == "no_loop" || value == "one_shot" || + value == "loop_continuous"; + if (modeIsSupported) { + buildingRegion->loop_mode = + static_cast(loopModeValue(value)); + } else { + juce::String fauxOpcode = + juce::String(opcode.getStart(), opcode.length()) + "=" + + value; sound_->addUnsupportedOpcode(fauxOpcode); } - } - else if (opcode == "loop_start") - { + } else if (opcode == "loop_start") { buildingRegion->loop_start = value.getLargeIntValue(); - } - else if (opcode == "loop_end") - { + } else if (opcode == "loop_end") { buildingRegion->loop_end = value.getLargeIntValue(); - } - else if (opcode == "transpose") - { + } else if (opcode == "transpose") { buildingRegion->transpose = value.getIntValue(); - } - else if (opcode == "tune") - { + } else if (opcode == "tune") { buildingRegion->tune = value.getIntValue(); - } - else if (opcode == "pitch_keycenter") - { + } else if (opcode == "pitch_keycenter") { buildingRegion->pitch_keycenter = keyValue(value); - } - else if (opcode == "pitch_keytrack") - { + } else if (opcode == "pitch_keytrack") { buildingRegion->pitch_keytrack = value.getIntValue(); - } - else if (opcode == "bend_up") - { + } else if (opcode == "bend_up") { buildingRegion->bend_up = value.getIntValue(); - } - else if (opcode == "bend_down") - { + } else if (opcode == "bend_down") { buildingRegion->bend_down = value.getIntValue(); - } - else if (opcode == "volume") - { + } else if (opcode == "volume") { buildingRegion->volume = value.getFloatValue(); - } - else if (opcode == "pan") - { + } else if (opcode == "pan") { buildingRegion->pan = value.getFloatValue(); - } - else if (opcode == "amp_veltrack") - { + } else if (opcode == "amp_veltrack") { buildingRegion->amp_veltrack = value.getFloatValue(); - } - else if (opcode == "ampeg_delay") - { + } else if (opcode == "ampeg_delay") { buildingRegion->ampeg.delay = value.getFloatValue(); - } - else if (opcode == "ampeg_start") - { + } else if (opcode == "ampeg_start") { buildingRegion->ampeg.start = value.getFloatValue(); - } - else if (opcode == "ampeg_attack") - { + } else if (opcode == "ampeg_attack") { buildingRegion->ampeg.attack = value.getFloatValue(); - } - else if (opcode == "ampeg_hold") - { + } else if (opcode == "ampeg_hold") { buildingRegion->ampeg.hold = value.getFloatValue(); - } - else if (opcode == "ampeg_decay") - { + } else if (opcode == "ampeg_decay") { buildingRegion->ampeg.decay = value.getFloatValue(); - } - else if (opcode == "ampeg_sustain") - { + } else if (opcode == "ampeg_sustain") { buildingRegion->ampeg.sustain = value.getFloatValue(); - } - else if (opcode == "ampeg_release") - { + } else if (opcode == "ampeg_release") { buildingRegion->ampeg.release = value.getFloatValue(); - } - else if (opcode == "ampeg_vel2delay") - { + } else if (opcode == "ampeg_vel2delay") { buildingRegion->ampeg_veltrack.delay = value.getFloatValue(); - } - else if (opcode == "ampeg_vel2attack") - { + } else if (opcode == "ampeg_vel2attack") { buildingRegion->ampeg_veltrack.attack = value.getFloatValue(); - } - else if (opcode == "ampeg_vel2hold") - { + } else if (opcode == "ampeg_vel2hold") { buildingRegion->ampeg_veltrack.hold = value.getFloatValue(); - } - else if (opcode == "ampeg_vel2decay") - { + } else if (opcode == "ampeg_vel2decay") { buildingRegion->ampeg_veltrack.decay = value.getFloatValue(); - } - else if (opcode == "ampeg_vel2sustain") - { + } else if (opcode == "ampeg_vel2sustain") { buildingRegion->ampeg_veltrack.sustain = value.getFloatValue(); - } - else if (opcode == "ampeg_vel2release") - { + } else if (opcode == "ampeg_vel2release") { buildingRegion->ampeg_veltrack.release = value.getFloatValue(); - } - else if (opcode == "default_path") - { + } else if (opcode == "default_path") { error("\"default_path\" outside of tag"); - } - else - { - sound_->addUnsupportedOpcode(juce::String(opcode.getStart(), opcode.length())); + } else { + sound_->addUnsupportedOpcode( + juce::String(opcode.getStart(), opcode.length())); } } } @@ -406,17 +288,14 @@ void sfzero::Reader::read(const char *text, unsigned int length) // Skip to next element. nextElement: c = 0; - while (p < end) - { + while (p < end) { c = *p; - if ((c != ' ') && (c != '\t')) - { + if ((c != ' ') && (c != '\t')) { break; } p += 1; } - if ((c == '\r') || (c == '\n')) - { + if ((c == '\r') || (c == '\n')) { p = handleLineEnd(p); break; } @@ -424,54 +303,44 @@ void sfzero::Reader::read(const char *text, unsigned int length) } fatalError: - if (buildingRegion && (buildingRegion == &curRegion)) - { + if (buildingRegion && (buildingRegion == &curRegion)) { finishRegion(buildingRegion); } } -const char *sfzero::Reader::handleLineEnd(const char *p) -{ +const char *sfzero::Reader::handleLineEnd(const char *p) { // Check for DOS-style line ending. char lineEndChar = *p++; - if ((lineEndChar == '\r') && (*p == '\n')) - { + if ((lineEndChar == '\r') && (*p == '\n')) { p += 1; } line_ += 1; return p; } -const char *sfzero::Reader::readPathInto(juce::String *pathOut, const char *pIn, const char *endIn) -{ +const char *sfzero::Reader::readPathInto(juce::String *pathOut, const char *pIn, + const char *endIn) { // Paths are kind of funny to parse because they can contain whitespace. const char *p = pIn; const char *end = endIn; const char *pathStart = p; const char *potentialEnd = nullptr; - while (p < end) - { + while (p < end) { char c = *p; - if (c == ' ') - { + if (c == ' ') { // Is this space part of the path? Or the start of the next opcode? We // don't know yet. potentialEnd = p; p += 1; // Skip any more spaces. - while (p < end && *p == ' ') - { + while (p < end && *p == ' ') { p += 1; } - } - else if ((c == '\n') || (c == '\r') || (c == '\t')) - { + } else if ((c == '\n') || (c == '\r') || (c == '\t')) { break; - } - else if (c == '=') - { + } else if (c == '=') { // We've been looking at an opcode; we need to rewind to // potentialEnd. p = potentialEnd; @@ -479,30 +348,25 @@ const char *sfzero::Reader::readPathInto(juce::String *pathOut, const char *pIn, } p += 1; } - if (p > pathStart) - { + if (p > pathStart) { // Can't do this: // juce::String path(CharPointer_UTF8(pathStart), CharPointer_UTF8(p)); // It won't compile for some unfathomable reason. juce::CharPointer_UTF8 end2(p); juce::String path(juce::CharPointer_UTF8(pathStart), end2); *pathOut = path; - } - else - { - *pathOut = juce::String::empty; + } else { + *pathOut = juce::String(); } return p; } -int sfzero::Reader::keyValue(const juce::String &str) -{ +int sfzero::Reader::keyValue(const juce::String &str) { auto chars = str.toRawUTF8(); char c = chars[0]; - if ((c >= '0') && (c <= '9')) - { + if ((c >= '0') && (c <= '9')) { return str.getIntValue(); } @@ -510,26 +374,19 @@ int sfzero::Reader::keyValue(const juce::String &str) static const int notes[] = { 12 + 0, 12 + 2, 3, 5, 7, 8, 10, }; - if ((c >= 'A') && (c <= 'G')) - { + if ((c >= 'A') && (c <= 'G')) { note = notes[c - 'A']; - } - else if ((c >= 'a') && (c <= 'g')) - { + } else if ((c >= 'a') && (c <= 'g')) { note = notes[c - 'a']; } int octaveStart = 1; c = chars[1]; - if ((c == 'b') || (c == '#')) - { + if ((c == 'b') || (c == '#')) { octaveStart += 1; - if (c == 'b') - { + if (c == 'b') { note -= 1; - } - else - { + } else { note += 1; } } @@ -540,54 +397,43 @@ int sfzero::Reader::keyValue(const juce::String &str) return result; } -int sfzero::Reader::triggerValue(const juce::String &str) -{ - if (str == "release") - { +int sfzero::Reader::triggerValue(const juce::String &str) { + if (str == "release") { return sfzero::Region::release; } - if (str == "first") - { + if (str == "first") { return sfzero::Region::first; } - if (str == "legato") - { + if (str == "legato") { return sfzero::Region::legato; } return sfzero::Region::attack; } -int sfzero::Reader::loopModeValue(const juce::String &str) -{ - if (str == "no_loop") - { +int sfzero::Reader::loopModeValue(const juce::String &str) { + if (str == "no_loop") { return sfzero::Region::no_loop; } - if (str == "one_shot") - { + if (str == "one_shot") { return sfzero::Region::one_shot; } - if (str == "loop_continuous") - { + if (str == "loop_continuous") { return sfzero::Region::loop_continuous; } - if (str == "loop_sustain") - { + if (str == "loop_sustain") { return sfzero::Region::loop_sustain; } return sfzero::Region::sample_loop; } -void sfzero::Reader::finishRegion(sfzero::Region *region) -{ +void sfzero::Reader::finishRegion(sfzero::Region *region) { sfzero::Region *newRegion = new sfzero::Region(); *newRegion = *region; sound_->addRegion(newRegion); } -void sfzero::Reader::error(const juce::String &message) -{ +void sfzero::Reader::error(const juce::String &message) { juce::String fullMessage = message; fullMessage += " (line " + juce::String(line_) + ")."; diff --git a/sfzero/SFZReader.h b/sfzero/SFZReader.h index 201af63..a1e4e73 100644 --- a/sfzero/SFZReader.h +++ b/sfzero/SFZReader.h @@ -2,31 +2,31 @@ * Original code copyright (C) 2012 Steve Folta * Converted to Juce module (C) 2016 Leo Olivers * Forked from https://github.com/stevefolta/SFZero - * For license info please see the LICENSE file distributed with this source code + * For license info please see the LICENSE file distributed with this source + *code *************************************************************************************/ #ifndef SFZREADER_H_INCLUDED #define SFZREADER_H_INCLUDED #include "SFZCommon.h" -namespace sfzero -{ +namespace sfzero { struct Region; class Sound; -class Reader -{ -public: +class Reader { + public: explicit Reader(Sound *sound); ~Reader(); void read(const juce::File &file); void read(const char *text, unsigned int length); -private: + private: const char *handleLineEnd(const char *p); - const char *readPathInto(juce::String *pathOut, const char *p, const char *end); + const char *readPathInto(juce::String *pathOut, const char *p, + const char *end); int keyValue(const juce::String &str); int triggerValue(const juce::String &str); int loopModeValue(const juce::String &str); @@ -39,22 +39,27 @@ class Reader JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(Reader) }; -class StringSlice -{ -public: - StringSlice(const char *startIn, const char *endIn) : start_(startIn), end_(endIn) {} +class StringSlice { + public: + StringSlice(const char *startIn, const char *endIn) + : start_(startIn), end_(endIn) {} virtual ~StringSlice() {} unsigned int length() { return static_cast(end_ - start_); } - bool operator==(const char *other) { return (strncmp(start_, other, length()) == 0); } - bool operator!=(const char *other) { return (strncmp(start_, other, length()) != 0); } + bool operator==(const char *other) { + return (strncmp(start_, other, length()) == 0); + } + bool operator!=(const char *other) { + return (strncmp(start_, other, length()) != 0); + } const char *getStart() const { return start_; } const char *getEnd() const { return end_; } -private: + + private: const char *start_; const char *end_; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(StringSlice) }; -} +} // namespace sfzero -#endif // SFZREADER_H_INCLUDED +#endif // SFZREADER_H_INCLUDED diff --git a/sfzero/SFZRegion.cpp b/sfzero/SFZRegion.cpp index e37aa33..539ebd2 100644 --- a/sfzero/SFZRegion.cpp +++ b/sfzero/SFZRegion.cpp @@ -2,13 +2,14 @@ * Original code copyright (C) 2012 Steve Folta * Converted to Juce module (C) 2016 Leo Olivers * Forked from https://github.com/stevefolta/SFZero - * For license info please see the LICENSE file distributed with this source code + * For license info please see the LICENSE file distributed with this source + *code *************************************************************************************/ #include "SFZRegion.h" + #include "SFZSample.h" -void sfzero::EGParameters::clear() -{ +void sfzero::EGParameters::clear() { delay = 0.0; start = 0.0; attack = 0.0; @@ -18,20 +19,18 @@ void sfzero::EGParameters::clear() release = 0.0; } -void sfzero::EGParameters::clearMod() -{ +void sfzero::EGParameters::clearMod() { // Clear for velocity or other modification. delay = start = attack = hold = decay = sustain = release = 0.0; } sfzero::Region::Region() { clear(); } -void sfzero::Region::clear() -{ +void sfzero::Region::clear() { memset(this, 0, sizeof(*this)); hikey = 127; hivel = 127; - pitch_keycenter = 60; // C4 + pitch_keycenter = 60; // C4 pitch_keytrack = 100; bend_up = 200; bend_down = -200; @@ -41,8 +40,7 @@ void sfzero::Region::clear() ampeg_veltrack.clearMod(); } -void sfzero::Region::clearForSF2() -{ +void sfzero::Region::clearForSF2() { clear(); pitch_keycenter = -1; loop_mode = no_loop; @@ -56,16 +54,14 @@ void sfzero::Region::clearForSF2() ampeg.release = -12000.0; } -void sfzero::Region::clearForRelativeSF2() -{ +void sfzero::Region::clearForRelativeSF2() { clear(); pitch_keytrack = 0; amp_veltrack = 0.0; ampeg.sustain = 0.0; } -void sfzero::Region::addForSF2(sfzero::Region *other) -{ +void sfzero::Region::addForSF2(sfzero::Region *other) { offset += other->offset; end += other->end; loop_start += other->loop_start; @@ -84,63 +80,55 @@ void sfzero::Region::addForSF2(sfzero::Region *other) ampeg.release += other->ampeg.release; } -void sfzero::Region::sf2ToSFZ() -{ +void sfzero::Region::sf2ToSFZ() { // EG times need to be converted from timecents to seconds. ampeg.delay = timecents2Secs(static_cast(ampeg.delay)); ampeg.attack = timecents2Secs(static_cast(ampeg.attack)); ampeg.hold = timecents2Secs(static_cast(ampeg.hold)); ampeg.decay = timecents2Secs(static_cast(ampeg.decay)); - if (ampeg.sustain < 0.0f) - { + if (ampeg.sustain < 0.0f) { ampeg.sustain = 0.0f; } - ampeg.sustain = 100.0f * juce::Decibels::decibelsToGain(-ampeg.sustain / 10.0f); + ampeg.sustain = + 100.0f * juce::Decibels::decibelsToGain(-ampeg.sustain / 10.0f); ampeg.release = timecents2Secs(static_cast(ampeg.release)); // Pin very short EG segments. Timecents don't get to zero, and our EG is // happier with zero values. - if (ampeg.delay < 0.01f) - { + if (ampeg.delay < 0.01f) { ampeg.delay = 0.0f; } - if (ampeg.attack < 0.01f) - { + if (ampeg.attack < 0.01f) { ampeg.attack = 0.0f; } - if (ampeg.hold < 0.01f) - { + if (ampeg.hold < 0.01f) { ampeg.hold = 0.0f; } - if (ampeg.decay < 0.01f) - { + if (ampeg.decay < 0.01f) { ampeg.decay = 0.0f; } - if (ampeg.release < 0.01f) - { + if (ampeg.release < 0.01f) { ampeg.release = 0.0f; } // Pin values to their ranges. - if (pan < -100.0f) - { + if (pan < -100.0f) { pan = -100.0f; - } - else if (pan > 100.0f) - { + } else if (pan > 100.0f) { pan = 100.0f; } } -juce::String sfzero::Region::dump() -{ - juce::String info = juce::String::formatted("%d - %d, vel %d - %d", lokey, hikey, lovel, hivel); - if (sample) - { +juce::String sfzero::Region::dump() { + juce::String info = juce::String::formatted("%d - %d, vel %d - %d", lokey, + hikey, lovel, hivel); + if (sample) { info << sample->getShortName(); } info << "\n"; return info; } -float sfzero::Region::timecents2Secs(int timecents) { return static_cast(pow(2.0, timecents / 1200.0)); } +float sfzero::Region::timecents2Secs(int timecents) { + return static_cast(pow(2.0, timecents / 1200.0)); +} diff --git a/sfzero/SFZRegion.h b/sfzero/SFZRegion.h index 0fd27b4..be12d97 100644 --- a/sfzero/SFZRegion.h +++ b/sfzero/SFZRegion.h @@ -2,40 +2,31 @@ * Original code copyright (C) 2012 Steve Folta * Converted to Juce module (C) 2016 Leo Olivers * Forked from https://github.com/stevefolta/SFZero - * For license info please see the LICENSE file distributed with this source code + * For license info please see the LICENSE file distributed with this source + *code *************************************************************************************/ #ifndef SFZREGION_H_INCLUDED #define SFZREGION_H_INCLUDED #include "SFZCommon.h" -namespace sfzero -{ +namespace sfzero { class Sample; // Region is designed to be able to be bitwise-copied. -struct EGParameters -{ +struct EGParameters { float delay, start, attack, hold, decay, sustain, release; void clear(); void clearMod(); }; -struct Region -{ - enum Trigger - { - attack, - release, - first, - legato - }; +struct Region { + enum Trigger { attack, release, first, legato }; - enum LoopMode - { + enum LoopMode { sample_loop, no_loop, one_shot, @@ -43,11 +34,7 @@ struct Region loop_sustain }; - enum OffMode - { - fast, - normal - }; + enum OffMode { fast, normal }; Region(); void clear(); @@ -57,10 +44,11 @@ struct Region void sf2ToSFZ(); juce::String dump(); - bool matches(int note, int velocity, Trigger trig) - { - return (note >= lokey && note <= hikey && velocity >= lovel && velocity <= hivel && - (trig == this->trigger || (this->trigger == attack && (trig == first || trig == legato)))); + bool matches(int note, int velocity, Trigger trig) { + return (note >= lokey && note <= hikey && velocity >= lovel && + velocity <= hivel && + (trig == this->trigger || + (this->trigger == attack && (trig == first || trig == legato)))); } Sample *sample; @@ -88,6 +76,6 @@ struct Region static float timecents2Secs(int timecents); }; -} +} // namespace sfzero -#endif // SFZREGION_H_INCLUDED +#endif // SFZREGION_H_INCLUDED diff --git a/sfzero/SFZSample.cpp b/sfzero/SFZSample.cpp index db321f2..96e679c 100644 --- a/sfzero/SFZSample.cpp +++ b/sfzero/SFZSample.cpp @@ -2,17 +2,17 @@ * Original code copyright (C) 2012 Steve Folta * Converted to Juce module (C) 2016 Leo Olivers * Forked from https://github.com/stevefolta/SFZero - * For license info please see the LICENSE file distributed with this source code + * For license info please see the LICENSE file distributed with this source + *code *************************************************************************************/ #include "SFZSample.h" + #include "SFZDebug.h" -bool sfzero::Sample::load(juce::AudioFormatManager *formatManager) -{ +bool sfzero::Sample::load(juce::AudioFormatManager *formatManager) { juce::AudioFormatReader *reader = formatManager->createReaderFor(file_); - if (reader == nullptr) - { + if (reader == nullptr) { return false; } sampleRate_ = reader->sampleRate; @@ -21,13 +21,13 @@ bool sfzero::Sample::load(juce::AudioFormatManager *formatManager) // can be done without having to check for the edge all the time. jassert(sampleLength_ < std::numeric_limits::max()); - buffer_ = new juce::AudioSampleBuffer(reader->numChannels, static_cast(sampleLength_ + 4)); + buffer_ = new juce::AudioSampleBuffer(reader->numChannels, + static_cast(sampleLength_ + 4)); reader->read(buffer_, 0, static_cast(sampleLength_ + 4), 0, true, true); juce::StringPairArray *metadata = &reader->metadataValues; int numLoops = metadata->getValue("NumSampleLoops", "0").getIntValue(); - if (numLoops > 0) - { + if (numLoops > 0) { loopStart_ = metadata->getValue("Loop0Start", "0").getLargeIntValue(); loopEnd_ = metadata->getValue("Loop0End", "0").getLargeIntValue(); } @@ -39,14 +39,12 @@ sfzero::Sample::~Sample() { delete buffer_; } juce::String sfzero::Sample::getShortName() { return (file_.getFileName()); } -void sfzero::Sample::setBuffer(juce::AudioSampleBuffer *newBuffer) -{ +void sfzero::Sample::setBuffer(juce::AudioSampleBuffer *newBuffer) { buffer_ = newBuffer; sampleLength_ = buffer_->getNumSamples(); } -juce::AudioSampleBuffer *sfzero::Sample::detachBuffer() -{ +juce::AudioSampleBuffer *sfzero::Sample::detachBuffer() { juce::AudioSampleBuffer *result = buffer_; buffer_ = nullptr; return result; @@ -55,10 +53,8 @@ juce::AudioSampleBuffer *sfzero::Sample::detachBuffer() juce::String sfzero::Sample::dump() { return file_.getFullPathName() + "\n"; } #ifdef JUCE_DEBUG -void sfzero::Sample::checkIfZeroed(const char *where) -{ - if (buffer_ == nullptr) - { +void sfzero::Sample::checkIfZeroed(const char *where) { + if (buffer_ == nullptr) { sfzero::dbgprintf("SFZSample::checkIfZeroed(%s): no buffer!", where); return; } @@ -66,25 +62,19 @@ void sfzero::Sample::checkIfZeroed(const char *where) int samplesLeft = buffer_->getNumSamples(); juce::int64 nonzero = 0, zero = 0; const float *p = buffer_->getReadPointer(0); - for (; samplesLeft > 0; --samplesLeft) - { - if (*p++ == 0.0) - { + for (; samplesLeft > 0; --samplesLeft) { + if (*p++ == 0.0) { zero += 1; - } - else - { + } else { nonzero += 1; } } - if (nonzero > 0) - { - sfzero::dbgprintf("Buffer not zeroed at %s (%lu vs. %lu).", where, nonzero, zero); - } - else - { + if (nonzero > 0) { + sfzero::dbgprintf("Buffer not zeroed at %s (%lu vs. %lu).", where, nonzero, + zero); + } else { sfzero::dbgprintf("Buffer zeroed at %s! (%lu zeros)", where, zero); } } -#endif // JUCE_DEBUG +#endif // JUCE_DEBUG diff --git a/sfzero/SFZSample.h b/sfzero/SFZSample.h index dc5e2e5..3eaf986 100644 --- a/sfzero/SFZSample.h +++ b/sfzero/SFZSample.h @@ -2,21 +2,31 @@ * Original code copyright (C) 2012 Steve Folta * Converted to Juce module (C) 2016 Leo Olivers * Forked from https://github.com/stevefolta/SFZero - * For license info please see the LICENSE file distributed with this source code + * For license info please see the LICENSE file distributed with this source + *code *************************************************************************************/ #ifndef SFZSAMPLE_H_INCLUDED #define SFZSAMPLE_H_INCLUDED #include "SFZCommon.h" -namespace sfzero -{ - -class Sample -{ -public: - explicit Sample(const juce::File &fileIn) : file_(fileIn), buffer_(nullptr), sampleRate_(0), sampleLength_(0), loopStart_(0), loopEnd_(0) {} - explicit Sample(double sampleRateIn) : buffer_(nullptr), sampleRate_(sampleRateIn), sampleLength_(0), loopStart_(0), loopEnd_(0) {} +namespace sfzero { + +class Sample { + public: + explicit Sample(const juce::File &fileIn) + : file_(fileIn), + buffer_(nullptr), + sampleRate_(0), + sampleLength_(0), + loopStart_(0), + loopEnd_(0) {} + explicit Sample(double sampleRateIn) + : buffer_(nullptr), + sampleRate_(sampleRateIn), + sampleLength_(0), + loopStart_(0), + loopEnd_(0) {} virtual ~Sample(); bool load(juce::AudioFormatManager *formatManager); @@ -37,7 +47,7 @@ class Sample #endif -private: + private: juce::File file_; juce::AudioSampleBuffer *buffer_; double sampleRate_; @@ -45,6 +55,6 @@ class Sample JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(Sample) }; -} +} // namespace sfzero -#endif // SFZSAMPLE_H_INCLUDED +#endif // SFZSAMPLE_H_INCLUDED diff --git a/sfzero/SFZSound.cpp b/sfzero/SFZSound.cpp index ae4c447..2687f39 100644 --- a/sfzero/SFZSound.cpp +++ b/sfzero/SFZSound.cpp @@ -2,68 +2,65 @@ * Original code copyright (C) 2012 Steve Folta * Converted to Juce module (C) 2016 Leo Olivers * Forked from https://github.com/stevefolta/SFZero - * For license info please see the LICENSE file distributed with this source code + * For license info please see the LICENSE file distributed with this source + *code *************************************************************************************/ #include "SFZSound.h" + +#include + #include "SFZReader.h" #include "SFZRegion.h" #include "SFZSample.h" sfzero::Sound::Sound(const juce::File &fileIn) : file_(fileIn) {} -sfzero::Sound::~Sound() -{ +sfzero::Sound::~Sound() { int numRegions = regions_.size(); - for (int i = 0; i < numRegions; ++i) - { + for (int i = 0; i < numRegions; ++i) { delete regions_[i]; regions_.set(i, nullptr); } - for (juce::HashMap::Iterator i(samples_); i.next();) - { + for (juce::HashMap::Iterator i(samples_); + i.next();) { delete i.getValue(); } } -bool sfzero::Sound::appliesToNote(int /*midiNoteNumber*/) -{ +bool sfzero::Sound::appliesToNote(int /*midiNoteNumber*/) { // Just say yes; we can't truly know unless we're told the velocity as well. return true; } bool sfzero::Sound::appliesToChannel(int /*midiChannel*/) { return true; } void sfzero::Sound::addRegion(sfzero::Region *region) { regions_.add(region); } -sfzero::Sample *sfzero::Sound::addSample(juce::String path, juce::String defaultPath) -{ +sfzero::Sample *sfzero::Sound::addSample(juce::String path, + juce::String defaultPath) { path = path.replaceCharacter('\\', '/'); defaultPath = defaultPath.replaceCharacter('\\', '/'); juce::File sampleFile; - if (defaultPath.isEmpty()) - { + if (defaultPath.isEmpty()) { sampleFile = file_.getSiblingFile(path); - } - else - { + } else { juce::File defaultDir = file_.getSiblingFile(defaultPath); sampleFile = defaultDir.getChildFile(path); } juce::String samplePath = sampleFile.getFullPathName(); sfzero::Sample *sample = samples_[samplePath]; - if (sample == nullptr) - { + if (sample == nullptr) { sample = new sfzero::Sample(sampleFile); samples_.set(samplePath, sample); } return sample; } -void sfzero::Sound::addError(const juce::String &message) { errors_.add(message); } +void sfzero::Sound::addError(const juce::String &message) { + errors_.add(message); +} -void sfzero::Sound::addUnsupportedOpcode(const juce::String &opcode) -{ - if (!unsupportedOpcodes_.contains(opcode)) - { +void sfzero::Sound::addUnsupportedOpcode(const juce::String &opcode) { + if (!unsupportedOpcodes_.contains(opcode)) { unsupportedOpcodes_.set(opcode, opcode); juce::String warning = "unsupported opcode: "; warning << opcode; @@ -71,56 +68,48 @@ void sfzero::Sound::addUnsupportedOpcode(const juce::String &opcode) } } -void sfzero::Sound::loadRegions() -{ +void sfzero::Sound::loadRegions() { sfzero::Reader reader(this); reader.read(file_); } -void sfzero::Sound::loadSamples(juce::AudioFormatManager *formatManager, double *progressVar, juce::Thread *thread) -{ - if (progressVar) - { +void sfzero::Sound::loadSamples(juce::AudioFormatManager *formatManager, + double *progressVar, juce::Thread *thread) { + if (progressVar) { *progressVar = 0.0; } double numSamplesLoaded = 1.0, numSamples = samples_.size(); - for (juce::HashMap::Iterator i(samples_); i.next();) - { + for (juce::HashMap::Iterator i(samples_); + i.next();) { sfzero::Sample *sample = i.getValue(); bool ok = sample->load(formatManager); - if (!ok) - { + if (!ok) { addError("Couldn't load sample \"" + sample->getShortName() + "\""); } numSamplesLoaded += 1.0; - if (progressVar) - { + if (progressVar) { *progressVar = numSamplesLoaded / numSamples; } - if (thread && thread->threadShouldExit()) - { + if (thread && thread->threadShouldExit()) { return; } } - if (progressVar) - { + if (progressVar) { *progressVar = 1.0; } } -sfzero::Region *sfzero::Sound::getRegionFor(int note, int velocity, sfzero::Region::Trigger trigger) -{ +sfzero::Region *sfzero::Sound::getRegionFor(int note, int velocity, + sfzero::Region::Trigger trigger) { int numRegions = regions_.size(); - for (int i = 0; i < numRegions; ++i) - { + for (int i = 0; i < numRegions; ++i) { sfzero::Region *region = regions_[i]; - if (region->matches(note, velocity, trigger)) - { + if (region->matches(note, velocity, trigger)) { return region; } } @@ -134,61 +123,49 @@ sfzero::Region *sfzero::Sound::regionAt(int index) { return regions_[index]; } int sfzero::Sound::numSubsounds() { return 1; } -juce::String sfzero::Sound::subsoundName(int /*whichSubsound*/) { return juce::String::empty; } +juce::String sfzero::Sound::subsoundName(int /*whichSubsound*/) { + return juce::String(); +} void sfzero::Sound::useSubsound(int /*whichSubsound*/) {} int sfzero::Sound::selectedSubsound() { return 0; } -juce::String sfzero::Sound::dump() -{ +juce::String sfzero::Sound::dump() { juce::String info; auto &errors = getErrors(); - if (errors.size() > 0) - { + if (errors.size() > 0) { info << errors.size() << " errors: \n"; info << errors.joinIntoString("\n"); info << "\n"; - } - else - { + } else { info << "no errors.\n\n"; } auto &warnings = getWarnings(); - if (warnings.size() > 0) - { + if (warnings.size() > 0) { info << warnings.size() << " warnings: \n"; info << warnings.joinIntoString("\n"); - } - else - { + } else { info << "no warnings.\n"; } - if (regions_.size() > 0) - { + if (regions_.size() > 0) { info << regions_.size() << " regions: \n"; - for (int i = 0; i < regions_.size(); ++i) - { + for (int i = 0; i < regions_.size(); ++i) { info << regions_[i]->dump(); } - } - else - { + } else { info << "no regions.\n"; } - if (samples_.size() > 0) - { + if (samples_.size() > 0) { info << samples_.size() << " samples: \n"; - for (juce::HashMap::Iterator i(samples_); i.next();) - { + for (juce::HashMap::Iterator i(samples_); + i.next();) { info << i.getValue()->dump(); } - } - else - { + } else { info << "no samples.\n"; } return info; diff --git a/sfzero/SFZSound.h b/sfzero/SFZSound.h index 4c69ff5..fefa0a4 100644 --- a/sfzero/SFZSound.h +++ b/sfzero/SFZSound.h @@ -2,21 +2,22 @@ * Original code copyright (C) 2012 Steve Folta * Converted to Juce module (C) 2016 Leo Olivers * Forked from https://github.com/stevefolta/SFZero - * For license info please see the LICENSE file distributed with this source code + * For license info please see the LICENSE file distributed with this source + *code *************************************************************************************/ #ifndef SFZSOUND_H_INCLUDED #define SFZSOUND_H_INCLUDED +#include + #include "SFZRegion.h" -namespace sfzero -{ +namespace sfzero { class Sample; -class Sound : public juce::SynthesiserSound -{ -public: +class Sound : public juce::SynthesiserSound { + public: explicit Sound(const juce::File &file); virtual ~Sound(); @@ -25,16 +26,19 @@ class Sound : public juce::SynthesiserSound bool appliesToNote(int midiNoteNumber) override; bool appliesToChannel(int midiChannel) override; - void addRegion(Region *region); // Takes ownership of the region. - Sample *addSample(juce::String path, juce::String defaultPath = juce::String::empty); + void addRegion(Region *region); // Takes ownership of the region. + Sample *addSample(juce::String path, + juce::String defaultPath = juce::String()); void addError(const juce::String &message); void addUnsupportedOpcode(const juce::String &opcode); virtual void loadRegions(); - virtual void loadSamples(juce::AudioFormatManager *formatManager, double *progressVar = nullptr, + virtual void loadSamples(juce::AudioFormatManager *formatManager, + double *progressVar = nullptr, juce::Thread *thread = nullptr); - Region *getRegionFor(int note, int velocity, Region::Trigger trigger = Region::attack); + Region *getRegionFor(int note, int velocity, + Region::Trigger trigger = Region::attack); int getNumRegions(); Region *regionAt(int index); @@ -50,7 +54,7 @@ class Sound : public juce::SynthesiserSound juce::Array &getRegions() { return regions_; } juce::File &getFile() { return file_; } -private: + private: juce::File file_; juce::Array regions_; juce::HashMap samples_; @@ -60,6 +64,6 @@ class Sound : public juce::SynthesiserSound JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(Sound) }; -} +} // namespace sfzero -#endif // SFZSOUND_H_INCLUDED +#endif // SFZSOUND_H_INCLUDED diff --git a/sfzero/SFZSynth.cpp b/sfzero/SFZSynth.cpp index d798694..550fd68 100644 --- a/sfzero/SFZSynth.cpp +++ b/sfzero/SFZSynth.cpp @@ -2,16 +2,21 @@ * Original code copyright (C) 2012 Steve Folta * Converted to Juce module (C) 2016 Leo Olivers * Forked from https://github.com/stevefolta/SFZero - * For license info please see the LICENSE file distributed with this source code + * For license info please see the LICENSE file distributed with this source + *code *************************************************************************************/ + #include "SFZSynth.h" + +#include + #include "SFZSound.h" #include "SFZVoice.h" sfzero::Synth::Synth() : Synthesiser() {} -void sfzero::Synth::noteOn(int midiChannel, int midiNoteNumber, float velocity) -{ +void sfzero::Synth::noteOn(int midiChannel, int midiNoteNumber, + float velocity) { int i; const juce::ScopedLock locker(lock); @@ -21,27 +26,22 @@ void sfzero::Synth::noteOn(int midiChannel, int midiNoteNumber, float velocity) // First, stop any currently-playing sounds in the group. //*** Currently, this only pays attention to the first matching region. int group = 0; - sfzero::Sound *sound = dynamic_cast(getSound(0)); + sfzero::Sound *sound = dynamic_cast(getSound(0).get()); - if (sound) - { + if (sound) { sfzero::Region *region = sound->getRegionFor(midiNoteNumber, midiVelocity); - if (region) - { + if (region) { group = region->group; } } - if (group != 0) - { - for (i = voices.size(); --i >= 0;) - { - sfzero::Voice *voice = dynamic_cast(voices.getUnchecked(i)); - if (voice == nullptr) - { + if (group != 0) { + for (i = voices.size(); --i >= 0;) { + sfzero::Voice *voice = + dynamic_cast(voices.getUnchecked(i)); + if (voice == nullptr) { continue; } - if (voice->getOffBy() == group) - { + if (voice->getOffBy() == group) { voice->stopNoteForGroup(); } } @@ -50,26 +50,19 @@ void sfzero::Synth::noteOn(int midiChannel, int midiNoteNumber, float velocity) // Are any notes playing? (Needed for first/legato trigger handling.) // Also stop any voices still playing this note. bool anyNotesPlaying = false; - for (i = voices.size(); --i >= 0;) - { - sfzero::Voice *voice = dynamic_cast(voices.getUnchecked(i)); - if (voice == nullptr) - { + for (i = voices.size(); --i >= 0;) { + sfzero::Voice *voice = + dynamic_cast(voices.getUnchecked(i)); + if (voice == nullptr) { continue; } - if (voice->isPlayingChannel(midiChannel)) - { - if (voice->isPlayingNoteDown()) - { - if (voice->getCurrentlyPlayingNote() == midiNoteNumber) - { - if (!voice->isPlayingOneShot()) - { + if (voice->isPlayingChannel(midiChannel)) { + if (voice->isPlayingNoteDown()) { + if (voice->getCurrentlyPlayingNote() == midiNoteNumber) { + if (!voice->isPlayingOneShot()) { voice->stopNoteQuick(); } - } - else - { + } else { anyNotesPlaying = true; } } @@ -77,19 +70,16 @@ void sfzero::Synth::noteOn(int midiChannel, int midiNoteNumber, float velocity) } // Play *all* matching regions. - sfzero::Region::Trigger trigger = (anyNotesPlaying ? sfzero::Region::legato : sfzero::Region::first); - if (sound) - { + sfzero::Region::Trigger trigger = + (anyNotesPlaying ? sfzero::Region::legato : sfzero::Region::first); + if (sound) { int numRegions = sound->getNumRegions(); - for (i = 0; i < numRegions; ++i) - { + for (i = 0; i < numRegions; ++i) { sfzero::Region *region = sound->regionAt(i); - if (region->matches(midiNoteNumber, midiVelocity, trigger)) - { - sfzero::Voice *voice = - dynamic_cast(findFreeVoice(sound, midiNoteNumber, midiChannel, isNoteStealingEnabled())); - if (voice) - { + if (region->matches(midiNoteNumber, midiVelocity, trigger)) { + sfzero::Voice *voice = dynamic_cast(findFreeVoice( + sound, midiNoteNumber, midiChannel, isNoteStealingEnabled())); + if (voice) { voice->setRegion(region); startVoice(voice, sound, midiChannel, midiNoteNumber, velocity); } @@ -100,64 +90,58 @@ void sfzero::Synth::noteOn(int midiChannel, int midiNoteNumber, float velocity) noteVelocities_[midiNoteNumber] = midiVelocity; } -void sfzero::Synth::noteOff(int midiChannel, int midiNoteNumber, float velocity, bool allowTailOff) -{ +void sfzero::Synth::noteOff(int midiChannel, int midiNoteNumber, float velocity, + bool allowTailOff) { const juce::ScopedLock locker(lock); Synthesiser::noteOff(midiChannel, midiNoteNumber, velocity, allowTailOff); // Start release region. - sfzero::Sound *sound = dynamic_cast(getSound(0)); - if (sound) - { - sfzero::Region *region = sound->getRegionFor(midiNoteNumber, noteVelocities_[midiNoteNumber], sfzero::Region::release); - if (region) - { - sfzero::Voice *voice = dynamic_cast(findFreeVoice(sound, midiNoteNumber, midiChannel, false)); - if (voice) - { + sfzero::Sound *sound = dynamic_cast(getSound(0).get()); + if (sound) { + sfzero::Region *region = + sound->getRegionFor(midiNoteNumber, noteVelocities_[midiNoteNumber], + sfzero::Region::release); + if (region) { + sfzero::Voice *voice = dynamic_cast( + findFreeVoice(sound, midiNoteNumber, midiChannel, false)); + if (voice) { // Synthesiser is too locked-down (ivars are private rt protected), so // we have to use a "setRegion()" mechanism. voice->setRegion(region); - startVoice(voice, sound, midiChannel, midiNoteNumber, noteVelocities_[midiNoteNumber] / 127.0f); + startVoice(voice, sound, midiChannel, midiNoteNumber, + noteVelocities_[midiNoteNumber] / 127.0f); } } } } -int sfzero::Synth::numVoicesUsed() -{ +int sfzero::Synth::numVoicesUsed() { int numUsed = 0; - for (int i = voices.size(); --i >= 0;) - { - if (voices.getUnchecked(i)->getCurrentlyPlayingNote() >= 0) - { + for (int i = voices.size(); --i >= 0;) { + if (voices.getUnchecked(i)->getCurrentlyPlayingNote() >= 0) { numUsed += 1; } } return numUsed; } -juce::String sfzero::Synth::voiceInfoString() -{ - enum - { +juce::String sfzero::Synth::voiceInfoString() { + enum { maxShownVoices = 20, }; juce::StringArray lines; int numUsed = 0, numShown = 0; - for (int i = voices.size(); --i >= 0;) - { - sfzero::Voice *voice = dynamic_cast(voices.getUnchecked(i)); - if (voice->getCurrentlyPlayingNote() < 0) - { + for (int i = voices.size(); --i >= 0;) { + sfzero::Voice *voice = + dynamic_cast(voices.getUnchecked(i)); + if (voice->getCurrentlyPlayingNote() < 0) { continue; } numUsed += 1; - if (numShown >= maxShownVoices) - { + if (numShown >= maxShownVoices) { continue; } lines.add(voice->infoString()); diff --git a/sfzero/SFZSynth.h b/sfzero/SFZSynth.h index ab126d4..d153574 100644 --- a/sfzero/SFZSynth.h +++ b/sfzero/SFZSynth.h @@ -2,32 +2,32 @@ * Original code copyright (C) 2012 Steve Folta * Converted to Juce module (C) 2016 Leo Olivers * Forked from https://github.com/stevefolta/SFZero - * For license info please see the LICENSE file distributed with this source code + * For license info please see the LICENSE file distributed with this source + *code *************************************************************************************/ #ifndef SFZSYNTH_H_INCLUDED #define SFZSYNTH_H_INCLUDED #include "SFZCommon.h" -namespace sfzero -{ +namespace sfzero { -class Synth : public juce::Synthesiser -{ -public: +class Synth : public juce::Synthesiser { + public: Synth(); virtual ~Synth() {} void noteOn(int midiChannel, int midiNoteNumber, float velocity) override; - void noteOff(int midiChannel, int midiNoteNumber, float velocity, bool allowTailOff) override; + void noteOff(int midiChannel, int midiNoteNumber, float velocity, + bool allowTailOff) override; int numVoicesUsed(); juce::String voiceInfoString(); -private: + private: int noteVelocities_[128]; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(Synth) }; -} +} // namespace sfzero -#endif // SFZSYNTH_H_INCLUDED +#endif // SFZSYNTH_H_INCLUDED diff --git a/sfzero/SFZVoice.cpp b/sfzero/SFZVoice.cpp index b8efeca..631eae3 100644 --- a/sfzero/SFZVoice.cpp +++ b/sfzero/SFZVoice.cpp @@ -2,52 +2,64 @@ * Original code copyright (C) 2012 Steve Folta * Converted to Juce module (C) 2016 Leo Olivers * Forked from https://github.com/stevefolta/SFZero - * For license info please see the LICENSE file distributed with this source code + * For license info please see the LICENSE file distributed with this source + *code *************************************************************************************/ +#include "SFZVoice.h" + +#include + #include "SFZDebug.h" #include "SFZRegion.h" #include "SFZSample.h" #include "SFZSound.h" -#include "SFZVoice.h" -#include static const float globalGain = -1.0; sfzero::Voice::Voice() - : region_(nullptr), trigger_(0), curMidiNote_(0), curPitchWheel_(0), pitchRatio_(0), noteGainLeft_(0), noteGainRight_(0), - sourceSamplePosition_(0), sampleEnd_(0), loopStart_(0), loopEnd_(0), numLoops_(0), curVelocity_(0) -{ + : region_(nullptr), + trigger_(0), + curMidiNote_(0), + curPitchWheel_(0), + pitchRatio_(0), + noteGainLeft_(0), + noteGainRight_(0), + sourceSamplePosition_(0), + sampleEnd_(0), + loopStart_(0), + loopEnd_(0), + numLoops_(0), + curVelocity_(0) { ampeg_.setExponentialDecay(true); } sfzero::Voice::~Voice() {} -bool sfzero::Voice::canPlaySound(juce::SynthesiserSound *sound) { return dynamic_cast(sound) != nullptr; } +bool sfzero::Voice::canPlaySound(juce::SynthesiserSound *sound) { + return dynamic_cast(sound) != nullptr; +} -void sfzero::Voice::startNote(int midiNoteNumber, float floatVelocity, juce::SynthesiserSound *soundIn, - int currentPitchWheelPosition) -{ +void sfzero::Voice::startNote(int midiNoteNumber, float floatVelocity, + juce::SynthesiserSound *soundIn, + int currentPitchWheelPosition) { sfzero::Sound *sound = dynamic_cast(soundIn); - if (sound == nullptr) - { + if (sound == nullptr) { killNote(); return; } int velocity = static_cast(floatVelocity * 127.0); curVelocity_ = velocity; - if (region_ == nullptr) - { + if (region_ == nullptr) { region_ = sound->getRegionFor(midiNoteNumber, velocity); } - if ((region_ == nullptr) || (region_->sample == nullptr) || (region_->sample->getBuffer() == nullptr)) - { + if ((region_ == nullptr) || (region_->sample == nullptr) || + (region_->sample->getBuffer() == nullptr)) { killNote(); return; } - if (region_->negative_end) - { + if (region_->negative_end) { killNote(); return; } @@ -62,49 +74,44 @@ void sfzero::Voice::startNote(int midiNoteNumber, float floatVelocity, juce::Syn // Thanks to for explaining the // velocity curve in a way that I could understand, although they mean // "log10" when they say "log". - double velocityGainDB = -20.0 * log10((127.0 * 127.0) / (velocity * velocity)); + double velocityGainDB = + -20.0 * log10((127.0 * 127.0) / (velocity * velocity)); velocityGainDB *= region_->amp_veltrack / 100.0; noteGainDB += velocityGainDB; - noteGainLeft_ = noteGainRight_ = static_cast(juce::Decibels::decibelsToGain(noteGainDB)); + noteGainLeft_ = noteGainRight_ = + static_cast(juce::Decibels::decibelsToGain(noteGainDB)); // The SFZ spec is silent about the pan curve, but a 3dB pan law seems // common. This sqrt() curve matches what Dimension LE does; Alchemy Free // seems closer to sin(adjustedPan * pi/2). double adjustedPan = (region_->pan + 100.0) / 200.0; noteGainLeft_ *= static_cast(sqrt(1.0 - adjustedPan)); noteGainRight_ *= static_cast(sqrt(adjustedPan)); - ampeg_.startNote(®ion_->ampeg, floatVelocity, getSampleRate(), ®ion_->ampeg_veltrack); + ampeg_.startNote(®ion_->ampeg, floatVelocity, getSampleRate(), + ®ion_->ampeg_veltrack); // Offset/end. sourceSamplePosition_ = static_cast(region_->offset); sampleEnd_ = region_->sample->getSampleLength(); - if ((region_->end > 0) && (region_->end < sampleEnd_)) - { + if ((region_->end > 0) && (region_->end < sampleEnd_)) { sampleEnd_ = region_->end + 1; } // Loop. loopStart_ = loopEnd_ = 0; sfzero::Region::LoopMode loopMode = region_->loop_mode; - if (loopMode == sfzero::Region::sample_loop) - { - if (region_->sample->getLoopStart() < region_->sample->getLoopEnd()) - { + if (loopMode == sfzero::Region::sample_loop) { + if (region_->sample->getLoopStart() < region_->sample->getLoopEnd()) { loopMode = sfzero::Region::loop_continuous; - } - else - { + } else { loopMode = sfzero::Region::no_loop; } } - if ((loopMode != sfzero::Region::no_loop) && (loopMode != sfzero::Region::one_shot)) - { - if (region_->loop_start < region_->loop_end) - { + if ((loopMode != sfzero::Region::no_loop) && + (loopMode != sfzero::Region::one_shot)) { + if (region_->loop_start < region_->loop_end) { loopStart_ = region_->loop_start; loopEnd_ = region_->loop_end; - } - else - { + } else { loopStart_ = region_->sample->getLoopStart(); loopEnd_ = region_->sample->getLoopEnd(); } @@ -112,42 +119,32 @@ void sfzero::Voice::startNote(int midiNoteNumber, float floatVelocity, juce::Syn numLoops_ = 0; } -void sfzero::Voice::stopNote(float /*velocity*/, bool allowTailOff) -{ - if (!allowTailOff || (region_ == nullptr)) - { +void sfzero::Voice::stopNote(float /*velocity*/, bool allowTailOff) { + if (!allowTailOff || (region_ == nullptr)) { killNote(); return; } - if (region_->loop_mode != sfzero::Region::one_shot) - { + if (region_->loop_mode != sfzero::Region::one_shot) { ampeg_.noteOff(); } - if (region_->loop_mode == sfzero::Region::loop_sustain) - { + if (region_->loop_mode == sfzero::Region::loop_sustain) { // Continue playing, but stop looping. loopEnd_ = loopStart_; } } -void sfzero::Voice::stopNoteForGroup() -{ - if (region_->off_mode == sfzero::Region::fast) - { +void sfzero::Voice::stopNoteForGroup() { + if (region_->off_mode == sfzero::Region::fast) { ampeg_.fastRelease(); - } - else - { + } else { ampeg_.noteOff(); } } void sfzero::Voice::stopNoteQuick() { ampeg_.fastRelease(); } -void sfzero::Voice::pitchWheelMoved(int newValue) -{ - if (region_ == nullptr) - { +void sfzero::Voice::pitchWheelMoved(int newValue) { + if (region_ == nullptr) { return; } @@ -155,22 +152,26 @@ void sfzero::Voice::pitchWheelMoved(int newValue) calcPitchRatio(); } -void sfzero::Voice::controllerMoved(int /*controllerNumber*/, int /*newValue*/) { /***/} -void sfzero::Voice::renderNextBlock(juce::AudioSampleBuffer &outputBuffer, int startSample, int numSamples) -{ - if (region_ == nullptr) - { +void sfzero::Voice::controllerMoved(int /*controllerNumber*/, + int /*newValue*/) { /***/ +} +void sfzero::Voice::renderNextBlock(juce::AudioSampleBuffer &outputBuffer, + int startSample, int numSamples) { + if (region_ == nullptr) { return; } juce::AudioSampleBuffer *buffer = region_->sample->getBuffer(); const float *inL = buffer->getReadPointer(0, 0); - const float *inR = buffer->getNumChannels() > 1 ? buffer->getReadPointer(1, 0) : nullptr; + const float *inR = + buffer->getNumChannels() > 1 ? buffer->getReadPointer(1, 0) : nullptr; float *outL = outputBuffer.getWritePointer(0, startSample); - float *outR = outputBuffer.getNumChannels() > 1 ? outputBuffer.getWritePointer(1, startSample) : nullptr; + float *outR = outputBuffer.getNumChannels() > 1 + ? outputBuffer.getWritePointer(1, startSample) + : nullptr; - int bufferNumSamples = buffer->getNumSamples(); // leoo + int bufferNumSamples = buffer->getNumSamples(); // leoo // Cache some values, to give them at least some chance of ending up in // registers. @@ -183,25 +184,25 @@ void sfzero::Voice::renderNextBlock(juce::AudioSampleBuffer &outputBuffer, int s float loopEnd = static_cast(this->loopEnd_); float sampleEnd = static_cast(this->sampleEnd_); - while (--numSamples >= 0) - { + while (--numSamples >= 0) { int pos = static_cast(sourceSamplePosition); - jassert(pos >= 0 && pos < bufferNumSamples); // leoo + jassert(pos >= 0 && pos < bufferNumSamples); // leoo float alpha = static_cast(sourceSamplePosition - pos); float invAlpha = 1.0f - alpha; int nextPos = pos + 1; - if ((loopStart < loopEnd) && (nextPos > loopEnd)) - { + if ((loopStart < loopEnd) && (nextPos > loopEnd)) { nextPos = static_cast(loopStart); } // Simple linear interpolation with buffer overrun check float nextL = nextPos < bufferNumSamples ? inL[nextPos] : inL[pos]; - float nextR = inR ? (nextPos < bufferNumSamples ? inR[nextPos] : inR[pos]) : nextL; + float nextR = + inR ? (nextPos < bufferNumSamples ? inR[nextPos] : inR[pos]) : nextL; float l = (inL[pos] * invAlpha + nextL * alpha); float r = inR ? (inR[pos] * invAlpha + nextR * alpha) : l; - //// Simple linear interpolation, old version (possible buffer overrun with non-loop??) + //// Simple linear interpolation, old version (possible buffer overrun with + /// non-loop??) // float l = (inL[pos] * invAlpha + inL[nextPos] * alpha); // float r = inR ? (inR[pos] * invAlpha + inR[nextPos] * alpha) : l; @@ -211,35 +212,27 @@ void sfzero::Voice::renderNextBlock(juce::AudioSampleBuffer &outputBuffer, int s r *= gainRight; // Shouldn't we dither here? - if (outR) - { + if (outR) { *outL++ += l; *outR++ += r; - } - else - { + } else { *outL++ += (l + r) * 0.5f; } // Next sample. sourceSamplePosition += pitchRatio_; - if ((loopStart < loopEnd) && (sourceSamplePosition > loopEnd)) - { + if ((loopStart < loopEnd) && (sourceSamplePosition > loopEnd)) { sourceSamplePosition = loopStart; numLoops_ += 1; } // Update EG. - if (ampSegmentIsExponential) - { + if (ampSegmentIsExponential) { ampegGain *= ampegSlope; - } - else - { + } else { ampegGain += ampegSlope; } - if (--samplesUntilNextAmpSegment < 0) - { + if (--samplesUntilNextAmpSegment < 0) { ampeg_.setLevel(ampegGain); ampeg_.nextSegment(); ampegGain = ampeg_.getLevel(); @@ -248,8 +241,7 @@ void sfzero::Voice::renderNextBlock(juce::AudioSampleBuffer &outputBuffer, int s ampSegmentIsExponential = ampeg_.getSegmentIsExponential(); } - if ((sourceSamplePosition >= sampleEnd) || ampeg_.isDone()) - { + if ((sourceSamplePosition >= sampleEnd) || ampeg_.isDone()) { killNote(); break; } @@ -260,68 +252,72 @@ void sfzero::Voice::renderNextBlock(juce::AudioSampleBuffer &outputBuffer, int s ampeg_.setSamplesUntilNextSegment(samplesUntilNextAmpSegment); } -bool sfzero::Voice::isPlayingNoteDown() { return region_ && region_->trigger != sfzero::Region::release; } +bool sfzero::Voice::isPlayingNoteDown() { + return region_ && region_->trigger != sfzero::Region::release; +} -bool sfzero::Voice::isPlayingOneShot() { return region_ && region_->loop_mode == sfzero::Region::one_shot; } +bool sfzero::Voice::isPlayingOneShot() { + return region_ && region_->loop_mode == sfzero::Region::one_shot; +} int sfzero::Voice::getGroup() { return region_ ? region_->group : 0; } juce::uint64 sfzero::Voice::getOffBy() { return region_ ? region_->off_by : 0; } -void sfzero::Voice::setRegion(sfzero::Region *nextRegion) { region_ = nextRegion; } +void sfzero::Voice::setRegion(sfzero::Region *nextRegion) { + region_ = nextRegion; +} -juce::String sfzero::Voice::infoString() -{ - const char *egSegmentNames[] = {"delay", "attack", "hold", "decay", "sustain", "release", "done"}; +juce::String sfzero::Voice::infoString() { + const char *egSegmentNames[] = {"delay", "attack", "hold", "decay", + "sustain", "release", "done"}; - const static int numEGSegments(sizeof(egSegmentNames) / sizeof(egSegmentNames[0])); + const static int numEGSegments(sizeof(egSegmentNames) / + sizeof(egSegmentNames[0])); const char *egSegmentName = "-Invalid-"; int egSegmentIndex = ampeg_.segmentIndex(); - if ((egSegmentIndex >= 0) && (egSegmentIndex < numEGSegments)) - { + if ((egSegmentIndex >= 0) && (egSegmentIndex < numEGSegments)) { egSegmentName = egSegmentNames[egSegmentIndex]; } juce::String info; - info << "note: " << curMidiNote_ << ", vel: " << curVelocity_ << ", pan: " << region_->pan << ", eg: " << egSegmentName + info << "note: " << curMidiNote_ << ", vel: " << curVelocity_ + << ", pan: " << region_->pan << ", eg: " << egSegmentName << ", loops: " << numLoops_; return info; } -void sfzero::Voice::calcPitchRatio() -{ +void sfzero::Voice::calcPitchRatio() { double note = curMidiNote_; note += region_->transpose; note += region_->tune / 100.0; - double adjustedPitch = region_->pitch_keycenter + (note - region_->pitch_keycenter) * (region_->pitch_keytrack / 100.0); - if (curPitchWheel_ != 8192) - { + double adjustedPitch = + region_->pitch_keycenter + + (note - region_->pitch_keycenter) * (region_->pitch_keytrack / 100.0); + if (curPitchWheel_ != 8192) { double wheel = ((2.0 * curPitchWheel_ / 16383.0) - 1.0); - if (wheel > 0) - { + if (wheel > 0) { adjustedPitch += wheel * region_->bend_up / 100.0; - } - else - { + } else { adjustedPitch += wheel * region_->bend_down / -100.0; } } double targetFreq = fractionalMidiNoteInHz(adjustedPitch); - double naturalFreq = juce::MidiMessage::getMidiNoteInHertz(region_->pitch_keycenter); - pitchRatio_ = (targetFreq * region_->sample->getSampleRate()) / (naturalFreq * getSampleRate()); + double naturalFreq = + juce::MidiMessage::getMidiNoteInHertz(region_->pitch_keycenter); + pitchRatio_ = (targetFreq * region_->sample->getSampleRate()) / + (naturalFreq * getSampleRate()); } -void sfzero::Voice::killNote() -{ +void sfzero::Voice::killNote() { region_ = nullptr; clearCurrentNote(); } -double sfzero::Voice::fractionalMidiNoteInHz(double note, double freqOfA) -{ +double sfzero::Voice::fractionalMidiNoteInHz(double note, double freqOfA) { // Like MidiMessage::getMidiNoteInHertz(), but with a float note. note -= 69; // Now 0 = A diff --git a/sfzero/SFZVoice.h b/sfzero/SFZVoice.h index e005593..688c166 100644 --- a/sfzero/SFZVoice.h +++ b/sfzero/SFZVoice.h @@ -2,31 +2,33 @@ * Original code copyright (C) 2012 Steve Folta * Converted to Juce module (C) 2016 Leo Olivers * Forked from https://github.com/stevefolta/SFZero - * For license info please see the LICENSE file distributed with this source code + * For license info please see the LICENSE file distributed with this source + *code *************************************************************************************/ #ifndef SFZVOICE_H_INCLUDED #define SFZVOICE_H_INCLUDED #include "SFZEG.h" -namespace sfzero -{ +namespace sfzero { struct Region; -class Voice : public juce::SynthesiserVoice -{ -public: +class Voice : public juce::SynthesiserVoice { + public: Voice(); virtual ~Voice(); bool canPlaySound(juce::SynthesiserSound *sound) override; - void startNote(int midiNoteNumber, float velocity, juce::SynthesiserSound *sound, int currentPitchWheelPosition) override; + void startNote(int midiNoteNumber, float velocity, + juce::SynthesiserSound *sound, + int currentPitchWheelPosition) override; void stopNote(float velocity, bool allowTailOff) override; void stopNoteForGroup(); void stopNoteQuick(); void pitchWheelMoved(int newValue) override; void controllerMoved(int controllerNumber, int newValue) override; - void renderNextBlock(juce::AudioSampleBuffer &outputBuffer, int startSample, int numSamples) override; + void renderNextBlock(juce::AudioSampleBuffer &outputBuffer, int startSample, + int numSamples) override; bool isPlayingNoteDown(); bool isPlayingOneShot(); @@ -38,7 +40,7 @@ class Voice : public juce::SynthesiserVoice juce::String infoString(); -private: + private: Region *region_; int trigger_; int curMidiNote_, curPitchWheel_; @@ -59,6 +61,6 @@ class Voice : public juce::SynthesiserVoice JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(Voice) }; -} +} // namespace sfzero -#endif // SFZVOICE_H_INCLUDED +#endif // SFZVOICE_H_INCLUDED diff --git a/sfzero/sf2-chunks/generators.h b/sfzero/sf2-chunks/generators.h index 488bf37..f46233f 100644 --- a/sfzero/sf2-chunks/generators.h +++ b/sfzero/sf2-chunks/generators.h @@ -1,23 +1,46 @@ -SF2GeneratorValue(startAddrsOffset, Short), SF2GeneratorValue(endAddrsOffset, Short), - SF2GeneratorValue(startloopAddrsOffset, Short), SF2GeneratorValue(endloopAddrsOffset, Short), - SF2GeneratorValue(startAddrsCoarseOffset, Short), SF2GeneratorValue(modLfoToPitch, Short), - SF2GeneratorValue(vibLfoToPitch, Short), SF2GeneratorValue(modEnvToPitch, Short), SF2GeneratorValue(initialFilterFc, Short), - SF2GeneratorValue(initialFilterQ, Short), SF2GeneratorValue(modLfoToFilterFc, Short), - SF2GeneratorValue(modEnvToFilterFc, Short), SF2GeneratorValue(endAddrsCoarseOffset, Short), - SF2GeneratorValue(modLfoToVolume, Short), SF2GeneratorValue(unused1, Short), SF2GeneratorValue(chorusEffectsSend, Short), - SF2GeneratorValue(reverbEffectsSend, Short), SF2GeneratorValue(pan, Short), SF2GeneratorValue(unused2, Short), - SF2GeneratorValue(unused3, Short), SF2GeneratorValue(unused4, Short), SF2GeneratorValue(delayModLFO, Short), - SF2GeneratorValue(freqModLFO, Short), SF2GeneratorValue(delayVibLFO, Short), SF2GeneratorValue(freqVibLFO, Short), - SF2GeneratorValue(delayModEnv, Short), SF2GeneratorValue(attackModEnv, Short), SF2GeneratorValue(holdModEnv, Short), - SF2GeneratorValue(decayModEnv, Short), SF2GeneratorValue(sustainModEnv, Short), SF2GeneratorValue(releaseModEnv, Short), - SF2GeneratorValue(keynumToModEnvHold, Short), SF2GeneratorValue(keynumToModEnvDecay, Short), - SF2GeneratorValue(delayVolEnv, Short), SF2GeneratorValue(attackVolEnv, Short), SF2GeneratorValue(holdVolEnv, Short), - SF2GeneratorValue(decayVolEnv, Short), SF2GeneratorValue(sustainVolEnv, Short), SF2GeneratorValue(releaseVolEnv, Short), - SF2GeneratorValue(keynumToVolEnvHold, Short), SF2GeneratorValue(keynumToVolEnvDecay, Short), - SF2GeneratorValue(instrument, Word), SF2GeneratorValue(reserved1, Short), SF2GeneratorValue(keyRange, Range), - SF2GeneratorValue(velRange, Range), SF2GeneratorValue(startloopAddrsCoarseOffset, Short), SF2GeneratorValue(keynum, Short), - SF2GeneratorValue(velocity, Short), SF2GeneratorValue(initialAttenuation, Short), SF2GeneratorValue(reserved2, Short), - SF2GeneratorValue(endloopAddrsCoarseOffset, Short), SF2GeneratorValue(coarseTune, Short), SF2GeneratorValue(fineTune, Short), - SF2GeneratorValue(sampleID, Word), SF2GeneratorValue(sampleModes, Word), SF2GeneratorValue(reserved3, Short), - SF2GeneratorValue(scaleTuning, Short), SF2GeneratorValue(exclusiveClass, Short), SF2GeneratorValue(overridingRootKey, Short), +SF2GeneratorValue(startAddrsOffset, Short), + SF2GeneratorValue(endAddrsOffset, Short), + SF2GeneratorValue(startloopAddrsOffset, Short), + SF2GeneratorValue(endloopAddrsOffset, Short), + SF2GeneratorValue(startAddrsCoarseOffset, Short), + SF2GeneratorValue(modLfoToPitch, Short), + SF2GeneratorValue(vibLfoToPitch, Short), + SF2GeneratorValue(modEnvToPitch, Short), + SF2GeneratorValue(initialFilterFc, Short), + SF2GeneratorValue(initialFilterQ, Short), + SF2GeneratorValue(modLfoToFilterFc, Short), + SF2GeneratorValue(modEnvToFilterFc, Short), + SF2GeneratorValue(endAddrsCoarseOffset, Short), + SF2GeneratorValue(modLfoToVolume, Short), SF2GeneratorValue(unused1, Short), + SF2GeneratorValue(chorusEffectsSend, Short), + SF2GeneratorValue(reverbEffectsSend, Short), SF2GeneratorValue(pan, Short), + SF2GeneratorValue(unused2, Short), SF2GeneratorValue(unused3, Short), + SF2GeneratorValue(unused4, Short), SF2GeneratorValue(delayModLFO, Short), + SF2GeneratorValue(freqModLFO, Short), SF2GeneratorValue(delayVibLFO, Short), + SF2GeneratorValue(freqVibLFO, Short), SF2GeneratorValue(delayModEnv, Short), + SF2GeneratorValue(attackModEnv, Short), + SF2GeneratorValue(holdModEnv, Short), SF2GeneratorValue(decayModEnv, Short), + SF2GeneratorValue(sustainModEnv, Short), + SF2GeneratorValue(releaseModEnv, Short), + SF2GeneratorValue(keynumToModEnvHold, Short), + SF2GeneratorValue(keynumToModEnvDecay, Short), + SF2GeneratorValue(delayVolEnv, Short), + SF2GeneratorValue(attackVolEnv, Short), + SF2GeneratorValue(holdVolEnv, Short), SF2GeneratorValue(decayVolEnv, Short), + SF2GeneratorValue(sustainVolEnv, Short), + SF2GeneratorValue(releaseVolEnv, Short), + SF2GeneratorValue(keynumToVolEnvHold, Short), + SF2GeneratorValue(keynumToVolEnvDecay, Short), + SF2GeneratorValue(instrument, Word), SF2GeneratorValue(reserved1, Short), + SF2GeneratorValue(keyRange, Range), SF2GeneratorValue(velRange, Range), + SF2GeneratorValue(startloopAddrsCoarseOffset, Short), + SF2GeneratorValue(keynum, Short), SF2GeneratorValue(velocity, Short), + SF2GeneratorValue(initialAttenuation, Short), + SF2GeneratorValue(reserved2, Short), + SF2GeneratorValue(endloopAddrsCoarseOffset, Short), + SF2GeneratorValue(coarseTune, Short), SF2GeneratorValue(fineTune, Short), + SF2GeneratorValue(sampleID, Word), SF2GeneratorValue(sampleModes, Word), + SF2GeneratorValue(reserved3, Short), SF2GeneratorValue(scaleTuning, Short), + SF2GeneratorValue(exclusiveClass, Short), + SF2GeneratorValue(overridingRootKey, Short), SF2GeneratorValue(unused5, Short), SF2GeneratorValue(endOper, Short), diff --git a/sfzero/sf2-chunks/imod.h b/sfzero/sf2-chunks/imod.h index db985dc..9e27817 100644 --- a/sfzero/sf2-chunks/imod.h +++ b/sfzero/sf2-chunks/imod.h @@ -1,2 +1,3 @@ -SF2Field(word, modSrcOper) SF2Field(word, modDestOper) SF2Field(short, modAmount) SF2Field(word, modAmtSrcOper) - SF2Field(word, modTransOper) +SF2Field(word, modSrcOper) SF2Field(word, modDestOper) + SF2Field(short, modAmount) SF2Field(word, modAmtSrcOper) + SF2Field(word, modTransOper) diff --git a/sfzero/sf2-chunks/phdr.h b/sfzero/sf2-chunks/phdr.h index 56f7284..27ae949 100644 --- a/sfzero/sf2-chunks/phdr.h +++ b/sfzero/sf2-chunks/phdr.h @@ -1,2 +1,3 @@ -SF2Field(char20, presetName) SF2Field(word, preset) SF2Field(word, bank) SF2Field(word, presetBagNdx) SF2Field(dword, library) - SF2Field(dword, genre) SF2Field(dword, morphology) +SF2Field(char20, presetName) SF2Field(word, preset) SF2Field(word, bank) + SF2Field(word, presetBagNdx) SF2Field(dword, library) SF2Field(dword, genre) + SF2Field(dword, morphology) diff --git a/sfzero/sf2-chunks/pmod.h b/sfzero/sf2-chunks/pmod.h index db985dc..9e27817 100644 --- a/sfzero/sf2-chunks/pmod.h +++ b/sfzero/sf2-chunks/pmod.h @@ -1,2 +1,3 @@ -SF2Field(word, modSrcOper) SF2Field(word, modDestOper) SF2Field(short, modAmount) SF2Field(word, modAmtSrcOper) - SF2Field(word, modTransOper) +SF2Field(word, modSrcOper) SF2Field(word, modDestOper) + SF2Field(short, modAmount) SF2Field(word, modAmtSrcOper) + SF2Field(word, modTransOper) diff --git a/sfzero/sf2-chunks/shdr.h b/sfzero/sf2-chunks/shdr.h index 10de930..e0b486e 100644 --- a/sfzero/sf2-chunks/shdr.h +++ b/sfzero/sf2-chunks/shdr.h @@ -1,3 +1,5 @@ -SF2Field(char20, sampleName) SF2Field(dword, start) SF2Field(dword, end) SF2Field(dword, startLoop) SF2Field(dword, endLoop) - SF2Field(dword, sampleRate) SF2Field(byte, originalPitch) SF2Field(char, pitchCorrection) SF2Field(word, sampleLink) - SF2Field(word, sampleType) +SF2Field(char20, sampleName) SF2Field(dword, start) SF2Field(dword, end) + SF2Field(dword, startLoop) SF2Field(dword, endLoop) + SF2Field(dword, sampleRate) SF2Field(byte, originalPitch) + SF2Field(char, pitchCorrection) SF2Field(word, sampleLink) + SF2Field(word, sampleType)