// return the center of the key over the point p. // Vec2 TouchTracker::getKeyCenterAtPoint(const Vec2 p) { float x = p.x(); float y = p.y(); int ix, iy; float fx, fy; switch (mKeyboardType) { case(rectangularA): default: MLRange xRange(3.5f, 59.5f); xRange.convertTo(MLRange(1.f, 29.f)); float kx = xRange(x); kx = clamp(kx, 0.f, 30.f); ix = kx; MLRange yRange(1.25, 5.75); // Soundplane A as measured yRange.convertTo(MLRange(1.f, 4.f)); float ky = yRange(y); ky = clamp(ky, 0.f, 5.f); iy = ky; MLRange xRangeInv(1.f, 29.f); xRangeInv.convertTo(MLRange(3.5f, 59.5f)); fx = xRangeInv(ix + 0.5f); MLRange yRangeInv(1.f, 4.f); yRangeInv.convertTo(MLRange(1.25, 5.75)); fy = yRangeInv(iy + 0.5f); break; } return Vec2(fx, fy); }
// return the index of the key over the point p. // int TouchTracker::getKeyIndexAtPoint(const Vec2 p) { int k = -1; float x = p.x(); float y = p.y(); int ix, iy; switch (mKeyboardType) { case(rectangularA): default: MLRange xRange(3.5f, 59.5f); xRange.convertTo(MLRange(1.f, 29.f)); float kx = xRange(x); kx = clamp(kx, 0.f, 29.f); ix = kx; MLRange yRange(1.25, 5.75); // Soundplane A as measured yRange.convertTo(MLRange(1.f, 4.f)); float ky = yRange(y); ky = clamp(ky, 0.f, 4.f); iy = ky; k = iy*30 + ix; break; } return k; }
void MLGraph::resized() { MLLookAndFeel* myLookAndFeel = MLLookAndFeel::getInstance(); int m = myLookAndFeel->getSmallMargin(); int w = getWidth(); int h = getHeight(); // default ctor for MLRange sets [0, 1] // mResolution = w/4; mViewDomain.convertTo(MLRange(m + 0.5, w - m + 0.5)); mViewRange.convertTo(MLRange(h - m + 0.5, m + 0.5)); }
Vec2 TouchTracker::getKeyCenterByIndex(int idx) { // for Soundplane A only int iy = idx/30; int ix = idx - iy*30; MLRange xRangeInv(1.f, 29.f); xRangeInv.convertTo(MLRange(3.5f, 59.5f)); float fx = xRangeInv(ix + 0.5f); MLRange yRangeInv(1.f, 4.f); yRangeInv.convertTo(MLRange(1.25, 5.75)); float fy = yRangeInv(iy + 0.5f); return Vec2(fx, fy); }
void MLMultiSlider::paint (Graphics& g) { MLLookAndFeel* myLookAndFeel = (&(getRootViewResources(this).mLookAndFeel)); if (isOpaque()) myLookAndFeel->drawBackground(g, this); float outlineThickness = myLookAndFeel->getGridUnitSize() / 64.f; MLRect r = mPos.getLocalOutline(); const Colour outlineColor (findColour(MLLookAndFeel::outlineColor).withAlpha (isEnabled() ? 1.f : 0.5f)); // draw fills // vertical only Path full, empty; Colour fullColor, emptyColor; MLRect fullRect, emptyRect; float dialY; MLRange drawRange(mRange); drawRange.convertTo(MLRange(r.height(), 0.)); for (int i=0; i<mNumSliders; ++i) { MLRect sr = (mPos.getElementBounds(i)); dialY = drawRange(getFloatProperty(ml::textUtils::addFinalNumber(ml::Symbol("value"), i))); fullRect = sr; emptyRect = sr; fullRect.setTop(dialY); fullColor = findColour(trackFullDarkColor); emptyColor = findColour(trackEmptyDarkColor); // groups of 4 if (!(i&4)) { emptyColor = emptyColor.brighter(0.10f); fullColor = fullColor.brighter(0.20f); } empty.clear(); empty.addRectangle(MLToJuceRect(emptyRect)); g.setColour(emptyColor); g.fillPath(empty); full.clear(); full.addRectangle(MLToJuceRect(fullRect)); g.setColour(fullColor); g.fillPath(full); g.setColour(outlineColor); g.strokePath(empty, PathStrokeType (outlineThickness)); } }
void SoundplaneTouchGraphView::renderTouchBarGraphs() { if (!mpModel) return; if (!isShowing()) return; int viewW = getBackingLayerWidth(); int viewH = getBackingLayerHeight(); const MLSignal& currentTouch = mpModel->getTouchFrame(); const MLSignal& touchHistory = mpModel->getTouchHistory(); const int frames = mpModel->getFloatProperty("max_touches"); if (!frames) return; const Colour c = findColour(MLLookAndFeel::backgroundColor); float p = c.getBrightness(); int margin = viewH / 30; int numSize = margin*2; int left = margin*2 + numSize; int right = viewW - margin; int top = margin; int bottom = viewH - margin; int frameWidth = right - left; int frameOffset = (bottom - top)/frames; int frameHeight = frameOffset - margin; MLRect frameSize(0, 0, frameWidth, frameHeight); MLGL::orthoView(viewW, viewH); for(int j=0; j<frames; ++j) { // draw frames p = 0.9f; glColor4f(p, p, p, 1.0f); MLRect fr = frameSize.translated(Vec2(left, margin + j*frameOffset)); MLGL::fillRect(fr); p = 0.6f; glColor4f(p, p, p, 1.0f); MLGL::strokeRect(fr); // draw touch activity indicators at left glColor4fv(MLGL::getIndicatorColor(j)); MLRect r(0, 0, numSize, numSize); MLRect tr = r.translated(Vec2(margin, margin + j*frameOffset + (frameHeight - numSize)/2)); int age = currentTouch(4, j); if (age > 0) MLGL::fillRect(tr); else MLGL::strokeRect(tr); // draw history MLRange frameXRange(fr.left(), fr.right()); frameXRange.convertTo(MLRange(0, (float)kSoundplaneHistorySize)); MLRange frameYRange(0, 1); frameYRange.convertTo(MLRange(fr.bottom(), fr.top())); glBegin(GL_LINES); for(int i=fr.left() + 1; i<fr.right()-1; ++i) { int time = frameXRange(i); float force = touchHistory(2, j, time); // float d = touchHistory(3, j, time); // int age = touchHistory(4, j, time); float y = frameYRange.convert(force); // float drawY = (age > 0) ? y : 0.; // y = frameYRange.convert(d); // draw line glVertex2f(i, fr.bottom()); glVertex2f(i, y); } glEnd(); } }
void MLEnvelope::paint (Graphics& g) { float mDelay = getFloatProperty("delay"); float mAttack = getFloatProperty("attack"); float mSustain = getFloatProperty("sustain"); float mDecay = getFloatProperty("decay"); float mRelease = getFloatProperty("release"); float r = getFloatProperty("repeat"); float mRepeat = (r > 0.f) ? (1.f / (r + 0.0001f)) : 0.f; MLLookAndFeel* myLookAndFeel = (&(getRootViewResources(this).mLookAndFeel)); if (isOpaque()) myLookAndFeel->drawBackground(g, this); float margin = myLookAndFeel->getSmallMargin() * myLookAndFeel->getGridUnitSize(); int w = getWidth()-1; int h = getHeight()-1; float totalTime; float startX, delX, attX, decX, susX, relX, repX, endX; float attTime, decTime, relTime, susTime; float leadIn = 0.01; float leadOut = 0.01; float susHeight; float epsilon = 0.0005; float susLevel = mDARMode ? 1.0f : mSustain; attTime = mAttack + kMinAttack; decTime = mDecay * (1.f - susLevel) + kMinDecay; relTime = mRelease * susLevel + kMinDecay; // get times if (mDARMode) { susTime = (mSustain > 0.5) ? 1.f : 0.f; // is hold on? decTime = 0.; totalTime = leadIn + mDelay + attTime + susTime + relTime + leadIn + leadOut; } else { susTime = 1.f; totalTime = leadIn + attTime + decTime + susTime + relTime + leadIn + leadOut; } if (mRepeat > epsilon) { totalTime = ml::max(totalTime, (float)(leadIn + mDelay + mRepeat + leadOut)); } totalTime = ml::max(totalTime, 0.01f); // get dims MLRange vRange(UnityRange); MLRange wRange(0.f, totalTime); vRange.convertTo(MLRange(h - margin, margin)); wRange.convertTo(MLRange(margin, w - margin*2)); float t = 0.; startX = wRange(0.); delX = wRange(t += mDelay); attX = wRange(t += attTime); decX = wRange(t += decTime); susX = wRange(t += susTime); relX = wRange(t += relTime); endX = wRange(totalTime); repX = wRange(leadIn + mDelay + mRepeat); susHeight = vRange(susLevel); // draw env shape Path envPath; envPath.startNewSubPath(startX, floor(h - margin) + 0.5); envPath.lineTo(delX, floor(h - margin) + 0.5); envPath.quadraticTo(delX, floor(margin) + 0.5, attX, floor(margin) + 0.5); // up envPath.quadraticTo(attX, floor(susHeight) + 0.5, decX, floor(susHeight) + 0.5); // down envPath.quadraticTo(decX, floor(susHeight) + 0.5, susX, floor(susHeight) + 0.5); // across envPath.quadraticTo(susX, floor(h - margin) + 0.5, relX, floor(h - margin) + 0.5); // down envPath.quadraticTo(relX, floor(h - margin) + 0.5, endX, floor(h - margin) + 0.5); // across g.setColour(findColour(MLLookAndFeel::outlineColor)); g.strokePath(envPath, PathStrokeType (mOutlineThickness)); g.setColour(findColour(MLLookAndFeel::outlineColor).withAlpha(0.125f)); g.fillPath(envPath); // lines down envPath.clear(); envPath.startNewSubPath(attX, floor(margin) + 0.5); envPath.lineTo(attX, floor(h - margin) + 0.5); envPath.startNewSubPath(decX, floor(susHeight) + 0.5); envPath.lineTo(decX, floor(h - margin) + 0.5); envPath.startNewSubPath(susX, floor(susHeight) + 0.5); envPath.lineTo(susX, floor(h - margin) + 0.5); g.setColour(findColour(MLLookAndFeel::outlineColor)); g.strokePath(envPath, PathStrokeType (mOutlineThickness / 2)); // draw repeat bracket if (mRepeat > epsilon) { float thick = margin / 2; float high = margin * 1.5; envPath.clear(); envPath.startNewSubPath(floor(delX - thick/2) , floor(h - margin - high)); envPath.lineTo(floor(delX - thick/2) , floor(h - margin)); envPath.lineTo(floor( repX + thick/2) , floor(h - margin)); envPath.lineTo(floor( repX + thick/2) , floor(h - margin - high)); g.strokePath(envPath, PathStrokeType (mOutlineThickness * 4)); } //debug() << "DEL " << mDelay << " ATT " << attTime << " DEC " << decTime << " SUS " << susTime << " REL " << relTime << " REP " << mRepeat << "\n"; //debug() << "repeatX: " << repX << " delayX: " << delX << "\n"; /* // TEST Path tbounds; const Rectangle<int> & boundsRect ( getLocalBounds()); tbounds.addRectangle(boundsRect); g.setColour(Colours::red); g.strokePath(tbounds, PathStrokeType(0.5f)); */ }