You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
268 lines
8.7 KiB
268 lines
8.7 KiB
#!/usr/bin/env python3
|
|
"""
|
|
Audio and MIDI Diagnostic Tool
|
|
Helps identify issues with audio playback and MIDI output
|
|
"""
|
|
|
|
import sys
|
|
import os
|
|
import time
|
|
|
|
# Add project to path
|
|
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
|
|
|
def test_pygame_audio():
|
|
"""Test pygame audio system directly"""
|
|
print("=== Testing Pygame Audio ===")
|
|
|
|
try:
|
|
import pygame
|
|
import numpy as np
|
|
|
|
# Initialize pygame mixer
|
|
pygame.mixer.pre_init(frequency=22050, size=-16, channels=2, buffer=512)
|
|
pygame.mixer.init()
|
|
print("PASS: Pygame mixer initialized successfully")
|
|
|
|
# Test basic audio playback
|
|
print("Testing basic audio generation...")
|
|
|
|
# Generate a simple sine wave (440 Hz for 1 second)
|
|
sample_rate = 22050
|
|
duration = 1.0 # seconds
|
|
frequency = 440 # A4
|
|
|
|
# Generate samples
|
|
samples = np.sin(2 * np.pi * frequency * np.linspace(0, duration, int(sample_rate * duration)))
|
|
|
|
# Apply envelope and scale
|
|
envelope = np.exp(-np.linspace(0, 3, len(samples))) # Fade out
|
|
samples = samples * envelope * 0.5
|
|
|
|
# Convert to 16-bit integers and make stereo
|
|
samples = (samples * 32767).astype(np.int16)
|
|
stereo_samples = np.column_stack((samples, samples))
|
|
|
|
# Create and play sound
|
|
sound = pygame.sndarray.make_sound(stereo_samples)
|
|
print("Playing test tone (440Hz for 1 second)...")
|
|
sound.play()
|
|
|
|
# Wait for playback
|
|
time.sleep(1.2)
|
|
|
|
print("✓ Direct pygame audio test completed")
|
|
return True
|
|
|
|
except Exception as e:
|
|
print(f"✗ Pygame audio test failed: {e}")
|
|
import traceback
|
|
traceback.print_exc()
|
|
return False
|
|
|
|
def test_simulator_audio():
|
|
"""Test the simulator audio system"""
|
|
print("\n=== Testing Simulator Audio ===")
|
|
|
|
try:
|
|
from simulator.simulator_engine import SimulatorEngine
|
|
|
|
simulator = SimulatorEngine()
|
|
print(f"✓ Simulator initialized, audio enabled: {simulator.audio_enabled}")
|
|
print(f" Audio initialized: {simulator.audio_initialized_flag}")
|
|
print(f" Stereo mode: {getattr(simulator, 'stereo_mode', 'Unknown')}")
|
|
|
|
# Test note playback
|
|
print("Testing note playback through simulator...")
|
|
simulator.play_note(1, 60, 80) # Channel 1, Middle C, velocity 80
|
|
time.sleep(0.8)
|
|
simulator.stop_note(1, 60)
|
|
|
|
print("✓ Simulator audio test completed")
|
|
return True
|
|
|
|
except Exception as e:
|
|
print(f"✗ Simulator audio test failed: {e}")
|
|
import traceback
|
|
traceback.print_exc()
|
|
return False
|
|
|
|
def test_midi_devices():
|
|
"""Test MIDI device detection"""
|
|
print("\n=== Testing MIDI Devices ===")
|
|
|
|
try:
|
|
import mido
|
|
print("✓ Mido library available")
|
|
|
|
# List MIDI outputs
|
|
outputs = mido.get_output_names()
|
|
print(f"Available MIDI outputs ({len(outputs)}):")
|
|
for i, output in enumerate(outputs):
|
|
print(f" {i+1}. {output}")
|
|
|
|
if outputs:
|
|
print(f"\nTesting MIDI output with: {outputs[0]}")
|
|
try:
|
|
midi_out = mido.open_output(outputs[0])
|
|
print("✓ MIDI output opened successfully")
|
|
|
|
# Send test note
|
|
print("Sending test note (Middle C)...")
|
|
msg_on = mido.Message('note_on', channel=0, note=60, velocity=80)
|
|
msg_off = mido.Message('note_off', channel=0, note=60, velocity=0)
|
|
|
|
midi_out.send(msg_on)
|
|
print(" - Note ON sent")
|
|
time.sleep(0.5)
|
|
midi_out.send(msg_off)
|
|
print(" - Note OFF sent")
|
|
|
|
midi_out.close()
|
|
print("✓ MIDI test completed")
|
|
return True
|
|
|
|
except Exception as e:
|
|
print(f"✗ MIDI output test failed: {e}")
|
|
return False
|
|
else:
|
|
print("⚠ No MIDI outputs available")
|
|
return False
|
|
|
|
except ImportError:
|
|
print("✗ Mido library not available")
|
|
return False
|
|
except Exception as e:
|
|
print(f"✗ MIDI test failed: {e}")
|
|
return False
|
|
|
|
def test_arpeggiator_integration():
|
|
"""Test the full arpeggiator system"""
|
|
print("\n=== Testing Arpeggiator Integration ===")
|
|
|
|
try:
|
|
from core.midi_channel_manager import MIDIChannelManager
|
|
from core.volume_pattern_engine import VolumePatternEngine
|
|
from core.synth_router import SynthRouter
|
|
from simulator.simulator_engine import SimulatorEngine
|
|
from core.output_manager import OutputManager
|
|
from core.arpeggiator_engine import ArpeggiatorEngine
|
|
|
|
# Create components
|
|
channel_manager = MIDIChannelManager()
|
|
volume_engine = VolumePatternEngine()
|
|
synth_router = SynthRouter(channel_manager)
|
|
simulator = SimulatorEngine()
|
|
output_manager = OutputManager(simulator)
|
|
arpeggiator = ArpeggiatorEngine(channel_manager, synth_router, volume_engine, output_manager)
|
|
|
|
print("✓ All components initialized")
|
|
|
|
# Test simulator mode
|
|
output_manager.set_mode("simulator")
|
|
print(f"✓ Output mode: {output_manager.current_mode}")
|
|
|
|
# Configure arpeggiator
|
|
arpeggiator.set_root_note(60) # Middle C
|
|
arpeggiator.set_scale("major")
|
|
arpeggiator.set_pattern_type("up")
|
|
arpeggiator.set_tempo(120)
|
|
|
|
# Add notes to trigger arpeggiator
|
|
print("Adding notes and starting arpeggiator...")
|
|
arpeggiator.note_on(60) # C
|
|
arpeggiator.note_on(64) # E
|
|
|
|
# Start arpeggiator
|
|
started = arpeggiator.start()
|
|
print(f"✓ Arpeggiator started: {started}")
|
|
|
|
if started:
|
|
print("Letting arpeggiator run for 3 seconds...")
|
|
time.sleep(3)
|
|
arpeggiator.stop()
|
|
print("✓ Arpeggiator stopped")
|
|
|
|
return True
|
|
|
|
except Exception as e:
|
|
print(f"✗ Arpeggiator integration test failed: {e}")
|
|
import traceback
|
|
traceback.print_exc()
|
|
return False
|
|
|
|
def test_system_audio():
|
|
"""Test system audio capabilities"""
|
|
print("\n=== Testing System Audio ===")
|
|
|
|
try:
|
|
import pygame
|
|
|
|
# Get mixer info
|
|
pygame.mixer.init()
|
|
print(f"✓ Pygame version: {pygame.version.ver}")
|
|
|
|
# Check mixer settings
|
|
freq = pygame.mixer.get_init()
|
|
if freq:
|
|
print(f"✓ Mixer frequency: {freq[0]}Hz, {freq[1]}-bit, {freq[2]} channels")
|
|
else:
|
|
print("✗ Mixer not initialized")
|
|
|
|
# Check number of channels
|
|
channels = pygame.mixer.get_num_channels()
|
|
print(f"✓ Available sound channels: {channels}")
|
|
|
|
return True
|
|
|
|
except Exception as e:
|
|
print(f"✗ System audio test failed: {e}")
|
|
return False
|
|
|
|
def main():
|
|
"""Run all diagnostic tests"""
|
|
print("MIDI Arpeggiator - Audio & MIDI Diagnostics")
|
|
print("=" * 50)
|
|
|
|
results = {}
|
|
|
|
# Run tests
|
|
results['system_audio'] = test_system_audio()
|
|
results['pygame_audio'] = test_pygame_audio()
|
|
results['simulator_audio'] = test_simulator_audio()
|
|
results['midi_devices'] = test_midi_devices()
|
|
results['arpeggiator'] = test_arpeggiator_integration()
|
|
|
|
# Summary
|
|
print("\n" + "=" * 50)
|
|
print("DIAGNOSTIC SUMMARY:")
|
|
print("=" * 50)
|
|
|
|
for test_name, result in results.items():
|
|
status = "✓ PASS" if result else "✗ FAIL"
|
|
print(f"{test_name:20}: {status}")
|
|
|
|
# Recommendations
|
|
print("\nRECOMMENDATIONS:")
|
|
print("-" * 30)
|
|
|
|
if not results['pygame_audio']:
|
|
print("• Audio issues detected - check Windows audio settings")
|
|
print("• Try different audio drivers or devices")
|
|
print("• Check if other applications are using audio exclusively")
|
|
|
|
if not results['midi_devices']:
|
|
print("• No MIDI devices found for hardware mode")
|
|
print("• Install virtual MIDI cables (like loopMIDI) for software synths")
|
|
print("• Check MIDI device drivers")
|
|
|
|
if not results['simulator_audio']:
|
|
print("• Simulator audio not working - check pygame audio initialization")
|
|
|
|
if not results['arpeggiator']:
|
|
print("• Arpeggiator integration issues - check component initialization")
|
|
|
|
print(f"\nOverall success rate: {sum(results.values())}/{len(results)} tests passed")
|
|
|
|
if __name__ == "__main__":
|
|
main()
|