Enhance autocomplete sound system with completion feedback

- Add autocomplete_end sound event for completion confirmation
- Remove programmatic sound generation in favor of sound pack files
- Implement state tracking to prevent duplicate autocomplete sounds
- Add comprehensive sound system policy to CLAUDE.md
- Restore full CLAUDE.md documentation with development workflow
- Update Doom sound pack to include autocomplete_end.ogg mapping

Sound behavior improvements:
- Autocomplete sound plays once per session when suggestions appear
- Autocomplete_end sound plays when user selects or dismisses suggestions
- State resets cleanly for next autocomplete interaction
- Follows sound pack architecture instead of generating audio

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Storm Dragon
2025-07-20 21:38:16 -04:00
parent 2e0c7263b4
commit 31314764bf
3 changed files with 29 additions and 42 deletions

View File

@ -3,6 +3,10 @@
## Project Overview
Bifrost is a fully accessible fediverse client built with PySide6, designed specifically for screen reader users. The application uses "post/posts" terminology instead of "toot" and focuses on excellent keyboard navigation and audio feedback.
## Development Workflow
- Check for any changes in git project before doing anything else. Make sure the latest changes have been pulled
- See what has changed, use git commands and examine the code to make sure you are up to date with the latest code
## Core Features
- Full ActivityPub protocol support (Pleroma and GoToSocial primary targets)
- Threaded conversation navigation with collapsible tree view
@ -137,6 +141,15 @@ Timeline Item: "Alice posted: Hello world (3 replies, collapsed)"
- **collapse**: Thread collapsed
- **success**: General success feedback
- **error**: Error occurred
- **autocomplete**: Autocomplete suggestions available
- **autocomplete_end**: Autocomplete interaction ended
### Sound System Policy
- **No Sound Generation**: The application should never generate sounds programmatically
- **Sound Pack Reliance**: All audio feedback must come from sound pack files
- **Default Pack Requirement**: A complete default sound pack must ship with the project
- **Themed Packs**: Users can install additional themed sound packs (like Doom)
- If someone requests sound generation, gently remind them that all sounds should be covered by sound packs
### Sound Pack Structure
**pack.json Format:**

View File

@ -160,46 +160,6 @@ class SoundManager:
with open(pack_file, 'w') as f:
json.dump(pack_data, f, indent=2)
# Create default autocomplete sound if it doesn't exist
autocomplete_sound = default_dir / "autocomplete.wav"
if not autocomplete_sound.exists():
self.create_autocomplete_sound(autocomplete_sound)
def create_autocomplete_sound(self, output_path: Path):
"""Create a simple autocomplete notification sound"""
try:
# Parameters for a gentle notification chime
sample_rate = 22050 # Lower sample rate for smaller file
duration = 0.15 # Short 150ms sound
frequency = 800 # Pleasant mid-range frequency
# Generate time array
t = np.linspace(0, duration, int(sample_rate * duration), False)
# Create a gentle chime with fade in/out to avoid clicks
tone = np.sin(2 * np.pi * frequency * t)
# Add slight fade in/out to prevent audio clicks
fade_samples = int(sample_rate * 0.02) # 20ms fade
tone[:fade_samples] *= np.linspace(0, 1, fade_samples)
tone[-fade_samples:] *= np.linspace(1, 0, fade_samples)
# Reduce volume to be gentle
tone *= 0.3
# Convert to 16-bit PCM
audio = (tone * 32767).astype(np.int16)
# Write WAV file
with wave.open(str(output_path), 'w') as wav_file:
wav_file.setnchannels(1) # Mono
wav_file.setsampwidth(2) # 16-bit
wav_file.setframerate(sample_rate)
wav_file.writeframes(audio.tobytes())
except Exception as e:
print(f"Failed to create autocomplete sound: {e}")
def load_current_pack(self):
"""Load the currently selected sound pack"""
@ -438,6 +398,10 @@ class SoundManager:
"""Play autocomplete available sound"""
self.play_event("autocomplete")
def play_autocomplete_end(self):
"""Play autocomplete ended sound"""
self.play_event("autocomplete_end")
def test_sound(self, event_type: str):
"""Test play a specific sound type"""
self.play_event(event_type)

View File

@ -22,6 +22,9 @@ class AutocompleteTextEdit(QTextEdit):
# Sound manager for audio feedback
self.sound_manager = sound_manager
# Autocomplete sound state tracking
self.autocomplete_sound_played = False
# Lists for autocomplete
self.mention_list = [] # Will be populated from followers/following
self.emoji_list = [] # Will be populated from instance custom emojis
@ -257,19 +260,26 @@ class AutocompleteTextEdit(QTextEdit):
popup = self.completer.popup()
popup.setAccessibleName(f"{completion_type.title()} Autocomplete")
# Play autocomplete available sound
if self.sound_manager:
# Play autocomplete available sound (only once per session)
if self.sound_manager and not self.autocomplete_sound_played:
self.sound_manager.play_autocomplete()
self.autocomplete_sound_played = True
def hide_completer(self):
"""Hide the completer"""
if self.completer:
popup = self.completer.popup()
if popup.isVisible(): # Only play sound if completer was actually visible
# Play autocomplete end sound (only if autocomplete sound was played)
if self.sound_manager and self.autocomplete_sound_played:
self.sound_manager.play_autocomplete_end()
popup.hide()
# Clear the completion state
self.completion_prefix = ""
self.completion_start = 0
self.completion_type = None
# Reset sound state for next autocomplete session
self.autocomplete_sound_played = False
def insert_completion(self):
"""Insert the selected completion"""