Files
PinPoint/app/src/main/java/com/example/jnicpp/bowling/AudioCue.kt
T
Khalil Belabadia 9fcdc13699 Audio feedback update
Added the following files :

- AudioCue.kt
- AudioFeedbackEngine
- AudioFeedbackSettings

Edited files :

- BowlingCameraActivity (added the triggerAudiofeedback function)
2026-09-07 22:16:00 +08:00

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
}