Number of transmitted poly channels

ColinP
Posts: 1031
Joined: Mon Aug 03, 2020 7:46 pm

Re: Number of transmitted poly channels

Post by ColinP »

That's an interesting idea Rob. I'm guessing that there might be nothing in CA's code to prevent one using MIDI protocol to send 16 channels of 64 bit information per sample down a virtual MIDI cable that was originally intended to transmit 7 bits per message at 31,250 baud.

The scrambling and descrambling involved might not be so bad as to make your idea impractical. But it would be a lot easier if CA just modified a few lines of code to remove the restriction on poly cables.
ColinP
Posts: 1031
Joined: Mon Aug 03, 2020 7:46 pm

Re: Number of transmitted poly channels

Post by ColinP »

Roland, I don't think a VoltageModule.SetNumberOfPolyVoices() method exists.
User avatar
utdgrant
Posts: 679
Joined: Wed Apr 07, 2021 8:58 am
Location: Scotland
Contact:

Re: Number of transmitted poly channels

Post by utdgrant »

ColinP wrote: Fri Dec 27, 2024 8:38 pm Roland, I don't think a VoltageModule.SetNumberOfPolyVoices() method exists.
Yeah, it seems to be a method of the VoltageObjects class, which isn't available to module developers.
VoltageObjects-SetNumberOfPolyVoices.png
VoltageObjects-SetNumberOfPolyVoices.png (20.27 KiB) Viewed 6658 times
Voltage-Developer-Kit-2.9.2/Documentation/JavaDocs/voltage/core/VoltageObjects.html#SetNumberOfPolyVoices(int)
______________________
Dome Music Technologies
ColinP
Posts: 1031
Joined: Mon Aug 03, 2020 7:46 pm

Re: Number of transmitted poly channels

Post by ColinP »

That's really interesting Grant.

I still haven't managed to fully pin down package level scope control in Java. Does anyone have a link to a good tutorial?
User avatar
utdgrant
Posts: 679
Joined: Wed Apr 07, 2021 8:58 am
Location: Scotland
Contact:

Re: Number of transmitted poly channels

Post by utdgrant »

seal58 wrote: Fri Dec 27, 2024 7:29 pm Today I tryed to use SetNumberOfPolyVoices( n ) to temporarily change channel count.
I really don't think that would work, even if you could temporarily change the polyphony count during ProcessSample(). You need to ensure that all poly cables would be operating at that (boosted) polyphony count at all times to ensure that the data arrived at the intended receiving module.

I have a theory about how VM schedules its processing. The evidence points towards alternating between calling ProcessSample() for each active module, then performing the inter-module transfer of data for each active cable. CA have arranged it so that only data on channels [0] to [polyphony-1] is transferred between modules on a Poly Cable. TBH, I would probably have done exactly the same thing in their shoes, as it seems to be an obvious way to optimise the run-time performance. The hit for transferring data on the 'unused' channels might be small to the point of insignificance. However, you'd also have to factor in things like adding all the 'unused' data when you have multiple poly cables going into a single Poly Input jack. Also this would have to happen across ALL modules which use Poly Input and Poly Output jacks, regardless of whether the module's developer wanted to ignore those channels (the 'default' case) or utilise them for some 'custom purpose' (the 'unusual' case, as discussed in this thread).

FWIW, I DO like the idea of using MIDI cables for transferring arbitrary binary data between modules. As Colin suggests, It could get messy for packing/unpacking floating point numbers, etc. However, for simple integer quantities up to 14 bits in length, it would be very straightforward. FWIW, and IMHO, 14 bit audio isn't actually terrible (see the Golden Ears Bundle if you want to test your own hearing).
______________________
Dome Music Technologies
User avatar
Waverley Instruments
Posts: 154
Joined: Thu May 05, 2022 2:10 pm

Re: Number of transmitted poly channels

Post by Waverley Instruments »

:shock: Yikes. I didn't realise we were talking audio rate data transfer. Err... nope, I would not even try that with MIDI messages.

Normally with MIDI, I'd do some pre or post message processing and discard messages deemed redundant. Obviously depends on the application, but seems like you'd want everything all the time. IMHO, MIDI messages would not be fit for purpose.

I just thought it was the odd bit of data now and again over 16 channels. Err... like MIDI typically :D

Apologies for muddying the waters! -Rob @ WI
ColinP
Posts: 1031
Joined: Mon Aug 03, 2020 7:46 pm

Re: Number of transmitted poly channels

Post by ColinP »

Grant, I don't think there's any need for a data transfer phase as such. Instead each VoltageJack object can store it's own value from the previous sample. Poly jacks will simply have an array of 16 values rather than a scalar.

Any overhead will be in calling Get/SetPolyValue() on channels that are in use so no unused data needs to be transferred. So I don't think there would be any performance degradation if CA simply changed their poly index range check to be [0, 15] rather than [0, numberOfVoices - 1].

It's down to individual modules to decide which poly index to use but CA's code, instead of just doing a safety bounds check, imposes a limit that cripples the system for no benefit whatsoever as far as I can see. It's insane.

On 14 bit transmission using MIDI I can see that working relatively easily. One could send note on messages with the pitch data being one 7 bit chunk and the velocity being the other 7 bit chunk and do some bit twiddling to pack and uppack but as Rob says it's very inefficient. Plus I'd want better than 14 bit precision for things like transferring pitch CV. Although a back of a ciggy packet calculation gives me better than 1 cent precision over a 10 octave range so maybe it's doable, but I like the notion of transfering doubles anyway to maintain the idea that S-Poly is just a sensible form of Poly.
User avatar
seal58
Posts: 394
Joined: Fri Jul 12, 2019 5:28 pm
Location: Rostock, Germany
Contact:

