improve volume control

This commit is contained in:
2025-12-27 18:12:32 +01:00
parent bf6c443ebd
commit 2ad1fe0ea9
4 changed files with 90 additions and 28 deletions

View File

@@ -82,13 +82,32 @@
.success-message {
color: white;
font-size: 2.5rem;
font-weight: 800;
background-color: rgba(0, 0, 0, 0.7);
background-color: rgba(0, 0, 0, 0.75);
padding: 1rem 2rem;
border-radius: 50px;
border-radius: 40px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
backdrop-filter: blur(4px);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
line-height: 1.1;
text-align: center;
}
.success-prefix {
font-size: 1.5rem;
font-weight: 700;
opacity: 0.9;
text-transform: uppercase;
letter-spacing: 0.05em;
margin-bottom: 0.2rem;
}
.success-note {
font-size: 4rem;
font-weight: 800;
text-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
}
.instruction-text {

View File

@@ -53,6 +53,8 @@ function App() {
customMaxFret: 12,
autoPlaySightReading: false,
autoPlayVolume: 0.5,
virtualGuitarVolume: 0.5,
virtualGuitarMute: false,
disableAnimation: false
});
@@ -252,7 +254,9 @@ function App() {
// Virtual Guitar Handler
const handleVirtualGuitarPlay = useCallback((playedMidi: number) => {
playNote(playedMidi, 0.5); // Feedback sound
if (!settings.virtualGuitarMute) {
playNote(playedMidi, 0.5, settings.virtualGuitarVolume ?? 0.5); // Feedback sound
}
setVirtualNote(playedMidi);
// Clear the note visualization after a short delay
@@ -266,7 +270,7 @@ function App() {
handleMatchSuccess();
}
}
}, [playNote, targetMidi, feedbackMessage, handleMatchSuccess]);
}, [playNote, targetMidi, feedbackMessage, handleMatchSuccess, settings]);
// Match Logic
useEffect(() => {
@@ -428,7 +432,16 @@ function App() {
{!settings.zenMode && (
<div className="feedback-area">
{feedbackMessage ? (
<div className="success-message animate-pop">{feedbackMessage}</div>
<div className="success-message animate-pop">
{feedbackMessage.startsWith("Good! ") ? (
<>
<div className="success-prefix">Good!</div>
<div className="success-note">{feedbackMessage.replace("Good! ", "")}</div>
</>
) : (
feedbackMessage
)}
</div>
) : (
<div className="instruction-text">
{settings.gameMode === 'ear_training' ? "Listen and play the note" : "Play the note above"}

View File

@@ -31,6 +31,8 @@ export interface AppSettings {
customMaxFret?: number;
autoPlaySightReading?: boolean;
autoPlayVolume?: number;
virtualGuitarVolume?: number;
virtualGuitarMute?: boolean;
disableAnimation?: boolean;
}

View File

@@ -1,5 +1,5 @@
import React from 'react';
import { X, Volume2 } from 'lucide-react';
import { X, Volume2, VolumeX } from 'lucide-react';
import type { AppSettings } from './Controls';
interface SettingsModalProps {
@@ -39,6 +39,36 @@ export const SettingsModal: React.FC<SettingsModalProps> = ({ isOpen, onClose, s
<hr style={{ borderColor: 'rgba(255,255,255,0.1)', margin: '24px 0' }} />
<div className="control-group" style={{ marginBottom: '24px' }}>
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: '8px' }}>
<label className="control-label" style={{ marginBottom: 0, fontSize: '16px' }}>
<span>Virtual Guitar Sound</span>
</label>
<button
className={`switch-button ${!settings.virtualGuitarMute ? 'active' : ''}`}
onClick={() => onUpdateSettings({ ...settings, virtualGuitarMute: !settings.virtualGuitarMute })}
title={settings.virtualGuitarMute ? "Unmute" : "Mute"}
>
<div className="switch-thumb" />
</button>
</div>
<div style={{ display: 'flex', alignItems: 'center', gap: '12px', opacity: settings.virtualGuitarMute ? 0.5 : 1, transition: 'opacity 0.2s' }}>
{settings.virtualGuitarMute ? <VolumeX size={20} style={{ opacity: 0.7 }} /> : <Volume2 size={20} style={{ opacity: 0.7 }} />}
<input
type="range"
min="0"
max="1"
step="0.05"
value={settings.virtualGuitarVolume ?? 0.5}
onChange={(e) => onUpdateSettings({ ...settings, virtualGuitarVolume: parseFloat(e.target.value) })}
style={{ flex: 1 }}
disabled={settings.virtualGuitarMute}
/>
</div>
</div>
<hr style={{ borderColor: 'rgba(255,255,255,0.1)', margin: '24px 0' }} />
{/* Auto Play Settings */}
<div className="control-group">
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: '12px' }}>
@@ -63,28 +93,26 @@ export const SettingsModal: React.FC<SettingsModalProps> = ({ isOpen, onClose, s
</button>
</div>
{(settings.gameMode === 'ear_training' || settings.autoPlaySightReading) && (
<div style={{ display: 'flex', alignItems: 'center', gap: '12px' }}>
<Volume2 size={20} style={{ opacity: 0.7 }} />
<input
type="range"
min="0"
max="1"
step="0.05"
value={settings.autoPlayVolume ?? 0.5}
onChange={(e) => onUpdateSettings({ ...settings, autoPlayVolume: parseFloat(e.target.value) })}
style={{ flex: 1 }}
/>
</div>
)}
<p style={{ fontSize: '12px', opacity: 0.7, margin: '8px 0 0 0' }}>
{settings.gameMode === 'ear_training'
? "Automatically plays the note audio (Required for Ear Training)."
: "Automatically plays the note audio when a new note appears."}
</p>
<div style={{ display: 'flex', alignItems: 'center', gap: '12px' }}>
<Volume2 size={20} style={{ opacity: 0.7 }} />
<input
type="range"
min="0"
max="1"
step="0.05"
value={settings.autoPlayVolume ?? 0.5}
onChange={(e) => onUpdateSettings({ ...settings, autoPlayVolume: parseFloat(e.target.value) })}
style={{ flex: 1 }}
/>
</div>
</div>
<p style={{ fontSize: '12px', opacity: 0.7, margin: '8px 0 0 0' }}>
{settings.gameMode === 'ear_training'
? "Automatically plays the note audio (Required for Ear Training)."
: "Automatically plays the note audio when a new note appears."}
</p>
</div>
</div>
);
};