HISE Logo Forum
    • Categories
    • Register
    • Login

    More MIDI data

    Scheduled Pinned Locked Moved Feature Requests
    6 Posts 2 Posters 2.5k 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.
    • C
      channelrobot
      last edited by

      To run any sort of sequencer or tempo linked modulations etc. we are going to need MIDI Song Position Pointer data, we will need to know where we are in the song and the bar as well as Transport Start and Transport stop. I cant see this info anywhere in the current function calls.

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

        This data is accessible through the common plugin-wrapper from JUCE (copied from their API):

        @3a2jqf1l:

        double bpm
        The tempo in BPM. More…

        int timeSigNumerator
        Time signature numerator, e.g. More...

        int timeSigDenominator
        Time signature denominator, e.g. More...

        int64 timeInSamples
        The current play position, in samples from the start of the edit. More...

        double timeInSeconds
        The current play position, in seconds from the start of the edit. More...

        double editOriginTime
        For timecode, the position of the start of the edit, in seconds from 00:00:00:00. More...

        double ppqPosition
        The current play position, in pulses-per-quarter-note. More...

        double ppqPositionOfLastBarStart
        The position of the start of the last bar, in pulses-per-quarter-note. More...

        FrameRateType frameRate
        The video frame rate, if applicable. More...

        bool isPlaying
        True if the transport is currently playing. More...

        bool isRecording
        True if the transport is currently recording. More...

        double ppqLoopStart
        The current cycle start position in pulses-per-quarter-note. More...

        double ppqLoopEnd
        The current cycle end position in pulses-per-quarter-note. More...

        bool isLooping
        True if the transport is currently looping. More...

        I could wrap them up into an Object which could be retrieved by this scripting call:

        Engine.getPlayHead().ppqLoopStart; // contains the current value for this property
        
        

        Although this will be a thing that is heavily dependant on the host DAW and needs some broad testing. I can check Cubase (5 + 8), Reaper 5 and Ableton 9 on both OSX and Windows.

        1 Reply Last reply Reply Quote 0
        • C
          channelrobot
          last edited by

          Well I dont think we need all of these, I think we need the following:

          bool isPlaying

          … but more importantly we need a call back that happens when this value is changed, in KSP its on Listener

          bool ppqPosition

          assuming this is 96ppq resolution, which is a bit too fine I imagine, it will add a lot of overhead into the engine, KSP allows me to set the resolution here from 1 to 24 , and again when this happens we need a call back

          So in some on-listener-type call back we need to interrogate some variable to see what type it is:

          SIGNAL_TYPE would need to be

          TRANSPORT_START
          TRANSPORT_STOP
          POSITION

          the following would be useful to get from a javascript call as you suggest:

          double bpm
          int timeSigNumerator
          int timeSigDenominator
          double ppqPositionOfLastBarStart
          double ppqLoopStart
          double ppqLoopEnd
          bool isLooping

          As you say not all DAWs in all situations will return these, but my experience is that all DAWs on all platforms return the vital transport and position data.

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

            Well, I added all properties (there's almost no overhead and some other properties may get interesting for other use cases).

            Alright, I added two callbacks (although you have to write them manually, I don't want to clutter the editor interface with too many callback buttons):

            // Callback that is called periodically and synchronized to the host (only called if the host is playing)
            function onClock(timeStamp);
            
            // Callback that indicates the transport change (isStart is 1 if the host is playing)
            function onTransport(isStart);
            
            

            Getting the timing right was rather complicated and the timing goes funky when the audio buffer size is bigger than the clock interval - but this should not be relevant in the real world.

            Every sound generator has its own clock and can be set from one bar (=4 quarters) to 32th notes (faster doesn't make sense). You can change the clock speed with the API call

            Synth.setClockSpeed(16); // would be 16th notes..
            Synth.setClockSpeed(0); // stops the clock (this is also the default).
            
            

            You can use the host info API call to write a sequencer like this (make sure you use this on a sound generator with fast decay and no sustain!):

            // A fast C-minor arpeggiator synched to the host
            
            Synth.setClockSpeed(32);
            
            var x = [48,51,55,60,63,67,72,75];
            var index = 0;
            
            function onClock()
            {
            	// You need to round up the ppqPosition because it is the value at the start of the buffer
            	index = parseInt(Math.ceil(Engine.getPlayHead().ppqPosition*8.0));
            
            	Synth.playNote(x[index%x.length],127);
            }
            
            

            This should be everything you need to write a sequencer. If you need more, let me know.

            1 Reply Last reply Reply Quote 0
            • C
              channelrobot
              last edited by

              yeah this should work, where would I write the onClock and onTransport functions, anywhere special?

              … you wont believe how long I've been asking UVI for this functionality in their engine... nice turn around, well done.

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

                Thanks. I wanted to add this feature for a long time because the onTimer callback is not perfectly accurate (it gets executed at the start of the buffer, so you don't have sample accurate timing).

                You can write them anywhere (outside of the other callbacks of course), but I would suggest adding them in the onInit page - the script processor checks if the other callback pages are empty and skips the callback to save overhead and if you add the onClock callback on the onNoteOn page, an empty callback will be executed for every incoming note on event.

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

                47

                Online

                1.7k

                Users

                11.7k

                Topics

                101.8k

                Posts