/************************************************************************** * Copyright (c) 2001 by Acunia N.V. All rights reserved. * * * * This software is copyrighted by and is the sole property of Acunia N.V. * * and its licensors, if any. All rights, title, ownership, or other * * interests in the software remain the property of Acunia N.V. and its * * licensors, if any. * * * * This software may only be used in accordance with the corresponding * * license agreement. Any unauthorized use, duplication, transmission, * * distribution or disclosure of this software is expressly forbidden. * * * * This Copyright notice may not be removed or modified without prior * * written consent of Acunia N.V. * * * * Acunia N.V. reserves the right to modify this software without notice. * * * * Acunia N.V. * * Vanden Tymplestraat 35 info@acunia.com * * 3000 Leuven http://www.acunia.com * * Belgium - EUROPE * **************************************************************************/ // Author: N. Oberfeld // Created: 2001/03/13 import java.awt.*; import java.awt.event.*; public class Metronome extends Frame { final static float HERZES[]={60.0f,63.5f,67.0f,71.0f,75.5f,80.0f,85.0f,90.0f,95.0f,101.0f,107.0f,113.0f}; final static Color BLINKLIGHT = new Color(255,196,64); final static Color BLINKDARK = new Color(196,64,64); /** Variables */ private Keyboard keyboard; private KeyboardLed led; private TextField display; private float[] blinkRate; private int[] blinkTime; /** constructor */ public Metronome(int octaves) { super("Keyboard Demo"); //set blink rate and blink time blinkRate = new float[octaves*12 +1]; blinkTime = new int[octaves*12 +1]; if(octaves==3) { for(int i=0; i<12; i++) { blinkRate[i]=HERZES[i]/2; blinkTime[i]=(int)(120000.0/HERZES[i]); blinkRate[i+12]=HERZES[i]; blinkTime[i+12]=(int)(60000.0/HERZES[i]); blinkRate[i+24]=HERZES[i]*2; blinkTime[i+24]=(int)(30000.0/HERZES[i]); } blinkRate[36]=HERZES[0]*4; blinkTime[36]=(int)(15000.0/HERZES[0]); } else if(octaves==2) { for(int i=0; i<12; i++) { blinkRate[i]=HERZES[i]; blinkTime[i]=(int)(60000.0/HERZES[i]); blinkRate[i+12]=HERZES[i]*2; blinkTime[i+12]=(int)(30000.0/HERZES[i]); } blinkRate[24]=HERZES[0]*4; blinkTime[24]=(int)(15000.0/HERZES[0]); } else { for(int i=0; i<12; i++) { blinkRate[i]=HERZES[i]; blinkTime[i]=(int)(60000.0/HERZES[i]); } blinkRate[12]=HERZES[0]*2; blinkTime[12]=(int)(30000.0/HERZES[0]); } //layout keyboard = new Keyboard(octaves); add(keyboard, BorderLayout.NORTH); led = new KeyboardLed(); add(led, BorderLayout.WEST); display = new TextField(); // new KeyboardDisplay(); add(display,BorderLayout.CENTER); setSize(400,234); show(); } /************************************************* * Interfaces between keyboard, text and led */ public void keyPressedEvent(int note) { if(note>=0) { display.setText("Metronome "+blinkRate[note]+" Bpm"); led.setBlinkRate(blinkTime[note]); } else { display.setText("( Metronome off )"); led.setBlinkRate(-1 ); } } /** main */ static public void main (String[] args) { new Metronome(3); } /**************************************************************************************************************************************/ /** * Inner class Keyboard */ class Keyboard extends Component implements MouseListener, MouseMotionListener { private Dimension size; private int keys; private int keyWidth; private int keysOffset; private boolean[] halfValid; private int halfkeysOffset; public Keyboard(int octaves) { super(); size = new Dimension(); keys = octaves*7; halfValid = new boolean[keys]; for(int i=0; i<octaves; i++) { halfValid[7*i]=true; halfValid[7*i+1]=true; halfValid[7*i+2]=false; halfValid[7*i+3]=true; halfValid[7*i+4]=true; halfValid[7*i+5]=true; halfValid[7*i+6]=false; } this.addMouseListener(this); this.addMouseMotionListener(this); } private int keyToNote(int keyno) { int scale=keyno/7; int note = keyno%7; if(note<0) return -1; else if(note<1) return scale*12; else if(note<2) return scale*12+2; else if(note<3) return scale*12+4; else if(note<4) return scale*12+5; else if(note<5) return scale*12+7; else if(note<6) return scale*12+9; else return scale*12+11; } private int halfToNote(int halfno) { int scale=halfno/7; int note = halfno%7; if(note<0) return -1; else if(note<1) return scale*12+1; else if(note<2) return scale*12+3; else if(note<3) return scale*-1; else if(note<4) return scale*12+6; else if(note<5) return scale*12+8; else if(note<6) return scale*12+10; else return -1; } /** * field sizes and key key dimensions */ public Dimension getPreferredSize() { return new Dimension(this.getSize().width, 100); } private void setFieldSize(Dimension newsize) { size.setSize(newsize); keyWidth = newsize.width/(keys+1); keysOffset = (newsize.width%(keys+1))/2; halfkeysOffset = (newsize.width%(keys+1)+keyWidth)/2; } /** * mouse listeners : detect key pressed */ public void mouseClicked(MouseEvent e) {} public void mouseEntered(MouseEvent e) {} public void mouseExited(MouseEvent e) {} public void mouseMoved(MouseEvent e) {} /** mouse down: detect the key and post key event to parent*/ public void mousePressed(MouseEvent e) { getKey(e.getX(), e.getY()); } public void mouseDragged(MouseEvent e) { getKey(e.getX(), e.getY()); } /** mouse up: no more key pressed*/ public void mouseReleased(MouseEvent e) {} //{keyPressedEvent(-1,-1); } /** Helper function to detect key pressed*/ private void getKey(int x, int y) { int note =-1; if(y>20 && y<55 && x>halfkeysOffset) //half tones { note=(x-halfkeysOffset)/keyWidth; if(note>=keys || !halfValid[note]) note=-1; else { note=halfToNote(note); keyPressedEvent(note); } } if(y>20 && x>keysOffset && note<0) //either under halfkeys, out of bounds or in field without half key (halfkeys[i]=-1) { note=(x-keysOffset)/keyWidth; if(note>keys) note=-1; else keyPressedEvent(keyToNote(note)); } if(note<0) keyPressedEvent(-1); } /** * Paint */ public void paint(Graphics g) { update(g); } public void update(Graphics g) { if(!size.equals(this.getSize()) ) setFieldSize(this.getSize()); g.setColor(Color.white); g.drawLine(2,2,size.width-2,2); g.drawLine(2,2,2,20); g.drawLine(4,4,4,18); g.drawLine(4,4,18,4); g.setColor(Color.black); g.drawLine(size.width-2,2,size.width-2,20); g.drawLine(2,20,size.width-2,20); g.drawLine(18,4,18,18); g.drawLine(4,18,18,18); g.setColor(Color.red); g.drawLine(6,6,16,16); g.drawLine(6,16,16,6); //draw keys int x=keysOffset+1; int dx=keyWidth-2; for(int i=0; i<=keys; i++) { g.setColor(Color.white); g.fillRect(x,21,dx,77); g.setColor(Color.black); g.drawLine(x,98,x+dx,98); g.drawLine(x+dx,21,x+dx,98); x+=keyWidth; } //draw halfkeys x=halfkeysOffset+1; for(int i=0; i<keys; i++) { if(halfValid[i]) { g.setColor(Color.black); g.fillRect(x,20,dx,35); g.setColor(Color.gray); g.drawLine(x,20,x,54); } x+=keyWidth; } } } /**************************************************************************************************************************************/ /** * Inner class KeyboardLed */ class KeyboardLed extends Component implements Runnable { private Dimension size; // private Rectangle led; width&height are 30 by definition, and with total width=50, x=(50-30)/2, which leaves us with only y private int led_y,led_y30; private int blinkRate; private long blinkTime; private Thread blinkerThread; private boolean flashing; public KeyboardLed() { super(); size = new Dimension(); blinkRate = -1; blinkTime=-1; flashing = false; blinkerThread = null; } /** * Sizes and offset vars */ public Dimension getPreferredSize() { return new Dimension(50,this.getSize().height); } private void setFieldSize(Dimension newsize) { size.setSize(newsize); led_y=(newsize.height-30)/2; led_y30=led_y+30; } /** * setting blink rate & launch runner if needed */ public synchronized void setBlinkRate(int rate) { if(blinkRate<0) { blinkRate = rate; blinkTime = System.currentTimeMillis() + rate; blinkerThread = new Thread(this,"scrollboxThread"); blinkerThread.start(); } else blinkRate = rate; } /** * run: force blinking */ public void run() { if(Thread.currentThread() == blinkerThread) { try { long sleeptime; while(blinkRate>0) { sleeptime = blinkTime - System.currentTimeMillis(); Thread.sleep(sleeptime); blinkTime = System.currentTimeMillis() + blinkRate; flashing = true; this.repaint(); Thread.sleep(120); flashing=false; this.repaint(); } } catch(InterruptedException e) { System.out.println(e.toString() ); } } } /** * Paint */ public void paint(Graphics g) { update(g); } public void update(Graphics g) { if(!size.equals(this.getSize())) setFieldSize(this.getSize()); g.setColor((flashing)?Color.red:Color.lightGray); g.drawLine(10, led_y, 30,led_y30); g.drawLine(10, led_y30, 30,led_y); g.drawLine(10, led_y, 30,led_y); g.drawLine(10, led_y30, 30,led_y30); g.drawLine(10, led_y, 10,led_y30); g.drawLine(30, led_y, 30,led_y30); } } }