Help with Sysex please

Home Forums General General MIDI discussion Help with Sysex please

Tagged: 

Viewing 20 posts - 1 through 20 (of 24 total)
  • Author
    Posts
  • #11260
    lfo2vco
    Participant
      • Topics: 26
      • Replies: 162
      • Total: 188
      • ★★

      Hi, I hope someone can point me in the right direction please.

      I have been trying to use sysex in my panel to get two way editing, although I have been researching how to program with sysex my results have been unsuccessful.

      Maybe if someone could show me how to code for my synth I would understand where I am going wrong. I am trying to control the DCO 1 tune on a Kiwi-3P, this is what I have entered in the sysex field of the modulator:

      [f0] [7f 7f 7f] [60] [01] [00] [04] [15] [0xxxxxxx] [f7]

      Below are the sysex notes from the Kiwi-3P manual.

      _______________________________________________________________________________

      From the KiwiTechnics Manual:
      SYSEX HEADER
      Notes $nn = Hexadecimal Data – Decimal data is in Brackets e.g. $0a (10)
      $f0 Sysex Start
      $7f $7f $7f Non Specific Manufacturers ID
      $60 Kiwitechnics ID
      $01 Kiwitechnics 3P ID
      nn Device ID ($00-$0f)(3P Device ID 1-16)
      xx Command ID (see table 1.0)
      $01=Request Global Dump
      $02=Transmit/Receive Global Dump
      $03=Request Tone Edit Buffer Dump
      $04=Transmit/Receive Tone Edit Buffer Dump
      $05=Request Tone Dump
      $06=Transmit/Receive Tone Dump
      $07=Request Pattern Dump
      $08=Transmit/Receive Pattern Dump
      $09=Request Seq Dump
      $0a=Transmit/Receive Seq Dump
      $0b=Request Tone Name
      $0c=Transmit/Receive Tone Name
      $0d=Request Tone Parameter
      $0e=Transmit/Receive Tone Parameter
      $0f=Request Global Parameter
      $10=Transmit/Receive Global Parameter
      $11=Request Pattern Edit Buffer Dump
      $12=Transmit/Receive Pattern Edit Buffer Dump
      $13=Request Sequence Edit Buffer Dump
      $14=Transmit/Receive Sequence Edit Buffer Dump
      Data Depending on command type (see table 1.0)
      $f7 Sysex Footer
      _______________________________________________________________________________

      $04 (4) Transmit/Receive Tone Edit Buffer Dump
      Null x 2 + 128 data bytes
      2 x null bytes sent followed by 128 bytes of data in the following format
      $00-$13 (0-19) = Tone Name Ascii Bytes Tone Name
      $14 (20) = DCO1 Wave/Range 0000yyxx xx = DCO 1 Range
      00 = 16′
      01 = 8′
      10 = 4′
      yy = DCO 1 Wave
      00 = Saw
      01 = Pulse
      10 = Sqr
      $15 (21) = DCO1 Tune 0xxxxxxx (0-127) Split Control +-63
      (+- 1 octave or +-1200 cents)

      Here is some noise I organised into an acceptable format:
      https://soundcloud.com/lfo2vco/a-dark-crystal

      #11268
      msepsis
      Participant
        • Topics: 219
        • Replies: 732
        • Total: 951
        • ★★★

        As far as I know, you don’t want to represent 0-127 as binary in your sysex formula.. replace the 0xxxxxxx with simply “xx” and loose the brackets. Your formula should look just like this:

        f0 7f 7f 7f 60 01 00 04 15 xx f7

        place that formula into the sysex formula property of a ctrlr slider (referred to as a “modulator” in ctrlr) and set the midi message type to “sysex”. the value of the slider will go where the “xx” is in your formula.

        Im not positive this will work as I haven’t built panels for synths that notate parameters in binary but it should do the trick, or at least someone can correct me if I’m wrong here.

        Monstrum Media | Music, Sound & Software Design, Chicago / San Francisco listen

        #11280
        atom
        Keymaster
          • Topics: 159
          • Replies: 2945
          • Total: 3104
          • ★★★★★

          The Roland JUNO106 uses Sysex to do bi-directional editing. You can use that as an example.

          #11282
          lfo2vco
          Participant
            • Topics: 26
            • Replies: 162
            • Total: 188
            • ★★

            Many thanks msepsis, your response let me know I was working somewhere in the right ball park.

            I entered the formula as you specified but it locked up the patch on my 3P. So I fiddled about a bit. Your comment about binary made me reconsider the formula, so I checked what MIDI the 3P was sending out when in edit mode (via MIDI Monitor). It seemed that the 04 and the 15 where replaced by b0 and 0a in the formula from the 3P. So I tried this:

            f0 7f 7f 7f 60 01 00 b0 0a xx f7

            It worked! the results looked like this:
            [22:49:02:000181]: [System exclusive] RAW:[f0 7f 7f 7f 60 01 00 b0 0a 44 f7]
            [22:49:02:000281]: [System exclusive] RAW:[f0 7f 7f 7f 60 01 00 b0 0a 43 f7]
            [22:49:02:000315]: [System exclusive] RAW:[f0 7f 7f 7f 60 01 00 b0 0a 42 f7]
            [22:49:03:000678]: [System exclusive] RAW:[f0 7f 7f 7f 60 01 00 b0 0a 40 f7]

            Next stage is to see if this method will also apply to a DCO Range uiCombo popup menu.

            Many thanks msepsis for your assistance and pointing me in the right direction.

            Here is some noise I organised into an acceptable format:
            https://soundcloud.com/lfo2vco/a-dark-crystal

            #11283
            lfo2vco
            Participant
              • Topics: 26
              • Replies: 162
              • Total: 188
              • ★★

              The Roland JUNO106 uses Sysex to do bi-directional editing. You can use that as an example.

              Hi Atom, I have indeed been looking at your Juno 106 panel as an example of what I wish to achieve. What confused me initially was the considerable differences in Manufacturer IDs between Roland and KiwiTechnics. Once msepsis had confirmed that part was correct I felt confident to explore the formula further.

              I should say many thanks for putting Ctrlr out there, brilliant software. I am using the panel in CC at present and it has enabled me to start getting sounds together very quickly.

              One question regarding sysex, I’m hoping that the panel will be able to reflect patch changes made on the 3P. Will this require extra scripting or settings to be made in the Ctrlr panel?

              Here is some noise I organised into an acceptable format:
              https://soundcloud.com/lfo2vco/a-dark-crystal

              #11291
              msepsis
              Participant
                • Topics: 219
                • Replies: 732
                • Total: 951
                • ★★★

                One question regarding sysex, I’m hoping that the panel will be able to reflect patch changes made on the 3P. Will this require extra scripting or settings to be made in the Ctrlr panel?

                yes.. you will need to get familiar with getting data and assigning values to modulators (knobs, sliders, buttons, etc).. Basically what you need to do is create a program change knob (or two buttons, – and +) that send a multimessage to your synth. first message is a program change, second message is a sysex program dump request.

                Then on your panel itself (just click on “blank” space on your panel) go to the properties on the far right and look for “called when the panel receives a MIDI message”.

                You’ll need to create a Lua method there called something like midiMessageRecieved. You need to create some hook that determines whether the message coming in is a program dump. Best ways to do this is ether by getting the nth byte to see if it is equal to your synth’s message ID for a program dump, or get the size of the message to compare to what a program dump’s byte length is. Here’s some example code of getting the 4th byte to see if it is equal to 0x10 (0x before a number represents HEX) which in my synths’s case indicates the message is a program dump from the synth:

                
                midiMessageReceived = function(midiMessage)
                
                --this is a comment, it is ignored by the lua interpreter
                --create a variable "IDM" which is the value of the 4th byte of any incoming MIDI message:
                
                IDM = midiMessage:getLuaData():getByte(4)
                
                --is the fourth byte of incoming midi message equal to 0x10?
                		if IDM == 0x10 then
                --if yes, then run another method called "assignValues"
                				assignValues(midiMessage)
                --this next line is just a console message that alerts you that the script has run this far. View these in the "Lua Console"
                				console ("program change sent, standby for panel update...")
                		end
                end
                

                IF the message is a program dump from the synth, you’ll then get the bytes that contain the values for your parameters, assign them to a variable (each one) and then assign that variable as the value for each modulator on your panel.
                Here’s a shortened example of my “assignValues” method:

                function assignValues(midiMessage)
                
                -- create a variable that contains all bytes of program data from the synths program dump, get this info from synth's manual:
                	programData = midiMessage:getData():getRange(7,256)
                
                -- cool, we've got everything, all we need to do now is actually assign the values to the modulators.
                --NOTE: use "setValueMapped" if the modulator is a combobox with custom values.
                --use "setModulatorValue" if the modulator is a typical modulator with a value range of, say 0-127 
                
                	panel:getModulatorByName("Osc 1 Octave"):setValueMapped(programData:getByte(1), false)
                	panel:getModulatorByName("Osc 1 Semitone"):setValueMapped(programData:getByte(2), false)
                	panel:getModulatorByName("Osc 1 Detune"):setModulatorValue(programData:getByte(3), false, false, false)
                
                --continue for ALL parameters within your program dump.. . 
                
                end

                Monstrum Media | Music, Sound & Software Design, Chicago / San Francisco listen

                #11312
                lfo2vco
                Participant
                  • Topics: 26
                  • Replies: 162
                  • Total: 188
                  • ★★

                  Many thanks msepsis, a very clear explanation.

                  Here is some noise I organised into an acceptable format:
                  https://soundcloud.com/lfo2vco/a-dark-crystal

                  #11318
                  drsteve
                  Participant
                    • Topics: 3
                    • Replies: 33
                    • Total: 36

                    I tried this: f0 7f 7f 7f 60 01 00 b0 0a xx f7

                    It worked! the results looked like this:
                    [22:49:02:000181]: [System exclusive] RAW:[f0 7f 7f 7f 60 01 00 b0 0a 44 f7]

                    I am a newbie to ctrlr, but have worked with sysex and midi for decades. I never knew that you could send a byte with the most significant bit set as data within a sysex command. Perhaps none of the gear I ever had used it. Hmmmmmm. Something new to explore.

                    #12021
                    lfo2vco
                    Participant
                      • Topics: 26
                      • Replies: 162
                      • Total: 188
                      • ★★

                      OK, not had as much time to work on this lately. However the panel is sending the Tone Buffer Edit Dump request then the Lua method is hooking up with the resulting Sysex response as msepsis instructed above. But then the values from the Lua assign method are not responding as I would expect.

                      For example a DCO1 Tune that should be set at 64 by the Lua assign ends up placed at 32 on one patch and then 115 on the next.

                      Any ideas on where I am getting it wrong would be very welcome.

                      Here’s the dump request:
                      [System exclusive] Ch:[–] No:[—-] RAW:[f0 7f 7f 7f 60 01 00 03 f7]

                      This is what the 3P returns:
                      [System exclusive] Ch:[–] No:[—-] RAW:[f0 7f 7f 7f 60 01 00 04 00 01 48 69 67 68 20 53 74 72 69 6e 67 73 20 20 20 20 20 20 20 20 01 3f 3f 00 3f 01 40 29 3f 00 3f 00 3f 0a 00 57 00 00 43 3b 3f 00 00 13 1f 61 13 1f 1f 61 1c 01 68 18 01 79 18 00 2f 03 41 00 00 3f 00 00 00 00 03 0c 00 00 00 00 6f 00 00 00 00 00 3f 3f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 f7]

                      This is how the KiwiTechnics manual describes the first few lines of data:
                      $04 (4) Transmit/Receive Tone Edit Buffer Dump
                      2 x null bytes sent followed by 128 bytes of data in the following format

                      Data $00-$13 / Byte (0-19) = Tone Name / Data Type Ascii Bytes / Data Details Tone Name
                      Data $14 / Byte (20) = DCO1 Wave/Range / Data Type 0000yyxx / Data Details xx =DCO 1 Range 00=16′ 01=8’10=4′ yy =DCO 1 Wave 00=Saw 01=Pulse 10=Sqr
                      Data $15 / Byte (21) = DCO1 Tune / Data Type 0xxxxxxx / Data Details (0-127) Split Control +-63 (+- 1 octave or +-1200 cents)
                      Data $16 / Byte (22) = DCO1 Env Mod Amount / Data Type 0xxxxxxx / Data Details (0-127) Split Control +-63

                      Here is some noise I organised into an acceptable format:
                      https://soundcloud.com/lfo2vco/a-dark-crystal

                      #12022
                      lfo2vco
                      Participant
                        • Topics: 26
                        • Replies: 162
                        • Total: 188
                        • ★★

                        Better post the assign method too:

                        assignValues = function(midiMessage)
                        
                        programData = midiMessage:getData():getRange(1,112)
                        
                        	-- DCO 1 Wave/Range here (19)
                        	panel:getModulatorByName("DCO 1 Frequency"):setModulatorValue(programData:getByte(20), false, false, false)
                        	panel:getModulatorByName("DCO 1 Env Mod Amt"):setModulatorValue(programData:getByte(21), false, false, false)
                        	panel:getModulatorByName("DCO 1 LFO Mod Amt"):setModulatorValue(programData:getByte(22), false, false, false)
                        	-- Byte (23) Not used
                        	-- DCO 2 Wave/Range here (24)
                        	panel:getModulatorByName("DCO 2 Frequency"):setModulatorValue(programData:getByte(25), false, false, false)
                        	panel:getModulatorByName("DCO 2 Fine Tune"):setModulatorValue(programData:getByte(26), false, false, false)
                        	panel:getModulatorByName("DCO 2 Env Mod Amt"):setModulatorValue(programData:getByte(27), false, false, false)
                        	panel:getModulatorByName("DCO 2 LFO Mod Amt"):setModulatorValue(programData:getByte(28), false, false, false)
                        	-- Byte (29) Not used
                        	panel:getModulatorByName("Cross Mod"):setValueMapped(programData:getByte(30), false)
                        	panel:getModulatorByName("DCO Source Mix"):setModulatorValue(programData:getByte(31), false, false, false)
                        
                        end

                        Here is some noise I organised into an acceptable format:
                        https://soundcloud.com/lfo2vco/a-dark-crystal

                        #12023
                        atom
                        Keymaster
                          • Topics: 159
                          • Replies: 2945
                          • Total: 3104
                          • ★★★★★

                          You must remember that getData() returns the entire message as a memory block, so you’ll get any “headers” and sysex prefixes that you should bypass to get to the actual data.

                          Well here is how i was able to extract the program name, you should be able to go on from this (i hardcoded the MIDI data into the lua method)

                          	-- Your method code here
                          
                          	data = "f0 7f 7f 7f 60 01 00 04 00 01 48 69 67 68 20 53 74 72 69 6e 67 73 20 20 20 20 20 20 20 20 01 3f 3f 00 3f 01 40 29 3f 00 3f 00 3f 0a 00 57 00 00 43 3b 3f 00 00 13 1f 61 13 1f 1f 61 1c 01 68 18 01 79 18 00 2f 03 41 00 00 3f 00 00 00 00 03 0c 00 00 00 00 6f 00 00 00 00 00 3f 3f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 f7"
                          
                          	mb = MemoryBlock(data)
                          	r = mb:getRange(8,130)
                          	console ("--------------------")
                          	console (r:getRange(2,16):toString()) -- 2 null bytes
                          

                          You can just paste this into Lua console, and it should print

                          --------------------
                          High Strings
                          
                          • This reply was modified 10 years, 7 months ago by atom.
                          • This reply was modified 10 years, 7 months ago by atom.
                          #12026
                          atom
                          Keymaster
                            • Topics: 159
                            • Replies: 2945
                            • Total: 3104
                            • ★★★★★

                            Also i noticed that the KIWI manual says it might start transmitting garbage data, keep an eye for that, if that starts to happen you should do a memory wipe according to the manual.

                            #12029
                            lfo2vco
                            Participant
                              • Topics: 26
                              • Replies: 162
                              • Total: 188
                              • ★★

                              You must remember that getData() returns the entire message as a memory block, so you’ll get any “headers” and sysex prefixes that you should bypass to get to the actual data.

                              Many thanks for the prompt response Atom. I took me a while to understand your reply, but in essence I take to mean that I should include the headers in the byte count so:
                              panel:getModulatorByName(“DCO 1 Frequency”):setModulatorValue(programData:getByte(20), false, false, false)
                              becomes:
                              panel:getModulatorByName(“DCO 1 Frequency”):setModulatorValue(programData:getByte(32), false, false, false)

                              Here is some noise I organised into an acceptable format:
                              https://soundcloud.com/lfo2vco/a-dark-crystal

                              #12031
                              atom
                              Keymaster
                                • Topics: 159
                                • Replies: 2945
                                • Total: 3104
                                • ★★★★★

                                Yeah you need to calculate your byte positions in the data. Very often the manufacturer will say “byte 0” and that means byte 0 in the data section, that’s actualy 6th or 7th or whatever byte in the message. More often they don’t count the heading “F0” as part of the message, they assume it’s like a prefix and you should ignore it.

                                You need to read their minds, or just do what i do and go through a hard process of try-and-fail, many many times.

                                Also index is not byte number, byte numer 1 is index 0 and so on.

                                #12032
                                lfo2vco
                                Participant
                                  • Topics: 26
                                  • Replies: 162
                                  • Total: 188
                                  • ★★

                                  Again many thanks. I am totally new to programming so I copied msepsis’ code not fully understanding what the instructions are doing! For example I now realise…

                                  programData = midiMessage:getData():getRange(1,112)

                                  should be..

                                  programData = midiMessage:getData():getRange(10,128)

                                  Most of the modulators correctly reflect the patch now, it seems the comboboxes are still not changing.

                                  Also some of the combobox bytes are expressed like this:
                                  Byte (20) DCO1 Wave/Range, Data Type 0000yyxx, xx =DCO 1 Range 00=16′ 01=8’10=4′ yy =DCO 1 Wave 00=Saw 01=Pulse 10=Square
                                  Wave and range being two separate comboboxes, I guess that the bits have to be assigned individually?

                                  Here is some noise I organised into an acceptable format:
                                  https://soundcloud.com/lfo2vco/a-dark-crystal

                                  #12039
                                  atom
                                  Keymaster
                                    • Topics: 159
                                    • Replies: 2945
                                    • Total: 3104
                                    • ★★★★★

                                    Yeah it should be simple. take a byte you need to split(read bits from it) and read them using BigInteger()

                                    I’m writing from my head so it might not compile but it should bring you on the right path

                                    
                                    byte = data:getByte(0)
                                    bi = BigInteger(byte)
                                    
                                    part1 = bi:getBitRangeAsInt(0,2) -- Data Type 0000yyxx - XX part
                                    part2 = bi:getBitRangeAsint(2,2) -- Data Type 0000yyxx - YY part
                                    
                                    
                                    • This reply was modified 10 years, 7 months ago by atom.
                                    #12051
                                    lfo2vco
                                    Participant
                                      • Topics: 26
                                      • Replies: 162
                                      • Total: 188
                                      • ★★

                                      Well, I have got so far. The code doesn’t crash the panel. Syntax was bugging me, as I don’t fully understand what I am doing so I missed a few things initially.

                                      byte = programData:getByte(20) 
                                      bi = BigInteger(byte)
                                      
                                      panel:getModulatorByName("DCO 1 Range"):setValueMapped(bi:getBitRangeAsInt(0,2), false)
                                      panel:getModulatorByName("DCO 1 Waveform"):setValueMapped(bi:getBitRangeAsInt(2,2), false)

                                      It works a treat, however I had to change the Combo Contents to this:

                                      00=16
                                      01=8
                                      10=4

                                      from this:

                                      16=0
                                      8=32
                                      4=64

                                      Now I am going to look at some putting Lua in the Combobox to make this conversion.
                                      Cheers Dude : )

                                      • This reply was modified 10 years, 7 months ago by lfo2vco.
                                      • This reply was modified 10 years, 7 months ago by lfo2vco.
                                      • This reply was modified 10 years, 7 months ago by lfo2vco.
                                      • This reply was modified 10 years, 7 months ago by lfo2vco.
                                      • This reply was modified 10 years, 7 months ago by lfo2vco.

                                      Here is some noise I organised into an acceptable format:
                                      https://soundcloud.com/lfo2vco/a-dark-crystal

                                      #13445
                                      msepsis
                                      Participant
                                        • Topics: 219
                                        • Replies: 732
                                        • Total: 951
                                        • ★★★

                                        Also some of the combobox bytes are expressed like this:
                                        Byte (20) DCO1 Wave/Range, Data Type 0000yyxx, xx =DCO 1 Range 00=16′ 01=8’10=4′ yy =DCO 1 Wave 00=Saw 01=Pulse 10=Square
                                        Wave and range being two separate comboboxes, I guess that the bits have to be assigned individually?

                                        Ok now after helping you with assigning values from program dumps I’m actually a little stumped here myself with understanding the most efficient way, given the same data expression as lfo2vco stated above I’m stuck with how to send values from the PANEL to the synth..

                                        So, taking the same example:
                                        0000yyxx
                                        if yy = DCO 1 Wave
                                        and xx = DCO 1 Range

                                        what do you give your DCO 1 Wave and DCO 1 Range knob/combobox to send the data? I’m imagining you need to do it with lua, both modulators get the same script – Script must involve getting the current values of both DCO 1 Wave and Range, putting them together then sending out the combined values from bin to hex in the defined sysex formula for those combined values. I can visualize what needs to happen but I need a nudge or an example so I know how to express this correctly and efficiently.

                                        I checked out the Juno 106 (i used to own a 6, loved that thing) panel but only saw two scripts that were not involved at all in any way.

                                        • This reply was modified 10 years, 6 months ago by msepsis.

                                        Monstrum Media | Music, Sound & Software Design, Chicago / San Francisco listen

                                        #13454
                                        Hecticcc
                                        Participant
                                          • Topics: 25
                                          • Replies: 160
                                          • Total: 185
                                          • ★★

                                          I suggest you take a look at the amt8 panel i made, it is in the panels section.

                                          All switches are used to set specific bits in 16 different bytes, those are then sent to a method that makes and transmits the midimessage.

                                          #13468
                                          lfo2vco
                                          Participant
                                            • Topics: 26
                                            • Replies: 162
                                            • Total: 188
                                            • ★★

                                            Hi Msepsis & Hecticcc, thanks for the follow up. Atom talked me through this one and together we got it sorted. But for completeness and also in case anyone else follows this thread looking for an answer here is the method used.

                                            Some of the combobox bytes are expressed like this in the Kiwi-3P user manual:
                                            Byte (20) DCO1 Wave/Range,
                                            Data Type 0000yyxx,
                                            xx =DCO 1 Range 00=16′ 01=8’10=4′
                                            yy =DCO 1 Wave 00=Saw 01=Pulse 10=Square

                                            So the on receiving the MIDI message from the synth Lua treats it like this:

                                            byte = programData:getByte(20)
                                            bi = BigInteger(byte)
                                            panel:getModulatorByName("DCO 1 Range"):setValueMapped(bi:getBitRangeAsInt(0,2), false)
                                            panel:getModulatorByName("DCO 1 Waveform"):setValueMapped(bi:getBitRangeAsInt(2,2), false)

                                            And to get the data into Byte 20 for a Sysex dump Lua treats it like this:

                                            dco1range = panel:getModulatorByName("DCO 1 Range")
                                            dco1waveform = panel:getModulatorByName("DCO 1 Waveform")
                                            bi = BigInteger(0)
                                            bi:setBitRangeAsInt (0,2,dco1range:getValue())
                                            bi:setBitRangeAsInt (2,2,dco1waveform:getValue())
                                            byte20 = bi:getBitRangeAsInt(0,7)

                                            I get a bit of a buzz from doing this kind of stuff with data, perhaps because I am new to the game… perhaps because I am just a bit odd : )

                                            Here is some noise I organised into an acceptable format:
                                            https://soundcloud.com/lfo2vco/a-dark-crystal

                                          Viewing 20 posts - 1 through 20 (of 24 total)
                                          • The forum ‘General MIDI discussion’ is closed to new topics and replies.
                                          There is currently 0 users and 69 guests online
                                          No users are currently active
                                          Forum Statistics
                                          Threads: 2,495, Posts: 17,374, Members: 77,605
                                          Most users ever online was 12 on January 22, 2019 3:47 pm
                                          Ctrlr