srecord noeq HamburgerAudioHaarFeature(IAudioSample sample, double start, double end) { double[] positions = new[4]; *(IAudioSample *sample, double... *positions) { } double factor = 1; double length() { ret positions[3]-positions[0]; } DoubleRange meatRange() { ret doubleRange(positions[1], positions[2]; } double meatHeight() { ret l(meatRange()); } double blackArea() { ret length()-meatHeight(); } double whiteArea() { ret meatHeight(); } double get(int channel) { double blackArea = blackArea(); double whiteArea = whiteArea(); double whiteSum = sample.sampleSum(channel, positions[1], positions[2]); double blackSum = sample.sampleSum(channel, positions[0], positions[1]) + sample.sampleSum(channel, positions[2], positions[3]); ret mul_optFor1(factor, (doubleRatio(whiteSum, whiteArea) - doubleRatio(blackSum, blackArea))/255.0); } // 0 for transparent, 1 for white, -1 for black double getMask(double x) { ret x < positions[0] || x >= positions[3] ? 0.0 : x >= positions[1] && x < positions[2] ? factor : -factor; } Channels get() { ret mapChannels get(sample.channels()); } HamburgerAudioHaarFeature inverted() { HamburgerAudioHaarFeature f = new(sample, positions); f.factor = -factor; ret f; } HamburgerAudioHaarFeature shifted(double ofs) { HamburgerAudioHaarFeature f = new(sample, doubleAdd(positions, ofs)); f.factor = factor; ret f; } void pinOuter(DoubleRange r) { positions[0] = r.start; positions[3] = r.end; } bool ok() { ret doublesAreSorted(positions); } }