package ch.retorte.intervalmusiccompositor.compilation;
import javafx.scene.image.WritableImage;
import javafx.scene.paint.Color;
import java.util.List;
/**
* @author nw
*/
class EnvelopeImage {
private WritableImage writableImage;
private int width = 0;
private int height = 0;
private int background_red = 245;
private int background_green = 245;
private int background_blue = 245;
private int env_red = 55;
private int env_green = 119;
private int env_blue = 248;
private int env_mean_red = 113;
private int env_mean_green = 174;
private int env_mean_blue = 243;
EnvelopeImage(Integer width, Integer height) {
writableImage = new WritableImage(width, height);
this.width = width;
this.height = height;
// Initialize image with color
fill(background_red, background_green, background_blue);
}
void generateEnvelope(byte[] audioByteArray, List<Integer> soundPattern, List<Integer> breakPattern, int iterations) {
if (audioByteArray == null || audioByteArray.length == 0) {
return;
}
int samples = audioByteArray.length / 4;
int samplesPerPixel = (samples / width);
// Adjust samplesPerPixel to something dividable by 4 by rounding
if (samplesPerPixel % 4 != 0) {
samplesPerPixel = samplesPerPixel - (samplesPerPixel % 4);
}
int[] aggregatedAudioIntArrayLeft = new int[width];
int[] aggregatedAudioIntArrayRight = new int[width];
int[] aggregatedAudioIntArrayLeftMean = new int[width];
int[] aggregatedAudioIntArrayRightMean = new int[width];
int leftSample = 0;
int rightSample = 0;
for (int i = 0; i < width; i++) {
aggregatedAudioIntArrayLeftMean[i] = 0;
aggregatedAudioIntArrayRightMean[i] = 0;
// Go through audio byte array and make an aggregated int array out of it
for (int j = (i * samplesPerPixel); j < ((i + 1) * samplesPerPixel); j++) {
leftSample = Math.abs(bytesToInt16(audioByteArray, (4 * j), false));
rightSample = Math.abs(bytesToInt16(audioByteArray, (4 * j) + 2, false));
aggregatedAudioIntArrayLeft[i] = Math.max(aggregatedAudioIntArrayLeft[i], leftSample);
aggregatedAudioIntArrayRight[i] = Math.max(aggregatedAudioIntArrayRight[i], rightSample);
aggregatedAudioIntArrayLeftMean[i] += leftSample;
aggregatedAudioIntArrayRightMean[i] += rightSample;
}
aggregatedAudioIntArrayLeftMean[i] = aggregatedAudioIntArrayLeftMean[i] / samplesPerPixel;
aggregatedAudioIntArrayRightMean[i] = aggregatedAudioIntArrayRightMean[i] / samplesPerPixel;
drawEnvelopeAmplitude(i, (double) aggregatedAudioIntArrayLeft[i] / 32767, (double) aggregatedAudioIntArrayRight[i] / 32767, env_red, env_green, env_blue);
drawEnvelopeAmplitude(i, (double) aggregatedAudioIntArrayLeftMean[i] / 32767, (double) aggregatedAudioIntArrayRightMean[i] / 32767, env_mean_red, env_mean_green, env_mean_blue);
}
}
private void drawEnvelopeAmplitude(int x_px_position, double amp_left, double amp_right, int red, int green, int blue) {
if (1 < amp_left) {
amp_left = 1;
}
if (amp_left < 0) {
amp_left = 0;
}
if (1 < amp_right) {
amp_right = 1;
}
if (amp_right < 0) {
amp_right = 0;
}
// Calculate the respective left and right pixel values
int centerPixel = height / 2;
int left = centerPixel;
int right = height - centerPixel;
// Draw left (which is from center to top)
for (int i = centerPixel; i > ((int) (left * (1 - amp_left))); i--) {
setPixel(x_px_position, i, red, green, blue);
}
// Draw right (which is from center to bottom)
for (int i = centerPixel; i < centerPixel + ((int) (right * (amp_right))); i++) {
setPixel(x_px_position, i, red, green, blue);
}
}
private void setPixel(int x, int y, int red, int green, int blue) {
writableImage.getPixelWriter().setColor(x, y, Color.rgb(red, green, blue));
}
private void fill(int red, int green, int blue) {
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
setPixel(j, i, red, green, blue);
}
}
}
WritableImage getBufferedImage() {
return writableImage;
}
/**
* Taken from org.tritonus.share.sampled.TConversionTool.
*/
private int bytesToInt16(byte[] buffer, int byteOffset, boolean bigEndian) {
if (bigEndian) {
return ((buffer[byteOffset] << 8) | (buffer[byteOffset + 1] & 0xFF));
}
return ((buffer[byteOffset + 1] << 8) | (buffer[byteOffset] & 0xFF));
}
}