Skip to content

Commit 1d30935

Browse files
higher samplerates for delta sigma
1 parent 02ea2b4 commit 1d30935

5 files changed

Lines changed: 112 additions & 21 deletions

File tree

delta-sigma-panels/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ <h2>Delta-Sigma</h2>
5959
<div class="panel" id="delta-mod-panel"></div>
6060
</div>
6161
<div class="row sliders">
62-
<div class="slider" id="sample-rate-slider"></div>
62+
<div class="slider" id="ds-sample-rate-slider"></div>
6363
<div class="slider" id="delta-sigma-step-slider"></div>
6464
</div>
6565
<button class="play-button" id="play-delta-sigma">Play</button>

panel.js

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -136,15 +136,30 @@ class Panel {
136136
let pixel_max = this.plotHeight/2;
137137
let pixel_per_fullscale = pixel_max * this.settings.ampZoom;
138138
this.buffer.noFill();
139-
//TODO: there are some artifacts here due to the way the signal is drawn, especially when zoomed in and/or large amplitude
140139
this.buffer.beginShape();
141140
this.buffer.curveTightness(1.0);
142-
for (let x = 0; x < this.plotWidth; x++) {
143-
let pixel_amp = pixel_per_fullscale * signal[Math.round(x/this.settings.timeZoom)];
141+
142+
const iToXScale = this.settings.timeZoom * (this.settings.displaySignalSize) / (signal.length);
143+
144+
const increment = Math.max(1, Math.floor(0.5/iToXScale));
145+
146+
console.log("inc", increment, "scale", iToXScale);
147+
148+
for (let i = 0; i < signal.length; i += increment) {
149+
let x = i * iToXScale;
150+
let pixel_amp = signal[i] * pixel_per_fullscale;
144151
let y = this.halfh - pixel_amp;
145-
y = (y<this.plotTop)? y=this.plotTop : (y>this.plotBottom)? y= this.plotBottom : y=y; this.buffer.curveTightness(0.0);
152+
// y = (y<this.plotTop)? this.plotTop : (y>this.plotBottom)? this.plotBottom : y;
153+
this.buffer.curveTightness(0.0);
146154
this.buffer.curveVertex(x + this.plotLeft, y);
155+
if (i === 0) {
156+
this.buffer.curveVertex(x + this.plotLeft, y);
157+
}
158+
if (x > this.plotWidth) {
159+
break;
160+
}
147161
}
162+
148163
this.buffer.endShape();
149164
}
150165

@@ -436,7 +451,7 @@ class DeltaModPanel extends Panel {
436451
this.drawName();
437452
this.drawSignalAmplitudeTicks(this, this.plotHeight/2, 4);
438453
this.drawTimeTicks(this, this.numTimeTicks/this.settings.timeZoom, 1/(this.settings.timeZoom*this.settings.sampleRate));
439-
}
454+
}
440455
}
441456

442457

slider.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,20 @@ class NumHarmSlider extends RangedSlider {
217217
}
218218
}
219219

220+
class DeltaSigmaSampleRateSlider extends RangedSlider {
221+
setup(p,settings){
222+
this.settings = settings;
223+
this.name ="Delta-Sigma sampling rate";
224+
this.propName="deltaSigmaSamplingRate"
225+
this.min = 1;
226+
this.max = 1000000;
227+
this.initial = 44100;
228+
this.step = 1;
229+
this.displayVal = this.initial;
230+
231+
this.makeSlider(p);
232+
}
233+
}
220234

