Added the following files : - AudioCue.kt - AudioFeedbackEngine - AudioFeedbackSettings Edited files : - BowlingCameraActivity (added the triggerAudiofeedback function)
67 lines
3.1 KiB
Kotlin
67 lines
3.1 KiB
Kotlin
/**
|
|
* @file AudioCue.kt
|
|
* @brief Spoken coaching cues and queue policy for [AudioFeedbackEngine].
|
|
*/
|
|
package com.example.jnicpp.bowling
|
|
|
|
/**
|
|
* @brief A spoken coaching cue delivered by [AudioFeedbackEngine].
|
|
*
|
|
* [text] is handed verbatim to TTS. [priority] is informational for callers
|
|
* deciding which [QueuePolicy] to apply, higher numbers are more urgent
|
|
* (e.g. a timing correction mid-approach outranks a general encouragement).
|
|
*
|
|
* Extend this sealed class to add new domain-specific cues without touching
|
|
* the engine; the engine only cares about [text] and the policy the caller
|
|
* chooses.
|
|
*/
|
|
sealed class AudioCue(val text: String, val priority: Int) {
|
|
|
|
// -- Arm / elbow cues (medium priority) --
|
|
/** Elbow angle too acute -- arm is over-bent during swing. */
|
|
object StraightenArm : AudioCue("Straighten your bowling arm", priority = 5)
|
|
/** Elbow locking out too early, arm rigid before release point. */
|
|
object BendElbow : AudioCue("Bend your elbow slightly", priority = 5)
|
|
|
|
// -- Shoulder cues (medium priority) --
|
|
/** Bowling-side shoulder rising, disrupting swing plane. */
|
|
object LowerShoulder : AudioCue("Keep your shoulder down", priority = 5)
|
|
/** Shoulder plane collapsing -- both shoulders dropping together. */
|
|
object LevelShoulders : AudioCue("Level your shoulders", priority = 5)
|
|
|
|
// -- Approach / timing cues (higher priority) --
|
|
/** Approach tempo too fast; bowler rushing the delivery. */
|
|
object SlowDown : AudioCue("Slow down your approach", priority = 7)
|
|
/** Positive reinforcement -- form looks good this frame. */
|
|
object GoodForm : AudioCue("Good form, keep it up", priority = 3)
|
|
|
|
// -- Escape hatch for one-off or dynamically constructed messages --
|
|
/**
|
|
* @brief Arbitrary spoken message not covered by the predefined cues above.
|
|
* @param message The text to speak.
|
|
* @param p Priority; defaults to medium (5).
|
|
*/
|
|
data class Custom(val message: String, val p: Int = 5) : AudioCue(message, p)
|
|
}
|
|
|
|
/**
|
|
* @brief Controls how [AudioFeedbackEngine] handles a new cue when TTS is already busy.
|
|
*
|
|
* Choose the policy at the call site based on how time-sensitive the cue is:
|
|
*
|
|
* | Policy | Behaviour |
|
|
* |-------------------|------------------------------------------------------------------|
|
|
* | [INTERRUPT] | Flushes the TTS queue and speaks immediately. Use for urgent |
|
|
* | | corrections that must be heard right now. |
|
|
* | [QUEUE] | Appended after whatever is currently playing. Use for cues |
|
|
* | | that can wait their turn (e.g. a sequence of tips post-throw). |
|
|
* | [DISCARD_IF_BUSY] | Silently dropped if TTS is already speaking. The default for |
|
|
* | | live per-frame cues, preventing the same note from stacking up |
|
|
* | | across many frames while TTS works through an earlier one. |
|
|
*/
|
|
enum class QueuePolicy {
|
|
INTERRUPT,
|
|
QUEUE,
|
|
DISCARD_IF_BUSY
|
|
}
|