sclass AudioAdder extends AbstractAudioSample is IAddPlateau { new Cl sources; srecord SumAndSlope(double sum, double slope) { double sumFor(double myTime, double time) { ret sum+(time-myTime)*slope; } } // for now same value in all channels new TreeMap additions; void addSource(IAudioSample source) { addUnlessNull(sources, source); } void grabSpecsFromSource(IAudioSample source) { if (source == null) ret; setSampleRate(source.sampleRate()); setChannels(source.channels()); setBounds(source.bounds()); } public void addPlateau(double start, double end, double intensity) { //printVars("addPlateau", +start, +end, +intensity); if (start >= end) ret; _incSlope(start, intensity); _incSlope(end, -intensity); } // We will probably add plateaus rather randomly throughout an area, // so could optimize this doing something akin to LogNArray. void _incSlope(double time, double intensity) { if (intensity == 0) ret; // create, overwrite or delete var last = floorPair(additions, time); if (last == null) { // we are first node mapPut(additions, time, new SumAndSlope(0, intensity); } else if (last.a == time) { // we are our own node already last.b.slope += intensity; } else { // we are an insertion! mapPut(additions, time, new SumAndSlope( last.b.sumFor(last.a, time), last.b.slope+intensity); } recalcFrom(time); //printVars _incSlope(+time, +intensity, v := additions.get(time)); } void recalcFrom(double time) { SumAndSlope me = additions.get(time); if (me == null) ret; Pair next; while ((next = higherPair(additions, time)) != null) { next.b.sum = me.sumFor(time, next.a); time = next.a; me = next.b; } } @Override public double readSumTable(int channel, int t) { double t2 = t+1; var p = floorPair(additions, t2); double sum = p == null ? 0.0 : p.b.sumFor(p.a, t2); //printVars readSumTable(+t, +p, +sum); for (source : sources) sum += source.readSumTable(channel, t); ret sum; } }