package ch.retorte.intervalmusiccompositor.commons;
import static com.google.common.collect.Lists.reverse;
import static java.util.Collections.sort;
import java.util.List;
import com.google.common.collect.Lists;
/**
* @author nw
*/
public class ArrayHelper {
private static final String ITEM_DELIMITER = "-";
public static List<Integer> arrayToList(int[] array) {
List<Integer> result = Lists.newArrayList();
for (Integer e : array) {
result.add(e);
}
return result;
}
/**
* Merges two byte arrays -- source and destination -- together by summing field-wise where a field is a 16bit word, which is
* two of these array bytes. The result is written into the destination array.
*/
public static void arrayMerge16bit(byte[] sourceArray, int sourceStart, byte[] destinationArray, int destinationStart, int length) {
if (sourceArray.length - sourceStart < length || destinationArray.length - destinationStart < length) {
throw new IllegalStateException("Length too large for input arrays.");
}
for(int i = 0; i < length; i = i + 2) {
int srcValue = (sourceArray[sourceStart+i] & 0xFF) | (sourceArray[sourceStart+i+1] << 8);
int dstValue = (destinationArray[destinationStart+i] & 0xFF) | (destinationArray[destinationStart+i+1] << 8);
int sum = srcValue + dstValue;
if(32768 <= sum) {
sum = 32768;
}
if(sum <= -32767) {
sum = -32767;
}
destinationArray[destinationStart+i] = (byte) (sum & 0xFF);
destinationArray[destinationStart+i+1] = (byte) (sum >> 8);
}
}
/**
* We prepare a list of indices for removal by reversing the ordered list, thus removing the item with the highest index first.
* This prevents that the indices get out of order.
*/
public static List<Integer> prepareListForRemoval(int[] list) {
List<Integer> integers = arrayToList(list);
sort(integers);
return reverse(integers);
}
/**
* Calculates the average difference between the last n timestamp intervals of the input array. The assumption is that the list of timestamps is increasing.
*
* @param tapTimestamps
* the list of timestamps
* @param n
* the number of timestamp intervals we'd like to use for the calculation.
* @return the average interval between the considered values
*/
public static long getAverageInterval(List<Long> tapTimestamps, int n) {
long result = 0;
int start = tapTimestamps.size() - (n + 1);
if(start < 0) {
start = 0;
n = tapTimestamps.size() - 1;
}
if (n == 0) {
return 0;
}
for (int i = start; i < tapTimestamps.size() - 1; i++) {
result += Math.abs(tapTimestamps.get(i + 1) - tapTimestamps.get(i));
}
return (result / n);
}
/**
* Goes through the array and determines if the entries differ by at most eps pairwise. If yes (meaning if the difference is always smaller than eps), then
* the values are considered convergent.
*
* @param list
* List of values to be checked
* @param eps
* The difference two consecutive values may have at most
* @return True is the difference of any two consecutive entries is smaller or equal to eps
*/
public static boolean isConvergent(List<Double> list, int range, double eps) {
Boolean result = true;
if(list.size() < 2 || list.size() - 1 < range) {
return false;
}
for(int i = list.size() - range; i < list.size(); i++) {
double difference = Math.abs(list.get(i-1) - list.get(i));
if (eps < difference) {
result = false;
}
}
return result;
}
/**
* Takes a list of integers and returns a conveniently formatted string. We
* need this to create filenames with the elements of the lists in them.
*
* @param list the list of items to be pretty printed.
* @return String representation of the elements of said list
*/
public static String prettyPrintList(List<Integer> list) {
String result = "";
for(int i = 0; i < list.size(); i++) {
result += list.get(i).toString();
if(i < list.size() - 1) {
result += ITEM_DELIMITER;
}
}
return result;
}
}