You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
177 lines
5.3 KiB
177 lines
5.3 KiB
/*
|
|
* Copyright 2011 Google Inc.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
package com.levien.synthesizer.android.widgets.piano;
|
|
|
|
import android.graphics.Canvas;
|
|
import android.graphics.Color;
|
|
import android.graphics.Paint;
|
|
import android.graphics.Rect;
|
|
import android.util.Log;
|
|
|
|
import com.levien.synthesizer.core.music.Note;
|
|
|
|
/**
|
|
* PianoKey is the abstract base class for any key on the piano.
|
|
* It keeps track of whether the key is currently being pressed.
|
|
*/
|
|
public abstract class PianoKey {
|
|
public PianoKey(PianoView piano) {
|
|
piano_ = piano;
|
|
pressed_ = new boolean[PianoView.FINGERS];
|
|
rect_ = new Rect();
|
|
|
|
for (int i = 0; i < pressed_.length; ++i) {
|
|
pressed_[i] = false;
|
|
}
|
|
|
|
// Set up some default objects for the key to draw itself with.
|
|
fillPaint_ = new Paint();
|
|
strokePaint_ = new Paint();
|
|
fillPaint_.setStyle(Paint.Style.FILL);
|
|
strokePaint_.setStyle(Paint.Style.STROKE);
|
|
strokePaint_.setColor(Color.BLACK);
|
|
}
|
|
|
|
/**
|
|
* Sets rect_ to the position of this key, based on the drawing rect of the piano it's on.
|
|
* @param drawingRect - the position of the piano itself.
|
|
* @param octaves - the number of octaves visible on the piano keyboard.
|
|
*/
|
|
abstract public void layout(Rect drawingRect, int octaves);
|
|
|
|
/**
|
|
* Draws the key in the current rect_.
|
|
*/
|
|
abstract public void draw(Canvas canvas);
|
|
|
|
/**
|
|
* Called when the key's pressed_ state has changed.
|
|
* @param move - true if the key became pressed because the touch moved onto it.
|
|
*/
|
|
abstract protected void onPressedChanged(boolean move);
|
|
|
|
/**
|
|
* Returns true if the given co-ordinate is inside the key's current rect_.
|
|
*/
|
|
public boolean contains(int x_, int y_) {
|
|
return rect_.contains(x_, y_);
|
|
}
|
|
|
|
/**
|
|
* Returns true if any finger is pressing this key.
|
|
*/
|
|
public boolean isPressed() {
|
|
for (int i = 0; i < pressed_.length; ++i) {
|
|
if (pressed_[i]) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Called when a finger has touched down onto this key.
|
|
* Returns true iff whether the pressed state changed.
|
|
*/
|
|
final public boolean onTouchDown(int finger) {
|
|
if (finger >= pressed_.length) {
|
|
Log.e(getClass().getName(),
|
|
"Finger " + finger + " was pressed down, but PianoKey only supports " +
|
|
pressed_.length + " fingers.");
|
|
}
|
|
boolean wasPressed = isPressed();
|
|
pressed_[finger] = true;
|
|
if (!wasPressed) {
|
|
onPressedChanged(false);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Called on a touch event where this key is not being touched. It may already be up.
|
|
* Returns true iff whether the pressed state changed.
|
|
*/
|
|
final public boolean onTouchUp(int finger) {
|
|
if (finger >= pressed_.length) {
|
|
Log.e(getClass().getName(),
|
|
"Finger " + finger + " was released, but PianoKey only supports " +
|
|
pressed_.length + " fingers.");
|
|
}
|
|
boolean wasPressed = isPressed();
|
|
pressed_[finger] = false;
|
|
boolean isPressed = isPressed();
|
|
if (wasPressed && !isPressed) {
|
|
onPressedChanged(false);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Called when there's a touch event where the finger was moved onto this key.
|
|
* Returns true iff whether the pressed state changed.
|
|
*/
|
|
final public boolean onTouchMoved(int finger) {
|
|
if (finger >= pressed_.length) {
|
|
Log.e(getClass().getName(),
|
|
"Finger " + finger + " was pressed down, but PianoKey only supports " +
|
|
pressed_.length + " fingers.");
|
|
}
|
|
boolean wasPressed = isPressed();
|
|
pressed_[finger] = true;
|
|
if (!wasPressed) {
|
|
onPressedChanged(true);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Utility function to calculate the width that a standard white key on this keyboard should be.
|
|
*/
|
|
protected static int getWhiteKeyWidth(Rect drawingRect, int octaves) {
|
|
// It's +2 to reserve space for the octave-up/down buttons.
|
|
return drawingRect.width() / ((WHITE_KEYS.length * octaves) + 2);
|
|
}
|
|
|
|
/**
|
|
* Utility function to calculate the height that a standard white key on this keyboard should be.
|
|
*/
|
|
protected static int getWhiteKeyHeight(Rect drawingRect) {
|
|
return drawingRect.height();
|
|
}
|
|
|
|
// The piano this key is on.
|
|
protected PianoView piano_;
|
|
|
|
// Is each keys currently being pressed?
|
|
protected boolean[] pressed_;
|
|
|
|
// The area this key occupies.
|
|
protected Rect rect_;
|
|
|
|
// Objects for subclasses to use for painting, just so they don't have to reallocate every time.
|
|
protected Paint fillPaint_;
|
|
protected Paint strokePaint_;
|
|
|
|
// Constants to map notes onto the keys.
|
|
protected static final int WHITE_KEYS[] = {
|
|
Note.C, Note.D, Note.E, Note.F, Note.G, Note.A, Note.B };
|
|
protected static final int BLACK_KEYS[] = {
|
|
Note.C_SHARP, Note.E_FLAT, Note.NONE, Note.F_SHARP, Note.A_FLAT, Note.B_FLAT, Note.NONE };
|
|
}
|
|
|