diff options
-rw-r--r-- | src/com/pheelicks/visualizer/AudioData.java | 11 | ||||
-rw-r--r-- | src/com/pheelicks/visualizer/FFTData.java | 11 | ||||
-rw-r--r-- | src/com/pheelicks/visualizer/VisualizerView.java | 435 | ||||
-rw-r--r-- | src/com/pheelicks/visualizer/renderer/BarGraphRenderer.java | 95 | ||||
-rw-r--r-- | src/com/pheelicks/visualizer/renderer/CircleBarRenderer.java | 200 | ||||
-rw-r--r-- | src/com/pheelicks/visualizer/renderer/CircleRenderer.java | 171 | ||||
-rw-r--r-- | src/com/pheelicks/visualizer/renderer/LineRenderer.java | 155 | ||||
-rw-r--r-- | src/com/pheelicks/visualizer/renderer/Renderer.java | 101 |
8 files changed, 644 insertions, 535 deletions
diff --git a/src/com/pheelicks/visualizer/AudioData.java b/src/com/pheelicks/visualizer/AudioData.java index 68d9c8a..6c1a5f8 100644 --- a/src/com/pheelicks/visualizer/AudioData.java +++ b/src/com/pheelicks/visualizer/AudioData.java @@ -4,15 +4,16 @@ * Licensed under the MIT license: * http://creativecommons.org/licenses/MIT/ */ + package com.pheelicks.visualizer; // Data class to explicitly indicate that these bytes are raw audio data public class AudioData { - public AudioData(byte[] bytes) - { - this.bytes = bytes; - } + public AudioData(byte[] bytes) + { + this.bytes = bytes; + } - public byte[] bytes; + public byte[] bytes; } diff --git a/src/com/pheelicks/visualizer/FFTData.java b/src/com/pheelicks/visualizer/FFTData.java index 70ddb01..66aac74 100644 --- a/src/com/pheelicks/visualizer/FFTData.java +++ b/src/com/pheelicks/visualizer/FFTData.java @@ -4,15 +4,16 @@ * Licensed under the MIT license: * http://creativecommons.org/licenses/MIT/ */ + package com.pheelicks.visualizer; // Data class to explicitly indicate that these bytes are the FFT of audio data public class FFTData { - public FFTData(byte[] bytes) - { - this.bytes = bytes; - } + public FFTData(byte[] bytes) + { + this.bytes = bytes; + } - public byte[] bytes; + public byte[] bytes; } diff --git a/src/com/pheelicks/visualizer/VisualizerView.java b/src/com/pheelicks/visualizer/VisualizerView.java index 78e047e..9ab5e22 100644 --- a/src/com/pheelicks/visualizer/VisualizerView.java +++ b/src/com/pheelicks/visualizer/VisualizerView.java @@ -4,10 +4,8 @@ * Licensed under the MIT license: * http://creativecommons.org/licenses/MIT/ */ -package com.pheelicks.visualizer; -import java.util.HashSet; -import java.util.Set; +package com.pheelicks.visualizer; import android.content.Context; import android.graphics.Bitmap; @@ -19,208 +17,293 @@ import android.graphics.Paint; import android.graphics.PorterDuff.Mode; import android.graphics.PorterDuffXfermode; import android.graphics.Rect; -import android.media.MediaPlayer; import android.media.audiofx.Visualizer; import android.util.AttributeSet; +import android.util.Log; import android.view.View; +import com.pheelicks.visualizer.renderer.BarGraphRenderer; +import com.pheelicks.visualizer.renderer.CircleBarRenderer; +import com.pheelicks.visualizer.renderer.CircleRenderer; +import com.pheelicks.visualizer.renderer.LineRenderer; import com.pheelicks.visualizer.renderer.Renderer; +import java.util.HashSet; +import java.util.Set; + /** * A class that draws visualizations of data received from a * {@link Visualizer.OnDataCaptureListener#onWaveFormDataCapture } and * {@link Visualizer.OnDataCaptureListener#onFftDataCapture } */ public class VisualizerView extends View { - private static final String TAG = "VisualizerView"; - - private byte[] mBytes; - private byte[] mFFTBytes; - private Rect mRect = new Rect(); - private Visualizer mVisualizer; - - private Set<Renderer> mRenderers; - - private Paint mFlashPaint = new Paint(); - private Paint mFadePaint = new Paint(); - - public VisualizerView(Context context, AttributeSet attrs, int defStyle) - { - super(context, attrs); - init(); - } - - public VisualizerView(Context context, AttributeSet attrs) - { - this(context, attrs, 0); - } - - public VisualizerView(Context context) - { - this(context, null, 0); - } - - private void init() { - mBytes = null; - mFFTBytes = null; - - mFlashPaint.setColor(Color.argb(122, 255, 255, 255)); - mFadePaint.setColor(Color.argb(238, 255, 255, 255)); // Adjust alpha to change how quickly the image fades - mFadePaint.setXfermode(new PorterDuffXfermode(Mode.MULTIPLY)); - - mRenderers = new HashSet<Renderer>(); - } - - /** - * Links the visualizer to a player - * @param player - MediaPlayer instance to link to - */ - public void link(MediaPlayer player) - { - if(player == null) + + private static final String TAG = "VisualizerView"; + + private byte[] mBytes; + private byte[] mFFTBytes; + private Rect mRect = new Rect(); + private Visualizer mVisualizer; + private int mAudioSessionId; + + private Set<Renderer> mRenderers; + + private Paint mFlashPaint = new Paint(); + private Paint mFadePaint = new Paint(); + + public VisualizerView(Context context, AttributeSet attrs, int defStyle) { - throw new NullPointerException("Cannot link to null MediaPlayer"); + super(context, attrs); + init(); } - // Create the Visualizer object and attach it to our media player. - mVisualizer = new Visualizer(player.getAudioSessionId()); - mVisualizer.setCaptureSize(Visualizer.getCaptureSizeRange()[1]); + public VisualizerView(Context context, AttributeSet attrs) + { + this(context, attrs, 0); + } - // Pass through Visualizer data to VisualizerView - Visualizer.OnDataCaptureListener captureListener = new Visualizer.OnDataCaptureListener() + public VisualizerView(Context context) { - @Override - public void onWaveFormDataCapture(Visualizer visualizer, byte[] bytes, - int samplingRate) - { - updateVisualizer(bytes); - } - - @Override - public void onFftDataCapture(Visualizer visualizer, byte[] bytes, - int samplingRate) - { - updateVisualizerFFT(bytes); - } - }; - - mVisualizer.setDataCaptureListener(captureListener, - Visualizer.getMaxCaptureRate() / 2, true, true); - - // Enabled Visualizer and disable when we're done with the stream - mVisualizer.setEnabled(true); - player.setOnCompletionListener(new MediaPlayer.OnCompletionListener() + this(context, null, 0); + } + + private void init() { + mBytes = null; + mFFTBytes = null; + + mFlashPaint.setColor(Color.argb(122, 255, 255, 255)); + mFadePaint.setColor(Color.argb(238, 255, 255, 255)); // Adjust alpha to + // change how + // quickly the + // image fades + mFadePaint.setXfermode(new PorterDuffXfermode(Mode.MULTIPLY)); + + mRenderers = new HashSet<Renderer>(); + } + + /** + * Links the visualizer to a player + * + * @param player - MediaPlayer instance to link to + */ + public void link(int audioSessionId) { - @Override - public void onCompletion(MediaPlayer mediaPlayer) - { - mVisualizer.setEnabled(false); - } - }); - } - - public void addRenderer(Renderer renderer) - { - if(renderer != null) + if (mVisualizer != null && audioSessionId != mAudioSessionId) { + mVisualizer.setEnabled(false); + mVisualizer.release(); + mVisualizer = null; + } + + Log.i(TAG, "session=" + audioSessionId); + mAudioSessionId = audioSessionId; + + if (mVisualizer == null) { + + // Create the Visualizer object and attach it to our media player. + try { + mVisualizer = new Visualizer(audioSessionId); + } catch (Exception e) { + Log.e(TAG, "Error enabling visualizer!", e); + return; + } + mVisualizer.setEnabled(false); + mVisualizer.setCaptureSize(Visualizer.getCaptureSizeRange()[1]); + + // Pass through Visualizer data to VisualizerView + Visualizer.OnDataCaptureListener captureListener = new Visualizer.OnDataCaptureListener() + { + @Override + public void onWaveFormDataCapture(Visualizer visualizer, byte[] bytes, + int samplingRate) + { + updateVisualizer(bytes); + } + + @Override + public void onFftDataCapture(Visualizer visualizer, byte[] bytes, + int samplingRate) + { + updateVisualizerFFT(bytes); + } + }; + + mVisualizer.setDataCaptureListener(captureListener, + (int) (Visualizer.getMaxCaptureRate() * 0.75), true, true); + + } + mVisualizer.setEnabled(true); + + } + + public void unlink() { + if (mVisualizer != null) { + mVisualizer.setEnabled(false); + mVisualizer.release(); + mVisualizer = null; + } + } + + public void addRenderer(Renderer renderer) { - mRenderers.add(renderer); - } - } - - public void clearRenderers() - { - mRenderers.clear(); - } - - /** - * Call to release the resources used by VisualizerView. Like with the - * MediaPlayer it is good practice to call this method - */ - public void release() - { - mVisualizer.release(); - } - - /** - * Pass data to the visualizer. Typically this will be obtained from the - * Android Visualizer.OnDataCaptureListener call back. See - * {@link Visualizer.OnDataCaptureListener#onWaveFormDataCapture } - * @param bytes - */ - public void updateVisualizer(byte[] bytes) { - mBytes = bytes; - invalidate(); - } - - /** - * Pass FFT data to the visualizer. Typically this will be obtained from the - * Android Visualizer.OnDataCaptureListener call back. See - * {@link Visualizer.OnDataCaptureListener#onFftDataCapture } - * @param bytes - */ - public void updateVisualizerFFT(byte[] bytes) { - mFFTBytes = bytes; - invalidate(); - } - - boolean mFlash = false; - - /** - * Call this to make the visualizer flash. Useful for flashing at the start - * of a song/loop etc... - */ - public void flash() { - mFlash = true; - invalidate(); - } - - Bitmap mCanvasBitmap; - Canvas mCanvas; - - - @Override - protected void onDraw(Canvas canvas) { - super.onDraw(canvas); - - // Create canvas once we're ready to draw - mRect.set(0, 0, getWidth(), getHeight()); - - if(mCanvasBitmap == null) + if (renderer != null) + { + mRenderers.add(renderer); + } + } + + public void clearRenderers() { - mCanvasBitmap = Bitmap.createBitmap(canvas.getWidth(), canvas.getHeight(), Config.ARGB_8888); + mRenderers.clear(); } - if(mCanvas == null) + + /** + * Call to release the resources used by VisualizerView. Like with the + * MediaPlayer it is good practice to call this method + */ + public void release() { - mCanvas = new Canvas(mCanvasBitmap); + mVisualizer.release(); } - if (mBytes != null) { - // Render all audio renderers - AudioData audioData = new AudioData(mBytes); - for(Renderer r : mRenderers) - { - r.render(mCanvas, audioData, mRect); - } + /** + * Pass data to the visualizer. Typically this will be obtained from the + * Android Visualizer.OnDataCaptureListener call back. See + * {@link Visualizer.OnDataCaptureListener#onWaveFormDataCapture } + * + * @param bytes + */ + public void updateVisualizer(byte[] bytes) { + mBytes = bytes; + invalidate(); + } + + /** + * Pass FFT data to the visualizer. Typically this will be obtained from the + * Android Visualizer.OnDataCaptureListener call back. See + * {@link Visualizer.OnDataCaptureListener#onFftDataCapture } + * + * @param bytes + */ + public void updateVisualizerFFT(byte[] bytes) { + mFFTBytes = bytes; + invalidate(); + } + + boolean mFlash = false; + + /** + * Call this to make the visualizer flash. Useful for flashing at the start + * of a song/loop etc... + */ + public void flash() { + mFlash = true; + invalidate(); } - if (mFFTBytes != null) { - // Render all FFT renderers - FFTData fftData = new FFTData(mFFTBytes); - for(Renderer r : mRenderers) - { - r.render(mCanvas, fftData, mRect); - } + Bitmap mCanvasBitmap; + Canvas mCanvas; + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + // Create canvas once we're ready to draw + mRect.set(0, 0, getWidth(), getHeight()); + + if (mCanvasBitmap == null) + { + mCanvasBitmap = Bitmap.createBitmap(canvas.getWidth(), canvas.getHeight(), + Config.ARGB_8888); + } + if (mCanvas == null) + { + mCanvas = new Canvas(mCanvasBitmap); + } + + if (mBytes != null) { + // Render all audio renderers + AudioData audioData = new AudioData(mBytes); + for (Renderer r : mRenderers) + { + r.render(mCanvas, audioData, mRect); + } + } + + if (mFFTBytes != null) { + // Render all FFT renderers + FFTData fftData = new FFTData(mFFTBytes); + for (Renderer r : mRenderers) + { + r.render(mCanvas, fftData, mRect); + } + } + + // Fade out old contents + mCanvas.drawPaint(mFadePaint); + + if (mFlash) + { + mFlash = false; + mCanvas.drawPaint(mFlashPaint); + } + + canvas.drawBitmap(mCanvasBitmap, new Matrix(), null); } - // Fade out old contents - mCanvas.drawPaint(mFadePaint); + // Methods for adding renderers to visualizer + public void addBarGraphRendererBottom() + { + Paint paint = new Paint(); + paint.setStrokeWidth(50f); + paint.setAntiAlias(true); + paint.setColor(Color.argb(200, 56, 138, 252)); + BarGraphRenderer barGraphRendererBottom = new BarGraphRenderer(16, paint, false); + addRenderer(barGraphRendererBottom); + } + + public void addBarGraphRendererTop() { + Paint paint2 = new Paint(); + paint2.setStrokeWidth(12f); + paint2.setAntiAlias(true); + paint2.setColor(Color.argb(200, 181, 111, 233)); + BarGraphRenderer barGraphRendererTop = new BarGraphRenderer(4, paint2, true); + addRenderer(barGraphRendererTop); + } + + public void addCircleBarRenderer() + { + Paint paint = new Paint(); + paint.setStrokeWidth(8f); + paint.setAntiAlias(true); + paint.setXfermode(new PorterDuffXfermode(Mode.LIGHTEN)); + paint.setColor(Color.argb(255, 222, 92, 143)); + CircleBarRenderer circleBarRenderer = new CircleBarRenderer(paint, 32, true); + addRenderer(circleBarRenderer); + } + + public void addCircleRenderer() + { + Paint paint = new Paint(); + paint.setStrokeWidth(3f); + paint.setAntiAlias(true); + paint.setColor(Color.argb(255, 222, 92, 143)); + CircleRenderer circleRenderer = new CircleRenderer(paint, true); + addRenderer(circleRenderer); + } - if(mFlash) + public void addLineRenderer() { - mFlash = false; - mCanvas.drawPaint(mFlashPaint); + Paint linePaint = new Paint(); + linePaint.setStrokeWidth(1f); + linePaint.setAntiAlias(true); + linePaint.setColor(Color.argb(88, 0, 128, 255)); + + Paint lineFlashPaint = new Paint(); + lineFlashPaint.setStrokeWidth(5f); + lineFlashPaint.setAntiAlias(true); + lineFlashPaint.setColor(Color.argb(188, 255, 255, 255)); + LineRenderer lineRenderer = new LineRenderer(linePaint, lineFlashPaint, true); + addRenderer(lineRenderer); } - canvas.drawBitmap(mCanvasBitmap, new Matrix(), null); - } -}
\ No newline at end of file +} diff --git a/src/com/pheelicks/visualizer/renderer/BarGraphRenderer.java b/src/com/pheelicks/visualizer/renderer/BarGraphRenderer.java index b17a695..fefd36c 100644 --- a/src/com/pheelicks/visualizer/renderer/BarGraphRenderer.java +++ b/src/com/pheelicks/visualizer/renderer/BarGraphRenderer.java @@ -4,6 +4,7 @@ * Licensed under the MIT license: * http://creativecommons.org/licenses/MIT/ */ + package com.pheelicks.visualizer.renderer; import android.graphics.Canvas; @@ -15,55 +16,57 @@ import com.pheelicks.visualizer.FFTData; public class BarGraphRenderer extends Renderer { - private int mDivisions; - private Paint mPaint; - private boolean mTop; + private int mDivisions; + private Paint mPaint; + private boolean mTop; - /** - * Renders the FFT data as a series of lines, in histogram form - * @param divisions - must be a power of 2. Controls how many lines to draw - * @param paint - Paint to draw lines with - * @param top - whether to draw the lines at the top of the canvas, or the bottom - */ - public BarGraphRenderer(int divisions, - Paint paint, - boolean top) - { - super(); - mDivisions = divisions; - mPaint = paint; - mTop = top; - } + /** + * Renders the FFT data as a series of lines, in histogram form + * + * @param divisions - must be a power of 2. Controls how many lines to draw + * @param paint - Paint to draw lines with + * @param top - whether to draw the lines at the top of the canvas, or the + * bottom + */ + public BarGraphRenderer(int divisions, + Paint paint, + boolean top) + { + super(); + mDivisions = divisions; + mPaint = paint; + mTop = top; + } - @Override - public void onRender(Canvas canvas, AudioData data, Rect rect) - { - // Do nothing, we only display FFT data - } + @Override + public void onRender(Canvas canvas, AudioData data, Rect rect) + { + // Do nothing, we only display FFT data + } - @Override - public void onRender(Canvas canvas, FFTData data, Rect rect) - { - for (int i = 0; i < data.bytes.length / mDivisions; i++) { - mFFTPoints[i * 4] = i * 4 * mDivisions; - mFFTPoints[i * 4 + 2] = i * 4 * mDivisions; - byte rfk = data.bytes[mDivisions * i]; - byte ifk = data.bytes[mDivisions * i + 1]; - float magnitude = (rfk * rfk + ifk * ifk); - int dbValue = (int) (10 * Math.log10(magnitude)); + @Override + public void onRender(Canvas canvas, FFTData data, Rect rect) + { + for (int i = 0; i < data.bytes.length / mDivisions; i++) { + mFFTPoints[i * 4] = i * 4 * mDivisions; + mFFTPoints[i * 4 + 2] = i * 4 * mDivisions; + byte rfk = data.bytes[mDivisions * i]; + byte ifk = data.bytes[mDivisions * i + 1]; + float magnitude = (rfk * rfk + ifk * ifk); + int dbValue = (int) (10 * Math.log10(magnitude)); - if(mTop) - { - mFFTPoints[i * 4 + 1] = 0; - mFFTPoints[i * 4 + 3] = (dbValue * 2 - 10); - } - else - { - mFFTPoints[i * 4 + 1] = rect.height(); - mFFTPoints[i * 4 + 3] = rect.height() - (dbValue * 2 - 10); - } - } + if (mTop) + { + mFFTPoints[i * 4 + 1] = 0; + mFFTPoints[i * 4 + 3] = (dbValue * 2 - 10); + } + else + { + mFFTPoints[i * 4 + 1] = rect.height(); + mFFTPoints[i * 4 + 3] = rect.height() - (dbValue * 2 - 10); + } + } - canvas.drawLines(mFFTPoints, mPaint); - } + canvas.drawLines(mFFTPoints, mPaint); + } } diff --git a/src/com/pheelicks/visualizer/renderer/CircleBarRenderer.java b/src/com/pheelicks/visualizer/renderer/CircleBarRenderer.java index ff1e7d5..6d4e47f 100644 --- a/src/com/pheelicks/visualizer/renderer/CircleBarRenderer.java +++ b/src/com/pheelicks/visualizer/renderer/CircleBarRenderer.java @@ -4,6 +4,7 @@ * Licensed under the MIT license: * http://creativecommons.org/licenses/MIT/ */ + package com.pheelicks.visualizer.renderer; import android.graphics.Canvas; @@ -16,106 +17,111 @@ import com.pheelicks.visualizer.FFTData; public class CircleBarRenderer extends Renderer { - private int mDivisions; - private Paint mPaint; - private boolean mCycleColor; - - /** - * Renders the FFT data onto a pulsing, rotating circle - * @param canvas - * @param paint - Paint to draw lines with - */ - public CircleBarRenderer(Paint paint, int divisions) - { - this(paint, divisions, false); - } - - /** - * Renders the audio data onto a pulsing circle - * @param canvas - * @param paint - Paint to draw lines with - * @param divisions - must be a power of 2. Controls how many lines to draw - * @param cycleColor - If true the color will change on each frame - */ - public CircleBarRenderer(Paint paint, int divisions, boolean cycleColor) - { - super(); - mPaint = paint; - mDivisions = divisions; - mCycleColor = cycleColor; - } - - @Override - public void onRender(Canvas canvas, AudioData data, Rect rect) - { - // Do nothing, we only display FFT data - } - - @Override - public void onRender(Canvas canvas, FFTData data, Rect rect) - { - if(mCycleColor) + private int mDivisions; + private Paint mPaint; + private boolean mCycleColor; + + /** + * Renders the FFT data onto a pulsing, rotating circle + * + * @param canvas + * @param paint - Paint to draw lines with + */ + public CircleBarRenderer(Paint paint, int divisions) + { + this(paint, divisions, false); + } + + /** + * Renders the audio data onto a pulsing circle + * + * @param canvas + * @param paint - Paint to draw lines with + * @param divisions - must be a power of 2. Controls how many lines to draw + * @param cycleColor - If true the color will change on each frame + */ + public CircleBarRenderer(Paint paint, int divisions, boolean cycleColor) { - cycleColor(); + super(); + mPaint = paint; + mDivisions = divisions; + mCycleColor = cycleColor; } - for (int i = 0; i < data.bytes.length / mDivisions; i++) { - // Calculate dbValue - byte rfk = data.bytes[mDivisions * i]; - byte ifk = data.bytes[mDivisions * i + 1]; - float magnitude = (rfk * rfk + ifk * ifk); - float dbValue = 75 * (float)Math.log10(magnitude); - - float[] cartPoint = { - (float)(i * mDivisions) / (data.bytes.length - 1), - rect.height() / 2 - dbValue / 4 - }; - - float[] polarPoint = toPolar(cartPoint, rect); - mFFTPoints[i * 4] = polarPoint[0]; - mFFTPoints[i * 4 + 1] = polarPoint[1]; - - float[] cartPoint2 = { - (float)(i * mDivisions) / (data.bytes.length - 1), - rect.height() / 2 + dbValue - }; - - float[] polarPoint2 = toPolar(cartPoint2, rect); - mFFTPoints[i * 4 + 2] = polarPoint2[0]; - mFFTPoints[i * 4 + 3] = polarPoint2[1]; + @Override + public void onRender(Canvas canvas, AudioData data, Rect rect) + { + // Do nothing, we only display FFT data + } + + @Override + public void onRender(Canvas canvas, FFTData data, Rect rect) + { + if (mCycleColor) + { + cycleColor(); + } + + for (int i = 0; i < data.bytes.length / mDivisions; i++) { + // Calculate dbValue + byte rfk = data.bytes[mDivisions * i]; + byte ifk = data.bytes[mDivisions * i + 1]; + float magnitude = (rfk * rfk + ifk * ifk); + float dbValue = 75 * (float) Math.log10(magnitude); + + float[] cartPoint = { + (float) (i * mDivisions) / (data.bytes.length - 1), + rect.height() / 2 - dbValue / 4 + }; + + float[] polarPoint = toPolar(cartPoint, rect); + mFFTPoints[i * 4] = polarPoint[0]; + mFFTPoints[i * 4 + 1] = polarPoint[1]; + + float[] cartPoint2 = { + (float) (i * mDivisions) / (data.bytes.length - 1), + rect.height() / 2 + dbValue + }; + + float[] polarPoint2 = toPolar(cartPoint2, rect); + mFFTPoints[i * 4 + 2] = polarPoint2[0]; + mFFTPoints[i * 4 + 3] = polarPoint2[1]; + } + + canvas.drawLines(mFFTPoints, mPaint); + + // Controls the pulsing rate + modulation += 0.13; + angleModulation += 0.28; } - canvas.drawLines(mFFTPoints, mPaint); - - // Controls the pulsing rate - modulation += 0.13; - angleModulation += 0.28; - } - - float modulation = 0; - float modulationStrength = 0.4f; // 0-1 - float angleModulation = 0; - float aggresive = 0.4f; - private float[] toPolar(float[] cartesian, Rect rect) - { - double cX = rect.width()/2; - double cY = rect.height()/2; - double angle = (cartesian[0]) * 2 * Math.PI; - double radius = ((rect.width()/2) * (1 - aggresive) + aggresive * cartesian[1]/2) * ((1 - modulationStrength) + modulationStrength * (1 + Math.sin(modulation)) / 2); - float[] out = { - (float)(cX + radius * Math.sin(angle + angleModulation)), - (float)(cY + radius * Math.cos(angle + angleModulation)) - }; - return out; - } - - private float colorCounter = 0; - private void cycleColor() - { - int r = (int)Math.floor(128*(Math.sin(colorCounter) + 1)); - int g = (int)Math.floor(128*(Math.sin(colorCounter + 2) + 1)); - int b = (int)Math.floor(128*(Math.sin(colorCounter + 4) + 1)); - mPaint.setColor(Color.argb(128, r, g, b)); - colorCounter += 0.03; - } + float modulation = 0; + float modulationStrength = 0.4f; // 0-1 + float angleModulation = 0; + float aggresive = 0.4f; + + private float[] toPolar(float[] cartesian, Rect rect) + { + double cX = rect.width() / 2; + double cY = rect.height() / 2; + double angle = (cartesian[0]) * 2 * Math.PI; + double radius = ((rect.width() / 2) * (1 - aggresive) + aggresive * cartesian[1] / 2) + * ((1 - modulationStrength) + modulationStrength * (1 + Math.sin(modulation)) / 2); + float[] out = { + (float) (cX + radius * Math.sin(angle + angleModulation)), + (float) (cY + radius * Math.cos(angle + angleModulation)) + }; + return out; + } + + private float colorCounter = 0; + + private void cycleColor() + { + int r = (int) Math.floor(128 * (Math.sin(colorCounter) + 1)); + int g = (int) Math.floor(128 * (Math.sin(colorCounter + 2) + 1)); + int b = (int) Math.floor(128 * (Math.sin(colorCounter + 4) + 1)); + mPaint.setColor(Color.argb(128, r, g, b)); + colorCounter += 0.03; + } } diff --git a/src/com/pheelicks/visualizer/renderer/CircleRenderer.java b/src/com/pheelicks/visualizer/renderer/CircleRenderer.java index 8c7fab5..722ce09 100644 --- a/src/com/pheelicks/visualizer/renderer/CircleRenderer.java +++ b/src/com/pheelicks/visualizer/renderer/CircleRenderer.java @@ -4,6 +4,7 @@ * Licensed under the MIT license: * http://creativecommons.org/licenses/MIT/ */ + package com.pheelicks.visualizer.renderer; import android.graphics.Canvas; @@ -16,94 +17,100 @@ import com.pheelicks.visualizer.FFTData; public class CircleRenderer extends Renderer { - private Paint mPaint; - private boolean mCycleColor; - - /** - * Renders the audio data onto a pulsing circle - * @param canvas - * @param paint - Paint to draw lines with - */ - public CircleRenderer(Paint paint) - { - this(paint, false); - } - - /** - * Renders the audio data onto a pulsing circle - * @param canvas - * @param paint - Paint to draw lines with - * @param cycleColor - If true the color will change on each frame - */ - public CircleRenderer(Paint paint, boolean cycleColor) - { - super(); - mPaint = paint; - mCycleColor = cycleColor; - } - - @Override - public void onRender(Canvas canvas, AudioData data, Rect rect) - { - if(mCycleColor) + private Paint mPaint; + private boolean mCycleColor; + + /** + * Renders the audio data onto a pulsing circle + * + * @param canvas + * @param paint - Paint to draw lines with + */ + public CircleRenderer(Paint paint) + { + this(paint, false); + } + + /** + * Renders the audio data onto a pulsing circle + * + * @param canvas + * @param paint - Paint to draw lines with + * @param cycleColor - If true the color will change on each frame + */ + public CircleRenderer(Paint paint, boolean cycleColor) { - cycleColor(); + super(); + mPaint = paint; + mCycleColor = cycleColor; } - for (int i = 0; i < data.bytes.length - 1; i++) { - float[] cartPoint = { - (float)i / (data.bytes.length - 1), - rect.height() / 2 + ((byte) (data.bytes[i] + 128)) * (rect.height() / 2) / 128 - }; + @Override + public void onRender(Canvas canvas, AudioData data, Rect rect) + { + if (mCycleColor) + { + cycleColor(); + } + + for (int i = 0; i < data.bytes.length - 1; i++) { + float[] cartPoint = { + (float) i / (data.bytes.length - 1), + rect.height() / 2 + ((byte) (data.bytes[i] + 128)) * (rect.height() / 2) / 128 + }; + + float[] polarPoint = toPolar(cartPoint, rect); + mPoints[i * 4] = polarPoint[0]; + mPoints[i * 4 + 1] = polarPoint[1]; - float[] polarPoint = toPolar(cartPoint, rect); - mPoints[i * 4] = polarPoint[0]; - mPoints[i * 4 + 1] = polarPoint[1]; + float[] cartPoint2 = { + (float) (i + 1) / (data.bytes.length - 1), + rect.height() / 2 + ((byte) (data.bytes[i + 1] + 128)) * (rect.height() / 2) + / 128 + }; - float[] cartPoint2 = { - (float)(i + 1) / (data.bytes.length - 1), - rect.height() / 2 + ((byte) (data.bytes[i + 1] + 128)) * (rect.height() / 2) / 128 - }; + float[] polarPoint2 = toPolar(cartPoint2, rect); + mPoints[i * 4 + 2] = polarPoint2[0]; + mPoints[i * 4 + 3] = polarPoint2[1]; + } - float[] polarPoint2 = toPolar(cartPoint2, rect); - mPoints[i * 4 + 2] = polarPoint2[0]; - mPoints[i * 4 + 3] = polarPoint2[1]; + canvas.drawLines(mPoints, mPaint); + + // Controls the pulsing rate + modulation += 0.04; } - canvas.drawLines(mPoints, mPaint); - - // Controls the pulsing rate - modulation += 0.04; - } - - @Override - public void onRender(Canvas canvas, FFTData data, Rect rect) - { - // Do nothing, we only display audio data - } - - float modulation = 0; - float aggresive = 0.33f; - private float[] toPolar(float[] cartesian, Rect rect) - { - double cX = rect.width()/2; - double cY = rect.height()/2; - double angle = (cartesian[0]) * 2 * Math.PI; - double radius = ((rect.width()/2) * (1 - aggresive) + aggresive * cartesian[1]/2) * (1.2 + Math.sin(modulation))/2.2; - float[] out = { - (float)(cX + radius * Math.sin(angle)), - (float)(cY + radius * Math.cos(angle)) - }; - return out; - } - - private float colorCounter = 0; - private void cycleColor() - { - int r = (int)Math.floor(128*(Math.sin(colorCounter) + 1)); - int g = (int)Math.floor(128*(Math.sin(colorCounter + 2) + 1)); - int b = (int)Math.floor(128*(Math.sin(colorCounter + 4) + 1)); - mPaint.setColor(Color.argb(128, r, g, b)); - colorCounter += 0.03; - } + @Override + public void onRender(Canvas canvas, FFTData data, Rect rect) + { + // Do nothing, we only display audio data + } + + float modulation = 0; + float aggresive = 0.33f; + + private float[] toPolar(float[] cartesian, Rect rect) + { + double cX = rect.width() / 2; + double cY = rect.height() / 2; + double angle = (cartesian[0]) * 2 * Math.PI; + double radius = ((rect.width() / 2) * (1 - aggresive) + aggresive * cartesian[1] / 2) + * (1.2 + Math.sin(modulation)) / 2.2; + float[] out = { + (float) (cX + radius * Math.sin(angle)), + (float) (cY + radius * Math.cos(angle)) + }; + return out; + } + + private float colorCounter = 0; + + private void cycleColor() + { + int r = (int) Math.floor(128 * (Math.sin(colorCounter) + 1)); + int g = (int) Math.floor(128 * (Math.sin(colorCounter + 2) + 1)); + int b = (int) Math.floor(128 * (Math.sin(colorCounter + 4) + 1)); + mPaint.setColor(Color.argb(128, r, g, b)); + colorCounter += 0.03; + } } diff --git a/src/com/pheelicks/visualizer/renderer/LineRenderer.java b/src/com/pheelicks/visualizer/renderer/LineRenderer.java index 55de67d..0645a84 100644 --- a/src/com/pheelicks/visualizer/renderer/LineRenderer.java +++ b/src/com/pheelicks/visualizer/renderer/LineRenderer.java @@ -4,6 +4,7 @@ * Licensed under the MIT license: * http://creativecommons.org/licenses/MIT/ */ + package com.pheelicks.visualizer.renderer; import android.graphics.Canvas; @@ -16,92 +17,94 @@ import com.pheelicks.visualizer.FFTData; public class LineRenderer extends Renderer { - private Paint mPaint; - private Paint mFlashPaint; - private boolean mCycleColor; - private float amplitude = 0; - - - /** - * Renders the audio data onto a line. The line flashes on prominent beats - * @param canvas - * @param paint - Paint to draw lines with - * @param paint - Paint to draw flash with - */ - public LineRenderer(Paint paint, Paint flashPaint) - { - this(paint, flashPaint, false); - } - - /** - * Renders the audio data onto a line. The line flashes on prominent beats - * @param canvas - * @param paint - Paint to draw lines with - * @param paint - Paint to draw flash with - * @param cycleColor - If true the color will change on each frame - */ - public LineRenderer(Paint paint, - Paint flashPaint, - boolean cycleColor) - { - super(); - mPaint = paint; - mFlashPaint = flashPaint; - mCycleColor = cycleColor; - } + private Paint mPaint; + private Paint mFlashPaint; + private boolean mCycleColor; + private float amplitude = 0; - @Override - public void onRender(Canvas canvas, AudioData data, Rect rect) - { - if(mCycleColor) + /** + * Renders the audio data onto a line. The line flashes on prominent beats + * + * @param canvas + * @param paint - Paint to draw lines with + * @param paint - Paint to draw flash with + */ + public LineRenderer(Paint paint, Paint flashPaint) { - cycleColor(); + this(paint, flashPaint, false); } - // Calculate points for line - for (int i = 0; i < data.bytes.length - 1; i++) { - mPoints[i * 4] = rect.width() * i / (data.bytes.length - 1); - mPoints[i * 4 + 1] = rect.height() / 2 - + ((byte) (data.bytes[i] + 128)) * (rect.height() / 3) / 128; - mPoints[i * 4 + 2] = rect.width() * (i + 1) / (data.bytes.length - 1); - mPoints[i * 4 + 3] = rect.height() / 2 - + ((byte) (data.bytes[i + 1] + 128)) * (rect.height() / 3) / 128; - } - - // Calc amplitude for this waveform - float accumulator = 0; - for (int i = 0; i < data.bytes.length - 1; i++) { - accumulator += Math.abs(data.bytes[i]); + /** + * Renders the audio data onto a line. The line flashes on prominent beats + * + * @param canvas + * @param paint - Paint to draw lines with + * @param paint - Paint to draw flash with + * @param cycleColor - If true the color will change on each frame + */ + public LineRenderer(Paint paint, + Paint flashPaint, + boolean cycleColor) + { + super(); + mPaint = paint; + mFlashPaint = flashPaint; + mCycleColor = cycleColor; } - float amp = accumulator/(128 * data.bytes.length); - if(amp > amplitude) + @Override + public void onRender(Canvas canvas, AudioData data, Rect rect) { - // Amplitude is bigger than normal, make a prominent line - amplitude = amp; - canvas.drawLines(mPoints, mFlashPaint); + if (mCycleColor) + { + cycleColor(); + } + + // Calculate points for line + for (int i = 0; i < data.bytes.length - 1; i++) { + mPoints[i * 4] = rect.width() * i / (data.bytes.length - 1); + mPoints[i * 4 + 1] = rect.height() / 2 + + ((byte) (data.bytes[i] + 128)) * (rect.height() / 3) / 128; + mPoints[i * 4 + 2] = rect.width() * (i + 1) / (data.bytes.length - 1); + mPoints[i * 4 + 3] = rect.height() / 2 + + ((byte) (data.bytes[i + 1] + 128)) * (rect.height() / 3) / 128; + } + + // Calc amplitude for this waveform + float accumulator = 0; + for (int i = 0; i < data.bytes.length - 1; i++) { + accumulator += Math.abs(data.bytes[i]); + } + + float amp = accumulator / (128 * data.bytes.length); + if (amp > amplitude) + { + // Amplitude is bigger than normal, make a prominent line + amplitude = amp; + canvas.drawLines(mPoints, mFlashPaint); + } + else + { + // Amplitude is nothing special, reduce the amplitude + amplitude *= 0.99; + canvas.drawLines(mPoints, mPaint); + } } - else + + @Override + public void onRender(Canvas canvas, FFTData data, Rect rect) { - // Amplitude is nothing special, reduce the amplitude - amplitude *= 0.99; - canvas.drawLines(mPoints, mPaint); + // Do nothing, we only display audio data } - } - @Override - public void onRender(Canvas canvas, FFTData data, Rect rect) - { - // Do nothing, we only display audio data - } + private float colorCounter = 0; - private float colorCounter = 0; - private void cycleColor() - { - int r = (int)Math.floor(128*(Math.sin(colorCounter) + 3)); - int g = (int)Math.floor(128*(Math.sin(colorCounter + 1) + 1)); - int b = (int)Math.floor(128*(Math.sin(colorCounter + 7) + 1)); - mPaint.setColor(Color.argb(128, r, g, b)); - colorCounter += 0.03; - } + private void cycleColor() + { + int r = (int) Math.floor(128 * (Math.sin(colorCounter) + 3)); + int g = (int) Math.floor(128 * (Math.sin(colorCounter + 1) + 1)); + int b = (int) Math.floor(128 * (Math.sin(colorCounter + 7) + 1)); + mPaint.setColor(Color.argb(128, r, g, b)); + colorCounter += 0.03; + } } diff --git a/src/com/pheelicks/visualizer/renderer/Renderer.java b/src/com/pheelicks/visualizer/renderer/Renderer.java index 12be4b8..2d18d55 100644 --- a/src/com/pheelicks/visualizer/renderer/Renderer.java +++ b/src/com/pheelicks/visualizer/renderer/Renderer.java @@ -4,6 +4,7 @@ * Licensed under the MIT license: * http://creativecommons.org/licenses/MIT/ */ + package com.pheelicks.visualizer.renderer; import android.graphics.Canvas; @@ -14,60 +15,64 @@ import com.pheelicks.visualizer.FFTData; abstract public class Renderer { - // Have these as members, so we don't have to re-create them each time - protected float[] mPoints; - protected float[] mFFTPoints; - public Renderer() - { - } + // Have these as members, so we don't have to re-create them each time + protected float[] mPoints; + protected float[] mFFTPoints; + + public Renderer() + { + } - // As the display of raw/FFT audio will usually look different, subclasses - // will typically only implement one of the below methods - /** - * Implement this method to render the audio data onto the canvas - * @param canvas - Canvas to draw on - * @param data - Data to render - * @param rect - Rect to render into - */ - abstract public void onRender(Canvas canvas, AudioData data, Rect rect); + // As the display of raw/FFT audio will usually look different, subclasses + // will typically only implement one of the below methods + /** + * Implement this method to render the audio data onto the canvas + * + * @param canvas - Canvas to draw on + * @param data - Data to render + * @param rect - Rect to render into + */ + abstract public void onRender(Canvas canvas, AudioData data, Rect rect); - /** - * Implement this method to render the FFT audio data onto the canvas - * @param canvas - Canvas to draw on - * @param data - Data to render - * @param rect - Rect to render into - */ - abstract public void onRender(Canvas canvas, FFTData data, Rect rect); + /** + * Implement this method to render the FFT audio data onto the canvas + * + * @param canvas - Canvas to draw on + * @param data - Data to render + * @param rect - Rect to render into + */ + abstract public void onRender(Canvas canvas, FFTData data, Rect rect); + // These methods should actually be called for rendering + /** + * Render the audio data onto the canvas + * + * @param canvas - Canvas to draw on + * @param data - Data to render + * @param rect - Rect to render into + */ + final public void render(Canvas canvas, AudioData data, Rect rect) + { + if (mPoints == null || mPoints.length < data.bytes.length * 4) { + mPoints = new float[data.bytes.length * 4]; + } - // These methods should actually be called for rendering - /** - * Render the audio data onto the canvas - * @param canvas - Canvas to draw on - * @param data - Data to render - * @param rect - Rect to render into - */ - final public void render(Canvas canvas, AudioData data, Rect rect) - { - if (mPoints == null || mPoints.length < data.bytes.length * 4) { - mPoints = new float[data.bytes.length * 4]; + onRender(canvas, data, rect); } - onRender(canvas, data, rect); - } + /** + * Render the FFT data onto the canvas + * + * @param canvas - Canvas to draw on + * @param data - Data to render + * @param rect - Rect to render into + */ + final public void render(Canvas canvas, FFTData data, Rect rect) + { + if (mFFTPoints == null || mFFTPoints.length < data.bytes.length * 4) { + mFFTPoints = new float[data.bytes.length * 4]; + } - /** - * Render the FFT data onto the canvas - * @param canvas - Canvas to draw on - * @param data - Data to render - * @param rect - Rect to render into - */ - final public void render(Canvas canvas, FFTData data, Rect rect) - { - if (mFFTPoints == null || mFFTPoints.length < data.bytes.length * 4) { - mFFTPoints = new float[data.bytes.length * 4]; + onRender(canvas, data, rect); } - - onRender(canvas, data, rect); - } } |