Java wrapper for Ms Pinky!

Topics regarding other applications that use the MsPinky Vinyl Control Interface
Post Reply
Kotuha
Posts:6
Joined:Sun Apr 12, 2009 1:14 am
Contact:
Java wrapper for Ms Pinky!

Post by Kotuha » Wed Apr 22, 2009 4:27 pm

Hello all,

I got kind of curious about using Java and the Ms Pinky Vinyl Tracking system, so I tried it out and managed to create a small wrapper class for the pinky functions. So if there are any Java programmers out there who would like to incorporate the functionalities of ms pinky, go to http://pinkywrapper.kotuha.be and have fun :-)

It's far from perfect right now, still have a lot of things to read and learn but it does work at this moment. Only biggest problem is ASIO support in Java atm, but I know it is possible and I will figure it out sooner or later and make an update :-) I just wanted to share the dll and java class so others might start using it to!

I do have a couple of questions though about the MPVT object:

1. Whenever I try to pass a sample buffer (left/right) with a array size bigger than 2048, the object seems to crash. I know that Java can easily handle arrays with a bigger size, so either the object just does not support it, or C++ doesn't ? My only C++ experience is the one I got while writing the wrapper dll, so it isn't much. Could anyone tell me what could be going on? Is there a maximum array size in this programming language, or will I have to take a closer look at how I pass the arrays between Java and the C++ dll? This is not really relevant to the pinky wrapper anymore, particularly now that Asio support in Java is a fact!

2. In the software specification PDF, it says the object will create a new measurement every 32 samples. But in the BinkyToy MFC example, I see that num_measurements is determined by dividing the buffer size by 64, not 32 ? And the size of the measurements arrays (gPowerVals, gPositionVals, gVelocityVals) is determined by dividing the buffersize by 128?

Code: Select all

		int buffsize = 4096;
		buffsize = (buffsize>>7) + 1; 
		// result is 33, so divided by 128?
		
		buffsize = 4096;
		buffsize = (buffsize>>6) + 1; 
		// result is 65, so divided by 64?
Using 32 samples per measurement returns velocity values which are correct for the first half, and then become smaller and smaller until they are all zero? Is there something important I am missing here, or have I misread something? :-)

3. While the values I recieve from ProcessBuffer() seem to be correct (except that the first value of the arrays always returns 0.0 so that I get one less measurement then specified..), the values from the Query_SignalPower() and Query_Velocity() are always 0.0, unless I set the cutoff frequency lower or equal to -60dB.

Are there any specific reasons for these problems? Or does this mean there is still something important wrong in my own code? Please let me know :-)

For what I needed it to, it works great; I can play an mp3 file and control it's playback speed and position with my pinky vinyl record. Although I still need to figure out a better way to keep track of the positions, sometimes I still miss a position change! Any tips on that maybe as well? I am currently just checking each positionValue with the previous one to see if there is a bigger change than usual (usual meaning the normal difference at the current playback velocity). I am comparing these differences with hardcoded numbers I got from reading the velocity & position values. But perhaps there is a more robust and statistical approach to this?

Thanks for any tips, I am looking forward to exploring more about this wrapper programming and building a better version ;)
Last edited by Kotuha on Fri Apr 24, 2009 10:03 am, edited 1 time in total.
"Western society has many flaws, and it is good for an educated person to have thought
some of these through, even at the expense of losing a lecture or two to tear gas."
Kotuha
Posts:6
Joined:Sun Apr 12, 2009 1:14 am
Contact:

ASIO !

Post by Kotuha » Fri Apr 24, 2009 9:51 am

ASIO Support now available, thanks to Martin Roth's recently (less than one month old!) released JAsioHost ( http://wiki.github.com/mhroth/jasiohost ) and his fast email replies ;-)
I will update the example classes on my webpage within a couple of hours!
"Western society has many flaws, and it is good for an educated person to have thought
some of these through, even at the expense of losing a lecture or two to tear gas."
dlpinkstah
Site Admin
Posts:1093
Joined:Mon Jun 07, 2004 9:17 pm

