<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>