Re: Number of transmitted poly channels

Post by seal58 »

Hi folks,

this is an interesting diskussion here and I could learn something from it (as "not for developers") even when my basic goal cannot get achieved.
So I will continue coding my module without "channel cleaning service".

Until now I did not do any coding with MIDI stuff. If there is some spare time, I will focus on that thing.

Thanks for your messages. Have a nice weekend.

Roland
ColinP
Posts: 1031
Joined: Mon Aug 03, 2020 7:46 pm

Re: Number of transmitted poly channels

Post by ColinP »

It's really been bugging me that there MUST be some good reason why CA decided to cripple the poly mechanism by limiting the index to [0, numVoices - 1] rather than [0, 15].

It bugged me so much that I didn't get much sleep last night as I worked through the following ideas while lying in bed.

This is going to get a bit technical and I may well have made a real blunder somewhere in my reasoning so just skip this post if you aren't interested in the low-level detail of how VM may or may not work. And as always I very much welcome anyone showing where I have made any error in my thinking.

The following is bare bones pseudocode, I'm using my own terms (so socket rather than jack, etc), using imaginary classes and ignoring various details in order to focus on why CA might have crippled poly in order to improve performance.

Here's the mechanism I would use to implement VM's core functionality...

The main thread would look like this...

Code: Select all

mainThread
{
	isEven = true
	while running
		while buffer not full
			for each module m in patch
				m.processSample()
			isEven = ! isEven
			buffer.put( leftOutputSocket.getValue(), rightOutputSocket.getValue() )
		tell audio output thread that buffer is ready
		sleep until audio output thread has made a copy of the buffer
		set buffer to empty
}
In this scheme all inter-module communication is driven from inside processSample() by calls to getValue() and setValue() methods of MonoSocket and PolySocket objects.

Code: Select all

class monoSocket
{
	double getValue()
	{
		result = 0
		if isInput
			for each monoCable c that is connected
				result += c.getSource().getValue()
		else
			if isEven
				result = valueB
			else
				result = valueA 
		return result
	}

	setValue( double value )
	{
		if isEven
			valueA = value
		else
			valueB = value
	}
}

Code: Select all

class polySocket
{
	double getValue( int index )
	{
		result = 0
		if isInput
			for each polyCable c that is connected
				result += c.getSource().getValue( index )
		else
			if isEven
				result = valueBArray[ index ]
			else
				result = valueAArray[ index ] 
		return result
	}

	setValue( int index, double value )
	{
		if isEven
			valueAArray[ index ] = value
		else
			valueBArray[ index ] = value
	}
}
The reason why there are A and B values inside the socket (VoltageJack like) classes is that we need the sample update to maintain atomicity. So output sockets have two sets of values, one from the previous sample period that forms a stable input for calculations made in the current one and then a more dynamic and messy set of values that are steadily being calculated as we work through the modules in an arbitary order.

I think this code works but I've only run it in my head.

Now here's how I suspect CA's code works.

The main thread would look like this...

Code: Select all

mainThread
{
	while running
		while buffer not full
			for each module m in patch
				m.processSample()
			for each output monoSocket ms in patch
				ms.oldValue = ms.newValue
			for each output polySocket ps in patch
				if ps.isConnected
					for index = 0 to index = numVoices - 1
						ps.oldValueArray[ index ] = ps.newValueArray[ index ] 
			buffer.put( leftOutputSocket.getValue(), rightOutputSocket.getValue() )
		tell audio output thread that buffer is ready
		sleep until audio output thread has made a copy of the buffer
		set buffer to empty
}
As before everything is driven from inside processSample() by calls to getValue() and setValue() methods of MonoSocket and PolySocket objects.

But this time a brute-force algorithm is used to attain atomicity.

This simplifies the get/setValue() methods as shown below...

Code: Select all

class monoSocket
{
	double getValue()
	{
		result = 0
		if isInput
			for each monoCable c that is connected
				result += c.getSource().getValue()
		else
			result = oldValue
		return result
	}

	setValue( double value )
	{
		newValue = value
	}
}

Code: Select all

class polySocket
{
	double getValue( int index )
	{
		result = 0
		if isInput
			for each polyCable c that is connected
				result += c.getSource().getValue( index )
		else
			result = oldValueArray[ index ]
		return result
	}

	setValue( int index, double value )
	{
		newValueArray[ index ] = value
	}
}
So now instead of A and B values we have old and new values. This is easier to understand but now instead of just inverting the isEven boolean the main thread has to traverse all output sockets and copy the new values to the old values every sample period.

This is an expensive operation especially for polySockets so the code is optimized to only handle polySockets that are connected and also limit the data copying to the range [0, numVoices - 1].

Testing monoSocket's isConnected state would be unlikely to result in performance improvement as the test and branch would probably cost more than always doing the simple assignment.

It could be further optimized either by manipulating the socket lists as cables are connected and disconnected (but that might be pretty fiddly) or by traversing the cable lists for each module instead (but that involves more looping and dereferencing).

So in summary the first "demand-driven" algorithm which is how I imagined CA would have coded things would not incur a penalty for allowing poly indices to be full-range but in practice they probably implemented the second "brute-force" algorithm so decided it was worth crippling the system to make it more efficient.
User avatar
utdgrant
Posts: 679
Joined: Wed Apr 07, 2021 8:58 am
Location: Scotland
Contact:

Re: Number of transmitted poly channels

Post by utdgrant »

Proof of concept for multi-channel (audio-rate) signals over MIDI ShortMessage.

YouTube video for now, as I'm just about to celebrate the New Year.

Code to follow shortly.
______________________
Dome Music Technologies
Post Reply

Return to “Module Designer”