Re: Java wrapper for Ms Pinky!

Post by dlpinkstah » Sat Apr 25, 2009 5:42 am

Kotuha wrote:Hello all,

I got kind of curious about using Java and the Ms Pinky Vinyl Tracking system, so I tried it out and managed to create a small wrapper class for the pinky functions. So if there are any Java programmers out there who would like to incorporate the functionalities of ms pinky, go to http://pinkywrapper.kotuha.be and have fun :-)
Totally hot!! That's awesome.
Kotuha wrote: It's far from perfect right now, still have a lot of things to read and learn but it does work at this moment. Only biggest problem is ASIO support in Java atm, but I know it is possible and I will figure it out sooner or later and make an update :-) I just wanted to share the dll and java class so others might start using it to!

I do have a couple of questions though about the MPVT object:

1. Whenever I try to pass a sample buffer (left/right) with a array size bigger than 2048, the object seems to crash. I know that Java can easily handle arrays with a bigger size, so either the object just does not support it, or C++ doesn't ? My only C++ experience is the one I got while writing the wrapper dll, so it isn't much. Could anyone tell me what could be going on? Is there a maximum array size in this programming language, or will I have to take a closer look at how I pass the arrays between Java and the C++ dll? This is not really relevant to the pinky wrapper anymore, particularly now that Asio support in Java is a fact!
What was the maximum buffer size parameter that you passed in to the MPVT_CreateNew(int max_buffer_size, double sample_rate) function? If you set max_buffer_size equal to something higher than 2048, then it should certainly be able to handle buffer sizes larger than 2048. Try calling MPVT_CreateNew(int max_buffer_size, double sample_rate) with max_buffer_size = 8192 or something bigger.

Kotuha wrote: 2. In the software specification PDF, it says the object will create a new measurement every 32 samples. But in the BinkyToy MFC example, I see that num_measurements is determined by dividing the buffer size by 64, not 32 ? And the size of the measurements arrays (gPowerVals, gPositionVals, gVelocityVals) is determined by dividing the buffersize by 128?

Code: Select all

		int buffsize = 4096;
		buffsize = (buffsize>>7) + 1; 
		// result is 33, so divided by 128?
		
		buffsize = 4096;
		buffsize = (buffsize>>6) + 1; 
		// result is 65, so divided by 64?
Using 32 samples per measurement returns velocity values which are correct for the first half, and then become smaller and smaller until they are all zero? Is there something important I am missing here, or have I misread something? :-)
Ouch!! You're so right. Pardon my unpardonable ineptitude. Please recognize that new velocity, power, position measurements are now calculated every 32 samples. So anything that assumes 64 samples between measurements is old hat.
Kotuha wrote: 3. While the values I recieve from ProcessBuffer() seem to be correct (except that the first value of the arrays always returns 0.0 so that I get one less measurement then specified..), the values from the Query_SignalPower() and Query_Velocity() are always 0.0, unless I set the cutoff frequency lower or equal to -60dB.

Are there any specific reasons for these problems? Or does this mean there is still something important wrong in my own code? Please let me know :-)
I'm betting that your code is not wrong here. See above caveats. If you set buffer size to something really high (8192 or higher) and also always assume new measurements every 32 input samples, then Query_Velocity() and Query_etc() should return correct values.... that you say they don't is very weird to me....
Kotuha wrote: For what I needed it to, it works great; I can play an mp3 file and control it's playback speed and position with my pinky vinyl record. Although I still need to figure out a better way to keep track of the positions, sometimes I still miss a position change! Any tips on that maybe as well? I am currently just checking each positionValue with the previous one to see if there is a bigger change than usual (usual meaning the normal difference at the current playback velocity). I am comparing these differences with hardcoded numbers I got from reading the velocity & position values. But perhaps there is a more robust and statistical approach to this?

