Feature request: extract XYZ data metadata
-
Could we please get more helpers for getting the xyz (samplemap) metadata in c++?
Actual Data:
Extracted Data:
[FileReader] Mode: XYZ multisample provider: SampleMap items: 2 item 0 map : key=[60..91] vel=[0..128] rr=1 root=69.00 audio: ch=2 samples=159976 sr=48000.000 loop : [45..149976] item 1 map : key=[23..60] vel=[0..128] rr=1 root=48.00 audio: ch=2 samples=159976 sr=48000.000 loop : [45..149976]
^ Here is the data I was able to pull out of a samplemap / monolyth using the xyz data in c++
I noticed that some data is missing and incorrect!
We are missing:- SampleStart
- XfadeLength
- LoopStart.
Additionally 'loopstart' that xyz data gives us, seems to actually be (loopstart - samplestart) rather than the actual loopstart!
Here is the code I used to extract the data:
// FILE: FileReader.h /* ExternalData XYZ samplemap inspector */ #pragma once #include <JuceHeader.h> #if JUCE_WINDOWS #include <windows.h> #endif namespace project { using namespace juce; using namespace hise; using namespace scriptnode; template <int NV> struct FileReader : public data::base { SNEX_NODE(FileReader); struct MetadataClass { SN_NODE_ID("FileReader"); }; static constexpr bool isModNode() { return false; } static constexpr bool isPolyphonic() { return NV > 1; } static constexpr bool hasTail() { return false; } static constexpr bool isSuspendedOnSilence() { return false; } static constexpr int getFixChannelAmount() { return 2; } static constexpr int NumTables = 0; static constexpr int NumSliderPacks = 0; static constexpr int NumAudioFiles = 1; static constexpr int NumFilters = 0; static constexpr int NumDisplayBuffers = 0; void prepare(PrepareSpecs) {} void reset() {} void handleHiseEvent(HiseEvent&) {} template <typename T> void process(T& d) { static_cast<void>(d); } template <typename T> void processFrame(T&) {} int handleModulation(double&) { return 0; } void setExternalData(const ExternalData& data, int index) { if (index != 0) return; extData = data; dumpExternal(extData); } template <int P> void setParameter(double v) { static_cast<void>(v); if (P == 0) {} } void createParameters(ParameterDataList& list) { parameter::data p("Dummy", { 0.0, 1.0 }); registerCallback<0>(p); p.setDefaultValue(0.0); list.add(std::move(p)); } private: ExternalData extData; /* Dumps all accessible metadata for the bound ExternalData. */ void dumpExternal(const ExternalData& ed) { if (ed.obj == nullptr) { logLine("[FileReader] No ExternalData object set."); return; } if (!SimpleReadWriteLock::ScopedTryReadLock(ed.obj->getDataLock())) { logLine("[FileReader] Could not lock ExternalData for reading."); return; } auto* m = static_cast<MultiChannelAudioBuffer*>(ed.obj); if (!ed.isXYZ()) { logLine("[FileReader] Mode: Single sample"); const auto& buf = m->getBuffer(); const int ch = buf.getNumChannels(); const int ns = buf.getNumSamples(); const double sr = m->sampleRate; const auto total = m->getTotalRange(); const auto current = m->getCurrentRange(); const auto loopAbs = m->getLoopRange(false); const auto loopRel = m->getLoopRange(true); logLine(" audio: ch=" + String(ch) + " samples=" + String(ns) + " sr=" + String(sr, 3)); logLine(" range: total=" + rangeStr(total) + " current=" + rangeStr(current)); logLine(" loop : abs=" + rangeStr(loopAbs) + " rel=" + rangeStr(loopRel)); return; } logLine("[FileReader] Mode: XYZ multisample"); logLine(" provider: " + m->getCurrentXYZId().toString()); logLine(" items: " + String(ed.numSamples)); auto* items = static_cast<MultiChannelAudioBuffer::XYZItem*>(ed.data); for (int i = 0; i < ed.numSamples; ++i) { logLine(" item " + String(i)); const auto& it = items[i]; logLine(" map : key=" + rangeStr(it.keyRange) + " vel=" + rangeStr(it.veloRange) + " rr=" + String(it.rrGroup) + " root=" + String(it.root, 2)); int ch = 0, ns = 0; double sr = 0.0; Range<int> lr; String ref; if (it.data != nullptr) { ch = it.data->buffer.getNumChannels(); ns = it.data->buffer.getNumSamples(); sr = it.data->sampleRate; lr = it.data->loopRange; ref = it.data->reference; } logLine(" audio: ch=" + String(ch) + " samples=" + String(ns) + " sr=" + String(sr, 3)); logLine(" loop : " + (lr.getLength() > 0 ? rangeStr(lr) : String("-"))); if (ref.isNotEmpty()) logLine(" ref : " + ref); } } String rangeStr(const Range<int>& r) const { return "[" + String(r.getStart()) + ".." + String(r.getEnd()) + "]"; } void logLine(const String& s) { #if JUCE_WINDOWS const auto msg = (s + "\r\n").toStdString(); OutputDebugStringA(msg.c_str()); #else Logger::writeToLog(s); #endif } }; } // namespace project
-
G griffinboy marked this topic as a question
-
Definitely a question for @Christoph-Hart this one!
Following on from our discussion about the XYZ data. -
Womp womp bump
-
@griffinboy Ha you're impatient today
-
Yeah it's naughty of me
The timeline of this project I'm working on became really stretched, so now that I'm finally approaching the end I'm too excited to resolve the final barriers.
-
@griffinboy that's not so easy, the buffer that is passed with the ExternalData is already truncated with the sample-start and sample-end values. But why do you need this, just playback the part you want to play?
-
Wait, does the xfade get baked into the sound file then?
My client was hoping to take some sample maps that have already been created, and load them into a custom c++ sampler.
And then mess around with the loop points etc.
But if what you're saying is true, then I can't do that
-
G griffinboy marked this topic as a regular topic