package com.codefixia.drumcloud;
import java.util.LinkedList;
import com.codefixia.ui.ToggleButton;
import processing.core.PApplet;
import processing.core.PVector;
public class Sequencer {
private final DrumCloud drumCloud;
Sequencer(DrumCloud drumCloud) {
this.drumCloud = drumCloud;
}
ToggleButton[][] tracks;
float buttonWidth=0;
float buttonHeight=0;
float barOffset=0,lastBarOffset=0;
float xOffset=0, yOffset=0;
float totalHeight;
float maxTotalHeight;
float totalWidth;
float maxTotalWidth;
float visibleHeight;
float visibleWidth;
int lastClickX=5000;
int lastClickY=5000;
int displacementX=0;
int displacementY=0;
float verticalScrollBarOffset=0;
float horizontalScrollBarOffset=0;
float scrollBarYSize;
float scrollBarXSize;
float scrollBarWidth;
float playBarWidth;
int miniMapOriginX;
int miniMapOriginY;
float miniMapScale=0.1f;
LinkedList<Integer> mouseMovesX=new LinkedList<Integer>();
LinkedList<Integer> mouseMovesY=new LinkedList<Integer>();
float maxAccel=40;
float velocityX=0;
float velocityY=0;
float friction=1;
boolean released=false;
private float zoom=1.0f;
public void setup() {
buttonWidth=(float)(drumCloud.width/drumCloud.totalSamples);
buttonHeight=buttonWidth;
tracks=new ToggleButton[drumCloud.totalSamples][drumCloud.totalGrids+1];
totalHeight=(drumCloud.totalGrids+1)*buttonHeight+drumCloud.height*0.05f;
maxTotalHeight=totalHeight;
totalWidth=(drumCloud.totalSamples)*buttonWidth;
maxTotalWidth=totalWidth;
playBarWidth=(drumCloud.totalSamples)*buttonWidth;
visibleHeight=drumCloud.height;
visibleWidth=drumCloud.width;
scrollBarYSize=(visibleHeight/totalHeight)*visibleHeight;
scrollBarXSize=(visibleWidth/totalWidth)*visibleWidth;
scrollBarWidth=drumCloud.width*0.02f;
miniMapOriginX=(int) (drumCloud.width*0.05f);
miniMapOriginY=(int) (drumCloud.height*0.778f);
for (int i=0;i<drumCloud.samplesPerBeat.length;i++) {
for (int j=0;j<drumCloud.samplesPerBeat[i].length+1;j++) {
tracks[i][j]=new ToggleButton(drumCloud.width-((i+1)*buttonWidth), j*buttonHeight, buttonWidth, buttonHeight);
if (j==0) {
tracks[i][j].setText((i%4)+1+"");
}
if (((j-1)/8)%2==0) {
switch((int)i/4) {
case 0:
tracks[i][j].setFillColor(drumCloud.redColor);
break;
case 1:
tracks[i][j].setFillColor(drumCloud.orangeColor);
break;
case 2:
tracks[i][j].setFillColor(drumCloud.blueColor);
break;
case 3:
tracks[i][j].setFillColor(drumCloud.greenColor);
break;
}
}
else {
switch((int)i/4) {
case 0:
tracks[i][j].setFillColor(drumCloud.color(drumCloud.red(drumCloud.redColor)*0.9f, drumCloud.green(drumCloud.redColor)*0.9f, drumCloud.blue(drumCloud.redColor)*0.9f));
break;
case 1:
tracks[i][j].setFillColor(drumCloud.color(drumCloud.red(drumCloud.orangeColor)*0.9f, drumCloud.green(drumCloud.orangeColor)*0.9f, drumCloud.blue(drumCloud.orangeColor)*0.9f));
break;
case 2:
tracks[i][j].setFillColor(drumCloud.color(drumCloud.red(drumCloud.blueColor)*0.9f, drumCloud.green(drumCloud.blueColor)*0.9f, drumCloud.blue(drumCloud.blueColor)*0.9f));
break;
case 3:
tracks[i][j].setFillColor(drumCloud.color(drumCloud.red(drumCloud.greenColor)*0.9f, drumCloud.green(drumCloud.greenColor)*0.9f, drumCloud.blue(drumCloud.greenColor)*0.9f));
break;
}
}
}
}
}
public void drawScrollBars() {
drumCloud.fill(127, 127);
drumCloud.noStroke();
//println("YBar posY:"+yOffset+" restY"+(totalHeight-visibleHeight)+" sizeH:"+(visibleHeight/totalHeight)*visibleHeight);
float scrollYPos=PApplet.map(yOffset, 0, (totalHeight-visibleHeight)/this.zoom, 0, visibleHeight-scrollBarYSize);
drumCloud.rect(drumCloud.width*0.005f, scrollYPos, scrollBarWidth, scrollBarYSize);
//println("XBar posX:"+xOffset+" restX"+(totalWidth-visibleWidth)+" sizeH:"+(totalWidth/visibleWidth)*visibleWidth);
float scrollXPos=PApplet.map(xOffset, 0, (totalWidth-visibleWidth)/this.zoom, 0, visibleWidth-scrollBarXSize);
drumCloud.rect(scrollXPos, drumCloud.height-(drumCloud.width*0.025f), scrollBarXSize, scrollBarWidth);
}
public void drawPlayBar() {
if (drumCloud.pausedMS<0) {
drumCloud.fill(drumCloud.yellowColor,180.0f);
barOffset=PApplet.map((drumCloud.millis()-drumCloud.totalPaused)%drumCloud.tempoMS, 0.0f, drumCloud.tempoMS, buttonHeight, maxTotalHeight);
lastBarOffset=barOffset;
//println("barOffset:"+barOffset+" val:"+(millis()-totalPaused)%tempoMS);
drumCloud.rect(visibleWidth-maxTotalWidth, barOffset, maxTotalWidth, buttonHeight);
}else{
drumCloud.fill(150,180.0f);
drumCloud.rect(visibleWidth-maxTotalWidth, lastBarOffset, maxTotalWidth, buttonHeight);
}
}
public void updateState() {
for (int i=0;i<drumCloud.samplesPerBeat.length;i++) {
for (int j=1;j<drumCloud.samplesPerBeat[i].length+1;j++) {
tracks[drumCloud.getSampleIndexBySoundType(i)][j].setON(drumCloud.samplesPerBeat[i][j-1]);
}
}
}
public void draw() {
processDrawAccel();
drumCloud.pushMatrix();
drumCloud.scale(this.zoom, this.zoom);
drumCloud.translate(-xOffset, -yOffset);
//drumCloud.translate(xScaleFix, 0);
for (int i=0;i<drumCloud.samplesPerBeat.length;i++) {
for (int j=0;j<drumCloud.samplesPerBeat[i].length+1;j++) {
tracks[i][j].drawState();
}
}
drawPlayBar();
drumCloud.popMatrix();
drawScrollBars();
drawMiniMap();
//debug();
}
public void mousePressed(float x, float y) {
mousePressed((int)x, (int)y);
}
public void mousePressed(int mouseX, int mouseY) {
//PApplet.println("Press on sequencer mx:"+drumCloud.mouseX+" my:"+drumCloud.mouseY);
lastClickX=mouseX;
lastClickY=mouseY;
released=false;
}
public void mouseReleased(float x, float y) {
displacementX=0;
displacementY=0;
mouseReleased((int)x, (int)y);
}
public PVector mouseToScreen(int x, int y) {
return new PVector((x/this.zoom)+xOffset, (y/this.zoom)+yOffset);
}
public void mouseReleased(int mouseX, int mouseY) {
//PApplet.println("Release on sequencer mx:"+drumCloud.mouseX+" my:"+drumCloud.mouseY);
if(mouseY>drumCloud.height*0.95f){
return;
}
PVector screenCoords=mouseToScreen(mouseX, mouseY);
for (int i=0;i<drumCloud.samplesPerBeat.length;i++) {
for (int j=1;j<drumCloud.samplesPerBeat[i].length+1;j++) {
if (displacementX<buttonWidth*0.5 && displacementY<buttonHeight*0.5) {//dist(mouseX,mouseY,lastClickX,lastClickY)<buttonWidth){
if (tracks[i][j].isReleased((int)screenCoords.x, (int)screenCoords.y)) {
int soundGroup=(i/4)+((i%4)*4);
//println("From:"+i+" to:"+soundGroup);
drumCloud.samplesPerBeat[soundGroup][j-1]=!drumCloud.samplesPerBeat[soundGroup][j-1];
}
}
else {
tracks[i][j].cancelClick();
}
}
}
displacementX=0;
displacementY=0;
released=true;
}
public void debug() {
drumCloud.text("OFFSET("+xOffset+","+yOffset+")", drumCloud.width*0.2f, drumCloud.height*0.1f);
drumCloud.text("TOTAL("+totalWidth+","+totalHeight+")", drumCloud.width*0.25f, drumCloud.height*0.2f);
drumCloud.text("VISIBLE("+visibleWidth+","+visibleHeight+")", drumCloud.width*0.25f, drumCloud.height*0.3f);
}
public void drawMiniMap() {
drumCloud.rect(miniMapOriginX+xOffset*0.1f, miniMapOriginY+yOffset*0.1f, visibleWidth/this.zoom*0.1f, visibleHeight/this.zoom*0.1f);
drumCloud.rect(miniMapOriginX, miniMapOriginY, maxTotalWidth*0.1f, maxTotalHeight*0.1f);
for (int i=0;i<drumCloud.samplesPerBeat.length;i++) {
for (int j=1;j<drumCloud.samplesPerBeat[i].length+1;j++) {
drumCloud.noFill();
drumCloud.stroke(150);
if (tracks[i][j].isON())
drumCloud.rect(miniMapOriginX+tracks[i][j].getX()*miniMapScale,
miniMapOriginY+tracks[i][j].getY()*miniMapScale,
tracks[i][j].getW()*miniMapScale, tracks[i][j].getH()*miniMapScale);
}
}
}
public void processDrawAccel() {
if (velocityY!=0 && released) {
yOffset+=velocityY;
limitOffsetY();
if (velocityY>friction*2)
velocityY-=friction;
else if (velocityY<-friction*2)
velocityY+=friction;
else velocityY=0;
}
if (velocityX!=0 && released) {
xOffset+=velocityX;
limitOffsetX();
if (velocityX>friction*2)
velocityX-=friction;
else if (velocityX<-friction*2)
velocityX+=friction;
else velocityX=0;
}
}
public void limitOffsetX(){
xOffset=PApplet.constrain(xOffset, 0, (totalWidth-visibleWidth)/this.zoom);
}
public void limitOffsetY(){
yOffset=PApplet.constrain(yOffset, 0, (totalHeight-visibleHeight)/this.zoom);
}
public void processDragAccel(int pmouseX, int pmouseY, int mouseX, int mouseY) {
int distX=pmouseX-mouseX;
int distY=pmouseY-mouseY;
xOffset+=distX;
limitOffsetX();
yOffset+=distY;
limitOffsetY();
displacementX+=PApplet.abs(distX);
displacementY+=PApplet.abs(distY);
//println("DisX:"+displacementX+" DisY:"+displacementY);
if (mouseMovesY.size()>=3) {
mouseMovesY.remove();
mouseMovesX.remove();
}
mouseMovesY.add(distY);
mouseMovesX.add(distX);
int size=mouseMovesY.size();
float avgY = 0, avgX = 0;
for (int i=0;i<size;i++) {
avgY+=(float)mouseMovesY.get(i);
avgX+=(float)mouseMovesX.get(i);
}
avgY/=size;
avgX/=size;
velocityY=PApplet.map(PApplet.constrain(avgY, -25, 25), -25, 25, -maxAccel, maxAccel);
velocityX=PApplet.map(PApplet.constrain(avgX, -25, 25), -25, 25, -maxAccel, maxAccel);
}
public void mouseDragged(int pmouseX,int pmouseY,int mouseX,int mouseY) {
//println("Drag on sequencer mx:"+mouseX+" my:"+mouseY);
processDragAccel(pmouseX, pmouseY, mouseX, mouseY);
for (int i=0;i<drumCloud.samplesPerBeat.length;i++) {
for (int j=1;j<drumCloud.samplesPerBeat[i].length+1;j++) {
tracks[i][j].isDragging(drumCloud.mouseX+(int)xOffset, drumCloud.mouseY+(int)yOffset);
}
}
released=false;
}
public void mouseMoved() {
PApplet.println("Moved on sequencer px:"+drumCloud.pmouseX+" py:"+drumCloud.pmouseY+" mx:"+drumCloud.mouseX+" my:"+drumCloud.mouseY);
}
public void changeZoom(int centerX, int centerY, float pinchAmount) {
if ( (pinchAmount>0 && this.zoom<2.0)||(pinchAmount<0 && this.zoom>1.0f) ) {
this.zoom=PApplet.constrain(this.zoom+pinchAmount * 0.003f, 1, 2.0f);
float newButtonWidth=(float)(drumCloud.width/drumCloud.totalSamples*this.zoom);
totalHeight=(drumCloud.totalGrids+1)*newButtonWidth+drumCloud.height*0.05f;
playBarWidth=totalHeight;
totalWidth=(drumCloud.totalSamples)*newButtonWidth;
scrollBarYSize=(visibleHeight/totalHeight)*visibleHeight;
scrollBarXSize=(visibleWidth/totalWidth)*visibleWidth;
limitOffsetX();
limitOffsetY();
}
}
}