Thanks for any tips, I am looking forward to exploring more about this wrapper programming and building a better version ;)
Wow! Against all odds you're doing a great job! Sounds very promising. I'm sorry it's not 100% correct yet. So please adjust the max_buffer_size param to MPVT_CreateNew and let me know if that helps at all.
Kotuha
Posts:6
Joined:Sun Apr 12, 2009 1:14 am
Contact:

Re: Java wrapper for Ms Pinky!

Post by Kotuha » Mon Apr 27, 2009 10:02 pm

dlpinkstah wrote:What was the maximum buffer size parameter that you passed in to the MPVT_CreateNew(int max_buffer_size, double sample_rate) function? If you set max_buffer_size equal to something higher than 2048, then it should certainly be able to handle buffer sizes larger than 2048. Try calling MPVT_CreateNew(int max_buffer_size, double sample_rate) with max_buffer_size = 8192 or something bigger.
The maximum buffer size was set to values bigger or equal to the buffer size passed. The crash still occured..

dlpinkstah wrote:.. anything that assumes 64 samples between measurements is old hat.
Good to know :)
dlpinkstah wrote:I'm betting that your code is not wrong here. See above caveats. If you set buffer size to something really high (8192 or higher) and also always assume new measurements every 32 input samples, then Query_Velocity() and Query_etc() should return correct values.... that you say they don't is very weird to me....
As said above, the crash still occurs and these values still return 0.0 (while the processBuffer value does return correct and useful values!)

I have fixed some small issues in the last few days here and there, but still not the sudden crashes when passing arrays bigger than 2048. Tried to pass the arrays with ByteBuffers (which are Java's way of improving communication between native code and the Java Virtual Machine) and it still occured. So I am thinking, maybe this is some compiler option that I have to set, in order to let my dll work with big arrays? Anyway, thank you very much for your helpful replies already, and if you say this should not happen, it must be something in my own code. I will google some more and let'see what comes to mind :-)

Regards,
Steven
"Western society has many flaws, and it is good for an educated person to have thought
some of these through, even at the expense of losing a lecture or two to tear gas."
dlpinkstah
Site Admin
Posts:1093
Joined:Mon Jun 07, 2004 9:17 pm

Post by dlpinkstah » Mon Apr 27, 2009 11:23 pm

You may have already noted this, but with a call to MPVT_ProcessBuffer of this form:

void MPVT_ProcessBuffer(void *the_object, Float32 *inBufferLeft,
Float32 *inBufferRight, long num_samps, Float64 *velocityVals,
Float64 *powerVals, Float64 *positionVals, long &num_measurements);

Be sure that the value of num_samps equals the length of the input sample buffers (which must not exceed the maximum array size specified when you instantiated this instance of MPVT), and that the value of num_measurements that is passed into the routine when calling it is equal to the length of the arrays pointed to by velocityVals, powerVals, and positionVals. MPVT_ProcessBuffer will only return as many values into velocityVals, powerVals, and positionVals as is specified by the value of num_meaurements when the routine is called. To be safe, allocate the arrays velocityVals, powerVals, and positionVals to have lengths equal to at least (2 * MAX_INPUT_SAMPLE_BUFFER_LENGTH/32), where MAX_INPUT_SAMPLE_BUFFER_LENGTH is of course the maximum length of a sample buffer.
Kotuha
Posts:6
Joined:Sun Apr 12, 2009 1:14 am
Contact:

Post by Kotuha » Tue Apr 28, 2009 4:25 pm

Thank you again for your fast reply :)

Everything works as it should now, the query methods also return correct results all the time now! But I still can not pass input arrays bigger than 2048 samples.
I provided num_samps and num_measurements with correct values, according to the software specification and your suggestions made above. The value arrays are big enough (2 * MAX_INPUT_SAMPLE_BUFFER_LENGTH/32) to hold all calculated values.

