/** * This control allows the user to set the levels of several * harmonics. * * James Brink 3/10/2020, replaced OnOff spans by clickable labels */ let harmonic; let harmonicOnOffChecks = []; // turn harmonic on/off - these are js - not p5js // use .checked not .checked() let harmonicOnOffSpans = []; // displays harmonic on/off - these are js - not p5js // use innerHTML = not .html( ) let harmonicFreqSpans = []; // displays frequency of harmonic let harmonicVolSlides = []; // controls volume of harmonic let harmonicVolSpans = []; // display volume of harmonic let harmonicPlusMinusChecks = []; // used to allow harmonic subtraction let envelope = []; let onString = "On"; let offString = "Off" class HarmonicControl { /** * constructor where the colors are HTML/CSS color names */ constructor(itsWidth, itsHeight, itsParent) { this.controlWidth = itsWidth; this.controlHeight = itsHeight; this.controlParent = itsParent; this.harmonicDiv; } // end constructor setupHarmonicControl() { let harmonDivs = []; this.harmonicDiv = createFaceplateDiv('HARMONICS', this.controlWidth, this.controlHeight, this.controlParent); this.harmonicDiv.style("text-size: smaller; height: 200px; display:none;"); for (let i = 0; i < numOsc; i++) { harmonDivs[i] = createDiv(); let hd = harmonDivs[i]; hd.parent(this.harmonicDiv); harmonDivs[i].style("height:18px"); let titleSpan = createSpan("Harmonic " + (i+1) + "   "); //label titleSpan.parent(hd); let result = createSpanCheck(i, onOffChanged, hd); harmonicOnOffChecks[i] = result[0]; harmonicOnOffSpans[i] = result[1]; harmonicFreqSpans[i] = createSpan((round(100 * osc[i].getFreq()) / 100) + " Hz"); // Hz display harmonicFreqSpans[i].parent(hd); harmonicFreqSpans[i].style("color:red; background-color: white;" + " display: inline-block; width: 115px; height:16px"); let spacer1Span = createSpan("   "); // spacer spacer1Span.parent(hd); harmonicVolSlides[i] = createSlider(0, 1000, 1000 * 1/(i+1)); // slider harmonicVolSlides[i].parent(hd); harmonicVolSlides[i].input(function () {harmonicVolSlideChanging(i)}); let spacer3Span = createSpan("   "); // spacer spacer3Span.parent(hd); harmonicVolSpans[i] = createSpan(round(harmonicVolSlides[i].value())/10); // vol display harmonicVolSpans[i].parent(hd); harmonicVolSpans[i].style("color: green; background-color:white;" + " display: inline-block; width: 40px; height:16px"); } let spacer4Span = createSpan("
"); // spacer spacer4Span.parent(this.harmonicDiv); this.oneBtn = createButton("Set volume: 1"); this.oneBtn.parent(this.harmonicDiv); this.oneBtn.style("height: 24px"); this.oneBtn.mousePressed(function () {overNPushed(0)}); this.overNBtn = createButton("Set volume: 1/n"); this.overNBtn.parent(this.harmonicDiv); this.overNBtn.style("height: 24px"); this.overNBtn.mousePressed(function () {overNPushed(1)}); this.overN2Btn = createButton("Set volume: 1/n2"); this.overN2Btn.parent(this.harmonicDiv); this.overN2Btn.style("height: 24px"); this.overN2Btn.mousePressed(function () {overNPushed(2)}); harmonicOnOffChecks[0].checked = true; harmonicOnOffSpans[0].innerHTML = onString; // set values for (let i = 0; i < numOsc; i++) { envelope[i] = new p5.Envelope(); } // however setADSR and setRange will be set each time a note is played } // setupHarmonicControl() } // end setupHarmonicControl function setOnOff(vol0) { for (let i = 0; i < numOsc; i++ ) { if (vol0 == 0) { // off mode harmonicOnOffChecks[0].checked = false; // but osc[0] is off harmonicOnOffSpans[0].innerHTML(offString); } else { // tone and harmonic mode harmonicOnOffChecks[0].checked = true; harmonicOnOffSpans[0].innerHTML(onString) } } // end setOnOff } // class harmonicControl /** * This functions called every time the slide is changed OR when the * correspondin plus/minuscheckbox changed */ function harmonicVolSlideChanging(i) { let vol = harmonicVolSlides[i].value(); vol = map(vol, volumeSliderMax, 0, volumeDisplayMax, volumeDisplayMin); harmonicVolSpans[i].html(round(10 * vol)/10); if (playing && harmonicOnOffChecks[i].checked) { if (modeCtrl.mode == "piano") { envelope[i].triggerAttack(); } else { osc[i].amp(vol/100); } } } // end harmonicVolSlideChanged function onOffChanged(i) { if ( harmonicOnOffChecks[i].checked) { harmonicOnOffSpans[i].innerHTML = onString; if (playing) { if (modeCtrl.mode == "piano") { envelope[i].triggerAttack(); } else if (modeCtrl.mode != offString){ osc[i].amp(harmonicVolSpans[i].html()/100, .5); } } } else { harmonicOnOffSpans[i].innerHTML = offString; if (modeCtrl.mode == "piano") { envelope[i].triggerRelease(); } else { osc[i].amp(0, .3); } } } // end onOffChanged function turnSoundOn() { for (let i = 0; i < numOsc; i++) { if (harmonicOnOffChecks[i].checked) { if (modeCtrl.mode == "piano") { // sounds will not be turned until a key is pressed and processed in // keyboard control } else if (modeCtrl.mode != offString) { osc[i].amp(harmonicVolSpans[i].html()/100); } } else { osc[i].amp(0, .1); } } } //turn soundOn function turnSoundOff() { for (let i = 0; i < numOsc; i++) { osc[i].amp(0, .3); } } // turnSoundOff function overNPushed(p) { for (let i = 0; i < numOsc; i++) { let v = 100/pow(i+1, p); if (p == 2 && (volumeDisplayMin < 0) && (round(i/2) == 1 || round(i/2) == 3)) { v = -v; } harmonicSetVolume(v, i); } } // overNPushed function harmonicInvertChanged() { for (let i = 0; i < numOsc; i++) { let v = abs(harmonicVolSpans[i].html()); harmonicSetVolume(v, i); } if (volumeDisplayMin < 0) { harmonic.overN2Btn.html("Set volume: ± 1/n2"); } else { harmonic.overN2Btn.html("Set volume: 1/n2"); } } // harmonicInvertChanged function harmonicSetVolume(v, i) { let sliderPos = map(v, volumeDisplayMax, volumeDisplayMin, volumeSliderMax, 0); harmonicVolSlides[i].value(sliderPos); harmonicVolSpans[i].html(round(10 * v)/10); if (playing && harmonicOnOffChecks[i].checked) { osc[i].amp(v/100); } } // harmonicSetVolume // function for 3rd method that creates the span/checkbox/label. Also sets parent. // i: sequence number to make sure ids are unique - also needed for f // f: function (no quotes) // par: parent function createSpanCheck(i, f, par) { let chkId = "c" + i; let labId = "l" + i; let style = 'display: inline-block; width: 35px; text-align: center;'; let s = ' ' + ''; let sp = createSpan(s); sp.parent(par); let chk = document.getElementById(chkId); let lab = document.getElementById(labId); chk.onchange = (function() {f(i);}); let ret = [chk, lab]; return ret; } // createSpanCheck