From 1503b654398b902f1ac90d83da9cbac1daa76167 Mon Sep 17 00:00:00 2001 From: Ruben Date: Fri, 19 Aug 2016 12:38:59 +0100 Subject: [PATCH] Add sound and proper tick for scenario --- .../emotionhero/GamingActivity.java | 87 +++++++++-- .../rubenvandeven/emotionhero/Scenario.java | 147 +++++++++++++++--- .../emotionhero/ScenarioAnger.java | 5 + .../emotionhero/ScenarioView.java | 87 ++++++++--- app/src/main/res/raw/score2.mp3 | Bin 0 -> 17137 bytes 5 files changed, 261 insertions(+), 65 deletions(-) create mode 100644 app/src/main/res/raw/score2.mp3 diff --git a/app/src/main/java/com/rubenvandeven/emotionhero/GamingActivity.java b/app/src/main/java/com/rubenvandeven/emotionhero/GamingActivity.java index cea872f..b29eaf2 100644 --- a/app/src/main/java/com/rubenvandeven/emotionhero/GamingActivity.java +++ b/app/src/main/java/com/rubenvandeven/emotionhero/GamingActivity.java @@ -2,9 +2,12 @@ package com.rubenvandeven.emotionhero; import android.Manifest; import android.annotation.SuppressLint; +import android.annotation.TargetApi; import android.content.pm.PackageManager; -import android.graphics.Bitmap; -import android.graphics.Canvas; +import android.media.AudioAttributes; +import android.media.AudioManager; +import android.media.SoundPool; +import android.os.Build; import android.support.v4.app.ActivityCompat; import android.support.v7.app.ActionBar; import android.support.v7.app.AppCompatActivity; @@ -25,6 +28,7 @@ import com.affectiva.android.affdex.sdk.detector.CameraDetector; import com.affectiva.android.affdex.sdk.detector.Detector; import com.affectiva.android.affdex.sdk.detector.Face; +import java.util.HashMap; import java.util.List; /** @@ -123,6 +127,12 @@ public class GamingActivity extends AppCompatActivity implements Detector.ImageL TextView paramText; + public SoundPool sound; + public HashMap soundIds = new HashMap<>(); + + final static int SOUND_SCORE = 1; + + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -182,6 +192,7 @@ public class GamingActivity extends AppCompatActivity implements Detector.ImageL } } setMeasuredDimension(width,height); +// setMeasuredDimension(1,1); // this DOES increase performance.... } }; RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); @@ -191,16 +202,15 @@ public class GamingActivity extends AppCompatActivity implements Detector.ImageL videoLayout.addView(cameraPreview,0); - currentScenario = new ScenarioAnger(); + currentScenario = new ScenarioAnger(this); scenarioView = new ScenarioView(this, currentScenario); RelativeLayout.LayoutParams scenarioViewParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); videoLayout.addView(scenarioView, 1, scenarioViewParams); -// new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT) -// videoLayout.addView(scenarioView, 200, 100); + createSoundPool(); // instantiate SoundPool in sound + soundIds.put(SOUND_SCORE, sound.load(this, R.raw.score2, 1)); -// startDetector(); } @Override @@ -254,14 +264,16 @@ public class GamingActivity extends AppCompatActivity implements Detector.ImageL if(detector == null) { // SurfaceView surfaceView = (SurfaceView) findViewById(R.id.surfaceView); - detector = new CameraDetector(this, CameraDetector.CameraType.CAMERA_FRONT, cameraPreview); + + detector = new CameraDetector(this, CameraDetector.CameraType.CAMERA_FRONT, cameraPreview, 1, Detector.FaceDetectorMode.LARGE_FACES); detector.setLicensePath("emotionhero_dev.license"); + detector.setMaxProcessRate(10); detector.setDetectAllEmotions(true); detector.setDetectAllAppearances(false); detector.setDetectAllEmojis(false); detector.setDetectAllExpressions(false); - detector.setMaxProcessRate(12); + detector.setMaxProcessRate(20); detector.setImageListener(this); detector.setOnCameraEventListener(this); @@ -269,7 +281,7 @@ public class GamingActivity extends AppCompatActivity implements Detector.ImageL } detector.start(); - mContentView.setText("STARTING..."); + setText("STARTING..."); Log.d(LOG_TAG, Boolean.toString(detector.isRunning())); } } @@ -321,10 +333,12 @@ public class GamingActivity extends AppCompatActivity implements Detector.ImageL * Detector callback gives the faces found so we can match their scores to the given scenario. */ public void onImageResults(List list, Frame frame, float timestamp) { +// frame.getOriginalBitmapFrame() // Log.e(LOG_TAG, "RESULT! faces: " + Integer.toString(list.size()) + " t: " + Float.toString(timestamp) + "s" ); - if(!currentScenario.isWithinTime(timestamp)) +// if(!currentScenario.isWithinTime(timestamp)) + if(currentScenario.isFinished()) { - mContentView.setText(String.format("LEVEL ENDED\nScore: %.2f", currentScenario.getTotalScore())); + setText(String.format("LEVEL ENDED\nScore: %.2f", currentScenario.getTotalScore())); stopDetector(); restartButton.setVisibility(View.VISIBLE); return; @@ -332,12 +346,12 @@ public class GamingActivity extends AppCompatActivity implements Detector.ImageL if (list == null) return; if (list.size() == 0) { - mContentView.setText("NO FACE FOUND"); +// mContentView.setText("NO FACE FOUND"); // this happens in onFaceDetectionStopped } else { + hideText(); // hide textView as we want as few elements as possible. Face face = list.get(0); - currentScenario.validateFaceOnTime(face, timestamp); + currentScenario.setCurrentAttributeScoresForFace(face); scenarioView.setCurrentAttributeScoresForFace(face); - mContentView.setText(String.format("SCORE \n%.2f",currentScenario.getTotalScore())); // String paramString = ""; // paramString += "Anger " + String.format("%02.2f", face.emotions.getAnger()) + "%\n"; @@ -394,14 +408,53 @@ public class GamingActivity extends AppCompatActivity implements Detector.ImageL @Override public void onFaceDetectionStarted() { - mContentView.setText("START!"); + setText("START!"); currentScenario.start(); } @Override public void onFaceDetectionStopped() { - mContentView.setText("No face found..."); -// paramText.setText("No face found"); + setText("No face found..."); + currentScenario.pause(); + } + + public void setText(String text) + { + mContentView.setVisibility(View.VISIBLE); + mContentView.setText(text); + } + + public void hideText() + { + mContentView.setVisibility(View.GONE); + } + + +// http://stackoverflow.com/a/27552576 + protected void createSoundPool() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + createNewSoundPool(); + } else { + createOldSoundPool(); + } + } + +// http://stackoverflow.com/a/27552576 + @TargetApi(Build.VERSION_CODES.LOLLIPOP) + protected void createNewSoundPool(){ + AudioAttributes attributes = new AudioAttributes.Builder() + .setUsage(AudioAttributes.USAGE_GAME) + .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION) + .build(); + sound = new SoundPool.Builder() + .setAudioAttributes(attributes) + .build(); + } + +// http://stackoverflow.com/a/27552576 + @SuppressWarnings("deprecation") + protected void createOldSoundPool(){ + sound = new SoundPool(5, AudioManager.STREAM_MUSIC,0); } } diff --git a/app/src/main/java/com/rubenvandeven/emotionhero/Scenario.java b/app/src/main/java/com/rubenvandeven/emotionhero/Scenario.java index a345fd4..2b40f57 100644 --- a/app/src/main/java/com/rubenvandeven/emotionhero/Scenario.java +++ b/app/src/main/java/com/rubenvandeven/emotionhero/Scenario.java @@ -1,16 +1,12 @@ package com.rubenvandeven.emotionhero; -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Paint; -import android.util.Log; - import com.affectiva.android.affdex.sdk.detector.Face; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; +import java.util.Timer; +import java.util.TimerTask; /** * Created by ruben on 16/08/16. @@ -18,10 +14,36 @@ import java.util.Map; abstract public class Scenario { + static int DESIRED_FPS = 25; + float duration = 0; + /** + * @deprecated + */ long startTime = 0; + /** + * The timer that provides the tick + */ + Timer timer; + + /** + * Increment on each tick + */ + float runningTime = -1; + + + boolean isRunning = false; + + private GamingActivity _activity; + + /** + * The scorres in this moment, as to draw them on the screen. + * Indexes are Emotion ordinals + */ + private Map currentAttributeScores = new HashMap<>(); + ArrayList targets = new ArrayList<>(); abstract void createScenario(); @@ -30,6 +52,7 @@ abstract public class Scenario { public Emotion emotion; public float value; public float timestamp; + public Score score; } ArrayList scores = new ArrayList<>(); @@ -40,20 +63,68 @@ abstract public class Scenario { * Extra bonus given */ public boolean isSpotOn = false; - /** - * The target the score is awarded for - */ - public Target target; } /** * Constructor */ - public Scenario() + public Scenario(GamingActivity activity) { createScenario(); + timer = new Timer("ScenarioTimer"); + TimerTask tickTask; + tickTask = new TimerTask() { + @Override + public void run() { + // if (System.currentTimeMillis() - scheduledExecutionTime() >= + // MAX_TARDINESS) + // return; // Too late; skip this execution. + tick(); + } + }; + timer.schedule(tickTask, 0, 1000/DESIRED_FPS); + _activity = activity; } + /** + * To be called on each timer tick + */ + public void tick() + { + if(!isRunning) + return; + + runningTime += 1.0f/DESIRED_FPS; + + if(isFinished()) { + stop(); + return; + } + + for (int i = targets.size() - 1; i >= 0; i--) { + Target target = targets.get(i); + // skip targets that are already scored + if(target.score != null) { + continue; + } + if(target.timestamp <= runningTime) { + float scored_value = currentAttributeScores.get(target.emotion); + float required_value = target.value; + Score score = new Score(); + score.value = Math.round(100 - Math.abs(scored_value-required_value)); + scores.add(score); + + // + _activity.sound.play(_activity.soundIds.get(_activity.SOUND_SCORE), 1, 1, + 1,0, score.value / 200f + 0.5f ); // play back the sound slower + // depending on score value + target.score = score; + } + } + + } + + /** * Add a target on given timestamp * @param emotion @@ -63,9 +134,9 @@ abstract public class Scenario { public void setTarget(Emotion emotion, float value, float timestamp) { // Log.e(GamingActivity.LOG_TAG, "Set target:" + Float.toString(timestamp) + " " + Float.toString(duration)); - if(timestamp > duration) + if((timestamp + 1) > duration) { - duration = timestamp; + duration = timestamp + 1; // always a bit onger than last target, as it otherwise the game does not finish pretty } Target target = new Target(); target.timestamp = timestamp; @@ -91,6 +162,11 @@ abstract public class Scenario { setTarget(emotion, value, timestamp); } + /** + * @deprecated use @see tick() + * @param face + * @param timestamp + */ public void validateFaceOnTime(Face face, float timestamp) { // TODO: interpolation of time @@ -101,7 +177,7 @@ abstract public class Scenario { float required_value = target.value; Score score = new Score(); score.value = 100 - Math.abs(scored_value-required_value); - score.target = target; + target.score = score; scores.add(score); } } @@ -135,21 +211,46 @@ abstract public class Scenario { * Get the time within the scenario (so since start() has been called) */ public float getTime() { + return runningTime; // if not started, don't move the labels, if started, move them by diff_y - if(startTime == 0) { - return 0; - } else { - float diff_t = ((System.currentTimeMillis() - startTime)) / (float) 1000; - if(diff_t > duration) { // never larger than scenario duration - return duration; - } - return diff_t; - } +// if(startTime == 0) { +// return 0; +// } else { +// float diff_t = ((System.currentTimeMillis() - startTime)) / (float) 1000; +// if(diff_t > duration) { // never larger than scenario duration +// return duration; +// } +// return diff_t; +// } } public void start() { startTime = System.currentTimeMillis(); + isRunning = true; + } + + public void pause() { + isRunning = false; + } + + public void stop() + { + isRunning = false; + } + + + // TODO: create AttributeScoreCollection class, with this method. + public void setCurrentAttributeScoresForFace(Face face) + { + for(Emotion emotion: Emotion.values()) { + currentAttributeScores.put(emotion, emotion.getValueFromFace(face)); + } + } + + public boolean isFinished() + { + return runningTime > duration; } // TODO: create a 'tick' that checks all current values with requirements and increases the timer etc diff --git a/app/src/main/java/com/rubenvandeven/emotionhero/ScenarioAnger.java b/app/src/main/java/com/rubenvandeven/emotionhero/ScenarioAnger.java index 31450cd..c879b12 100644 --- a/app/src/main/java/com/rubenvandeven/emotionhero/ScenarioAnger.java +++ b/app/src/main/java/com/rubenvandeven/emotionhero/ScenarioAnger.java @@ -7,6 +7,11 @@ import android.util.Log; */ public class ScenarioAnger extends Scenario { + + public ScenarioAnger(GamingActivity activity) { + super(activity); + } + void createScenario() { Log.d(GamingActivity.LOG_TAG, "CREATE SCENARIO: anger"); diff --git a/app/src/main/java/com/rubenvandeven/emotionhero/ScenarioView.java b/app/src/main/java/com/rubenvandeven/emotionhero/ScenarioView.java index 608d7f3..815b06e 100644 --- a/app/src/main/java/com/rubenvandeven/emotionhero/ScenarioView.java +++ b/app/src/main/java/com/rubenvandeven/emotionhero/ScenarioView.java @@ -6,8 +6,7 @@ import android.graphics.Color; import android.graphics.Paint; import android.graphics.Path; import android.graphics.PixelFormat; -import android.util.AttributeSet; -import android.util.Log; +import android.graphics.Typeface; import android.view.SurfaceHolder; import android.view.SurfaceView; @@ -32,6 +31,14 @@ public class ScenarioView extends SurfaceView implements SurfaceHolder.Callback */ private Map currentAttributeScores = new HashMap<>(); + //avoid object instantiation on each onDraw + private Map emoPaints = new HashMap<>(); + private Map emoOutlinePaints = new HashMap<>(); + private Map emoScoredPaints = new HashMap<>(); + private Paint mainPaint = new Paint(); + private Paint attrScorePaint = new Paint(); + private Paint linePaint = new Paint(); + // see: http://blog.danielnadeau.io/2012/01/android-canvas-beginners-tutorial.html class PanelThread extends Thread { @@ -58,6 +65,7 @@ public class ScenarioView extends SurfaceView implements SurfaceHolder.Callback c = null; //set to false and loop ends, stopping thread try { +// c = _surfaceHolder.lockCanvas(null); c = _surfaceHolder.lockCanvas(null); synchronized (_surfaceHolder) { //Insert methods to modify positions of items in onDraw() @@ -76,6 +84,43 @@ public class ScenarioView extends SurfaceView implements SurfaceHolder.Callback super(context); getHolder().addCallback(this); _scenario = s; + + //setup paints for drawing + mainPaint.setColor(Color.GRAY); + mainPaint.setTextSize(40); + mainPaint.setTypeface(Typeface.SANS_SERIF); + + linePaint.setColor(Color.GRAY); + linePaint.setStrokeWidth(5); + attrScorePaint.setColor(Color.DKGRAY); + + for(Emotion emotion: Emotion.values()) { + Paint emoPaint = new Paint(); + emoPaint.setTextSize(20); + emoPaint.setColor(emotion.getColor()); + emoPaints.put(emotion, emoPaint); + + Paint emoPaintOutline = new Paint(); + emoPaintOutline.setColor(emotion.getColor()); + emoPaintOutline.setStyle(Paint.Style.STROKE); + emoPaintOutline.setStrokeWidth(2); + emoOutlinePaints.put(emotion, emoPaintOutline); + + Paint emoScoredPaint = new Paint(); + + float darkenFactor = 0.4f; + int red = (int) ((Color.red(emotion.getColor()) * darkenFactor)); + int green = (int) ((Color.green(emotion.getColor()) * darkenFactor)); + int blue = (int) ((Color.blue(emotion.getColor()) * darkenFactor)); + int emoLightenedColor = Color.rgb(red, green, blue); + + emoScoredPaint.setColor(emoLightenedColor); + emoScoredPaint.setTextSize(20); + emoScoredPaint.setStrokeWidth(2); + emoScoredPaint.setStyle(Paint.Style.FILL_AND_STROKE); + emoScoredPaints.put(emotion, emoScoredPaint); + + } } @@ -96,15 +141,6 @@ public class ScenarioView extends SurfaceView implements SurfaceHolder.Callback float step_y = (canvas.getWidth() * used_width) / Emotion.values().length; float max_ball_radius = step_y * (float) 0.8 / 2; - -// bottom at 80%; - Paint mainPaint = new Paint(); - mainPaint.setColor(Color.GRAY); - - - Paint linePaint = new Paint(); - linePaint.setColor(Color.GRAY); - linePaint.setStrokeWidth(5); // canvas.drawLine(0, bottomline_height, width, bottomline_height, linePaint); @@ -117,22 +153,16 @@ public class ScenarioView extends SurfaceView implements SurfaceHolder.Callback if(value < 5) { value = 5; } - Paint emoPaint = new Paint(); - Paint emoPaintOutline = new Paint(); - emoPaint.setTextSize(20); - emoPaint.setColor(emotion.getColor()); - emoPaintOutline.setColor(emotion.getColor()); - emoPaintOutline.setStyle(Paint.Style.STROKE); - emoPaintOutline.setStrokeWidth(2); float cx = padding_left + (step_y * emotion.ordinal() + step_y / 2); float cy = bottomline_height; canvas.drawCircle(cx, cy, max_ball_radius, mainPaint); - canvas.drawCircle(cx, cy, max_ball_radius, emoPaintOutline); + canvas.drawCircle(cx, cy, max_ball_radius, emoOutlinePaints.get(emotion)); - canvas.drawCircle(cx, cy, max_ball_radius * value/100, emoPaint); +// canvas.drawCircle(cx, cy, max_ball_radius * value/100, emoPaints.get(emotion.ordinal())); + canvas.drawCircle(cx, cy, max_ball_radius * value/100, attrScorePaint); Path emoNamePath = new Path(); emoNamePath.moveTo(cx, cy + max_ball_radius * 1.5f); @@ -141,7 +171,7 @@ public class ScenarioView extends SurfaceView implements SurfaceHolder.Callback emoNamePath.rLineTo(1000,1000); // canvas.drawText(emotion.toString(), cx, cy + max_ball_radius * (float) 1.3, emoPaint); - canvas.drawTextOnPath(emotion.toString(), emoNamePath, 0, 0, emoPaint); + canvas.drawTextOnPath(emotion.toString(), emoNamePath, 0, 0, emoPaints.get(emotion)); } // Draw targets: @@ -150,21 +180,28 @@ public class ScenarioView extends SurfaceView implements SurfaceHolder.Callback float diff_y = sec_height * _scenario.getTime(); for(Scenario.Target target: _scenario.getTargets()) { - Paint emoPaint = new Paint(); - emoPaint.setColor(target.emotion.getColor()); - + Paint targetPaint = (target.score == null) ? emoPaints.get(target.emotion) : emoScoredPaints.get(target.emotion); float cy = bottomline_height - (target.timestamp * sec_height) + diff_y; float cx = padding_left + (step_y * target.emotion.ordinal() + step_y / 2); - canvas.drawCircle(cx, cy, max_ball_radius * target.value/100, emoPaint); + canvas.drawCircle(cx, cy, max_ball_radius * target.value/100, targetPaint); + + if(target.score != null) { + canvas.drawText(Float.toString(target.score.value), cx, cy, targetPaint); + } + // String target_text = target.emotion.toString() + " " + target.value + "%"; // canvas.drawText(target_text, cx, y_pos + diff_y , emoPaint); } + canvas.drawText("Total: " + Float.toString(_scenario.getTotalScore()), 50, 50, mainPaint); + + } +// TODO: create AttributeScoreCollection class, with this method. public void setCurrentAttributeScoresForFace(Face face) { for(Emotion emotion: Emotion.values()) { diff --git a/app/src/main/res/raw/score2.mp3 b/app/src/main/res/raw/score2.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..489b7302331f394b5a1d0816fadf452d57cdd86b GIT binary patch literal 17137 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 VGhJw3(%t`q+y4K*{J(wz{|iFRUMc_p literal 0 HcmV?d00001