atsushieee's picture
Upload folder using huggingface_hub
5e84ffc verified
"""Console application for all practices."""
import time
from abc import ABC, abstractmethod
from typing import Optional
import numpy as np
from improvisation_lab.application.base_app import BasePracticeApp
from improvisation_lab.config import Config
from improvisation_lab.infrastructure.audio import DirectAudioProcessor
from improvisation_lab.presentation.console_view import ConsolePracticeView
from improvisation_lab.service.base_practice_service import BasePracticeService
class ConsoleBasePracticeApp(BasePracticeApp, ABC):
"""Console application class for all practices."""
def __init__(self, service: BasePracticeService, config: Config):
"""Initialize the application using console UI.
Args:
service: PracticeService instance.
config: Config instance.
"""
super().__init__(service, config)
self.audio_processor = DirectAudioProcessor(
sample_rate=config.audio.sample_rate,
callback=self._process_audio_callback,
buffer_duration=config.audio.buffer_duration,
)
self.ui: Optional[ConsolePracticeView] = None
def _process_audio_callback(self, audio_data: np.ndarray):
"""Process incoming audio data and update the application state.
Args:
audio_data: Audio data to process.
"""
if self.phrases is None:
return
current_note = self._get_current_note()
result = self.service.process_audio(audio_data, current_note)
if self.ui is not None:
self.ui.display_pitch_result(result)
# Progress to next note if current note is complete
if result.remaining_time <= 0:
self._advance_to_next_note()
def _advance_to_next_note(self):
"""Advance to the next note or phrase."""
if self.phrases is None:
return
self.current_note_idx += 1
if self.current_note_idx >= len(self._get_current_phrase()):
self.current_note_idx = 0
self.current_phrase_idx += 1
if self.current_phrase_idx >= len(self.phrases):
self.current_phrase_idx = 0
self.ui.display_phrase_info(self.current_phrase_idx, self.phrases)
def launch(self):
"""Launch the application."""
self.ui.launch()
self.phrases = self._generate_melody()
self.current_phrase_idx = 0
self.current_note_idx = 0
self.is_running = True
if not self.audio_processor.is_recording:
try:
self.audio_processor.start_recording()
self.ui.display_phrase_info(self.current_phrase_idx, self.phrases)
while True:
time.sleep(0.1)
except KeyboardInterrupt:
print("\nStopping...")
finally:
self.audio_processor.stop_recording()
@abstractmethod
def _get_current_note(self):
"""Return the current note to be processed."""
pass
@abstractmethod
def _get_current_phrase(self):
"""Return the current phrase to be processed."""
pass
@abstractmethod
def _generate_melody(self):
"""Generate melody specific to the practice type."""
pass