sclass PianoSampler { double sampleRate = 48000; double currentSample; IAudioSample audio; persistable class Oscillator extends HasKey { double currentPeriodStart; // all recorded intensities new TreeMap> intensities; *(Frequency f) { super(f); } Frequency frequency() { ret key(); } double interval() { ret frequency().interval(); } void record_impl(DoubleRange r, Channels c) { intensities.put(r, c); } void measure { double start = phaseMinus90(), end = start + interval(); AudioHaarFeature haar = new(audio, start, end); var re = haar!; haar = new AudioHaarFeature(audio, currentPeriodStart, currentPeriodStart + interval()); var im = haar!; record(this, doubleRange(start, end), complexChannels(re, im)); } void start(double currentSample) { relocate(currentSample + startPhase()); } void relocate(double time) { currentPeriodStart = time; completionsForSample.put(interval(), this); } double startPhase() { ret phase90(); } double quarterPhase() { ret interval()*.25; } double phaseMinus90() { ret currentPeriodStart - interval()*.25; } double phase0() { ret currentPeriodStart; } double phase90() { ret currentPeriodStart + interval()*.25; } double phase180() { ret currentPeriodStart + interval()*.5; } double phase270() { ret currentPeriodStart + interval()*.75; } double phase360() { ret currentPeriodStart + interval(); } double phase450() { ret currentPeriodStart + interval()*1.25; } } HasKeyMap oscillators = new(map(f -> new Oscillator(f), pianoFrequencies88())); new TreeMultiMap completionsForSample; *(IAudioSample *audio, double *currentSample) {} *(IAudioSample *audio) {} // start at time 0 void init { for (o : oscillators) o.start(currentSample); } void stepTo(double time) { Double t = firstKey(completionsForSample); if (t != null && t <= time) for (Oscillator o : completionsForSample.getAndClear(t)) { o.measure(); o.relocate(t); } } record RecordAdded(Oscillator oscillator, DoubleRange period, Channels intensity) {} transient event interface onRecordAdded as OnRecordAdded shipping RecordAdded; }