/* * Copyright (c) 2007 P.J.Leonard * * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * 3. The name of the author may not be used to endorse or promote * products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package com.frinika.audio.analysis.gui; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics2D; import java.awt.GraphicsConfiguration; import java.awt.GraphicsEnvironment; import java.awt.Transparency; import java.awt.image.BufferedImage; import java.util.Observable; import java.util.Observer; import com.frinika.audio.analysis.Mapper; import com.frinika.audio.analysis.SpectrogramDataListener; import com.frinika.audio.analysis.SpectrumDataBuilder; /** * * notifies observers if it need to be redrawn (typically the panel(s)) * * update() redoes all the drawing. * * SpectrogramListener * - does image resize * - incrementally redraws as the data become ready. * * @author pjl * */ public class SpectrogramImage extends Observable implements SpectrogramDataListener, Observer { private static final long serialVersionUID = 1L; BufferedImage img; Graphics2D graphic; private int[] rgbarray; Dimension imageSize; Dimension size; int scaleX = 1; int scaleY = 2; private boolean dirty = true; private double thresh; private SpectrumDataBuilder data; static final int nLevel = 256; static Color fcol[] = new Color[nLevel]; { for (int i = 0; i < nLevel; i++) { fcol[i] = new Color(255, 0, 0, i); } } int nChunks; int nBins; private int renderedCount = 0; Mapper mapper; /** * * * @param data * @param mapper */ public SpectrogramImage(SpectrumDataBuilder data, Mapper mapper) { // setDoubleBuffered(false); this.mapper = mapper; this.data = data; // mapper.update(this, null); } void createGraphics() { imageSize = new Dimension(nChunks, nBins); size = new Dimension(nChunks * scaleX, nBins * scaleY); GraphicsEnvironment graphicsEnvironment = GraphicsEnvironment .getLocalGraphicsEnvironment(); GraphicsConfiguration graphicsConfiguration = graphicsEnvironment .getDefaultScreenDevice().getDefaultConfiguration(); img = graphicsConfiguration.createCompatibleImage(imageSize.width, imageSize.height, Transparency.BITMASK); graphic = img.createGraphics(); } private void makeImage() { synchronized (data) { int chunksToRender=data.getChunkRenderedCount(); System.out.println(renderedCount + " -> " + chunksToRender ); nBins = data.getBinCount(); nChunks=data.getSizeInChunks(); if (nChunks == 0 || nBins == 0) return; if (imageSize == null || nBins != imageSize.height || nChunks != imageSize.width) createGraphics(); if (rgbarray == null || rgbarray.length < nBins) { rgbarray = new int[nBins]; } float buffer[][] = data.getMagnitude(); if (buffer == null) return; for (; renderedCount < chunksToRender; renderedCount++) { if (Thread.interrupted()) return; for (int i = 0; i < nBins; i++) { int bin = nBins - i - 1; float val = mapper.eval(buffer[renderedCount][bin]); if (val < 0) val = 0.0f; if (val > 1.0) val = 1.0f; int c_r = (int) (255 * val); int c_g = c_r; int c_b = 255 - c_r; int color = (c_b) + (c_g << 8) + (c_r << 16) + (0xFF << 24); rgbarray[i] = color; } img.setRGB(renderedCount, 0, 1, imageSize.height, rgbarray, 0, 1); } setChanged(); notifyObservers(); } } public void notifySizeChange(Dimension d) { // if (d.equals(size)) // return; renderedCount=0; System.out.println(" Remaking spectrogram image "); makeImage(); } public void drawImage(Graphics2D g, int i, int j) { // System.out.println(" Spectro DRAWIMAGE"); if (img == null) return; g.setColor(Color.WHITE); g.drawImage(img, i, j, size.width, size.height, 0, 0, imageSize.width, imageSize.height, null); g.setColor(Color.GREEN); g.drawString(" Spectrogram ", i + 10, j + 10); } public int getHeight() { if (size == null) return 200; return size.height; } /** * */ public void update(Observable o, Object arg) { System.out.println(" Spectrogram image update "); // null argument means I need to draw whole image renderedCount=0; makeImage(); } public void notifyMoreDataReady() { makeImage(); } public float pixToBin(int curY) { float bin=(int) (nBins-(curY+1.5)/scaleY); //System.out.println(bin); if (bin <0.0)bin=0.0f; return bin; } }