labstreaminglayer / liblsl-Csharp

C# bindings for liblsl

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

C# wrapper return value for pull_chunk is flat wrong

dmedine opened this issue · comments

Unless there are further axes to grind on this, I think we should merge #12 right away, because I found a bug.

This: https://github.com/labstreaminglayer/liblsl-Csharp/blob/master/LSL.cs#L652-L676 is wrong. I believe that the return value for each overload (except for string maybe, I haven't thought about that yet) should be:

return data_buffer.GetLength(0);

Here's a picture of my debugger that proves it:
lsl_csharp_wrong

A quick explanation of what is happening here: chunk' is a class that holds some fields including the 2d array called InternalDatawhich is the shape thatpull_chunk expects. I was naively using the incorrect return value (samples) to count up my samples to process, but as you can see from the watch console, this variable equals 1. It should be equal to 64 because resshould be 512 and the number of channels (the return ofdata_buffer.GetLength(1)) is 8, but it might revert to 1 due to a marshalling conflict---I'm not sure, but we are trying to shove an unsigned longfrom C into auintin C# and divide that by a C#int`.

But that is of no matter. The wrapper functions for pull_chunk ought to return:
return data_buffer.GetLength(0);

Unless there are further axes to grind on this, I think we should merge #12 right away, because I found a bug.

Not the motivation I expected to merge it, but I won't complain ;-)

First I thought it'd be a classical row-major vs col-major confusion, but now I think the code is correct.

My understanding is that pull_chunk_* returns the number of elements, i.e. num_sample * num_chan it put into the num_sample x num_chan data buffer. data_buffer.GetLength(1) returns the number of channels, so res/data_buffer.GetLength(1) is the number of actual samples written to the buffer, which is less than or equal to data_buffer.GetLength(0), i.e. the capacity of the data buffer. Those will be identical when pull_chunk filled the buffer, but with the timeout argument set it might be less.

If I understood it correctly, only chunk[0,0] to chunk[0,7] in your example will have values pulled from the inlet and chunk[1,0] to chunk[512,7] will be left as they were before the call to pull_chunk. NuGet is currently broken on Linux because Microsoft forgot to renew a certificate, so I can't check it.
Could you either check that in your code or add a timeout to the ReceiveDataInChunks example and run it alongside the SendDataInChunks example? With a timeout of one second, it should receive and print ~10 samples at once.

After a walk, I realized that I was completely wrong abiut this. I thought my buffer was being resized but it isn't. It is fixed. I am closing this. Sorry.

Also the 'axe to grind' comment was meant as a self-depricating joke, in case that wasn't clear. The lesson here is: don't post issues at 5pm...

After a walk, I realized that I was completely wrong about this. I thought my buffer was being resized but it isn't.

Generally, liblsl can't do anything to buffers provided by a runtime (e.g. the C# runtime) other than putting data in their and hope it's big enough. This behavior of pull_chunk_* is quite efficient, but also unintuitive and it should be explained in the docs some day.

Also the 'axe to grind' comment was meant as a self-depricating joke, in case that wasn't clear.

That's how I understood it, after all the hatchet's been buried. Once I've gotten around to fixing the commit attribution and examples, it could be merged.

The lesson here is: don't post issues at 5pm...

8am for me, so I had an unfair advantage.