diff --git a/app/src/main/java/com/ninja/mobile/communicator/data/AudioModule.java b/app/src/main/java/com/ninja/mobile/communicator/data/AudioModule.java index adc0e77d9db385162b777f3bf66d7bcb43d101cb..58bcec1af7eea7fd9ff21a4a0a7046583c6fcd37 100644 --- a/app/src/main/java/com/ninja/mobile/communicator/data/AudioModule.java +++ b/app/src/main/java/com/ninja/mobile/communicator/data/AudioModule.java @@ -6,8 +6,15 @@ import android.os.Environment; import android.os.Handler; import android.support.annotation.Nullable; +import java.io.ByteArrayOutputStream; import java.io.File; +import java.io.FileInputStream; import java.io.IOException; +import java.io.InputStream; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.ShortBuffer; +import java.util.ArrayList; import timber.log.Timber; @@ -120,4 +127,61 @@ public class AudioModule { void onVolumeUpdate(float volume); } + public interface OnWaveProgress { + void onWaveProgress(int progress); + } + + //SAMPLE start + public ArrayList getDataForWave(File file) { + ArrayList arrayList = null; + short data[] = null; + try { + data = getAudioSample(file); + } catch (IOException e) { + e.printStackTrace(); + } + if (data != null) { + arrayList = new ArrayList<>(data.length); + for (short item : data) { + arrayList.add(getSampleDouble(item)); + } + } + return arrayList; + } + + private short[] getAudioSample(File file) throws IOException { + FileInputStream is = new FileInputStream(file); + byte[] data; + try { + data = inputStreamToByteArray(is); + } finally { + if (is != null) { + is.close(); + } + } + + ShortBuffer sb = ByteBuffer.wrap(data).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer(); + short[] samples = new short[sb.limit()]; + sb.get(samples); + return samples; + } + + private byte[] inputStreamToByteArray(InputStream inputStream) throws IOException { + ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + + int nRead; + byte[] data = new byte[16384]; + + while ((nRead = inputStream.read(data, 0, data.length)) != -1) { + buffer.write(data, 0, nRead); + } + return buffer.toByteArray(); + } + + private double getSampleDouble(short item) { //converts short to equal double from 0 to 6 + double value = (float) Math.abs(item) / Short.MAX_VALUE; + return value * 6; + } + //SAMPLE END + } diff --git a/app/src/main/java/com/ninja/mobile/communicator/ui/views/WaveFormView.java b/app/src/main/java/com/ninja/mobile/communicator/ui/views/WaveFormView.java new file mode 100644 index 0000000000000000000000000000000000000000..61fd16317e62ee46fe749fd54303c752bf5dfef4 --- /dev/null +++ b/app/src/main/java/com/ninja/mobile/communicator/ui/views/WaveFormView.java @@ -0,0 +1,162 @@ +package com.ninja.mobile.communicator.ui.views; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.support.annotation.Nullable; +import android.util.AttributeSet; +import android.view.View; + +import com.ninja.mobile.communicator.R; + +import java.util.ArrayList; +import java.util.Collections; + +public class WaveFormView extends View { + private float COLUMN_MARG_RATION = 0.25f; + private int MAX_COLUMNS = 100;// + private double MAX_SOUND_VALUE = 6; + private Canvas mCanvas; + private ArrayList sound; + private int centerY; + private int width; + private int height; + private int progress; + private int listenedColor; + private int notListenedColor; + + + public WaveFormView(Context context) { + super(context); + } + + public WaveFormView(Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + } + + public WaveFormView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CirclePageIndicator, defStyleAttr, 0); + MAX_COLUMNS = a.getInt(R.styleable.WaveFormView_max_columns, 50); + COLUMN_MARG_RATION = a.getInt(R.styleable.WaveFormView_column_marg, 50); + MAX_SOUND_VALUE = a.getFloat(R.styleable.WaveFormView_max_sound, 6.0f); + listenedColor = a.getColor(R.styleable.WaveFormView_listened_color, Color.rgb(255, 0, 0)); + notListenedColor = a.getColor(R.styleable.WaveFormView_listened_color, Color.rgb(255, 255, 255)); + + + a.recycle(); + } + + @Override protected void onDraw(Canvas canvas) { + this.mCanvas = canvas; + width = canvas.getWidth(); + height = canvas.getHeight(); + centerY = canvas.getHeight() / 2; + if (sound != null) { + ArrayList avg = getAvarangeDataForColumnss(sound); + makeBeautiful(avg); + drawColumns(avg); + } + } + + private void drawColumns(ArrayList averanges) { + int columnWidth = (int) (width / (MAX_COLUMNS + (MAX_COLUMNS - 1) * COLUMN_MARG_RATION)); + int columntHeigtMax = height / 2; + for (int i = 0; i < MAX_COLUMNS; i++) { + float left = i * columnWidth + i * columnWidth * COLUMN_MARG_RATION; + float right = left + columnWidth; + double heightRatio = (averanges.get(i) / MAX_SOUND_VALUE); + float heigh = (float) (columntHeigtMax * heightRatio); + float bottom = centerY - heigh; + float top = centerY + heigh; + if (isListened(i)) { + drawListenedColumn(left, top, right, bottom); + } else { + drawUnListenedColumn(left, top, right, bottom); + } + } + } + + private void drawListenedColumn(float left, float top, float right, float bottom) { + Paint paint = new Paint(); + paint.setColor(listenedColor); + paint.setStyle(Paint.Style.FILL); + mCanvas.drawRect(left, top, right, bottom, paint); + } + + private void drawUnListenedColumn(float left, float top, float right, float bottom) { + Paint paint = new Paint(); + paint.setColor(notListenedColor); + paint.setStyle(Paint.Style.FILL); + mCanvas.drawRect(left, top, right, bottom, paint); + } + + private boolean isListened(int i) { + int step = 100 / MAX_COLUMNS; + return progress >= step * i; + } + + + @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + } + + @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + width = w; + height = h; + centerY = height / 2; + } + + /** + * Set data for building wave forms, from input stream for now + * + * @param audio - arraylist of audio data + */ + public void setAudio(ArrayList audio) { + this.sound = audio; + invalidate(); + } + + /** + * Set progress level from 0 to 100 + * + * @param progress - volume level + */ + public void setProgress(int progress) { //1 - 100 + this.progress = progress; + invalidate(); + } + + private ArrayList getAvarangeDataForColumnss(ArrayList income) { + int incomeSize = income.size(); + int numberForColumn = incomeSize / MAX_COLUMNS; + ArrayList averanges = new ArrayList<>(MAX_COLUMNS); + for (int i = 0; i < MAX_COLUMNS; i++) { + double current = 0; + for (int j = 0; j < numberForColumn; j++) { + int element = (i * numberForColumn) + j; + current += income.get(element); + } + averanges.add(current / numberForColumn); + } + return averanges; + } + + //increases difference between max and min points + private void makeBeautiful(ArrayList arrayList) { + double min = Collections.min(arrayList); + double max = Collections.max(arrayList); + + for (int i = 0; i < arrayList.size() - 1; i++) { + arrayList.set(i, arrayList.get(i) - min); + } + + for (int i = 0; i < arrayList.size() - 1; i++) { + arrayList.set(i, arrayList.get(i) * MAX_SOUND_VALUE / max); + } + } +} diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml index 8e56a73640611c1759d93745dd0ed987355223f3..d3eae09cd334759f790e6cdaa8001835554890c1 100644 --- a/app/src/main/res/values/attrs.xml +++ b/app/src/main/res/values/attrs.xml @@ -105,4 +105,14 @@ + + + + + + + + + + \ No newline at end of file