In the latest version I wrote, the memory for the arrays are allocated in native memory (not in Java memory) before I ever call ProcessBuffer.
I tried passing an array of size 4096 and I printed out every number through a simple loop, which gave correct results.
I thought about increasing the stack size that the Java VM uses for the shared library but this did not yield any positive result. (and it isn't really necessary because it's not like two 4096 float arrays = 16.384 bytes are too big for a modern system, I guess.)
The program crashes at the moment that ProcessBuffer is called and gives me an EXCEPTION_ACCESS_VIOLATION. Now I looked around for possible reasons to give this error, and it seems like there are a lot :-)
All smaller array sizes work perfectly, and I can read the array I am passing into the dll without a problem. It works well enough for now!

On the C++ side, there really isn't that much to it, this is all I need to write to get my buffer from java into c++. Perhaps you might see something wrong here? Could it be a linker/compiler setting that I don't know of?

Code: Select all

// allocating:

void *p;
if ( (p = malloc(size)) )
{
	// NewDirectByteBuffer will create a Java buffer class with it's content
	// from address p to p+size in native memory
	return javaEnv->NewDirectByteBuffer(p, (jlong)size);
}
.. // the result is a buffer class on which I can put and get numbers.

// looping through the buffer:

float *fBufRight = 0;
if(jBufRight) // jBufRight is a java buffer object
{
	 fBufRight = (float *)javaEnv->GetDirectBufferAddress(jBufRight);
}

for(int i=0;i<samplecount;i++)
{
	printf("%i = %f", i, fBufRight[i]); // works.
}

MPVT_ProcessBuffer(gMPVT, fBufLeft, fBufRight, ... ); // <-- crash..
(Same goes for the creation and passing as argument for the calculation values)

Anyway, I have posted this problem on a Java forum, because I really don't know where to start looking for the cause of this problem at the moment. (inside the java code? inside the c++ code?) Hopefully someone will have a better idea of what's going on.


I'm having loads of fun already with buffer sizes <= 2048 ;-)
Last edited by Kotuha on Tue Apr 28, 2009 4:33 pm, edited 1 time in total.
"Western society has many flaws, and it is good for an educated person to have thought
some of these through, even at the expense of losing a lecture or two to tear gas."
Kotuha
Posts:6
Joined:Sun Apr 12, 2009 1:14 am
Contact:

Post by Kotuha » Tue Apr 28, 2009 4:32 pm

Oh I kind of forgot; about 6 to 7 months ago, my Conectiv blew up for unknown reasons. I mailed you about it and you sent me through to the M-Audio website where I could locate a dealer nearby. It only took about two months, which in my experience is pretty fast,, and then I received a brand new working Conectiv and it never cost me anything to get it replaced. The people from the Dutch M-Audio dealer centre were very helpful as well!
So, thank you for the superb support :-)
"Western society has many flaws, and it is good for an educated person to have thought
some of these through, even at the expense of losing a lecture or two to tear gas."
dlpinkstah
Site Admin
Posts:1093
Joined:Mon Jun 07, 2004 9:17 pm

Post by dlpinkstah » Tue Apr 28, 2009 7:13 pm

Thanks for being so thorough in your tests. I'd have to say at this point I really should be looking very carefully through my code to find the memory access fault. It could be a bug in my code.:oops:

I'm also really glad to hear that M-Audio was helpful to get your "Defectiv Conectiv" replaced. :lol:
Kotuha
Posts:6
Joined:Sun Apr 12, 2009 1:14 am
Contact:

Post by Kotuha » Thu Apr 30, 2009 3:11 pm

Well it's not really that important to use bigger buffer size since ASIO buffersizes are supposed to be very small :-)
"Western society has many flaws, and it is good for an educated person to have thought
some of these through, even at the expense of losing a lecture or two to tear gas."
Post Reply