<span class="Apple-style-span" style="border-collapse: collapse; font-family: arial, sans-serif; font-size: 13px; "><div>I'm writing a program that talks with Wekinator, but I'm having a problem with sending the feature names over OSC that I'm fairly certain is a problem with chuck.</div>
<div><br></div><div>At the bottom of the code (see bottom of email) is the relevant method, sendOscFeatureNames(). When I run wekinator and get to the training screen, I run this code. The instant it sends the feature names to Wekinator (i.e., the instant it is run), an exception gets raised:</div>
<div><div><div><br></div><div>"</div><div>Exception in thread "Thread-4" java.lang.ArrayIndexOutOfBoundsException: 1536</div><div> at com.illposed.osc.utility.OSCByteArrayToJavaConverter.lengthOfCurrentS</div>
<div>tring(Unknown Source)</div><div> at com.illposed.osc.utility.OSCByteArrayToJavaConverter.readString(Unkno</div><div>wn Source)</div><div> at com.illposed.osc.utility.OSCByteArrayToJavaConverter.readArgument(Unk</div>
<div>nown Source)</div><div> at com.illposed.osc.utility.OSCByteArrayToJavaConverter.convertMessage(U</div><div>nknown Source)</div><div> at com.illposed.osc.utility.OSCByteArrayToJavaConverter.convert(Unknown</div>
<div>Source)</div><div> at com.illposed.osc.OSCPortIn.run(Unknown Source)</div><div> at java.lang.Thread.run(Unknown Source)</div></div><div>"</div><div><br></div><div>This exception is not thrown when I replace numDataPoints[i] with a constant (like 5).</div>
<div><br></div><div>Here is the entire .ck file. You can use it just like you would any OSC feature extractor with Wekinator.</div><div><br></div><div>//Extracts the following for different numDataPoints</div><div>//0 - centroidAvg</div>
<div>//1 - centroidStdDev</div><div>//2 - centroidMin</div><div>//3 - centroidMax</div><div>//4 - rmsAvg</div><div>//5 - rmsStdDev</div><div>//6 - rmsMin</div><div>//7 - rmsMax</div><div>//8 - fft bin with highest fval (highest over all windows)</div>
<div>//...</div><div>//whenever an amplitude > threshold is detected from input, computed over</div><div>//numDataPoints 128-sample ffts that overlap by 64-samples</div><div>//</div><div>"127.0.0.1" => string hostname;</div>
<div>OscSend xmit;</div><div>xmit.setHost( hostname, 6448 );</div><div>OscSend xmit2;</div><div>xmit2.setHost( hostname, 6448 );</div><div><br></div><div>//Custom objects</div><div>adc => FFT f =^ RMS rms => blackhole;</div>
<div>f =^ Centroid centroid => blackhole;</div><div>f =^ Flux flux => blackhole;</div><div>f =^ RollOff rolloff => blackhole;</div><div>UAnaBlob b;</div><div><br></div><div>//for storing the results from each window</div>
<div>float rmsArr[50];</div><div>float cent[50];</div><div>float highestFFTBin[50]; //bin with highest fft fval</div><div>float highestFFTVal[50]; //the actual value of the bin</div><div><br></div><div>//Set up bin stuff</div>
<div>128 => int FFT_SIZE;</div><div>FFT_SIZE => f.size;</div><div>Windowing.hamming(64) => f.window;</div><div><br></div><div>1::second / 1::samp => float SR;</div><div>SR/FFT_SIZE => float bin_width;</div>
<div><br></div><div>//constants</div><div>.5 => float threshold;</div><div>0 => int peakDetected; //flag if peak has been detected</div><div>now => time lastPeakTime;</div><div>100::samp => dur peakWindow;</div>
<div>10::samp => dur peakPollRate;</div><div>[1,5,10,15,20,25,30,35,40,45,50] @=> int numDataPoints[]; //list of numDataPoints values to try</div><div>1 => float rmsMultiplier; //so it isn't out of wek's range (this actually doesn't matter, leave it at 1)</div>
<div><br></div><div>0 => int currentlyAnalyzing; //flag if currently analyzing i.e. don't detect peak</div><div><br></div><div>//Run the peak detector in parallel to set the peakDetected flag</div><div>spork ~peakDetector();</div>
<div>spork ~sendOscFeatureNames();</div><div><br></div><div>//Extract features and send via osc when peak detected.</div><div>while (true) {</div><div> if (peakDetected) {</div><div> <<<"Peak detected! Analyzing">>>;</div>
<div> analyzeAndSend();</div><div> }</div><div> .1::second => now;</div><div>}</div><div><br></div><div>//When peak detected, compute min, max, avg, and std. dev for centroid and rms</div><div>//and send</div>
<div>fun void analyzeAndSend() { </div><div> 1 => currentlyAnalyzing;</div><div> xmit.startMsg( "/oscCustomFeatures", "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");</div>
<div> //Get all float and rms values for the maximum numDataPoints</div><div> getRmsCentroidAndFFT(); </div><div> </div><div> for (0 => int i; i < 11; i++) {</div><div> analyzeNumDataPoints(numDataPoints[i]) @=> float result[];</div>
<div> for (0 => int j; j < 9; j++) {</div><div> result[j] => xmit.addFloat;</div><div> } </div><div> }</div><div> <<<"done">>>;</div><div> 0 => currentlyAnalyzing;</div>
<div>}</div><div><br></div><div>//populates rms, cent, and fft arrays</div><div>fun void getRmsCentroidAndFFT() {</div><div> 50 => int maxDataPoints;</div><div> </div><div> 128::samp => now;</div><div> rms.upchuck();</div>
<div> </div><div> for (0 => int i; i < maxDataPoints; 1 +=> i) {</div><div> rms.fval(0) => rmsArr[i];</div><div> centroid.upchuck();</div><div> centroid.fval(0) => cent[i];</div><div>
</div><div> 0 => float highestBinMagnitude;</div><div> 0 => int highestBin;</div><div> f.upchuck();</div><div> //find highest bin</div><div> for (1 => int j; j < FFT_SIZE; j++) {</div>
<div> if (f.fval(j) > highestBinMagnitude) {</div><div> f.fval(j) => highestBinMagnitude;</div><div> j => highestBin;</div><div> }</div><div> }</div><div>
highestBin => highestFFTBin[i];</div><div> highestBinMagnitude => highestFFTVal[i];</div><div> </div><div> }</div><div>}</div><div><br></div><div>//Analyze data using the specified number of data points, return the float array corresponding to</div>
<div>//the osc message format described at top</div><div>//requires that the arrays have been populated</div><div>fun float[] analyzeNumDataPoints(int numDataPoints) {</div><div> float centroidTotal;</div><div> float centroidMin;</div>
<div> float centroidMax;</div><div> float centroidStdDev;</div><div> float rmsTotal;</div><div> float rmsMin;</div><div> float rmsMax;</div><div> float rmsStdDev;</div><div> float highestBin;</div><div>
float highestBinMagnitude;</div><div> new float[numDataPoints] @=> float centroidData[];</div><div> new float[numDataPoints] @=> float rmsData[];</div><div> </div><div> //get 1st centroid and rms</div>
<div><br></div><div> rmsArr[0] +=> rmsTotal;</div><div> rmsArr[0] => rmsMin => rmsMax => rmsData[0];</div><div> cent[0] +=> centroidTotal;</div><div> cent[0] => centroidMin => centroidMax => centroidData[0];</div>
<div> //do rest</div><div> for (1 => int i; i < numDataPoints; i++) {</div><div> rmsArr[i] +=> rmsTotal;</div><div> Math.max( rmsArr[i], rmsMax ) => rmsMax;</div><div> Math.min( rmsArr[i], rmsMin ) => rmsMin;</div>
<div> rmsArr[i] => rmsData[i];</div><div> cent[i] +=> centroidTotal;</div><div> Math.max( cent[i], centroidMax ) => centroidMax;</div><div> Math.min( cent[i], centroidMin ) => centroidMin;</div>
<div> cent[i] => centroidData[i];</div><div> </div><div> //compute current highestBin</div><div> if (highestFFTVal[i] > highestBinMagnitude) {</div><div> highestFFTVal[i] => highestBinMagnitude;</div>
<div> highestFFTBin[i] => highestBin;</div><div> }</div><div> }</div><div> //calculate</div><div> rmsTotal / numDataPoints => float rmsAvg;</div><div> centroidTotal / numDataPoints => float centroidAvg;</div>
<div> //get std dev</div><div> float rmsDevSquaredTotal;</div><div> float centroidDevSquaredTotal;</div><div> for (0 => int i; i < numDataPoints; i++) {</div><div> (rmsData[i] - rmsAvg)*(rmsData[i] - rmsAvg) +=> rmsDevSquaredTotal; </div>
<div> (centroidData[i] - centroidAvg)*(centroidData[i] - centroidAvg) +=> centroidDevSquaredTotal;</div><div> }</div><div> Math.sqrt(rmsDevSquaredTotal / numDataPoints) => rmsStdDev;</div><div> Math.sqrt(centroidDevSquaredTotal / numDataPoints) => centroidStdDev;</div>
<div> </div><div> float result[9];</div><div> </div><div><span style="white-space: pre-wrap; "> </span>centroidAvg => result[0]; </div><div> centroidStdDev => result[1];</div><div> centroidMin => result[2];</div>
<div> centroidMax => result[3];</div><div> rmsAvg * rmsMultiplier => result[4];</div><div> rmsStdDev * rmsMultiplier => result[5];</div><div> rmsMin * rmsMultiplier => result[6];</div><div> rmsMax * rmsMultiplier => result[7];</div>
<div> highestBin => result[8];</div><div> </div><div> return result;</div><div>}</div><div><br></div><div>//Pretty inefficient but does the trick</div><div>//Looks for a peak in the last peakWindow </div><div>
fun void peakDetector() {</div><div><span style="white-space: pre-wrap; "> </span>while (true){</div><div><span style="white-space: pre-wrap; "> </span>if (adc.last() > threshold || adc.last() < -1 * threshold) {</div>
<div><span style="white-space: pre-wrap; "> </span>1 => peakDetected; // analyze</div><div><span style="white-space: pre-wrap; "> </span>now => lastPeakTime;<span style="white-space: pre-wrap; "> </span></div><div>
<span style="white-space: pre-wrap; "> </span></div><div><span style="white-space: pre-wrap; "> </span>} else if (now > lastPeakTime + peakWindow) {</div><div><span style="white-space: pre-wrap; "> </span>0 => peakDetected;</div>
<div><span style="white-space: pre-wrap; "> </span>}</div><div><br></div><div> peakPollRate => now; //This is silly; would be better do do a low-pass filter envelope and look for peaks there. But don't worry about it right now.</div>
<div><br></div><div><span style="white-space: pre-wrap; "> </span>}</div><div><br></div><div>}</div><div><br></div><div>//run in parallel to send osc feature names</div><div>fun void sendOscFeatureNames() { </div><div>
while (true) {</div><div> xmit2.startMsg( "/oscCustomFeaturesNames sssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss");</div><div> for (0 => int i; i < 11; i++) {</div>
<div> numDataPoints[i] => int n;</div><div> xmit2.addString(n + "centroidAvg");</div><div> xmit2.addString(n + "centroidStdDev");</div><div> xmit2.addString(n + "centroidMin");</div>
<div> xmit2.addString(n + "centroidMax");</div><div> xmit2.addString(n + "rmsAvg");</div><div> xmit2.addString(n + "rmsStdDev");</div><div> xmit2.addString(n + "rmsMin");</div>
<div> xmit2.addString(n + "rmsMax");</div><div> xmit2.addString(n + "highestFFT"); </div><div> }</div><div> .1::second => now;</div><div> }</div><div>}</div>
</div></span>