mirror of
https://github.com/9x/sheetmusictrainer.git
synced 2026-09-02 09:34:33 +02:00
improve volume control
This commit is contained in:
27
src/App.css
27
src/App.css
@@ -82,13 +82,32 @@
|
|||||||
|
|
||||||
.success-message {
|
.success-message {
|
||||||
color: white;
|
color: white;
|
||||||
font-size: 2.5rem;
|
background-color: rgba(0, 0, 0, 0.75);
|
||||||
font-weight: 800;
|
|
||||||
background-color: rgba(0, 0, 0, 0.7);
|
|
||||||
padding: 1rem 2rem;
|
padding: 1rem 2rem;
|
||||||
border-radius: 50px;
|
border-radius: 40px;
|
||||||
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
|
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
|
||||||
backdrop-filter: blur(4px);
|
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 {
|
.instruction-text {
|
||||||
|
|||||||
19
src/App.tsx
19
src/App.tsx
@@ -53,6 +53,8 @@ function App() {
|
|||||||
customMaxFret: 12,
|
customMaxFret: 12,
|
||||||
autoPlaySightReading: false,
|
autoPlaySightReading: false,
|
||||||
autoPlayVolume: 0.5,
|
autoPlayVolume: 0.5,
|
||||||
|
virtualGuitarVolume: 0.5,
|
||||||
|
virtualGuitarMute: false,
|
||||||
disableAnimation: false
|
disableAnimation: false
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -252,7 +254,9 @@ function App() {
|
|||||||
|
|
||||||
// Virtual Guitar Handler
|
// Virtual Guitar Handler
|
||||||
const handleVirtualGuitarPlay = useCallback((playedMidi: number) => {
|
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);
|
setVirtualNote(playedMidi);
|
||||||
|
|
||||||
// Clear the note visualization after a short delay
|
// Clear the note visualization after a short delay
|
||||||
@@ -266,7 +270,7 @@ function App() {
|
|||||||
handleMatchSuccess();
|
handleMatchSuccess();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [playNote, targetMidi, feedbackMessage, handleMatchSuccess]);
|
}, [playNote, targetMidi, feedbackMessage, handleMatchSuccess, settings]);
|
||||||
|
|
||||||
// Match Logic
|
// Match Logic
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -428,7 +432,16 @@ function App() {
|
|||||||
{!settings.zenMode && (
|
{!settings.zenMode && (
|
||||||
<div className="feedback-area">
|
<div className="feedback-area">
|
||||||
{feedbackMessage ? (
|
{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">
|
<div className="instruction-text">
|
||||||
{settings.gameMode === 'ear_training' ? "Listen and play the note" : "Play the note above"}
|
{settings.gameMode === 'ear_training' ? "Listen and play the note" : "Play the note above"}
|
||||||
|
|||||||
@@ -31,6 +31,8 @@ export interface AppSettings {
|
|||||||
customMaxFret?: number;
|
customMaxFret?: number;
|
||||||
autoPlaySightReading?: boolean;
|
autoPlaySightReading?: boolean;
|
||||||
autoPlayVolume?: number;
|
autoPlayVolume?: number;
|
||||||
|
virtualGuitarVolume?: number;
|
||||||
|
virtualGuitarMute?: boolean;
|
||||||
disableAnimation?: boolean;
|
disableAnimation?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { X, Volume2 } from 'lucide-react';
|
import { X, Volume2, VolumeX } from 'lucide-react';
|
||||||
import type { AppSettings } from './Controls';
|
import type { AppSettings } from './Controls';
|
||||||
|
|
||||||
interface SettingsModalProps {
|
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' }} />
|
<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 */}
|
{/* Auto Play Settings */}
|
||||||
<div className="control-group">
|
<div className="control-group">
|
||||||
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: '12px' }}>
|
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: '12px' }}>
|
||||||
@@ -63,7 +93,6 @@ export const SettingsModal: React.FC<SettingsModalProps> = ({ isOpen, onClose, s
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{(settings.gameMode === 'ear_training' || settings.autoPlaySightReading) && (
|
|
||||||
<div style={{ display: 'flex', alignItems: 'center', gap: '12px' }}>
|
<div style={{ display: 'flex', alignItems: 'center', gap: '12px' }}>
|
||||||
<Volume2 size={20} style={{ opacity: 0.7 }} />
|
<Volume2 size={20} style={{ opacity: 0.7 }} />
|
||||||
<input
|
<input
|
||||||
@@ -76,7 +105,7 @@ export const SettingsModal: React.FC<SettingsModalProps> = ({ isOpen, onClose, s
|
|||||||
style={{ flex: 1 }}
|
style={{ flex: 1 }}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
</div>
|
||||||
<p style={{ fontSize: '12px', opacity: 0.7, margin: '8px 0 0 0' }}>
|
<p style={{ fontSize: '12px', opacity: 0.7, margin: '8px 0 0 0' }}>
|
||||||
{settings.gameMode === 'ear_training'
|
{settings.gameMode === 'ear_training'
|
||||||
? "Automatically plays the note audio (Required for Ear Training)."
|
? "Automatically plays the note audio (Required for Ear Training)."
|
||||||
@@ -85,6 +114,5 @@ export const SettingsModal: React.FC<SettingsModalProps> = ({ isOpen, onClose, s
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user