HISE Logo Forum
    • Categories
    • Register
    • Login

    Feature request: extract XYZ data metadata

    Scheduled Pinned Locked Moved Feature Requests
    7 Posts 3 Posters 89 Views
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • griffinboyG
      griffinboy
      last edited by griffinboy

      Could we please get more helpers for getting the xyz (samplemap) metadata in c++?

      Actual Data:
      0ce5f17e-a901-4533-a52f-1e5f0849918b-image.png

      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
      
      
      griffinboyG 1 Reply Last reply Reply Quote 1
      • griffinboyG griffinboy marked this topic as a question
      • griffinboyG
        griffinboy @griffinboy
        last edited by

        @griffinboy

        Definitely a question for @Christoph-Hart this one!
        Following on from our discussion about the XYZ data.

        griffinboyG 1 Reply Last reply Reply Quote 0
        • griffinboyG
          griffinboy @griffinboy
          last edited by

          @griffinboy

          Womp womp bump

          d.healeyD 1 Reply Last reply Reply Quote 0
          • d.healeyD
            d.healey @griffinboy
            last edited by

            @griffinboy Ha you're impatient today 😆

            Libre Wave - Freedom respecting instruments and effects
            My Patreon - HISE tutorials
            YouTube Channel - Public HISE tutorials

            griffinboyG 1 Reply Last reply Reply Quote 1
            • griffinboyG
              griffinboy @d.healey
              last edited by griffinboy

              @d-healey

              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.

              Christoph HartC 1 Reply Last reply Reply Quote 0
              • Christoph HartC
                Christoph Hart @griffinboy
                last edited by

                @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?

                griffinboyG 1 Reply Last reply Reply Quote 1
                • griffinboyG
                  griffinboy @Christoph Hart
                  last edited by griffinboy

                  @Christoph-Hart

                  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 😆

                  1 Reply Last reply Reply Quote 0
                  • griffinboyG griffinboy marked this topic as a regular topic
                  • First post
                    Last post

                  17

                  Online

                  1.9k

                  Users

                  12.3k

                  Topics

                  107.4k

                  Posts