221235
class SampleRateSlider extends RangedSlider{
222236
setup(p,settings){

waves.js

Lines changed: 74 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -287,19 +287,15 @@ function filterSignal(signal, frequency, order, mode, filterKernel) {
287287

288288
let characteristic = "butterworth";
289289

290-
// order = mode === "Butterworth" ? Math.min(order, 12) : Math.min(order, 4);
291-
292290
let filterCoeffs = iirCalculator.lowpass({
293-
order: order, // cascade 3 biquad filters (max: 12)
291+
order: order, // cascade 3 biquad filters
294292
characteristic: characteristic,
295293
Fs: WEBAUDIO_MAX_SAMPLERATE, // sampling frequency
296294
Fc: frequency, // cutoff frequency / center frequency for bandpass, bandstop, peak
297295
preGain: false // adds one constant multiplication for highpass and lowpass
298296
// k = (1 + cos(omega)) * 0.5 / k = 1 with preGain == false
299297
});
300298

301-
console.log(filterCoeffs);
302-
303299
let filter = new Fili.IirFilter(filterCoeffs);
304300

305301
signal.forEach((x, n, y) => y[n] = filter.singleStep(x));
@@ -391,24 +387,86 @@ function renderOriginal(settings, fft, playback) {
391387
normalize(original, settings.amplitude);
392388
}
393389

390+
function getInterpolatedSample(array, i) {
391+
if (i <= 0) {
392+
return array[0];
393+
}
394+
if (i >= array.length - 1) {
395+
return array[array.length - 1];
396+
}
397+
let lowIndex = Math.floor(i);
398+
let highIndex = lowIndex + 1;
399+
400+
return array[lowIndex] * (highIndex - i) + array[highIndex] * (i - lowIndex);
401+
}
402+
394403
function renderDeltaSigma(settings, fft, playback) {
395404
let originalUnfiltered = playback ? settings.buffers.originalUnfiltered.playback : settings.buffers.originalUnfiltered.display;
396405
let deltaSigma = playback ? settings.buffers.deltaSigma.playback : settings.buffers.deltaSigma.display;
397406
let reconstructed = playback ? settings.buffers.reconstructed.playback : settings.buffers.reconstructed.display;
398407

399-
let samplePeriod = Math.floor(settings.downsamplingFactor);
400408
let step = settings.deltaSigmaStep;
401-
let ds_state = 0;
402-
for (let i = 0; i < originalUnfiltered.length; i += samplePeriod) {
403-
if (ds_state > originalUnfiltered[i]) {
404-
ds_state -= step;
405-
} else {
406-
ds_state += step;
409+
410+
411+
if (settings.deltaSigmaSamplingRate <= (WEBAUDIO_MAX_SAMPLERATE/2)) {
412+
if (!playback && deltaSigma.length !== settings.displaySignalSize) {
413+
deltaSigma = new Float32Array(settings.displaySignalSize);
407414
}
408-
for (let j = 0; j < samplePeriod; j += 1) {
409-
deltaSigma[i+j] = ds_state;
410-
reconstructed[i+j] = ds_state;
415+
let samplePeriod = Math.floor(WEBAUDIO_MAX_SAMPLERATE / settings.deltaSigmaSamplingRate);
416+
let ds_state = 0;
417+
for (let i = 0; i < originalUnfiltered.length; i += samplePeriod) {
418+
if (ds_state > originalUnfiltered[i]) {
419+
ds_state -= step;
420+
} else {
421+
ds_state += step;
422+
}
423+
for (let j = 0; j < samplePeriod; j += 1) {
424+
deltaSigma[i+j] = ds_state;
425+
reconstructed[i+j] = ds_state;
426+
}
427+
}
428+
} else if (!playback) {
429+
// Simulate a higher sample rate
430+
if (settings.buffers.deltaSigma.display.length !== settings.displaySignalSize * settings.deltaSigmaSamplingRate / WEBAUDIO_MAX_SAMPLERATE) {
431+
settings.buffers.deltaSigma.display = new Float32Array(settings.displaySignalSize * settings.deltaSigmaSamplingRate / WEBAUDIO_MAX_SAMPLERATE);
432+
settings.buffers.reconstructed.display = new Float32Array(settings.displaySignalSize * settings.deltaSigmaSamplingRate / WEBAUDIO_MAX_SAMPLERATE);
411433
}
434+
let upsampledOutput = new Float32Array(settings.buffers.deltaSigma.display.length);
435+
436+
let ds_state = 0;
437+
let scale = originalUnfiltered.length / settings.buffers.deltaSigma.display.length;
438+
for (let i = 0; i < settings.buffers.deltaSigma.display.length; i += 1) {
439+
440+
if (ds_state > getInterpolatedSample(originalUnfiltered, i * scale)) {
441+
ds_state -= step;
442+
} else {
443+
ds_state += step;
444+
}
445+
settings.buffers.deltaSigma.display[i] = ds_state;
446+
settings.buffers.reconstructed.display[i] = ds_state;
447+
}
448+
449+
// let iirCalculator = new Fili.CalcCascades();
450+
//
451+
// let characteristic = "butterworth";
452+
//
453+
// let filterCoeffs = iirCalculator.lowpass({
454+
// order: 6, // cascade 3 biquad filters
455+
// characteristic: characteristic,
456+
// Fs: settings.deltaSigmaSamplingRate, // sampling frequency
457+
// Fc: 20000, // cutoff frequency / center frequency for bandpass, bandstop, peak
458+
// preGain: false // adds one constant multiplication for highpass and lowpass
459+
// });
460+
//
461+
// let filter = new Fili.IirFilter(filterCoeffs);
462+
//
463+
// upsampledOutput.forEach((x, n, y) => y[n] = filter.singleStep(x));
464+
//
465+
// const decimationRatio = settings.deltaSigmaSamplingRate / WEBAUDIO_MAX_SAMPLERATE;
466+
// console.log(decimationRatio);
467+
// for (let i = 0; i < reconstructed.length; ++i) {
468+
// reconstructed[i] = upsampledOutput[Math.min(Math.floor(i * decimationRatio), upsampledOutput.length - 1)];
469+
// }
412470
}
413471
}
414472

@@ -543,6 +601,7 @@ function downsampleWithQuantization(settings, fft, playback) {
543601
}
544602

545603
function antiImagingFilter(settings, fft, playback) {
604+
546605
let reconstructed = playback ? settings.buffers.reconstructed.playback : settings.buffers.reconstructed.display;
547606

548607
// render reconstructed wave by low pass filtering the zero stuffed array----

widget.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,12 @@ function getDefaultSettings() {
3939
deltaSigma: createBuffers()
4040
},
4141
amplitude: 1.0
42+
, displaySignalSize: displaySignalSize
4243
, inputType: "Additive Synth"
4344
, fundFreq: 1250 // input signal fundamental freq
4445
, sampleRate: WEBAUDIO_MAX_SAMPLERATE
4546
, downsamplingFactor: 2
47+
, deltaSigmaSamplingRate: 44100
4648
, noiseFloor: -96
4749
, numHarm: 2 //Number of harmonics
4850
, harmType: "All" // Harmonic series to evaluate - Odd, even or all
@@ -110,6 +112,7 @@ let sliderIdLookups = {
110112
'reconstruction-filter-order-slider': ReconstructionOrderSlider,
111113
'reconstruction-filter-freq-slider' : ReconstructionFilterFreqSlider,
112114
'sample-rate-slider' : SampleRateSlider,
115+
'ds-sample-rate-slider' : DeltaSigmaSampleRateSlider,
113116
'dither-slider' : DitherSlider,
114117
'quantization-slider' : BitDepthSlider,
115118
'delta-sigma-step-slider' : DeltaSigmaStepSlider,

0 commit comments

Comments
 (0)