MPAndroidChart allows you to zoom in the X axis, Y axis and both. I would like to rescale the remaining axis (or both) to match the one(s) being scaled.
For that I've created a OnChartGestureListener:
public class ZoomNotDistorting implements OnChartGestureListener {
private Chart chart;
private ViewPortHandler viewPortHandler;
private float startDist = 1f;
private float scaleX, scaleY;
public ZoomNotDistorting(Chart chart) {
this.chart = chart;
this.viewPortHandler = chart.getViewPortHandler();
}
#Override
public void onChartGestureStart(MotionEvent me, ChartTouchListener.ChartGesture lastPerformedGesture) {
int action = me.getAction() & MotionEvent.ACTION_MASK;
if(action == MotionEvent.ACTION_POINTER_DOWN && me.getPointerCount() >= 2) {
startDist = spacing(me);
}
}
#Override
public void onChartGestureEnd(MotionEvent me, ChartTouchListener.ChartGesture lastPerformedGesture) {
switch (lastPerformedGesture) {
case PINCH_ZOOM:
float scale = spacing(me) / startDist; // total scale
boolean isZoomingOut = (scale < 1);
if(isZoomingOut) {
if(scaleX < scaleY) {
viewPortHandler.zoom(scaleX, scaleX);
} else {
viewPortHandler.zoom(scaleY, scaleY);
}
} else {
if(scaleX > scaleY) {
viewPortHandler.zoom(scaleX, scaleX);
} else {
viewPortHandler.zoom(scaleY, scaleY);
}
}
break;
case X_ZOOM:
viewPortHandler.zoom(scaleX, scaleX);
break;
case Y_ZOOM:
viewPortHandler.zoom(scaleY, scaleY);
break;
}
chart.invalidate();
}
#Override
public void onChartLongPressed(MotionEvent me) {}
#Override
public void onChartDoubleTapped(MotionEvent me) {}
#Override
public void onChartSingleTapped(MotionEvent me) {}
#Override
public void onChartFling(MotionEvent me1, MotionEvent me2, float velocityX, float velocityY) {}
#Override
public void onChartScale(MotionEvent me, float scaleX, float scaleY) {
this.scaleX = scaleX;
this.scaleY = scaleY;
}
#Override
public void onChartTranslate(MotionEvent me, float dX, float dY) {}
/**
* returns the distance between two pointer touch points
*/
private static float spacing(MotionEvent event) {
float x = event.getX(0) - event.getX(1);
float y = event.getY(0) - event.getY(1);
return (float) Math.sqrt(x * x + y * y);
}
}
That class doesn't seem to be doing anything,How to set both axis's scales to be always the same?
Also, here is my chart class:
public class MathGraph extends LineChart {
public static final int BOUNDARIES = 100;
public static final int DATA_POINTS = 200;
private static final int LINE_WIDTH = 2;
private LineData data;
public MathGraph(Context context, AttributeSet attrs) {
super(context, attrs);
super.setDescription(null);
//Misc
getLegend().setEnabled(false);
setRenderer(new LineChatRendererNoData(this, mAnimator, mViewPortHandler));
//Lines encasing the chart
getXAxis().setAxisLineWidth(LINE_WIDTH);
getAxisLeft().setAxisLineWidth(LINE_WIDTH);
getAxisRight().setEnabled(false);
//Line for (x; 0)
getAxisLeft().setDrawZeroLine(true);
getAxisLeft().setZeroLineWidth(LINE_WIDTH);
getAxisRight().setDrawZeroLine(true);
getAxisRight().setZeroLineWidth(LINE_WIDTH);
//Line for (0; y)
LimitLine limitLine = new LimitLine(0f);
limitLine.setLineColor(Color.GRAY);
limitLine.setLineWidth(LINE_WIDTH);
getXAxis().addLimitLine(limitLine);
setOnChartGestureListener(new ZoomNotDistorting(this));
}
public void setFunction(Function f) {
if(!f.checkSyntax()) throw new IllegalStateException("Error in function: " + f.toString() + "!");
setDescription(f);
data = null;
LoadFunctionAsyncTask l = new LoadFunctionAsyncTask(f, -BOUNDARIES, BOUNDARIES, DATA_POINTS,
(List<Entry> pointList) -> {
if(data == null) {
ILineDataSet dataSet = new LineDataSet(new ArrayList<>(), null);
dataSet.setValueFormatter(new PointValueFormatter());
dataSet.setHighlightEnabled(true);
for (Entry dataPoint : pointList) {
dataSet.addEntry(dataPoint);
}
data = new LineData(dataSet);
setData(data);
} else {
for (Entry dataPoint : pointList) {
data.addEntry(dataPoint, 0);// 0 is the only dataset
}
data.notifyDataChanged();
notifyDataSetChanged();
invalidate();
}
});
l.execute();
}
private void setDescription(Function f) {
Description desc = new Description();
desc.setText(f.getDescription());
desc.setPosition(16, getBottom() - 16);
setDescription(desc);
}
private class PointValueFormatter implements IValueFormatter {
#Override
public String getFormattedValue(float value, Entry entry, int dataSetIndex, ViewPortHandler viewPortHandler) {
return "(" + entry.getX() + ", " + entry.getY() + ")";
}
}
}
OK, apparently chart.invalidate() isn't enough, the Matrix needs to be refreshed:
Matrix matrix = null;
//...
matrix = viewPortHandler.zoom(scaleX, scaleX);
//...
if(matrix != null) {
viewPortHandler.refresh(matrix, chart, true);
}
As a bonus, the last true in refresh() is for invalidate, so no need for chart.invalidate();.
Related
I am working on RecyclerView swipe to show an action button behind list items and my RecyclerView is in a fragment with Bottom Navigation and everything is going well but sometimes swipe stops and gets stuck so I can't completely swipe the item. I need your help with this. My codes:
The code in main activity:
ItemTouchHelper itemTouchhelper = new ItemTouchHelper(swipeController);
itemTouchhelper.attachToRecyclerView(movelistview);
movelistview.addItemDecoration(new RecyclerView.ItemDecoration() {
#Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
swipeController.onDraw(c,"action");
}
});
The code in the Swipe Controller class:
public class SwipeController extends ItemTouchHelper.Callback {
private static final float buttonWidth = 200;
private boolean swipeBack = false;
private ButtonsState buttonShowedState = ButtonsState.GONE;
private RectF buttonInstance = null;
private RecyclerView.ViewHolder currentItemViewHolder = null;
private SwipeControllerActions buttonsActions = null;
public SwipeController(SwipeControllerActions buttonsActions) {
this.buttonsActions = buttonsActions;
}
#Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
return makeMovementFlags(0, LEFT);
}
#Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
return false;
}
#Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
}
#Override
public int convertToAbsoluteDirection(int flags, int layoutDirection) {
if (swipeBack) {
swipeBack = buttonShowedState != ButtonsState.GONE;
return 0;
}
return super.convertToAbsoluteDirection(flags, layoutDirection);
}
#Override
public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
if (actionState == ACTION_STATE_SWIPE) {
if (buttonShowedState != ButtonsState.GONE) {
// if (buttonShowedState == ButtonsState.LEFT_VISIBLE) dX = Math.max(dX, buttonWidth);
if (buttonShowedState == ButtonsState.RIGHT_VISIBLE)
dX = Math.min(dX, -buttonWidth);
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
} else {
setTouchListener(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
}
}
if (buttonShowedState == ButtonsState.GONE) {
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
}
currentItemViewHolder = viewHolder;
}
private void setTouchListener(final Canvas c, final RecyclerView recyclerView, final RecyclerView.ViewHolder viewHolder, final float dX, final float dY, final int actionState, final boolean isCurrentlyActive) {
recyclerView.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
swipeBack = event.getAction() == MotionEvent.ACTION_CANCEL || event.getAction() == MotionEvent.ACTION_UP;
if (swipeBack) {
if (dX < -buttonWidth) buttonShowedState = ButtonsState.RIGHT_VISIBLE;
//else if (dX > buttonWidth) buttonShowedState = ButtonsState.LEFT_VISIBLE;
if (buttonShowedState != ButtonsState.GONE) {
setTouchDownListener(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
setItemsClickable(recyclerView, false);
}
}
return false;
}
});
}
private void setTouchDownListener(final Canvas c, final RecyclerView recyclerView, final RecyclerView.ViewHolder viewHolder, final float dX, final float dY, final int actionState, final boolean isCurrentlyActive) {
recyclerView.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
setTouchUpListener(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
}
return false;
}
});
}
private void setTouchUpListener(final Canvas c, final RecyclerView recyclerView, final RecyclerView.ViewHolder viewHolder, final float dX, final float dY, final int actionState, final boolean isCurrentlyActive) {
recyclerView.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_UP) {
SwipeController.super.onChildDraw(c, recyclerView, viewHolder, 0F, dY, actionState, isCurrentlyActive);
recyclerView.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
return false;
}
});
setItemsClickable(recyclerView, true);
swipeBack = false;
if (buttonsActions != null && buttonInstance != null && buttonInstance.contains(event.getX(), event.getY())) {
/*if (buttonShowedState == ButtonsState.LEFT_VISIBLE) {
buttonsActions.onLeftClicked(viewHolder.getAdapterPosition());
}else*/
if (buttonShowedState == ButtonsState.RIGHT_VISIBLE) {
buttonsActions.onRightClicked(viewHolder.getAdapterPosition());
}
}
buttonShowedState = ButtonsState.GONE;
currentItemViewHolder = null;
}
return false;
}
});
}
private void setItemsClickable(RecyclerView recyclerView, boolean isClickable) {
for (int i = 0; i < recyclerView.getChildCount(); ++i) {
recyclerView.getChildAt(i).setClickable(isClickable);
}
}
private void drawButtons(Canvas c, RecyclerView.ViewHolder viewHolder, String text) {
float buttonWidthWithoutPadding = buttonWidth - 0;
float corners = 0;
View itemView = viewHolder.itemView;
Paint p = new Paint();
int position = viewHolder.getAdapterPosition();
String button_text = "Report";
if (position >= 0) {
if (MainApplication.moves_list.get(position).getMove_userId().equals(MainApplication.user_id)) {
button_text = "Delete";
} else {
button_text = "Report";
}
}
RectF rightButton = new RectF(itemView.getRight() - buttonWidthWithoutPadding, itemView.getTop() + 0, itemView.getRight(), itemView.getBottom() - 0);
p.setColor(Color.RED);
c.drawRoundRect(rightButton, corners, corners, p);
drawText(button_text, c, rightButton, p);
buttonInstance = null;
if (buttonShowedState == ButtonsState.RIGHT_VISIBLE) {
buttonInstance = rightButton;
}
}
private void drawText(String text, Canvas c, RectF button, Paint p) {
float textSize = 40;
p.setColor(Color.WHITE);
p.setAntiAlias(true);
p.setTextSize(textSize);
float textWidth = p.measureText(text);
c.drawText(text, button.centerX() - (textWidth / 2), button.centerY() + (textSize / 2), p);
}
public void onDraw(Canvas c, String text) {
if (currentItemViewHolder != null) {
drawButtons(c, currentItemViewHolder, text);
}
}
}
I have had the same problem. swipe button stuck in UI, Behind recyclerview. So here is the easy and best solution ever i found.
create new Function in SwipeViewController as below
public void setSwipeBack()
{
swipeBack = false;
buttonShowedState = ButtonsStates.GONE;
}
and use this function in your fragment where your are filling data in the same recycler view.
as below
setSwipeBack();
I had the same problem, but the solution turned out to be easy.
This will happen when parent container will intercept your touch event. Any ViewGroup that overrides ViewGroup.onInterceptTouchEvent(MotionEvent) can do that (RecyclerView or ScrollView for instance).
And this will result in returning ACTION_CANCEL from your motionEvent when the Y value slightly changes, and sending touch events to parent view.
Proper way to deal with this is to call ViewParent.requestDisallowInterceptTouchEvent(boolean) method on your parent view once you think you need to keep the motion event.
Here's a quick example (attemptClaimDrag() method is taken from android source code):
/**
* Tries to claim the user's drag motion, and requests disallowing any
* ancestors from stealing events in the drag.
*/
private void attemptClaimDrag() {
// parent = yourView.getParent();
if (parent != null) {
parent.requestDisallowInterceptTouchEvent(true);
}
}
And in your onTouchEvent() or onTouch():
#Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
if (iWantToKeepThisEventForMyself(event)) {
attemptClaimDrag();
}
//your logic here
} else {
//your logic here
}
}
I'm trying to implement Yolo detector in Java (not Android, but desktops - Windows/Ubuntu)
There is already Yolo detector for Android: https://github.com/tensorflow/tensorflow/tree/master/tensorflow/examples/android
I copied some java classes from that project, added them to IntelliJ IDEA and edited them
I even copied and edited TensorFlowInferenceInterface.java which is from jar file (tensorflow library - libandroid_tensorflow_inference_java.jar) for Android
I'm almost succeeded to get it working.
Result
Console output (class title, confidence, x, y, width, height):
car 0.8836523, 148 166 270 267
car 0.51286024, 147 174 268 274
car 0.05002968, 174 164 275 262
So seems it correctly detected car, determined correct x, y
but something wrong with width and height
What could be wrong?
Here's the full code from my project
Main
public class Main implements Classifier {
private static final int BLOCK_SIZE = 32;
private static final int MAX_RESULTS = 3;
private static final int NUM_CLASSES = 20;
private static final int NUM_BOXES_PER_BLOCK = 5;
private static final int INPUT_SIZE = 416;
private static final String inputName = "input";
private static final String outputName = "output";
// Pre-allocated buffers.
private static int[] intValues;
private static float[] floatValues;
private static String[] outputNames;
// yolo 2
private static final double[] ANCHORS = { 1.3221, 1.73145, 3.19275, 4.00944, 5.05587, 8.09892, 9.47112, 4.84053, 11.2364, 10.0071 };
// tiny yolo
//private static final double[] ANCHORS = { 1.08, 1.19, 3.42, 4.41, 6.63, 11.38, 9.42, 5.11, 16.62, 10.52 };
private static final String[] LABELS = {
"aeroplane",
"bicycle",
"bird",
"boat",
"bottle",
"bus",
"car",
"cat",
"chair",
"cow",
"diningtable",
"dog",
"horse",
"motorbike",
"person",
"pottedplant",
"sheep",
"sofa",
"train",
"tvmonitor"
};
private static TensorFlowInferenceInterface inferenceInterface;
public static void main(String[] args) {
//String modelDir = "/home/user/JavaProjects/TensorFlowJavaProject"; // Ubuntu
String modelAndTestImagesDir = "D:\\JavaProjects\\TensorFlowJavaProject"; // Windows
String imageFile = modelAndTestImagesDir + File.separator + "0.png"; // 416x416 test image
outputNames = outputName.split(",");
floatValues = new float[INPUT_SIZE * INPUT_SIZE * 3];
// yolo 2 voc
inferenceInterface = new TensorFlowInferenceInterface(Paths.get(modelAndTestImagesDir, "yolo-voc.pb"));
// tiny yolo voc
//inferenceInterface = new TensorFlowInferenceInterface(Paths.get(modelAndTestImagesDir, "graph-tiny-yolo-voc.pb"));
BufferedImage img;
try {
img = ImageIO.read(new File(imageFile));
BufferedImage convertedImg = new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_INT_RGB);
convertedImg.getGraphics().drawImage(img, 0, 0, null);
intValues = ((DataBufferInt) convertedImg.getRaster().getDataBuffer()).getData() ;
List<Classifier.Recognition> recognitions = recognizeImage();
System.out.println("Result length " + recognitions.size());
Graphics2D graphics = convertedImg.createGraphics();
for (Recognition recognition : recognitions) {
RectF rectF = recognition.getLocation();
System.out.println(recognition.getTitle() + " " + recognition.getConfidence() + ", " +
(int) rectF.x + " " + (int) rectF.y + " " + (int) rectF.width + " " + ((int) rectF.height));
Stroke stroke = graphics.getStroke();
graphics.setStroke(new BasicStroke(3));
graphics.setColor(Color.green);
graphics.drawRoundRect((int) rectF.x, (int) rectF.y, (int) rectF.width, (int) rectF.height, 5, 5);
graphics.setStroke(stroke);
}
graphics.dispose();
ImageIcon icon=new ImageIcon(convertedImg);
JFrame frame=new JFrame();
frame.setLayout(new FlowLayout());
frame.setSize(convertedImg.getWidth(),convertedImg.getHeight());
JLabel lbl=new JLabel();
frame.setTitle("Java (Win/Ubuntu), Tensorflow & Yolo");
lbl.setIcon(icon);
frame.add(lbl);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
} catch (IOException e) {
e.printStackTrace();
}
}
private static List<Classifier.Recognition> recognizeImage() {
for (int i = 0; i < intValues.length; ++i) {
floatValues[i * 3 + 0] = ((intValues[i] >> 16) & 0xFF) / 255.0f;
floatValues[i * 3 + 1] = ((intValues[i] >> 8) & 0xFF) / 255.0f;
floatValues[i * 3 + 2] = (intValues[i] & 0xFF) / 255.0f;
}
inferenceInterface.feed(inputName, floatValues, 1, INPUT_SIZE, INPUT_SIZE, 3);
inferenceInterface.run(outputNames, false);
final int gridWidth = INPUT_SIZE / BLOCK_SIZE;
final int gridHeight = INPUT_SIZE / BLOCK_SIZE;
final float[] output = new float[gridWidth * gridHeight * (NUM_CLASSES + 5) * NUM_BOXES_PER_BLOCK];
inferenceInterface.fetch(outputNames[0], output);
// Find the best detections.
final PriorityQueue<Classifier.Recognition> pq =
new PriorityQueue<>(
1,
new Comparator<Classifier.Recognition>() {
#Override
public int compare(final Classifier.Recognition lhs, final Classifier.Recognition rhs) {
// Intentionally reversed to put high confidence at the head of the queue.
return Float.compare(rhs.getConfidence(), lhs.getConfidence());
}
});
for (int y = 0; y < gridHeight; ++y) {
for (int x = 0; x < gridWidth; ++x) {
for (int b = 0; b < NUM_BOXES_PER_BLOCK; ++b) {
final int offset =
(gridWidth * (NUM_BOXES_PER_BLOCK * (NUM_CLASSES + 5))) * y
+ (NUM_BOXES_PER_BLOCK * (NUM_CLASSES + 5)) * x
+ (NUM_CLASSES + 5) * b;
final float xPos = (x + expit(output[offset + 0])) * BLOCK_SIZE;
final float yPos = (y + expit(output[offset + 1])) * BLOCK_SIZE;
final float w = (float) (Math.exp(output[offset + 2]) * ANCHORS[2 * b + 0]) * BLOCK_SIZE;
final float h = (float) (Math.exp(output[offset + 3]) * ANCHORS[2 * b + 1]) * BLOCK_SIZE;
final RectF rect =
new RectF(
Math.max(0, xPos - w / 2),
Math.max(0, yPos - h / 2),
Math.min(INPUT_SIZE - 1, xPos + w / 2),
Math.min(INPUT_SIZE - 1, yPos + h / 2));
final float confidence = expit(output[offset + 4]);
int detectedClass = -1;
float maxClass = 0;
final float[] classes = new float[NUM_CLASSES];
for (int c = 0; c < NUM_CLASSES; ++c) {
classes[c] = output[offset + 5 + c];
}
softmax(classes);
for (int c = 0; c < NUM_CLASSES; ++c) {
if (classes[c] > maxClass) {
detectedClass = c;
maxClass = classes[c];
}
}
final float confidenceInClass = maxClass * confidence;
if (confidenceInClass > 0.01) {
pq.add(new Classifier.Recognition(detectedClass, LABELS[detectedClass], confidenceInClass, rect));
}
}
}
}
final ArrayList<Classifier.Recognition> recognitions = new ArrayList<>();
for (int i = 0; i < Math.min(pq.size(), MAX_RESULTS); ++i) {
recognitions.add(pq.poll());
}
return recognitions;
}
private static float expit(final float x) {
return (float) (1. / (1. + Math.exp(-x)));
}
private static void softmax(final float[] vals) {
float max = Float.NEGATIVE_INFINITY;
for (final float val : vals) {
max = Math.max(max, val);
}
float sum = 0.0f;
for (int i = 0; i < vals.length; ++i) {
vals[i] = (float) Math.exp(vals[i] - max);
sum += vals[i];
}
for (int i = 0; i < vals.length; ++i) {
vals[i] = vals[i] / sum;
}
}
public void close() {
inferenceInterface.close();
}
}
TensorFlowInferenceInterface
public class TensorFlowInferenceInterface {
private static final String TAG = "TensorFlowInferenceInterface";
private final Graph g;
private final Session sess;
private Runner runner;
private List<String> feedNames = new ArrayList();
private List<Tensor> feedTensors = new ArrayList();
private List<String> fetchNames = new ArrayList();
private List<Tensor> fetchTensors = new ArrayList();
private RunStats runStats;
public TensorFlowInferenceInterface(Path path) {
this.prepareNativeRuntime();
this.g = new Graph();
this.sess = new Session(this.g);
this.runner = this.sess.runner();
try {
this.loadGraph(readAllBytesOrExit(path), this.g);
} catch (IOException e) {
e.printStackTrace();
}
}
private static byte[] readAllBytesOrExit(Path path) {
try {
return Files.readAllBytes(path);
} catch (IOException e) {
System.err.println("Failed to read [" + path + "]: " + e.getMessage());
System.exit(1);
}
return null;
}
public void run(String[] var1) {
this.run(var1, false);
}
public void run(String[] var1, boolean var2) {
this.closeFetches();
String[] var3 = var1;
int var4 = var1.length;
for (int var5 = 0; var5 < var4; ++var5) {
String var6 = var3[var5];
this.fetchNames.add(var6);
TensorFlowInferenceInterface.TensorId var7 = TensorFlowInferenceInterface.TensorId.parse(var6);
this.runner.fetch(var7.name, var7.outputIndex);
}
try {
if (var2) {
Run var13 = this.runner.setOptions(RunStats.runOptions()).runAndFetchMetadata();
this.fetchTensors = var13.outputs;
if (this.runStats == null) {
this.runStats = new RunStats();
}
this.runStats.add(var13.metadata);
} else {
this.fetchTensors = this.runner.run();
}
} catch (RuntimeException var11) {
throw var11;
} finally {
this.closeFeeds();
this.runner = this.sess.runner();
}
}
public Graph graph() {
return this.g;
}
public Operation graphOperation(String var1) {
Operation var2 = this.g.operation(var1);
if (var2 == null) {
throw new RuntimeException("Node '" + var1 + "' does not exist in model '");
} else {
return var2;
}
}
public String getStatString() {
return this.runStats == null ? "" : this.runStats.summary();
}
public void close() {
this.closeFeeds();
this.closeFetches();
this.sess.close();
this.g.close();
if (this.runStats != null) {
this.runStats.close();
}
this.runStats = null;
}
protected void finalize() throws Throwable {
try {
this.close();
} finally {
super.finalize();
}
}
public void feed(String var1, float[] var2, long... var3) {
this.addFeed(var1, Tensor.create(var3, FloatBuffer.wrap(var2)));
}
public void fetch(String var1, float[] var2) {
this.fetch(var1, FloatBuffer.wrap(var2));
}
public void fetch(String var1, FloatBuffer var2) {
this.getTensor(var1).writeTo(var2);
}
private void prepareNativeRuntime() {
System.out.println("TensorFlowInferenceInterface Checking to see if TensorFlow native methods are already loaded");
try {
new RunStats();
System.out.println("TensorFlowInferenceInterface TensorFlow native methods already loaded");
} catch (UnsatisfiedLinkError var4) {
System.out.println("TensorFlowInferenceInterface TensorFlow native methods not found, attempting to load via tensorflow_inference");
}
}
private void loadGraph(byte[] var1, Graph var2) throws IOException {
try {
var2.importGraphDef(var1);
} catch (IllegalArgumentException var7) {
throw new IOException("Not a valid TensorFlow Graph serialization: " + var7.getMessage());
}
}
private void addFeed(String var1, Tensor var2) {
TensorFlowInferenceInterface.TensorId var3 = TensorFlowInferenceInterface.TensorId.parse(var1);
this.runner.feed(var3.name, var3.outputIndex, var2);
this.feedNames.add(var1);
this.feedTensors.add(var2);
}
private Tensor getTensor(String var1) {
int var2 = 0;
for (Iterator var3 = this.fetchNames.iterator(); var3.hasNext(); ++var2) {
String var4 = (String) var3.next();
if (var4.equals(var1)) {
return this.fetchTensors.get(var2);
}
}
throw new RuntimeException("Node '" + var1 + "' was not provided to run(), so it cannot be read");
}
private void closeFeeds() {
Iterator var1 = this.feedTensors.iterator();
while (var1.hasNext()) {
Tensor var2 = (Tensor) var1.next();
var2.close();
}
this.feedTensors.clear();
this.feedNames.clear();
}
private void closeFetches() {
Iterator var1 = this.fetchTensors.iterator();
while (var1.hasNext()) {
Tensor var2 = (Tensor) var1.next();
var2.close();
}
this.fetchTensors.clear();
this.fetchNames.clear();
}
private static class TensorId {
String name;
int outputIndex;
private TensorId() {
}
public static TensorFlowInferenceInterface.TensorId parse(String var0) {
TensorFlowInferenceInterface.TensorId var1 = new TensorFlowInferenceInterface.TensorId();
int var2 = var0.lastIndexOf(58);
if (var2 < 0) {
var1.outputIndex = 0;
var1.name = var0;
return var1;
} else {
try {
var1.outputIndex = Integer.parseInt(var0.substring(var2 + 1));
var1.name = var0.substring(0, var2);
} catch (NumberFormatException var4) {
var1.outputIndex = 0;
var1.name = var0;
}
return var1;
}
}
}
}
Classifier
public interface Classifier {
public class Recognition {
private final int id;
private final String title;
private final Float confidence;
private RectF location;
public Recognition(
final int id, final String title, final Float confidence, final RectF location) {
this.id = id;
this.title = title;
this.confidence = confidence;
this.location = location;
}
public int getId() {
return id;
}
public String getTitle() {
return title;
}
public Float getConfidence() {
return confidence;
}
public RectF getLocation() {
return new RectF(location);
}
public void setLocation(RectF location) {
this.location = location;
}
}
void close();
}
RunStats
public class RunStats implements AutoCloseable {
private long nativeHandle = allocate();
private static byte[] fullTraceRunOptions = new byte[]{8, 3};
public static byte[] runOptions() {
return fullTraceRunOptions;
}
public RunStats() {
}
public void close() {
if(this.nativeHandle != 0L) {
delete(this.nativeHandle);
}
this.nativeHandle = 0L;
}
public synchronized void add(byte[] var1) {
add(this.nativeHandle, var1);
}
public synchronized String summary() {
return summary(this.nativeHandle);
}
private static native long allocate();
private static native void delete(long var0);
private static native void add(long var0, byte[] var2);
private static native String summary(long var0);
}
RectF
public class RectF {
public float getX() {
return x;
}
public void setX(float x) {
this.x = x;
}
public float getY() {
return y;
}
public void setY(float y) {
this.y = y;
}
public float getWidth() {
return width;
}
public void setWidth(float width) {
this.width = width;
}
public float getHeight() {
return height;
}
public void setHeight(float height) {
this.height = height;
}
public float x = 0f;
public float y = 0f;
public float width = 0f;
public float height = 0f;
RectF(RectF rectF) {
this.x = rectF.x;
this.y = rectF.y;
this.width = rectF.width;
this.height = rectF.height;
}
RectF(float x, float y, float w, float h) {
this.x = x;
this.y = y;
this.width = w;
this.height = h;
}
}
solved (I mixed up with x,y,width,height and left,top,right,bottom)
here's an updated RectF:
public class RectF {
public float left;
public float top;
public float right;
public float bottom;
public RectF() {}
public RectF(float left, float top, float right, float bottom) {
this.left = left;
this.top = top;
this.right = right;
this.bottom = bottom;
}
public RectF(RectF r) {
if (r == null) {
left = top = right = bottom = 0.0f;
} else {
left = r.left;
top = r.top;
right = r.right;
bottom = r.bottom;
}
}
public String toString() {
return "RectF(" + left + ", " + top + ", "
+ right + ", " + bottom + ")";
}
public final float width() {
return right - left;
}
public final float height() {
return bottom - top;
}
public final float centerX() {
return (left + right) * 0.5f;
}
public final float centerY() {
return (top + bottom) * 0.5f;
}
}
and then
graphics.drawRoundRect((int) rectF.left, (int) rectF.top, (int) rectF.width(), (int) rectF.height(), 5, 5);
p.s. for TensorFlow 1.4.0 here's an updated TensorFlowInferenceInterface class:
public class TensorFlowInferenceInterface {
private final Graph g;
private final Session sess;
private Runner runner;
private List<String> feedNames = new ArrayList();
private List<Tensor<?>> feedTensors = new ArrayList();
private List<String> fetchNames = new ArrayList();
private List<Tensor<?>> fetchTensors = new ArrayList();
private RunStats runStats;
public TensorFlowInferenceInterface(Path path) {
this.prepareNativeRuntime();
this.g = new Graph();
this.sess = new Session(this.g);
this.runner = this.sess.runner();
try {
this.loadGraph(readAllBytesOrExit(path), this.g);
} catch (IOException e) {
e.printStackTrace();
}
}
private static byte[] readAllBytesOrExit(Path path) {
try {
return Files.readAllBytes(path);
} catch (IOException e) {
System.err.println("Failed to read [" + path + "]: " + e.getMessage());
System.exit(1);
}
return null;
}
public void run(String[] var1) {
this.run(var1, false);
}
public void run(String[] var1, boolean var2) {
this.closeFetches();
String[] var3 = var1;
int var4 = var1.length;
for(int var5 = 0; var5 < var4; ++var5) {
String var6 = var3[var5];
this.fetchNames.add(var6);
TensorFlowInferenceInterface.TensorId var7 = TensorFlowInferenceInterface.TensorId.parse(var6);
this.runner.fetch(var7.name, var7.outputIndex);
}
try {
if(var2) {
Run var13 = this.runner.setOptions(RunStats.runOptions()).runAndFetchMetadata();
this.fetchTensors = var13.outputs;
if(this.runStats == null) {
this.runStats = new RunStats();
}
this.runStats.add(var13.metadata);
} else {
this.fetchTensors = this.runner.run();
}
} catch (RuntimeException var11) {
System.out.println("Failed to run TensorFlow inference with inputs:["
+ String.join(", ", this.feedNames)
+ "], outputs:[" + String.join(", ", this.fetchNames) + "]");
throw var11;
} finally {
this.closeFeeds();
this.runner = this.sess.runner();
}
}
public Graph graph() {
return this.g;
}
public Operation graphOperation(String var1) {
Operation var2 = this.g.operation(var1);
if(var2 == null) {
throw new RuntimeException("Node '" + var1 + "' does not exist in model '");
} else {
return var2;
}
}
public String getStatString() {
return this.runStats == null?"":this.runStats.summary();
}
public void close() {
this.closeFeeds();
this.closeFetches();
this.sess.close();
this.g.close();
if(this.runStats != null) {
this.runStats.close();
}
this.runStats = null;
}
protected void finalize() throws Throwable {
try {
this.close();
} finally {
super.finalize();
}
}
public void feed(String var1, float[] var2, long... var3) {
this.addFeed(var1, Tensor.create(var3, FloatBuffer.wrap(var2)));
}
public void feed(String var1, int[] var2, long... var3) {
this.addFeed(var1, Tensor.create(var3, IntBuffer.wrap(var2)));
}
public void feed(String var1, long[] var2, long... var3) {
this.addFeed(var1, Tensor.create(var3, LongBuffer.wrap(var2)));
}
public void feed(String var1, double[] var2, long... var3) {
this.addFeed(var1, Tensor.create(var3, DoubleBuffer.wrap(var2)));
}
public void feed(String var1, byte[] var2, long... var3) {
this.addFeed(var1, Tensor.create(UInt8.class, var3, ByteBuffer.wrap(var2)));
}
public void feedString(String var1, byte[] var2) {
this.addFeed(var1, Tensors.create(var2));
}
public void feedString(String var1, byte[][] var2) {
this.addFeed(var1, Tensors.create(var2));
}
public void feed(String var1, FloatBuffer var2, long... var3) {
this.addFeed(var1, Tensor.create(var3, var2));
}
public void feed(String var1, IntBuffer var2, long... var3) {
this.addFeed(var1, Tensor.create(var3, var2));
}
public void feed(String var1, LongBuffer var2, long... var3) {
this.addFeed(var1, Tensor.create(var3, var2));
}
public void feed(String var1, DoubleBuffer var2, long... var3) {
this.addFeed(var1, Tensor.create(var3, var2));
}
public void feed(String var1, ByteBuffer var2, long... var3) {
this.addFeed(var1, Tensor.create(UInt8.class, var3, var2));
}
public void fetch(String var1, float[] var2) {
this.fetch(var1, FloatBuffer.wrap(var2));
}
public void fetch(String var1, int[] var2) {
this.fetch(var1, IntBuffer.wrap(var2));
}
public void fetch(String var1, long[] var2) {
this.fetch(var1, LongBuffer.wrap(var2));
}
public void fetch(String var1, double[] var2) {
this.fetch(var1, DoubleBuffer.wrap(var2));
}
public void fetch(String var1, byte[] var2) {
this.fetch(var1, ByteBuffer.wrap(var2));
}
public void fetch(String var1, FloatBuffer var2) {
this.getTensor(var1).writeTo(var2);
}
public void fetch(String var1, IntBuffer var2) {
this.getTensor(var1).writeTo(var2);
}
public void fetch(String var1, LongBuffer var2) {
this.getTensor(var1).writeTo(var2);
}
public void fetch(String var1, DoubleBuffer var2) {
this.getTensor(var1).writeTo(var2);
}
public void fetch(String var1, ByteBuffer var2) {
this.getTensor(var1).writeTo(var2);
}
private void prepareNativeRuntime() {
System.out.println("Checking to see if TensorFlow native methods are already loaded");
try {
new RunStats();
System.out.println("TensorFlow native methods already loaded");
} catch (UnsatisfiedLinkError var4) {
System.out.println("TensorFlow native methods not found, attempting to load via tensorflow_inference");
/* try {
System.loadLibrary("tensorflow_inference");
System.out.println("Successfully loaded TensorFlow native methods (RunStats error may be ignored)");
} catch (UnsatisfiedLinkError var3) {
throw new RuntimeException("Native TF methods not found; check that the correct native libraries are present in the APK.");
}*/
}
}
private void loadGraph(byte[] var1, Graph var2) throws IOException {
long var3 = System.currentTimeMillis();
try {
var2.importGraphDef(var1);
} catch (IllegalArgumentException var7) {
throw new IOException("Not a valid TensorFlow Graph serialization: " + var7.getMessage());
}
long var5 = System.currentTimeMillis();
System.out.println("Model load took " + (var5 - var3) + "ms, TensorFlow version: " + TensorFlow.version());
}
private void addFeed(String var1, Tensor<?> var2) {
TensorFlowInferenceInterface.TensorId var3 = TensorFlowInferenceInterface.TensorId.parse(var1);
this.runner.feed(var3.name, var3.outputIndex, var2);
this.feedNames.add(var1);
this.feedTensors.add(var2);
}
private Tensor<?> getTensor(String var1) {
int var2 = 0;
for(Iterator var3 = this.fetchNames.iterator(); var3.hasNext(); ++var2) {
String var4 = (String)var3.next();
if(var4.equals(var1)) {
return (Tensor)this.fetchTensors.get(var2);
}
}
throw new RuntimeException("Node '" + var1 + "' was not provided to run(), so it cannot be read");
}
private void closeFeeds() {
Iterator var1 = this.feedTensors.iterator();
while(var1.hasNext()) {
Tensor var2 = (Tensor)var1.next();
var2.close();
}
this.feedTensors.clear();
this.feedNames.clear();
}
private void closeFetches() {
Iterator var1 = this.fetchTensors.iterator();
while(var1.hasNext()) {
Tensor var2 = (Tensor)var1.next();
var2.close();
}
this.fetchTensors.clear();
this.fetchNames.clear();
}
private static class TensorId {
String name;
int outputIndex;
private TensorId() {
}
public static TensorFlowInferenceInterface.TensorId parse(String var0) {
TensorFlowInferenceInterface.TensorId var1 = new TensorFlowInferenceInterface.TensorId();
int var2 = var0.lastIndexOf(58);
if(var2 < 0) {
var1.outputIndex = 0;
var1.name = var0;
return var1;
} else {
try {
var1.outputIndex = Integer.parseInt(var0.substring(var2 + 1));
var1.name = var0.substring(0, var2);
} catch (NumberFormatException var4) {
var1.outputIndex = 0;
var1.name = var0;
}
return var1;
}
}
}
}
Is there an event in 1.7.10 for when a block is generated, so i can place something above it. Or do i have to do that within the generation?
I already have looked online but i could not find an
onBlockGenerated
event or something like that.
You need to extend WorldGenerator
class Foo extends WorldGenerator {
protected Block[] GetValidSpawnBlocks() {
return new Block[] { Blocks.quartz };
}
public boolean generate(final World world, final Random rand, final int x, final int y, final int z) {
world.setBlock(x,y+1,z,FooModBlocks.yourFancyBlock,0,2);
}
}
And register it in your iworldgenerator
public class MagicCookieWorldGen implements IWorldGenerator {
private Foo myGenerator;
public MagicCookieWorldGen() {
super();
myGenerator = new Foo();
}
#Override
public void generate(Random random, int chunkX, int chunkZ, World world,
IChunkProvider chunkGenerator, IChunkProvider chunkProvider) {
this.worldGeneration(random, chunkX, chunkZ, world, true);
}
public void worldGeneration(final Random random, final int chunkX, final int chunkZ, final World world, final boolean newGen) {
switch (world.provider.dimensionId) {
case -1: {
this.generateNether(world, random, chunkX, chunkZ, newGen);
break;
}
case 1: {
break;
}
default: {
break;
}
}
}
private void generateNether(final World world, final Random random, final int chunkX, final int chunkZ, final boolean newGen) {
int startX = chunkX * 16;
int startZ = chunkZ * 16;
int startY = 5;
int endX = startX + 16;
int endZ = startZ + 16;
int endY = 65;
for(int x=startX;x<endX;x++)for(int z=startZ;z<endZ;z++)for(int y = startY;y<endY;y++) {
Block block = world.getBlock(x,y,z);
for(Block match : Foo.GetValidSpawnBlocks()) {
if(match == block) {
Foo.generate(world, final Random random, x, y, z);
break;
}
}
}
}
}
Then in your commonproxy in the init phase
GameRegistry.registerWorldGenerator((IWorldGenerator)(StuffLoader.worldGenerator = new MagicCookieWorldGen()), 0);
MagicCookie.log.info("Registered worldgenerator" + StuffLoader.worldGenerator);
Item class:
public class Item {
public float x, y, speedx, speedy;
public Rectangle container;
public Texture texture;
static Timer timer = new Timer();
static int amount;
static int spawned;
public int itemtype;
// float delay = 1; // seconds
public void move() {
x += speedx;
y += speedy;
container.x = x;
container.y = y;
}
public void setTexture(int itemtype){
switch(itemtype){
case 1:
texture = new Texture("items/item1.png");
break;
case 2:
texture = new Texture("items/item2.png");
break;
case 3:
texture = new Texture("items/item3.png");
break;
case 4:
texture = new Texture("items/item4.png");
break;
case 5:
texture = new Texture("items/item5.png");
break;
case 6:
texture = new Texture("items/item6.png");
break;
case 7:
texture = new Texture("items/item7.png");
break;
case 8:
texture = new Texture("items/item8.png");
break;
case 9:
texture = new Texture("items/item9.png");
break;
case 10:
texture = new Texture("items/item10.png");
break;
default:
texture = new Texture("items/error.png");
break;
}
}
public static void spawnItem(int amount){
Item.amount = amount;
mainscreen.items.clear();
// for(int spawned = 0; spawned <= amount; spawned++){
timer.schedule(new Timer.Task() {
#Override
public void run() {
if (mainscreen.canclick == false) {
Item item = new Item();
item.x = 600;
item.y = -42;
item.speedx = -20;
item.speedy = 0;
Rectangle itemcontainer = new Rectangle();
itemcontainer.x = item.x;
itemcontainer.y = item.y;
itemcontainer.width = mainscreen.container.getWidth() / 4f;
itemcontainer.height = mainscreen.container.getHeight() - 15f;
item.container = itemcontainer;
item.itemtype = MathUtils.random(1, 10);
item.setTexture(item.itemtype);
mainscreen.items.add(item);
spawned++;
}
for (Item item : mainscreen.items) {
if (item.x <= -4000) {
if (spawned >= Item.amount) {
mainscreen.canclick = true;
timer.stop();
spawned = 0;
}
} else {
}
}
}
}, 0, 0.325f);
}
public void dispose(){
texture.dispose();
}
}
Mainscreen class:
public class mainscreen implements Screen, GestureDetector.GestureListener,InputProcessor {
#Override
public void render(float delta) {
this.delta = delta;
Gdx.gl.glClearColor(115 / 255F, 115 / 255F, 115 / 255F, 1 / 255F);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.setProjectionMatrix(camera.combined);
if(Gdx.input.justTouched()) {
Vector3 touch1 = new Vector3(Gdx.input.getX(), Gdx.input.getY(), 0);
camera.unproject(touch1);
if (debug.contains(touch1.x, touch1.y)) {
items.clear();
}
if (start.contains(touch1.x, touch1.y)) {
if (canclick == true) {
canclick = false;
Item.spawnItem(20);
}
}
}
}
LOG:
On first click start:
(After the Timer has finished)
canclick: true
items list: [com.abc.luckyllama.Item#37237aa0, com.abc.luckyllama.Item#2de938e3, com.abc.luckyllama.Item#3cb912d5, com.abc.luckyllama.Item#2bae592c, com.abc.luckyllama.Item#774c083, com.abc.luckyllama.Item#633edeae, com.abc.luckyllama.Item#176557a6, com.abc.luckyllama.Item#4edb1b5f, com.abc.luckyllama.Item#6f8abadf, com.abc.luckyllama.Item#7a54d22e, com.abc.luckyllama.Item#473162a5, com.abc.luckyllama.Item#51a698ff, com.abc.luckyllama.Item#6bc08c56, com.abc.luckyllama.Item#37d9e6a2, com.abc.luckyllama.Item#7bb19eb6, com.abc.luckyllama.Item#1eb5805f, com.abc.luckyllama.Item#71780de3, com.abc.luckyllama.Item#9ec0998, com.abc.luckyllama.Item#7edf723d, com.abc.luckyllama.Item#4c5aa2c1]
After clicking the debug button(clears arraylist):
canclick: true
items list: []
After clicking the start button again:
(After the Timer has finished)
canclick: true
items list: [com.abc.luckyllama.Item#7d7cb9bc, com.abc.luckyllama.Item#1435cf42, com.abc.luckyllama.Item#117e1963, com.abc.luckyllama.Item#82bfd27, com.abc.luckyllama.Item#108214c7, com.abc.luckyllama.Item#2a77864a, com.abc.luckyllama.Item#4b232766, com.abc.luckyllama.Item#1cb629e0, com.abc.luckyllama.Item#1c92229d, com.abc.luckyllama.Item#ac1b293, com.abc.luckyllama.Item#588bbcba, com.abc.luckyllama.Item#75df6762, com.abc.luckyllama.Item#78d4358e, com.abc.luckyllama.Item#7f86452d, com.abc.luckyllama.Item#7aed480b, com.abc.luckyllama.Item#7407d443, com.abc.luckyllama.Item#2da6e708, com.abc.luckyllama.Item#604470bc, com.abc.luckyllama.Item#70f9d1af, com.abc.luckyllama.Item#3a16a63f, com.abc.luckyllama.Item#201288d2, com.abc.luckyllama.Item#6310ddfc, com.abc.luckyllama.Item#5d5a1c98, com.abc.luckyllama.Item#52727e52, com.abc.luckyllama.Item#669228d6]
You see that the Items inside the ArrayList didn't get cleared. It increased. I think that's because the instances of Item created in spawnItem() are still there. How do I fix this?
I noticed that every time I click the button there aren't more items. The items are spawned faster. But how to stop this?
I fixed it! The problem was that I needed to create a Timer.Task seperately and the use task.cancel(); to stop the Timer.Task:
import com.badlogic.gdx.utils.Timer;
public class Item {
public static Timer.Task task;
public static void spawnItem(int amount){
Item.amount = amount;
task = new Timer.Task() {
#Override
public void run() {
if (mainscreen.canclick == false) {
item = new Item();
item.x = 600;
item.y = -42;
item.speedx = -20;
item.speedy = 0;
Rectangle itemcontainer = new Rectangle();
itemcontainer.x = item.x;
itemcontainer.y = item.y;
itemcontainer.width = mainscreen.container.getWidth() / 3f;
itemcontainer.height = mainscreen.container.getHeight() - 15f;
item.container = itemcontainer;
item.itemtype = MathUtils.random(1, 10);
item.setTexture(item.itemtype);
mainscreen.items.add(item);
mainscreen.itemsspawned += 1;
// mainscreen.items.remove(item);
spawned++;
}
for (Item item : mainscreen.items) {
if (item.x <= -4000) {
if (spawned >= Item.amount) {
mainscreen.canclick = true;
timer.clear();
timer.stop();
task.cancel();
spawned = 0;
}
}
}
}
};
timer.schedule(task, 0, 0.4f);
}
}
I'm coding my first audio application, and I'm struggling for hours on trying to change samplerate of a cached sound.
I'm using NAudio and I was able to change the Volume, tweaking the Read() method of my ISampleProvider.
Here is the CachedSound Class :
public class CachedSound
{
public float[] AudioData { get; private set; }
public WaveFormat WaveFormat { get; set; }
public CachedSound(string audioFileName)
{
using (var audioFileReader = new AudioFileReader(audioFileName))
{
WaveFormat = audioFileReader.WaveFormat;
var wholeFile = new List<float>((int)(audioFileReader.Length / 4));
var readBuffer = new float[audioFileReader.WaveFormat.SampleRate * audioFileReader.WaveFormat.Channels];
int samplesRead;
while ((samplesRead = audioFileReader.Read(readBuffer, 0, readBuffer.Length)) > 0)
{
wholeFile.AddRange(readBuffer.Take(samplesRead));
}
AudioData = wholeFile.ToArray();
}
}
}
And here is the CachedSoundSampleProvider class :
using NAudio.Wave;
using System;
public delegate void PlaybackEndedHandler();
public class CachedSoundSampleProvider : ISampleProvider
{
public event PlaybackEndedHandler PlaybackEnded;
private CachedSound cachedSound;
private long _position;
public long Position {
get { return _position; }
set { _position = value; }
}
private float _volume;
public float Volume {
get { return _volume; }
set { _volume = value; }
}
private float _pitchMultiplicator;
public float PitchMultiplicator
{
get { return _pitchMultiplicator; }
set { _pitchMultiplicator = value; }
}
public WaveFormat OriginalWaveFormat { get; set; }
public WaveFormat WaveFormat {
get { return cachedSound.WaveFormat; }
}
//Constructeur
public CachedSoundSampleProvider(CachedSound _cachedSound)
{
cachedSound = _cachedSound;
OriginalWaveFormat = WaveFormat;
}
public int Read(float[] destBuffer, int offset, int numBytes)
{
long availableSamples = cachedSound.AudioData.Length - Position;
long samplesToCopy = Math.Min(availableSamples, numBytes);
//Changing original audio data samplerate
//Double speed to check if working
cachedSound.WaveFormat = new WaveFormat(cachedSound.WaveFormat.SampleRate*2, cachedSound.WaveFormat.Channels);
Array.Copy(cachedSound.AudioData, Position, destBuffer, offset, samplesToCopy);
//Changing Volume
for (int i = 0; i < destBuffer.Length; ++i)
destBuffer[i] *= (Volume > -40) ? (float)Math.Pow(10.0f, Volume * 0.05f) : 0;
Position += samplesToCopy;
if (availableSamples == 0) PlaybackEnded();
return (int)samplesToCopy;
}
}
I don't know how I can achieve this yet.
My goal is simple, I want to be able to tweak sample rate at realtime.
I read it's impossible to change it on the ISampleProvider interface.
That's why I tried to change it on the original audioData.
Thanks in advance for your help ! :)