Skip to content

Commit

Permalink
Merge pull request #20 from lincollincol/dev
Browse files Browse the repository at this point in the history
Handle result with AmplitudaResult. Simplified version of function calls
  • Loading branch information
lincollincol authored Aug 15, 2021
2 parents c4fddf9 + 476efa5 commit 2cb6df1
Show file tree
Hide file tree
Showing 13 changed files with 540 additions and 501 deletions.
474 changes: 89 additions & 385 deletions app/src/main/java/linc/com/amplituda/Amplituda.java

Large diffs are not rendered by default.

10 changes: 6 additions & 4 deletions app/src/main/java/linc/com/amplituda/AmplitudaLogger.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@

import java.util.Locale;

public final class AmplitudaLogger {
final class AmplitudaLogger {

static final String OPERATION_PROCESSING = "Processing";
static final String OPERATION_PREPARING = "Preparing";
private static final String LIB_TAG = "AMPLITUDA";
private static int priority;
private static boolean enable;
private static int priority = Log.DEBUG;
private static boolean enable = false;

/**
* Print message to logcat
Expand Down Expand Up @@ -46,7 +48,7 @@ synchronized static void enable(final boolean logEnable) {

/**
* Set log message priority
* @param - android Log priority constant.
* @param logPrior - android Log priority constant.
*/
synchronized static void priority(final int logPrior) {
priority = logPrior;
Expand Down
160 changes: 160 additions & 0 deletions app/src/main/java/linc/com/amplituda/AmplitudaProcessingOutput.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
package linc.com.amplituda;

import java.util.LinkedHashSet;
import java.util.List;

import linc.com.amplituda.callback.AmplitudaErrorListener;
import linc.com.amplituda.callback.AmplitudaSuccessListener;
import linc.com.amplituda.exceptions.AmplitudaException;
import linc.com.amplituda.exceptions.processing.InvalidParameterFlagException;
import linc.com.amplituda.exceptions.processing.SampleOutOfBoundsException;

public final class AmplitudaProcessingOutput<T> {

private final AmplitudaResult<T> amplitudaResult;
private LinkedHashSet<AmplitudaException> processingErrors = new LinkedHashSet<>();

private AmplitudaProcessingOutput(
final String amplitudes,
final InputAudio<T> inputAudio
) {
amplitudaResult = new AmplitudaResult<>(amplitudes, inputAudio);
}

AmplitudaProcessingOutput(
final AmplitudaResultJNI processingData,
final InputAudio<T> inputAudio
) {
this(
processingData.getAmplitudes(),
inputAudio
);
this.processingErrors.addAll(processingData.getErrors());
}

AmplitudaProcessingOutput(final AmplitudaException exception, final InputAudio<T> inputAudio) {
this("", inputAudio);
this.processingErrors.add(exception);
}

/**
* Merge result amplitudes according to samplesPerSecond
* @param preferredSamplesPerSecond - number of samples per audio second
* For example:
* audio duration = 200 seconds
* after Amplituda processing, 1 second contains 40 samples
* 200 seconds contains 200 * 40 = 8000
* case 1: samplesPerSecond = 1, function will merge this 40 samples to 1.
* Output size will be 200 amplitudes
* case 2: samplesPerSecond = 20, function will merge this 40 samples to 20.
* Output size will be 4000 amplitudes
* Advantage: small output size
* Disadvantage: output quality
*/
public AmplitudaProcessingOutput<T> compress(final int preferredSamplesPerSecond) {
List<Integer> data = amplitudaResult.amplitudesAsList();

if(preferredSamplesPerSecond <= 0) {
throwException(new InvalidParameterFlagException(), null);
return this;
}

int duration = (int) amplitudaResult.getAudioDuration(AmplitudaResult.DurationUnit.SECONDS);
int aps = data.size() / duration;

if(preferredSamplesPerSecond > aps) {
throwException(new SampleOutOfBoundsException(aps, preferredSamplesPerSecond), null);
return this;
}

if(aps == preferredSamplesPerSecond) {
return this;
}

int apsDivider = aps / preferredSamplesPerSecond;
int sum = 0;
StringBuilder compressed = new StringBuilder();

if(apsDivider < 2) {
apsDivider = 2;
}

for(int sampleIndex = 0; sampleIndex < data.size(); sampleIndex++) {
if(sampleIndex % apsDivider == 0) {
compressed.append(sum / apsDivider);
compressed.append('\n');
sum = 0;
} else {
sum += data.get(sampleIndex);
}
}

amplitudaResult.setAmplitudes(compressed.toString());
return this;
}

/**
* Get Amplituda processing result. This function returns result in callback
* @param successListener - success processing operation callback
* @param errorListener - processing error callback
*/
public void get(
final AmplitudaSuccessListener<T> successListener,
final AmplitudaErrorListener errorListener
) {
handleAmplitudaProcessingErrors(errorListener);
successListener.onSuccess(amplitudaResult);
}

/**
* Get Amplituda processing result. This function returns result in callback
* @param successListener - success processing operation callback
*/
public void get(final AmplitudaSuccessListener<T> successListener) {
get(successListener, null);
}

/**
* Get Amplituda processing result
* @param errorListener - processing error callback
* @return AmplitudaResult object
*/
public AmplitudaResult<T> get(final AmplitudaErrorListener errorListener) {
handleAmplitudaProcessingErrors(errorListener);
return amplitudaResult;
}

/**
* Get Amplituda processing result
* @return AmplitudaResult object
*/
public AmplitudaResult<T> get() {
return amplitudaResult;
}

private void handleAmplitudaProcessingErrors(final AmplitudaErrorListener errorListener) {
if(processingErrors.isEmpty()){
processingErrors = null;
return;
}

for(final AmplitudaException exception : processingErrors) {
throwException(exception, errorListener);
}

processingErrors.clear();
processingErrors = null;
}

private void throwException(
final AmplitudaException exception,
final AmplitudaErrorListener errorListener
) {
if(errorListener == null) {
processingErrors.add(exception);
return;
}
errorListener.onError(exception);
}

}
172 changes: 172 additions & 0 deletions app/src/main/java/linc/com/amplituda/AmplitudaResult.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
package linc.com.amplituda;

import android.text.TextUtils;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

public final class AmplitudaResult<T> {

private String amplitudes;
private final InputAudio<T> inputAudio;

AmplitudaResult(
final String amplitudes,
final InputAudio<T> inputAudio
) {
this.amplitudes = amplitudes;
this.inputAudio = inputAudio;
}

/**
* Returns input audio source: String (path/url), File or Integer resource
*/
public T getAudioSource() {
return inputAudio.getSource();
}

/**
* Returns duration from file in seconds or millis
* @param unit - output time unit: SECONDS or MILLIS
*/
public long getAudioDuration(DurationUnit unit) {
if (unit == DurationUnit.SECONDS) {
return inputAudio.getDuration() / 1000;
}
return inputAudio.getDuration();
}

/**
* Returns input audio type: URL, RESOURCE or FILE
*/
public InputAudio.Type getInputAudioType() {
return inputAudio.getType();
}

/**
* Convert result amplitudes to List
*/
public List<Integer> amplitudesAsList() {
if(amplitudes == null || amplitudes.isEmpty())
return Collections.emptyList();

String[] log = amplitudes.split("\n");
List<Integer> amplitudes = new ArrayList<>();

for (String amplitude : log) {
if(amplitude.isEmpty()) {
break;
}
amplitudes.add(Integer.valueOf(amplitude));
}
return amplitudes;
}

/**
* Convert result amplitudes to JSON format
*/
public String amplitudesAsJson() {
if(amplitudes == null || amplitudes.isEmpty())
return "";
return Arrays.toString(amplitudesAsList().toArray());
}

/**
* Overload for amplitudesAsSequence method. Use space (" ") as a default delimiter
* @param format - output format: single line or multiline output string
*/
public String amplitudesAsSequence(final SequenceFormat format) {
if(amplitudes == null || amplitudes.isEmpty())
return "";
return amplitudesAsSequence(format, " ");
}

/**
* Convert result amplitudes to single line string with custom delimiter and send result to user via stringCallback
* @param format - output format: single line or multiline output string
* @param singleLineDelimiter - delimiter between amplitudes. WARNING: this parameter will be ignored when NEW_LINE_SEQUENCE_FORMAT passed as a parameter
*/
public String amplitudesAsSequence(
final SequenceFormat format,
final String singleLineDelimiter
) {
if(amplitudes == null || amplitudes.isEmpty())
return "";

if (format == SequenceFormat.SINGLE_LINE) {
return amplitudesToSingleLineSequence(
amplitudes,
singleLineDelimiter
);
}
return amplitudes;
}

/**
* Extracts list of amplitudes per specific second
* @param second - specific second from input file
*/
public List<Integer> amplitudesForSecond(final int second) {
List<Integer> data = amplitudesAsList();

final int duration = (int) getAudioDuration(DurationUnit.SECONDS);
final int aps = data.size() / duration; // amplitudes per second

// Use second as a map key
int currentSecond = 0;

// Map with format = Map<Second, Amplitudes>
Map<Integer, List<Integer>> amplitudes = new LinkedHashMap<>();

// Temporary amplitudes list
List<Integer> amplitudesPerSecond = new ArrayList<>();

for(int sampleIndex = 0; sampleIndex < data.size(); sampleIndex++) {
if(sampleIndex % aps == 0) { // Save all amplitudes when current frame index equals to aps
// Save amplitudes to map
amplitudes.put(currentSecond, new ArrayList<>(amplitudesPerSecond));
// Clear temporary amplitudes
amplitudesPerSecond.clear();
// Increase current second
currentSecond++;
} else {
// Add amplitude to temporary list
amplitudesPerSecond.add(data.get(sampleIndex));
}
}

return amplitudes.get(second);
}

/**
* Convert result amplitudes to single line string with delimiter
* @param amplitudes - result from native c++ code
* @param delimiter - amplitudes separator
* @return string from amplitudes with custom delimiter. Example -> 0, 1, 2 | delimiter = ", "
*/
private String amplitudesToSingleLineSequence(final String amplitudes, final String delimiter) {
String[] log = amplitudes.split("\n");
return TextUtils.join(delimiter, log);
}

/**
* Update amplitudes data
* Call only from internal compress()
*/
void setAmplitudes(final String amplitudes) {
this.amplitudes = amplitudes;
}

public enum DurationUnit {
SECONDS, MILLIS
}

public enum SequenceFormat {
SINGLE_LINE, NEW_LINE
}

}
Loading

0 comments on commit 2cb6df1

Please sign in to comment.