Page 3 of 3

Re: Number of transmitted poly channels

Posted: Wed Jan 01, 2025 6:28 pm
by seal58
Sounds good!

Re: Number of transmitted poly channels

Posted: Wed Jan 01, 2025 10:39 pm
by utdgrant
Here is the second demo video of the MIDI-based multi-channel encoder / decoder modules.
Encoder-Decoder.jpg
Encoder-Decoder.jpg (425.83 KiB) Viewed 7179 times
The source code for both modules has been included in the Dome Music Tech repository (zip file at the bottom of this page).
SourceCode.jpg
SourceCode.jpg (20.88 KiB) Viewed 7179 times
The code is just a proof-of-concept, so there are lots of 'magic numbers' in there, and other shoddy programming practices. However, if you want to utilise the mechanism for your own projects, it might be a good starting place. Feel free to ask why I did certain things a certain way.

Here is an excerpt of encoding an analogue voltage from a 64-bit double-precision floating point number into a 14-bit fixed-point integer. The 14-bit integer is then further decomposed into two 7-bit 'bytes' which are encoded as Controller Number and Controller Value in a MIDI CONTROL_CHANGE ("CC") message:

Code: Select all

      if (inputJackV1.IsConnected())
      {      
         // Read analogue input V1
         tmpFloat = (float)inputJackV1.GetValue();
   
         // Restrict to range +/- 8.0V and add 8.0 to make range 0.0 to 16.0
   
         tmpFloat = 8.0f + Math.min(8.0f, Math.max(-8.0f, tmpFloat));
   
         // Convert to int in range 0 to 16,000
         tmpFloat *= 1000.0f;
         tmpFloat += 0.5f;
         tmpInt = (int)tmpFloat;    // No need to use Math.Floor as all values are positive
      
         // Check if a change in value has occurred.      
         if (previousAnalogueValue[0] != tmpInt)
         {
            ShortMessage analogue14Bit1 = new ShortMessage();
            
            // Record value for next iteration of ProcessSample
            previousAnalogueValue[0] = tmpInt;
         
            // Split value into two 7-bit numbers
   
            intParam1 = (tmpInt & 0x3F80) >> 7;    // MS 'Byte'
            intParam2 = (tmpInt & 0x007F);         // LS 'Byte'
   
            try
            {
               analogue14Bit1.setMessage(ShortMessage.CONTROL_CHANGE, 0, intParam1, intParam2);
            }
            catch (InvalidMidiDataException e)
            {
               // Do nothing for time being
            }
               
            midiOutputJack1.AddMessage(analogue14Bit1);
         }
      }

And how that is reconstructed into a 64-bit double on the other side:

Code: Select all

      // Process any pending MIDI input stream messages
      ArrayList<ShortMessage> events = midiInputJack1.GetMessages();
   
      // events will be non-null if there are
      // MIDI events to process
      if (events != null)
      {
         int numEvents = events.size();   
         for (int ix = 0; ix < numEvents; ix++)
         {
            ShortMessage event = events.get(ix);
         
            int command = event.getCommand();
         
            if (command == ShortMessage.CONTROL_CHANGE)
            {
               midiChannel = event.getChannel();
               intParam1 = event.getData1();
               intParam2 = event.getData2();
               
               if (midiChannel < 8)
               {
                  // Analogue channel 1 to 8
                  tmpInt = (intParam1 << 7) + intParam2;               
                  tmpDouble = ((double)tmpInt * 0.001) - 8.0;
                  
                  analogueOutputValue[midiChannel] = tmpDouble;
               }
               else
               {
                  // Digital channel 15 or 16
                  
                  if (midiChannel == 14)
                  {
                     ch15Param1 = intParam1;
                     ch15Param2 = intParam2;
                     
                     tmpInt = (intParam1 << 7) + intParam2;               
                     tmpDouble = (double)tmpInt * 0.0006510417;
                     analogueOutput15 = tmpDouble;
                     
                     updateCh15 = true;
                  }
                  else if (midiChannel == 15)
                  {
                     ch16Param1 = intParam1;
                     ch16Param2 = intParam2;
                     
                     tmpInt = (intParam1 << 7) + intParam2;               
                     tmpDouble = (double)tmpInt * 0.0006510417;
                     analogueOutput16 = tmpDouble;
                     
                     updateCh16 = true;
                  }
               }
            
            }  // End of if (command == ShortMessage.CONTROL_CHANGE)
         }  // End of for (int ix=0; ix < numEvents; ix++)
      }  // End of if (events!= null)


Re: Number of transmitted poly channels

Posted: Fri Jan 03, 2025 4:57 pm
by ColinP
Hi Grant,

What's the special handling of channel 15 and 16 about? I'm guessing to test 14 bit pitch CV precision?

Ah, looking more closely at the screenshot it answers my question.

Re: Number of transmitted poly channels

Posted: Fri Jan 03, 2025 5:51 pm
by utdgrant
ColinP wrote: Fri Jan 03, 2025 4:57 pm Hi Grant,

What's the special handling of channel 15 and 16 about? I'm guessing to test 14 bit pitch CV precision?

Ah, looking more closely at the screenshot it answers my question.
Hi Colin,

Yeah, partly that. I also wanted to have some channels working continuously at audio rates (Ch1 - Ch8), and also have some 'on demand events' which were only transferred on an occassional basis (Ch15, 16).

Edit To Add: Having data transferred on MIDI channels 15 and 16 also demonstrates that the number of 'data channels' available is always 16, irrespective of the global polyphony setting in the VM control panel (8 in this particular patch).