/* Copyright (C) 2006 Christian Schneider * * This file is part of Nomad. * * Nomad is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * Nomad is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Nomad; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ /* * Created on Jul 24, 2006 */ package net.sf.nmedit.jtheme.clavia.nordmodular; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Insets; import java.awt.geom.AffineTransform; import java.awt.geom.GeneralPath; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import net.sf.nmedit.jtheme.JTContext; import net.sf.nmedit.jtheme.component.JTControlAdapter; import net.sf.nmedit.jtheme.component.JTDisplay; import net.sf.nmedit.jtheme.store2.BindParameter; public class LFODisplay extends JTDisplay implements ChangeListener { /** * */ private static final long serialVersionUID = 4431079405680653586L; public LFODisplay( JTContext context ) { super( context ); } public final static int WF_SINE = 0; public final static int WF_TRI = 1; public final static int WF_SAW = 2; public final static int WF_INV_SAW = 3; public final static int WF_SQUARE = 4; private int vwf = WF_SAW; private double vphase = 0.5; private GeneralPath gp = new GeneralPath(); private boolean rebuildpath = true; private int w = 0; private int h = 0; private int ww = 0; private int hh = 0; private JTControlAdapter phaseAdapter; private JTControlAdapter waveAdapter; private boolean modified = true; protected void setModified(boolean modified) { this.modified = modified; } protected void paintComponent(Graphics g) { if (modified) { modified = false; setDoubleBufferNeedsUpdate(); } super.paintComponentWithDoubleBuffer(g); } public JTControlAdapter getPhaseAdapter() { return phaseAdapter; } public JTControlAdapter getWaveAdapter() { return waveAdapter; } @BindParameter(name="phase") public void setPhaseAdapter(JTControlAdapter adapter) { JTControlAdapter oldAdapter = this.phaseAdapter; if (oldAdapter != adapter) { if (oldAdapter != null) oldAdapter.setChangeListener(null); this.phaseAdapter = adapter; if (adapter != null) adapter.setChangeListener(this); updatePhase(); } } @BindParameter(name="shape") public void setWaveAdapter(JTControlAdapter adapter) { JTControlAdapter oldAdapter = this.waveAdapter; if (oldAdapter != adapter) { if (oldAdapter != null) oldAdapter.setChangeListener(null); this.waveAdapter = adapter; if (adapter != null) adapter.setChangeListener(this); updateWave(); } } private void ensurePathBuilt() { if (rebuildpath || getWidth()!=w || getHeight()!=h) { gp.reset(); w = getWidth(); h = getHeight(); rebuildpath = false; switch (vwf) { case WF_SINE: generateSine(gp); break; case WF_TRI: generateTri(gp); break; case WF_SAW: generateSaw(gp); break; case WF_INV_SAW: generateInvSaw(gp); break; case WF_SQUARE: generateSquare(gp); break; } Insets insets = getInsets(); this.ww = w-insets.left-insets.right; this.hh = h-insets.top-insets.bottom; AffineTransform at = new AffineTransform(); at.translate(0, 1+(hh-1)/2d); at.scale(ww-1, (hh-1)/2d); at.scale(1, -1); gp.transform(at); } } public void paintDynamicLayer(Graphics2D g) { ensurePathBuilt(); Graphics2D g2 = (Graphics2D) g.create(); try { g2.setColor(getForeground()); double tx = (((1-vphase)-0.5)*(ww-1)); double ty = 0; g2.translate(tx, ty); g2.draw(gp); g2.translate(-ww, 0); g2.draw(gp); g2.translate(2*ww, 0); g2.draw(gp); } finally { g2.dispose(); } } // path bounds: // +1 // 0 ------- 1 // -1 private void generateSine(GeneralPath gp) { // peaks final float cx = 0.5f; final float var = 1/8f; final float h = 1.32f; gp.moveTo(0, 0); gp.curveTo( 0+var, h, cx-var, h, cx, 0); gp.curveTo( cx+var, -h, 1-var, -h, 1, 0); } private void generateTri(GeneralPath gp) { gp.moveTo(0, 0); gp.lineTo(1/4f, 1); gp.lineTo(2/4f, 0); gp.lineTo(3/4f,-1); gp.lineTo(1, 0); } private void generateSaw(GeneralPath gp) { gp.moveTo(0, 0); gp.lineTo(1/2f, 1); gp.lineTo(1/2f,-1); gp.lineTo(1, 0); } private void generateInvSaw(GeneralPath gp) { gp.moveTo(0, -1); gp.lineTo(0, 1); gp.lineTo(1, -1); } private void generateSquare(GeneralPath gp) { gp.moveTo(0,-1); gp.lineTo(0, 1); gp.lineTo(1/2f, 1); gp.lineTo(1/2f, -1); gp.lineTo(1, -1); } private double bounded(double v) { return Math.max(0, Math.min(v, 1.0d)); } @BindParameter(name="waveform") // TODO name=shape public void setWaveForm( int v ) { if (this.vwf!=v) { switch (v) { case WF_SINE: case WF_TRI: case WF_SAW: case WF_INV_SAW: case WF_SQUARE: break; default: throw new IllegalArgumentException("Unknown waveform id:"+v); } this.vwf = v; rebuildpath = true; setModified(true); repaint(); } } public void setPhase( double v ) { double oldValue = this.vphase; v = bounded(v); if (oldValue != v) { this.vphase = v; setModified(true); repaint(); } } public int getWaveForm() { return vwf; } public void stateChanged(ChangeEvent e) { if (e.getSource() == waveAdapter) { updateWave(); return; } if (e.getSource() == phaseAdapter) { updatePhase(); return; } } protected void updateWave() { if (waveAdapter != null) setWaveForm(waveAdapter.getValue()-waveAdapter.getMinValue()); } protected void updatePhase() { if (phaseAdapter != null) setPhase(phaseAdapter.getNormalizedValue()); } }