HISE Logo Forum
    • Categories
    • Register
    • Login

    Feature request: extract XYZ data metadata

    Scheduled Pinned Locked Moved Solved Feature Requests
    14 Posts 4 Posters 347 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 😆

                  DanHD 1 Reply Last reply Reply Quote 0
                  • griffinboyG griffinboy marked this topic as a regular topic
                  • DanHD
                    DanH @griffinboy
                    last edited by

                    @griffinboy @Christoph-Hart 🙏

                    DHPlugins / DC Breaks | Artist / Producer / DJ / Developer
                    https://dhplugins.com/ | https://dcbreaks.com/
                    London, UK

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

                      Does your project really have different xfade values for samplemaps or can you just use a project wide constant for this?

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

                        @Christoph-Hart

                        I think we could maybe get away with having a default length.
                        Knowing the real loop start is important though, which I can't extract it seems

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

                          @griffinboy but the real loop start is correct in your first post, no?

                          griffinboyG 2 Replies Last reply Reply Quote 0
                          • griffinboyG
                            griffinboy @Christoph Hart
                            last edited by

                            @Christoph-Hart

                            Oh you're correct, because it's chopped off the start of the sample

                            1 Reply Last reply Reply Quote 0
                            • griffinboyG griffinboy marked this topic as a question
                            • griffinboyG griffinboy has marked this topic as solved
                            • griffinboyG
                              griffinboy @Christoph Hart
                              last edited by

                              @Christoph-Hart

                              Seperate but related question:

                              How does one load a samplemap (xyz) into a c++ node from hise script?
                              And can the hisescript read the sample map metadata?

                              I'm wanting the hise script to be able to read out the saved loop points, so that as we load in a samplemap into the c++ sampler node, we can set the loop point parameters correctly.

                              else I'll have to do a funny loop where we use global cables to send the loop points extracted from the xyz data inside the node, into hise, which then uses that info to set the parameters on the c++ node.

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

                                @griffinboy

                                @Christoph-Hart

                                Bump! Sorry

                                1 Reply Last reply Reply Quote 0
                                • First post
                                  Last post

                                21

                                Online

                                1.9k

                                Users

                                12.4k

                                Topics

                                107.7k

                                Posts