package com.github.davidmoten.ar;

import static org.junit.Assert.assertEquals;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import javax.imageio.ImageIO;

import org.junit.Test;

import rx.functions.Action1;
import rx.functions.Func1;

public class AudioTest {

	@Test
	public void testReadUsingObservable() {
		int count = Audio
				.readSignal(
						AudioTest.class.getResourceAsStream("/alphabet.wav"))
				.count().toBlocking().single();
		assertEquals(296934, count);
	}

	@Test
	public void testReadUsingObservableAndFft() {
		final int bufferSize = 256;
		final BufferedImage image = new BufferedImage(1200, bufferSize,
				BufferedImage.TYPE_INT_ARGB);
		Func1<List<Integer>, List<Double>> toFft = new Func1<List<Integer>, List<Double>>() {

			@Override
			public List<Double> call(List<Integer> signal) {
				if (signal.size() == bufferSize) {
					Complex[] spectrum = FFT.fft(Complex.toComplex(signal));
					List<Double> list = new ArrayList<Double>(spectrum.length);
					for (Complex c : spectrum)
						list.add(c.abs());
					return list;
				} else
					return Collections.emptyList();
			}
		};
		Audio.readSignal(AudioTest.class.getResourceAsStream("/alphabet.wav"))
		// buffer
				.buffer(bufferSize)
				// extract frequenciess
				.map(toFft)
				// get all
				.toList().doOnNext(draw(image))
				// go
				.subscribe();
		;
	}

	private static Color toColor(double d) {
		return Color.getHSBColor(1f - (float) d, 1f, (float) d * 1.0f);
	}

	private static Action1<List<List<Double>>> draw(final BufferedImage image) {
		return new Action1<List<List<Double>>>() {
			@Override
			public void call(List<List<Double>> all) {
				Graphics2D g = image.createGraphics();
				Double min = null;
				Double max = null;
				for (List<Double> list : all)
					for (double d : list) {
						double dlog = Math.max(0, Math.log10(d));
						if (min == null || min > dlog)
							min = dlog;
						if (max == null || max < dlog)
							max = dlog;
					}
				int sample = 0;

				for (List<Double> list : all) {
					int freq = 0;
					for (double d : list) {
						double prop = Math.max(
								0,
								Math.min(1.0, (Math.log10(d) - min)
										/ (max - min)));
						Color color = toColor(prop);
						g.setColor(color);
						g.fillRect(sample,
								(freq + list.size() / 2) % list.size(), 1, 1);
						freq++;
					}
					sample += 1;
				}
				try {
					ImageIO.write(image, "png", new File("target/image.png"));
				} catch (IOException e) {
					throw new RuntimeException(e);
				}
			}
		};
	}
}

@@ -647,16 +647,125 @@
 t);%0A%09%7D%0A%0A
+%09private static final int pixelsPerVerticalCell = 1;%0A%09private static final int pixelsPerHorizontalCell = 8;%0A%0A
 %09@Test%0A%09
@@ -892,12 +892,43 @@
 age(
-1200
+%0A%09%09%09%091200 * pixelsPerHorizontalCell
 , bu
@@ -935,22 +935,48 @@
 fferSize
-,
 %0A%09%09%09%09
+%09%09* pixelsPerVerticalCell, 
 Buffered
@@ -2106,16 +2106,47 @@
 t : all)
+ %7B%0A%09%09%09%09%09boolean isFirst = true;
 %0A%09%09%09%09%09fo
@@ -2159,32 +2159,55 @@
 ble d : list) %7B%0A
+%09%09%09%09%09%09if (!isFirst) %7B%0A%09
 %09%09%09%09%09%09double dlo
@@ -2240,24 +2240,25 @@
 (d));%0A%09%09%09%09%09%09
+%09
 if (min == n
@@ -2272,24 +2272,25 @@
 min %3E dlog)%0A
+%09
 %09%09%09%09%09%09%09min =
@@ -2298,24 +2298,25 @@
 dlog;%0A%09%09%09%09%09%09
+%09
 if (max == n
@@ -2341,16 +2341,17 @@
 %0A%09%09%09%09%09%09%09
+%09
 max = dl
@@ -2354,23 +2354,60 @@
 = dlog;%0A
+%09%09%09%09%09%09%7D%0A%09%09%09%09%09%09isFirst = false;%0A
 %09%09%09%09%09%7D%0A
+%09%09%09%09%7D%0A
 %09%09%09%09int 
@@ -2698,16 +2698,42 @@
 t(sample
+ * pixelsPerHorizontalCell
 ,%0A%09%09%09%09%09%09
@@ -2776,14 +2776,98 @@
 ze()
-, 1, 1
+%0A%09%09%09%09%09%09%09%09%09%09* pixelsPerVerticalCell,%0A%09%09%09%09%09%09%09%09pixelsPerHorizontalCell, pixelsPerVerticalCell
 );%0A%09

change image dimensions