diff --git a/src/sfizz/FilePool.cpp b/src/sfizz/FilePool.cpp index 8b4ca8a3..9750da2c 100644 --- a/src/sfizz/FilePool.cpp +++ b/src/sfizz/FilePool.cpp @@ -216,14 +216,15 @@ absl::optional sfz::FilePool::getFileInformation(const Fil returnedValue.numChannels = reader->channels(); SF_INSTRUMENT instrumentInfo {}; + bool haveInstrumentInfo = reader->getInstrument(&instrumentInfo); FileMetadataReader mdReader; bool mdReaderOpened = mdReader.open(file); - if (!reader->getInstrument(&instrumentInfo)) { + if (!haveInstrumentInfo) { // if no instrument, then try extracting from embedded RIFF chunks (flac) if (mdReaderOpened) - mdReader.extractRiffInstrument(instrumentInfo); + haveInstrumentInfo = mdReader.extractRiffInstrument(instrumentInfo); } if (mdReaderOpened) { @@ -233,7 +234,7 @@ absl::optional sfz::FilePool::getFileInformation(const Fil } if (!fileId.isReverse()) { - if (instrumentInfo.loop_count > 0) { + if (haveInstrumentInfo && instrumentInfo.loop_count > 0) { returnedValue.hasLoop = true; returnedValue.loopBegin = instrumentInfo.loops[0].start; returnedValue.loopEnd = min(returnedValue.end, instrumentInfo.loops[0].end - 1); @@ -243,6 +244,9 @@ absl::optional sfz::FilePool::getFileInformation(const Fil // prehaps it can make use of SF_LOOP_BACKWARD? } + if (haveInstrumentInfo) + returnedValue.rootKey = clamp(instrumentInfo.basenote, 0, 127); + return returnedValue; } diff --git a/src/sfizz/FilePool.h b/src/sfizz/FilePool.h index dcef362c..f05712fd 100644 --- a/src/sfizz/FilePool.h +++ b/src/sfizz/FilePool.h @@ -56,6 +56,7 @@ struct FileInformation { bool hasLoop { false }; double sampleRate { config::defaultSampleRate }; int numChannels { 0 }; + int rootKey { 0 }; absl::optional wavetable; }; diff --git a/src/sfizz/Region.cpp b/src/sfizz/Region.cpp index 7ec6619d..83417fb5 100644 --- a/src/sfizz/Region.cpp +++ b/src/sfizz/Region.cpp @@ -779,7 +779,12 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) // Performance parameters: pitch case hash("pitch_keycenter"): - setValueFromOpcode(opcode, pitchKeycenter, Default::keyRange); + if (opcode.value == "sample") + pitchKeycenterFromSample = true; + else { + pitchKeycenterFromSample = false; + setValueFromOpcode(opcode, pitchKeycenter, Default::keyRange); + } break; case hash("pitch_keytrack"): setValueFromOpcode(opcode, pitchKeytrack, Default::pitchKeytrackRange); diff --git a/src/sfizz/Region.h b/src/sfizz/Region.h index 1d402bbe..61d97b27 100644 --- a/src/sfizz/Region.h +++ b/src/sfizz/Region.h @@ -382,6 +382,7 @@ struct Region { // Performance parameters: pitch uint8_t pitchKeycenter { Default::pitchKeycenter }; // pitch_keycenter + bool pitchKeycenterFromSample { false }; int pitchKeytrack { Default::pitchKeytrack }; // pitch_keytrack int pitchRandom { Default::pitchRandom }; // pitch_random int pitchVeltrack { Default::pitchVeltrack }; // pitch_veltrack diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index e63803c1..4dd86f5e 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -536,6 +536,9 @@ void sfz::Synth::finalizeSfzLoad() if (fileInformation->numChannels == 2) region->hasStereoSample = true; + if (region->pitchKeycenterFromSample) + region->pitchKeycenter = fileInformation->rootKey; + // TODO: adjust with LFO targets const auto maxOffset = [region]() { uint64_t sumOffsetCC = region->offset + region->offsetRandom; diff --git a/tests/FilesT.cpp b/tests/FilesT.cpp index d0d0b064..dbff1ba1 100644 --- a/tests/FilesT.cpp +++ b/tests/FilesT.cpp @@ -684,3 +684,25 @@ TEST_CASE("[Files] Duplicate labels") REQUIRE(xmlMidnam.find("") != xmlMidnam.npos); REQUIRE(xmlMidnam.find("") != xmlMidnam.npos); } + +TEST_CASE("[Files] Key center from audio file") +{ + sfz::Synth synth; + synth.loadSfzString(fs::current_path() / "tests/TestFiles/sample_keycenter.sfz", R"( + pitch_keycenter=sample oscillator=off + sample=root_key_38.wav + sample=root_key_62.wav + sample=root_key_38.flac + sample=root_key_62.flac + pitch_keycenter=10 sample=root_key_62.flac + key=10 sample=root_key_62.flac + )"); + + REQUIRE(synth.getNumRegions() == 6); + REQUIRE(synth.getRegionView(0)->pitchKeycenter == 38); + REQUIRE(synth.getRegionView(1)->pitchKeycenter == 62); + REQUIRE(synth.getRegionView(2)->pitchKeycenter == 38); + REQUIRE(synth.getRegionView(3)->pitchKeycenter == 62); + REQUIRE(synth.getRegionView(4)->pitchKeycenter == 10); + REQUIRE(synth.getRegionView(5)->pitchKeycenter == 62); +} diff --git a/tests/TestFiles/root_key_38.flac b/tests/TestFiles/root_key_38.flac new file mode 100644 index 00000000..d8eefb36 Binary files /dev/null and b/tests/TestFiles/root_key_38.flac differ diff --git a/tests/TestFiles/root_key_38.wav b/tests/TestFiles/root_key_38.wav new file mode 100644 index 00000000..e7a27089 Binary files /dev/null and b/tests/TestFiles/root_key_38.wav differ diff --git a/tests/TestFiles/root_key_62.flac b/tests/TestFiles/root_key_62.flac new file mode 100644 index 00000000..10006b58 Binary files /dev/null and b/tests/TestFiles/root_key_62.flac differ diff --git a/tests/TestFiles/root_key_62.wav b/tests/TestFiles/root_key_62.wav new file mode 100644 index 00000000..658d5bd4 Binary files /dev/null and b/tests/TestFiles/root_key_62.wav differ