public void setMatrix(boolean[][] newMatrix) {
    if (newMatrix == null) {
      throw new NullPointerException("setMatrix cannot be called on a null matrix.");
    } else if (newMatrix.length != ToneMatrixConstants.size()) {
      throw new IllegalArgumentException("Incorrect size for setMatrix");
    } else {
      int row;
      for (row = 0; row < newMatrix.length; ++row) {
        if (newMatrix[row] == null) {
          throw new IllegalArgumentException("Inner array is null.");
        }

        if (newMatrix[row].length != ToneMatrixConstants.size()) {
          throw new IllegalArgumentException("Incorrect size for setMatrix");
        }
      }

      for (row = 0; row < ToneMatrixConstants.size(); ++row) {
        for (int col = 0; col < ToneMatrixConstants.size(); ++col) {
          this.matrix[ToneMatrixConstants.size() - 1 - row][col] = newMatrix[row][col];
        }
      }

      this.redrawAll();
    }
  }
 public void clear() {
   for (int i = 0; i < ToneMatrixConstants.size(); ++i) {
     for (int j = 0; j < ToneMatrixConstants.size(); ++j) {
       this.markAt(i, j, false);
     }
   }
 }
 private void recalculateGeometry() {
   this.xScale = (double) this.getWidth() / (double) ToneMatrixConstants.size();
   this.yScale = (double) this.getHeight() / (double) ToneMatrixConstants.size();
   this.xScale = this.yScale = Math.min(this.xScale, this.yScale);
   this.xTrans =
       ((double) this.getWidth() - this.xScale * (double) ToneMatrixConstants.size()) / 2.0D;
   this.yTrans =
       ((double) this.getHeight() - this.yScale * (double) ToneMatrixConstants.size()) / 2.0D;
 }
  public boolean[][] getMatrix() {
    boolean[][] result = new boolean[ToneMatrixConstants.size()][ToneMatrixConstants.size()];

    for (int i = 0; i < ToneMatrixConstants.size(); ++i) {
      for (int j = 0; j < ToneMatrixConstants.size(); ++j) {
        result[ToneMatrixConstants.size() - 1 - i][j] = this.matrix[i][j];
      }
    }

    return result;
  }
  public void highlightColumn(int column) {
    if (column < 0 || column >= ToneMatrixConstants.size()) {
      column = -1;
    }

    this.highlightedColumn = column;
    this.redrawAll();
  }
  private void redrawAll() {
    for (int row = 0; row < ToneMatrixConstants.size(); ++row) {
      for (int col = 0; col < ToneMatrixConstants.size(); ++col) {
        this.matrixRects[row][col].setBounds(
            this.xScale * (double) col + this.xTrans,
            this.yScale * (double) row + this.yTrans,
            this.xScale,
            this.yScale);
        this.matrixRects[row][col].setFillColor(this.matrix[row][col] ? LIT_COLOR : UNLIT_COLOR);
      }
    }

    if (this.highlightedColumn == -1) {
      this.highlightRect.setBounds(0.0D, 0.0D, 0.0D, 0.0D);
    } else {
      this.highlightRect.setBounds(
          this.xScale * (double) this.highlightedColumn + this.xTrans,
          this.yTrans,
          this.xScale,
          this.yScale * (double) ToneMatrixConstants.size());
    }
  }
  public ToneMatrixDisplay() {
    this.setBackground(BACKGROUND_COLOR);

    for (int i = 0; i < ToneMatrixConstants.size(); ++i) {
      for (int j = 0; j < ToneMatrixConstants.size(); ++j) {
        this.matrixRects[i][j] = new GRect(0.0D, 0.0D, 0.0D, 0.0D);
        this.matrixRects[i][j].setFilled(true);
        this.matrixRects[i][j].setColor(Color.BLACK);
        this.matrixRects[i][j].setFillColor(UNLIT_COLOR);
        this.add(this.matrixRects[i][j]);
      }
    }

    this.highlightRect = new GRect(0.0D, 0.0D, 0.0D, 0.0D);
    this.highlightRect.setFilled(true);
    this.highlightRect.setColor(HIGHLIGHT_RECT_COLOR);
    this.add(this.highlightRect);
    this.setPreferredSize(
        new Dimension(ToneMatrixConstants.size() * 20, ToneMatrixConstants.size() * 20));
    this.addMouseListener(this);
    this.addMouseMotionListener(this);
    this.addComponentListener(this);
  }
  /**
   * Given the contents of the tone matrix, returns a string of notes that should be played to
   * represent that matrix.
   *
   * @param toneMatrix The contents of the tone matrix.
   * @param column The column number that is currently being played.
   * @param samples The sound samples associated with each row.
   * @return A sound sample corresponding to all notes currently being played.
   */
  public static double[] matrixToMusic(boolean[][] toneMatrix, int column, double[][] samples) {
    double[] result = new double[ToneMatrixConstants.sampleSize()];
    Arrays.fill(result, 0);
    double max = 1, min = -1, divider = 1;

    for (int i = 0; i < toneMatrix.length; ++i) {
      if (toneMatrix[i][column]) {
        for (int j = 0; j < samples[column].length; ++j) {
          /* calculates sum for every value of the column for samples */
          result[j] += samples[i][j];

          /* getting max and min values of the calculated result */
          if (result[j] > max) {
            max = result[j];
          }

          if (result[j] < min) {
            min = result[j];
          }
        }
      }
    }

    /* check for normalizing divider */
    if (max != 1 && max > Math.abs(min)) {
      divider = max;
    } else if (min != -1 && Math.abs(min) > max) {
      divider = min;
    }

    /* if we need to normalize wave, we going through result wave and divide each value for max value, that we got earlier */
    if (divider != 1) {
      for (int i = 0; i < result.length; ++i) {
        result[i] /= divider;
      }
    }

    return result;
  }
 private boolean inBounds(int row, int col) {
   return row >= 0
       && col >= 0
       && row < ToneMatrixConstants.size()
       && col < ToneMatrixConstants.size();
 }
