Perkeo
Registrierter Benutzer
Hallo zusammen,
ich suche schon seit längerem eine Möglichkeit, meine Übungszeit (E-Gitarre) zu protokollieren. Natürlich lässt sich das mit einer Stopuhr oder einem Timer verwirklichen, Problem dabei ist: Es ist umständlich und ich vergesse ständig, den Timerknopf zu drücken, hab keine Lust die Zeiten irgendwo einzugeben, einzutragen, etc. Also übe ich halt doch so mehr oder weniger bis es genug ist oder ich keine Lust mehr habe.
Deshalb hab ich mal ChatGTP befragt und heraus gekommen ist ein kleines Tool in html, welches wie eine Stopuhr funktioniert. Ausgelöst wird der Timer durch ein Signal des Audioeinganges an welchem mein Pod Go angeschlossen ist. Und das funktioniert so:
Sobald ein Signal über den Audioeingang kommt, startet der Timer. Wenn ich nun aufhöre zu üben, kommt kein Signal mehr. Mein Tool zählt dann noch 5 Minuten weiter bevor es die Protokollierung stoppt. Ist die Spielpause länger als 5 Minuten wird die Protokollierung beendet und diese 5 Minuten von der Spielzeit abgezogen.
Das Ganze wird dann in eine Tabelle eingetragen.
So wird also meine tägliche Übungszeit minutengenau erfasst und protokolliert. Einziger Aufwand dabei: Der Browser muss geöffnet sein (ist er bei mir sowieso fast immer) und der Schwellwert, ab welchem das Tool die Protokollierung startet muss vorher eingestellt werden.
Es funktioniert in seiner Grundfunktion, wurde aber noch nicht im Langzeitbetrieb getestet und ich würde es gern noch ein bißchen erweitern. Allerdings hab ich keinen kostenpflichtigen ChatGTP Account und muss jetzt bis morgen warten, um daran weiter zu arbeiten. Aber vielleicht hat jemand von euch Lust, es auszuprobieren oder selbst ein bißchen damit zu basteln.
lg Perkeo
Hier der Quelltext:
ich suche schon seit längerem eine Möglichkeit, meine Übungszeit (E-Gitarre) zu protokollieren. Natürlich lässt sich das mit einer Stopuhr oder einem Timer verwirklichen, Problem dabei ist: Es ist umständlich und ich vergesse ständig, den Timerknopf zu drücken, hab keine Lust die Zeiten irgendwo einzugeben, einzutragen, etc. Also übe ich halt doch so mehr oder weniger bis es genug ist oder ich keine Lust mehr habe.
Deshalb hab ich mal ChatGTP befragt und heraus gekommen ist ein kleines Tool in html, welches wie eine Stopuhr funktioniert. Ausgelöst wird der Timer durch ein Signal des Audioeinganges an welchem mein Pod Go angeschlossen ist. Und das funktioniert so:
Sobald ein Signal über den Audioeingang kommt, startet der Timer. Wenn ich nun aufhöre zu üben, kommt kein Signal mehr. Mein Tool zählt dann noch 5 Minuten weiter bevor es die Protokollierung stoppt. Ist die Spielpause länger als 5 Minuten wird die Protokollierung beendet und diese 5 Minuten von der Spielzeit abgezogen.
Das Ganze wird dann in eine Tabelle eingetragen.
So wird also meine tägliche Übungszeit minutengenau erfasst und protokolliert. Einziger Aufwand dabei: Der Browser muss geöffnet sein (ist er bei mir sowieso fast immer) und der Schwellwert, ab welchem das Tool die Protokollierung startet muss vorher eingestellt werden.
Es funktioniert in seiner Grundfunktion, wurde aber noch nicht im Langzeitbetrieb getestet und ich würde es gern noch ein bißchen erweitern. Allerdings hab ich keinen kostenpflichtigen ChatGTP Account und muss jetzt bis morgen warten, um daran weiter zu arbeiten. Aber vielleicht hat jemand von euch Lust, es auszuprobieren oder selbst ein bißchen damit zu basteln.
lg Perkeo
Hier der Quelltext:
Code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Guitar Practice Timer</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 20px;
background-color: black;
color: white;
}
h1 {
text-align: center;
}
#controls, #log {
margin-top: 20px;
}
table {
width: 100%;
border-collapse: collapse;
}
th, td {
border: 1px solid #555;
padding: 8px;
}
th {
background-color: #333;
color: white;
text-align: left;
}
td {
background-color: #222;
}
#threshold-container {
margin-top: 20px;
}
#visualizer {
width: 100%;
height: 20px;
background-color: #444;
position: relative;
margin-bottom: 10px;
}
#level {
height: 100%;
background-color: green;
width: 0;
}
#threshold-slider {
width: 100%;
}
#session-time {
color: white;
}
</style>
</head>
<body>
<h1>Guitar Practice Timer</h1>
<div id="controls">
<label for="audio-input">Select Audio Input:</label>
<select id="audio-input"></select>
<button id="start-button">Start Monitoring</button>
<button id="stop-button" disabled>Stop Monitoring</button>
</div>
<div id="threshold-container">
<div id="visualizer">
<div id="level"></div>
</div>
<label for="threshold-slider">Set Threshold:</label>
<input type="range" id="threshold-slider" min="0" max="100" value="5">
</div>
<div id="status">
<p><strong>Status:</strong> <span id="status-text">Stopped</span></p>
<p><strong>Current Session Time:</strong> <span id="session-time">0:00</span></p>
</div>
<div id="log">
<h2>Practice Log</h2>
<table>
<thead>
<tr>
<th>Date</th>
<th>Time Practiced</th>
</tr>
</thead>
<tbody id="log-table-body">
</tbody>
</table>
</div>
<script>
const audioInputSelect = document.getElementById('audio-input');
const startButton = document.getElementById('start-button');
const stopButton = document.getElementById('stop-button');
const statusText = document.getElementById('status-text');
const sessionTime = document.getElementById('session-time');
const logTableBody = document.getElementById('log-table-body');
const thresholdSlider = document.getElementById('threshold-slider');
const visualizer = document.getElementById('visualizer');
const level = document.getElementById('level');
let audioContext, analyser, source;
let monitoring = false;
let startTime = null;
let accumulatedTime = 0;
let silenceTimer = null;
let silenceThreshold = 5 * 60 * 1000; // 5 minutes in milliseconds
async function getAudioInputs() {
const devices = await navigator.mediaDevices.enumerateDevices();
const audioInputs = devices.filter(device => device.kind === 'audioinput');
audioInputs.forEach((device, index) => {
const option = document.createElement('option');
option.value = device.deviceId;
option.textContent = device.label || `Microphone ${index + 1}`;
audioInputSelect.appendChild(option);
});
}
function formatTime(ms) {
const totalSeconds = Math.floor(ms / 1000);
const minutes = Math.floor(totalSeconds / 60);
const seconds = totalSeconds % 60;
return `${minutes}:${seconds.toString().padStart(2, '0')}`;
}
function updateLog(date, time) {
const row = document.createElement('tr');
const dateCell = document.createElement('td');
const timeCell = document.createElement('td');
dateCell.textContent = date;
timeCell.textContent = formatTime(time);
row.appendChild(dateCell);
row.appendChild(timeCell);
logTableBody.appendChild(row);
}
async function saveData() {
const data = {
date: new Date().toLocaleDateString(),
accumulatedTime
};
const file = new Blob([JSON.stringify(data)], { type: 'application/json' });
const a = document.createElement('a');
a.href = URL.createObjectURL(file);
a.download = 'practice_data.json';
a.click();
}
async function startMonitoring() {
const selectedDeviceId = audioInputSelect.value;
const stream = await navigator.mediaDevices.getUserMedia({
audio: { deviceId: selectedDeviceId },
video: false
});
audioContext = new AudioContext();
analyser = audioContext.createAnalyser();
analyser.fftSize = 256;
source = audioContext.createMediaStreamSource(stream);
source.connect(analyser);
monitoring = true;
statusText.textContent = 'Monitoring';
startTime = Date.now();
accumulatedTime = 0;
silenceTimer = null;
startButton.disabled = true;
stopButton.disabled = false;
monitorAudio();
}
function stopMonitoring() {
monitoring = false;
statusText.textContent = 'Stopped';
if (startTime) {
accumulatedTime += Date.now() - startTime;
updateLog(new Date().toLocaleDateString(), accumulatedTime);
}
if (silenceTimer) {
clearTimeout(silenceTimer);
}
if (audioContext) {
audioContext.close();
}
saveData();
startButton.disabled = false;
stopButton.disabled = true;
}
function monitorAudio() {
if (!monitoring) return;
const buffer = new Uint8Array(analyser.frequencyBinCount);
analyser.getByteFrequencyData(buffer);
const volume = buffer.reduce((sum, value) => sum + value, 0) / buffer.length;
const threshold = parseInt(thresholdSlider.value, 10);
// Update visualizer
level.style.width = `${(volume / 256) * 100}%`;
if (volume > threshold) { // Noise detected
sessionTime.style.color = 'green';
if (silenceTimer) {
clearTimeout(silenceTimer);
silenceTimer = null;
}
if (!startTime) {
startTime = Date.now();
}
sessionTime.textContent = formatTime(accumulatedTime + (Date.now() - startTime));
} else {
sessionTime.style.color = 'red';
if (!silenceTimer) {
silenceTimer = setTimeout(() => {
accumulatedTime += Date.now() - startTime;
startTime = null;
}, silenceThreshold);
}
if (startTime) {
sessionTime.textContent = formatTime(accumulatedTime + (Date.now() - startTime));
}
}
requestAnimationFrame(monitorAudio);
}
startButton.addEventListener('click', startMonitoring);
stopButton.addEventListener('click', stopMonitoring);
getAudioInputs();
window.addEventListener('beforeunload', saveData);
</script>
</body>
</html>