package sound.musicg.graphic; import java.awt.Color; import java.awt.Graphics2D; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import javax.imageio.ImageIO; import sound.musicg.wave.Wave; import sound.musicg.wave.extension.Spectrogram; public class GraphicRender{ public static final float WAVEFORM_DEFAULT_TIMESTEP = 0.1F; private int xMarker=-1; private int yMarker=-1; public GraphicRender(){ } /** * Render a waveform of a wave file * * @param wave Wave object * @param filename output file * @see RGB graphic rendered */ public void renderWaveform(Wave wave, String filename) { renderWaveform(wave,WAVEFORM_DEFAULT_TIMESTEP,filename); } /** * Render a waveform of a wave file * * @param wave Wave object * @param timeStep time interval in second, as known as 1/fps * @param filename output file * @see RGB graphic rendered */ public void renderWaveform(Wave wave, float timeStep, String filename) { // for signed signals, the middle is 0 (-1 ~ 1) double middleLine=0; // usually 8bit is unsigned if (wave.getWaveHeader().getBitsPerSample()==8){ // for unsigned signals, the middle is 0.5 (0~1) middleLine=0.5; } double[] nAmplitudes = wave.getNormalizedAmplitudes(); int width = (int) (nAmplitudes.length / wave.getWaveHeader().getSampleRate() / timeStep); int height = 500; int middle = height / 2; int magnifier = 1000; int numSamples = nAmplitudes.length; if (width>0){ int numSamplePerTimeFrame = numSamples / width; int[] scaledPosAmplitudes = new int[width]; int[] scaledNegAmplitudes = new int[width]; // width scaling for (int i = 0; i < width; i++) { double sumPosAmplitude = 0; double sumNegAmplitude = 0; int startSample=i * numSamplePerTimeFrame; for (int j = 0; j < numSamplePerTimeFrame; j++) { double a = nAmplitudes[startSample + j]; if (a > middleLine) { sumPosAmplitude += (a-middleLine); } else { sumNegAmplitude += (a-middleLine); } } int scaledPosAmplitude = (int) (sumPosAmplitude / numSamplePerTimeFrame * magnifier + middle); int scaledNegAmplitude = (int) (sumNegAmplitude / numSamplePerTimeFrame * magnifier + middle); scaledPosAmplitudes[i] = scaledPosAmplitude; scaledNegAmplitudes[i] = scaledNegAmplitude; } // render wave form image BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); // set default white background Graphics2D graphics = bufferedImage.createGraphics(); graphics.setPaint(new Color(255, 255, 255)); graphics.fillRect(0, 0, bufferedImage.getWidth(), bufferedImage.getHeight()); // end set default white background for (int i = 0; i < width; i++) { for (int j = scaledNegAmplitudes[i]; j < scaledPosAmplitudes[i]; j++) { int y = height - j; // j from -ve to +ve, i.e. draw from top to bottom if (y < 0) { y = 0; } else if (y >= height) { y = height - 1; } bufferedImage.setRGB(i, y, 0); } } // end render wave form image // export image try { int dotPos = filename.lastIndexOf("."); String extension=filename.substring(dotPos + 1); ImageIO.write(bufferedImage, extension, new File(filename)); } catch (IOException e) { e.printStackTrace(); } // end export image } else{ System.err.println("renderWaveform error: Empty Wave"); } } /** * Render a spectrogram of a wave file * * @param spectrogram spectrogram object * @param filename output file * @see RGB graphic rendered */ public void renderSpectrogram(Spectrogram spectrogram,String filename){ renderSpectrogramData(spectrogram.getNormalizedSpectrogramData(),filename); } /** * * Render a spectrogram data array * * @param spectrogramData spectrogramData[time][frequency]=intensity, which time is the x-axis, frequency is the y-axis, intensity is the color darkness * @param filename output file * @see RGB graphic rendered */ public void renderSpectrogramData(double[][] spectrogramData, String filename) { if (spectrogramData!=null){ int width=spectrogramData.length; int height=spectrogramData[0].length; BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); for (int i=0; i<width; i++){ if (i==xMarker){ for (int j=0; j<height; j++){ bufferedImage.setRGB(i, j, 0xFF00); // green } } else{ for (int j=0; j<height; j++){ int value; if (j==yMarker){ value=0xFF0000; // red } else{ value=255-(int)(spectrogramData[i][j]*255); } bufferedImage.setRGB(i, height-1-j, value<<16|value<<8|value); } } } try { int dotPos = filename.lastIndexOf("."); String extension=filename.substring(dotPos + 1); ImageIO.write(bufferedImage, extension, new File(filename)); } catch (IOException e) { e.printStackTrace(); } } else{ System.err.println("renderSpectrogramData error: Empty Wave"); } } /** * Set the vertical marker * * @param x x-offset pixel of the marker */ public void setVerticalMarker(int x){ this.xMarker=x; } /** * Set the horizontal marker * * @param y y-offset pixel of the marker */ public void setHorizontalMarker(int y){ this.yMarker=y; } /** * Reset the markers */ public void resetMarkers(){ xMarker=-1; yMarker=-1; } }