Spaces:
Sleeping
Sleeping
File size: 4,154 Bytes
c1e08a0 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 |
"""Tests for MelodyPracticeService."""
import time
import numpy as np
import pytest
from improvisation_lab.config import Config
from improvisation_lab.service.melody_practice_service import (
MelodyPracticeService, PitchResult)
class TestMelodyService:
@pytest.fixture
def init_module(self):
"""Create MelodyService instance for testing."""
config = Config()
self.service = MelodyPracticeService(config)
@pytest.mark.usefixtures("init_module")
def test_generate_melody(self):
"""Test melody generation."""
phrases = self.service.generate_melody()
assert len(phrases) > 0
assert all(hasattr(phrase, "notes") for phrase in phrases)
assert all(hasattr(phrase, "chord_name") for phrase in phrases)
assert all(hasattr(phrase, "scale_info") for phrase in phrases)
assert all(hasattr(phrase, "length") for phrase in phrases)
@pytest.mark.usefixtures("init_module")
def test_process_audio_no_voice(self):
"""Test processing audio with no voice detected."""
audio_data = np.zeros(1024, dtype=np.float32)
result = self.service.process_audio(audio_data, target_note="A")
assert isinstance(result, PitchResult)
assert result.current_base_note is None
assert not result.is_correct
@pytest.mark.usefixtures("init_module")
def test_process_audio_with_voice(self):
"""Test processing audio with voice detected."""
sample_rate = 44100
duration = 0.1
t = np.linspace(0, duration, int(sample_rate * duration))
audio_data = np.sin(2 * np.pi * 440 * t)
result = self.service.process_audio(audio_data, target_note="A")
assert isinstance(result, PitchResult)
assert result.current_base_note == "A"
assert result.is_correct
@pytest.mark.usefixtures("init_module")
def test_process_audio_incorrect_pitch(self):
"""Test processing audio with incorrect pitch."""
sample_rate = 44100
duration = 0.1
t = np.linspace(0, duration, int(sample_rate * duration))
# Generate 440Hz (A4) when target is C4
audio_data = np.sin(2 * np.pi * 440 * t)
result = self.service.process_audio(audio_data, target_note="C")
assert isinstance(result, PitchResult)
assert result.current_base_note == "A"
assert not result.is_correct
assert result.remaining_time == self.service.config.audio.note_duration
@pytest.mark.usefixtures("init_module")
def test_correct_pitch_timing(self):
"""Test timing behavior with correct pitch."""
sample_rate = 44100
duration = 0.1
t = np.linspace(0, duration, int(sample_rate * duration))
audio_data = np.sin(2 * np.pi * 440 * t)
# First detection
result1 = self.service.process_audio(audio_data, target_note="A")
initial_time = self.service.correct_pitch_start_time
assert result1.is_correct
assert result1.remaining_time == self.service.config.audio.note_duration
# Wait a bit
time.sleep(0.5)
# Second detection
result2 = self.service.process_audio(audio_data, target_note="A")
assert result2.is_correct
assert result2.remaining_time < self.service.config.audio.note_duration
assert initial_time == self.service.correct_pitch_start_time
@pytest.mark.usefixtures("init_module")
def test_correct_pitch_completion(self):
"""Test completion of correct pitch duration."""
sample_rate = 44100
duration = 0.1
t = np.linspace(0, duration, int(sample_rate * duration))
audio_data = np.sin(2 * np.pi * 440 * t)
# First detection
result1 = self.service.process_audio(audio_data, target_note="A")
assert result1.remaining_time == self.service.config.audio.note_duration
# Wait for full duration
time.sleep(self.service.config.audio.note_duration + 0.1)
# Final detection
result2 = self.service.process_audio(audio_data, target_note="A")
assert result2.remaining_time == 0
|