Warning: session_start(): open(/var/lib/php/sessions/sess_ad5hcusnu2v4mhccdm8m1kk6u5, O_RDWR) failed: No space left on device (28) in /var/www/tb-usercake/models/config.php on line 51
Warning: session_start(): Failed to read session data: files (path: /var/lib/php/sessions) in /var/www/tb-usercake/models/config.php on line 51
// TODO: declare audio ended so we can ignore any incomplete bass frequencies
sclass ContinuousOscillators_v2 extends Meta {
macro dprint { if (debug) printVars } bool debug;
int channels = 1;
double sampleRate = 48000;
double currentSample;
IQuerySound sound; // unintegrated sound for on-demand querying
IAudioSample audio; // integrated audio sample
SubtractedAudio subtractedAudio; // audio with deleted frequencies
bool renderUsingSine; // or square wave
bool realOnly, imagOnly; // for testing
double maxRelFreq = 0.25; // maximum oscillator frequency relative to sample rate
long haarFeaturesChecked;
persistable class Oscillator extends HasKey {
double currentPeriodStart;
// all recorded intensities
new TreeMap> intensities;
double interval; // length of period in samples
*(Frequency f) {
super(f);
interval = frequency().interval()*sampleRate;
}
Frequency frequency() { ret key(); }
double interval() { ret interval; }
scaffolded void record_impl(DoubleRange r, Channels c) {
intensities.put(r, c);
subtractMeasured(r, c);
currentPeriodStart = phase360();
rcallF(oscillators.higher(this), o -> { o?.process(currentPeriodStart); });
}
void subtractMeasured(DoubleRange r, Channels c) {
renderer().subtractPeriodFrom(subtractedAudio, r, c.getSingleton());
}
scaffolded void process(double upTo) {
while (phase360() >= upTo)
measure();
}
scaffolded void measure() {
DoubleRange p1 = doubleRangeWithLength(currentPeriodStart, interval);
AudioHaarFeature haar = new(audio, p1);
haarFeaturesChecked += 2;
record(this, p1, haar.getComplex());
}
double phase360() { ret currentPeriodStart + interval(); }
} // end of Oscillator
TreeHasKeyMap oscillators;
*() {}
*(IAudioSample audio, double *currentSample) { setAudio(audio); }
*(IAudioSample audio) { setAudio(audio); } // start at time 0
void setFrequencies(Iterable frequencies) {
oscillators = new TreeHasKeyMap(map(f -> new Oscillator(f), filter(frequencies,
f -> between(f!, 1, sampleRate*maxRelFreq))));
}
void setAudio(IAudioSample audio) {
this.audio = audio;
subtractedAudio = new SubtractedAudio(audio);
}
int nFrequencies() { ret oscillators.size(); }
scaffolded void stepTo(DoubleRange timeRange) {
var o = first(oscillators);
o?.process(timeRange.end);
}
void record(Oscillator o, DoubleRange r, Channels c) {
if (o == null) ret;
o.record_impl(r, c);
}
Frequency lowestFrequency() { ret oscillators.firstKey(); }
Frequency highestFrequency() { ret oscillators.lastKey(); }
int minWindowSize() {
ret iceil(sampleRate*lowestFrequency().interval());
}
void makeSmallestWindow(IQuerySound sound) {
this.sound = sound;
setAudio(new SlidingWindow(channels, sampleRate, sound, 0, minWindowSize());
}
void makeFullWindow(IQuerySound sound, IntRange r) {
this.sound = sound;
setAudio(new SlidingWindow(channels, sampleRate, sound,
r.start, r.length()));
}
S stats() { ret renderVars(+audio, +haarFeaturesChecked); }
// how much horizontal area have we covered
L coverageByFreq() {
ret mapReversed(oscillators, o -> totalLengthOfDoubleRanges(keys(o.intensities)));
}
double windowSize() { ret window().length(); }
DoubleRange windowBounds() { ret window().bounds(); }
IIntegralImage imageColumn(DoubleRange timeRange) {
int n = nFrequencies();
double[] col = rawImageColumn(timeRange);
double[] col2 = normalizeDoubles(col, 255);
ret bwIntegralImageFromFunction(1, n, (x, y) -> ifloor(col2[y]));
}
double[] rawImageColumn(DoubleRange timeRange) {
int n = nFrequencies();
var l = reversedList(oscillators);
double[] col = new[n];
for y to n: {
TreeMap> l2 = l.get(y).intensities;
// find right period
DoubleRange period = l2.floorKey(timeRange);
if (period == null) continue;
double amplitude = l2.get(period).first().abs();
col[y] = amplitude;
}
ret col;
}
MakesBufferedImage imageForWindow(double pixelsPerSecond) {
new L images;
double len = windowBounds().length()/sampleRate;
int pixels = iround(len*pixelsPerSecond);
for i to pixels: {
DoubleRange range = doubleRange(
i/pixelsPerSecond*sampleRate+windowBounds().start(),
(i+1)/pixelsPerSecond*sampleRate+windowBounds().start());
//print(+range);
images.add(imageColumn(range));
}
ret mergeBWImagesHorizontally(map toBWImage(images), spacing := 0);
}
double[] toAudio(IntRange sampleRange, Iterable oscillatorsToRender default oscillators) {
double[] samples = new[l(sampleRange)];
class PerFreq {
Oscillator o;
DoubleRange period;
Channels intensity;
*(Oscillator *o) {
setPeriod(o.intensities.floorKey(toDoubleRange(sampleRange)));
//printVars("PerFreq", f := o.frequency(), +sampleRange, +period, firstPeriod := firstKey(o.intensities));
}
void setPeriod(DoubleRange period) {
this.period = period;
intensity = period == null ?: o.intensities.get(period);
}
void nextPeriod(double t) {
while (period != null && t >= period.end)
setPeriod(o.intensities.higherKey(period));
}
}
L perFreqs = map(oscillatorsToRender, o -> new PerFreq(o));
for i over samples: {
double t = sampleRange.start+i; // t is time in samples
double sum = 0;
for (pf : perFreqs) {
pf.nextPeriod(t);
bool shouldPrint = toAudio_shouldPrint(i, l(samples));
if (pf.intensity != null) {
Complex c = div(pf.intensity.first(), l(pf.period));
double t2 = t-pf.period.start;
double frac = t2/pf.o.interval;
//double phiRE = frac*pi()*2;
//double phiIM = phiRE+pi()/2;
if (shouldPrint)
printVars(f := pf.o.frequency(), +i, interval := formatDouble1(pf.o.interval)/*, interval2 := l(pf.period)*/, +t, +t2, frac := formatDouble2(frac),
c := renderComplexWithAngle(div(c, 32768)));
if (realOnly) c = complex(c.re());
else if (imagOnly) c = complex(0, c.im());
sum += renderFrequencySample(c, frac);
} else
if (shouldPrint)
printVars(f := pf.o.frequency(), +i, interval := pf.o.interval, +t, c := 0);
}
samples[i] = sum;
}
ret samples;
}
RenderFrequencySample renderer() {
ret renderUsingSine
? new RenderFrequencySample_Sine
: new RenderFrequencySample_SquareWave;
}
double renderFrequencySample(Complex c, double frac) {
ret renderer().get(c, frac);
}
swappable bool toAudio_shouldPrint(int i, int n) { false; }
SlidingWindow window() { ret optCast SlidingWindow(audio); }
}