public class ToneMatrixDisplay extends GCanvas
    implements MouseListener, MouseMotionListener, ComponentListener {
  private static final int GSCALE = 20;
  private static final Color LIT_COLOR = new Color(232, 232, 232);
  private static final Color UNLIT_COLOR = (new Color(134, 110, 255)).darker();
  private static final Color HIGHLIGHT_RECT_COLOR = new Color(255, 255, 0, 128);
  private static final Color BACKGROUND_COLOR;
  private boolean[][] matrix = new boolean[ToneMatrixConstants.size()][ToneMatrixConstants.size()];
  private GRect[][] matrixRects = new GRect[ToneMatrixConstants.size()][ToneMatrixConstants.size()];
  private double xScale;
  private double yScale;
  private double xTrans;
  private double yTrans;
  private boolean isMarking;
  private GRect highlightRect;
  private volatile int highlightedColumn = -1;

  static {
    BACKGROUND_COLOR = Color.GRAY;
  }

  public ToneMatrixDisplay() {
    this.setBackground(BACKGROUND_COLOR);

    for (int i = 0; i < ToneMatrixConstants.size(); ++i) {
      for (int j = 0; j < ToneMatrixConstants.size(); ++j) {
        this.matrixRects[i][j] = new GRect(0.0D, 0.0D, 0.0D, 0.0D);
        this.matrixRects[i][j].setFilled(true);
        this.matrixRects[i][j].setColor(Color.BLACK);
        this.matrixRects[i][j].setFillColor(UNLIT_COLOR);
        this.add(this.matrixRects[i][j]);
      }
    }

    this.highlightRect = new GRect(0.0D, 0.0D, 0.0D, 0.0D);
    this.highlightRect.setFilled(true);
    this.highlightRect.setColor(HIGHLIGHT_RECT_COLOR);
    this.add(this.highlightRect);
    this.setPreferredSize(
        new Dimension(ToneMatrixConstants.size() * 20, ToneMatrixConstants.size() * 20));
    this.addMouseListener(this);
    this.addMouseMotionListener(this);
    this.addComponentListener(this);
  }

  private void redrawAll() {
    for (int row = 0; row < ToneMatrixConstants.size(); ++row) {
      for (int col = 0; col < ToneMatrixConstants.size(); ++col) {
        this.matrixRects[row][col].setBounds(
            this.xScale * (double) col + this.xTrans,
            this.yScale * (double) row + this.yTrans,
            this.xScale,
            this.yScale);
        this.matrixRects[row][col].setFillColor(this.matrix[row][col] ? LIT_COLOR : UNLIT_COLOR);
      }
    }

    if (this.highlightedColumn == -1) {
      this.highlightRect.setBounds(0.0D, 0.0D, 0.0D, 0.0D);
    } else {
      this.highlightRect.setBounds(
          this.xScale * (double) this.highlightedColumn + this.xTrans,
          this.yTrans,
          this.xScale,
          this.yScale * (double) ToneMatrixConstants.size());
    }
  }

  private void recalculateGeometry() {
    this.xScale = (double) this.getWidth() / (double) ToneMatrixConstants.size();
    this.yScale = (double) this.getHeight() / (double) ToneMatrixConstants.size();
    this.xScale = this.yScale = Math.min(this.xScale, this.yScale);
    this.xTrans =
        ((double) this.getWidth() - this.xScale * (double) ToneMatrixConstants.size()) / 2.0D;
    this.yTrans =
        ((double) this.getHeight() - this.yScale * (double) ToneMatrixConstants.size()) / 2.0D;
  }

  private boolean inBounds(int row, int col) {
    return row >= 0
        && col >= 0
        && row < ToneMatrixConstants.size()
        && col < ToneMatrixConstants.size();
  }

  private void markAt(int row, int col, boolean set) {
    if (this.inBounds(row, col)) {
      this.matrix[row][col] = set;
      this.matrixRects[row][col].setFillColor(set ? LIT_COLOR : UNLIT_COLOR);
    }
  }

  public void clear() {
    for (int i = 0; i < ToneMatrixConstants.size(); ++i) {
      for (int j = 0; j < ToneMatrixConstants.size(); ++j) {
        this.markAt(i, j, false);
      }
    }
  }

  public void mouseDragged(MouseEvent e) {
    int x = (int) (((double) e.getX() - this.xTrans) / this.xScale);
    int y = (int) (((double) e.getY() - this.yTrans) / this.yScale);
    this.markAt(y, x, this.isMarking);
  }

  public void mousePressed(MouseEvent e) {
    int x = (int) (((double) e.getX() - this.xTrans) / this.xScale);
    int y = (int) (((double) e.getY() - this.yTrans) / this.yScale);
    if (this.inBounds(y, x)) {
      this.isMarking = !this.matrix[y][x];
    }

    this.markAt(y, x, this.isMarking);
  }

  public void mouseClicked(MouseEvent arg0) {}

  public void mouseEntered(MouseEvent arg0) {}

  public void mouseExited(MouseEvent arg0) {}

  public void mouseReleased(MouseEvent arg0) {}

  public void mouseMoved(MouseEvent arg0) {}

  public void componentHidden(ComponentEvent arg0) {}

  public void componentMoved(ComponentEvent arg0) {}

  public void componentShown(ComponentEvent arg0) {}

  public void componentResized(ComponentEvent arg0) {
    this.recalculateGeometry();
    this.redrawAll();
  }

  public boolean[][] getMatrix() {
    boolean[][] result = new boolean[ToneMatrixConstants.size()][ToneMatrixConstants.size()];

    for (int i = 0; i < ToneMatrixConstants.size(); ++i) {
      for (int j = 0; j < ToneMatrixConstants.size(); ++j) {
        result[ToneMatrixConstants.size() - 1 - i][j] = this.matrix[i][j];
      }
    }

    return result;
  }

  public void setMatrix(boolean[][] newMatrix) {
    if (newMatrix == null) {
      throw new NullPointerException("setMatrix cannot be called on a null matrix.");
    } else if (newMatrix.length != ToneMatrixConstants.size()) {
      throw new IllegalArgumentException("Incorrect size for setMatrix");
    } else {
      int row;
      for (row = 0; row < newMatrix.length; ++row) {
        if (newMatrix[row] == null) {
          throw new IllegalArgumentException("Inner array is null.");
        }

        if (newMatrix[row].length != ToneMatrixConstants.size()) {
          throw new IllegalArgumentException("Incorrect size for setMatrix");
        }
      }

      for (row = 0; row < ToneMatrixConstants.size(); ++row) {
        for (int col = 0; col < ToneMatrixConstants.size(); ++col) {
          this.matrix[ToneMatrixConstants.size() - 1 - row][col] = newMatrix[row][col];
        }
      }

      this.redrawAll();
    }
  }

  public void highlightColumn(int column) {
    if (column < 0 || column >= ToneMatrixConstants.size()) {
      column = -1;
    }

    this.highlightedColumn = column;
    this.redrawAll();
  }
}