Hei,
Jeg har implementert Weblydarkiv / Voicegram / Multiple-Location Audio Recording i HTML5 med W3C WebAudio og WebStorage API med en beskrivelse av implementasjonen i https://www.oleaamot.com/research/Aamot,2026.pdf
Dette har hittil vært mitt fokus i 2025 etter at jeg så et foredrag om AI med Bjørn Sverre Gulheim på Digital Competence Days 6. januar 2025.
Kanskje dette også etterhvert kan implementeres i Nikita Noark5 Core for weblydarkiv?
Her følger HTML5-implementasjonen som fungerer med lokal storage og XML med base64 encoding av audio som .flac-fil basert på W3C WebAudio og WebStorage. Kan sikkert utvides til å lagre flere filer, men dette er neste iterasjon av MLAR som også er publisert initielt med Makefile på https://www.oleaamot.com/research/Makefile og C-program på https://www.oleaamot.com/research/mlar.c som jeg ble inspirert til å skrive etter at jeg drakk en Gingerblue Blåbær Kombucha (grønn gjæret te) i 4. etasje på Oslo City med en kollega fra UiO, som startet utviklingen min av GarageJam 4.0.0 (https://www.garagejam.org/src/garagejam-4.0.0.tar.xz) og Gingerblue 8.0 Studio API'et på https://www.aamot.engineering/software/gingerblue/www/api/gingerblue/8.0/studio/?computer=GNOME/intelligence.aamot.io som også benytter seg av W3C WebStorage.
// voicegram.html //
<!DOCTYPE html> <html lang="no"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Flere Filer og Lydopptak</title> <style> body { font-family: Arial, sans-serif; margin: 20px; } #fileList { margin-top: 20px; } button { padding: 10px; margin: 10px; cursor: pointer; } #recorderControls { margin-top: 20px; } #audioPlayer { margin-top: 20px; } </style> </head> <body> <h1>Flere Filer og Lydopptak</h1>
<button id="loadFilesButton">Last inn lydfiler fra WebStorage</button> <button id="clearStorageButton">Tøm WebStorage</button>
<h2>Lydfiler:</h2> <div id="fileList"></div>
<h2>Lydopptaker:</h2> <div id="recorderControls"> <button id="startRecordingButton">Start opptak</button> <button id="stopRecordingButton" disabled>Stopp opptak</button> <audio id="audioPlayer" controls></audio> </div>
<input type="file" id="fileInput" accept=".flac" multiple />
<script> // JavaScript-kode for håndtering av flere .flac filer og opptak
// Funksjon for å hente og vise lagrede filer fra WebStorage function loadFilesFromStorage() { const files = JSON.parse(localStorage.getItem('flacFiles')) || []; const fileList = document.getElementById('fileList'); fileList.innerHTML = '';
if (files.length > 0) { files.forEach((fileData, index) => { const fileElement = document.createElement('div'); fileElement.innerHTML = `<strong>Fil ${index + 1}:</strong> <audio controls> <source src="${fileData.audioUrl}" type="audio/flac"> Din nettleser støtter ikke FLAC-formatet. </audio>`; fileList.appendChild(fileElement); }); } else { fileList.innerHTML = 'Ingen lydfiler lagret.'; } }
// Funksjon for å laste opp og lagre flac-filer i WebStorage function handleFileUpload(event) { const files = event.target.files; const fileArray = JSON.parse(localStorage.getItem('flacFiles')) || [];
Array.from(files).forEach(file => { if (file.type === 'audio/flac') { const reader = new FileReader();
reader.onloadend = function() { // Legg til filens base64-streng i WebStorage fileArray.push({ fileName: file.name, audioUrl: reader.result });
// Lagre de nye filene i WebStorage localStorage.setItem('flacFiles', JSON.stringify(fileArray));
// Last inn og vis de lagrede filene på nytt loadFilesFromStorage(); };
// Les filen som data-URL (base64) reader.readAsDataURL(file); } else { alert('Kun .flac-filer er tillatt.'); } }); }
// Funksjon for å tømme WebStorage og filene function clearStorage() { localStorage.removeItem('flacFiles'); loadFilesFromStorage(); }
// Lydopptak let mediaRecorder; let audioChunks = [];
// Start opptak function startRecording() { navigator.mediaDevices.getUserMedia({ audio: true }) .then(stream => { mediaRecorder = new MediaRecorder(stream); mediaRecorder.ondataavailable = event => { audioChunks.push(event.data); }; mediaRecorder.onstop = () => { const audioBlob = new Blob(audioChunks, { type: 'audio/wav' }); const audioUrl = URL.createObjectURL(audioBlob); document.getElementById('audioPlayer').src = audioUrl;
// Lagre opptaket i WebStorage som en data-URI const fileArray = JSON.parse(localStorage.getItem('flacFiles')) || []; fileArray.push({ fileName: 'recorded_audio.wav', audioUrl: audioUrl });
// Lagre de nye filene i WebStorage localStorage.setItem('flacFiles', JSON.stringify(fileArray));
// Last inn og vis de lagrede filene på nytt loadFilesFromStorage(); }; mediaRecorder.start();
// Deaktiver start-knappen og aktiver stopp-knappen document.getElementById('startRecordingButton').disabled = true; document.getElementById('stopRecordingButton').disabled = false; }) .catch(error => { console.error('Feil ved tilgang til mikrofonen:', error); alert('Kunne ikke starte opptaket.'); }); }
// Stopp opptak function stopRecording() { mediaRecorder.stop();
// Deaktiver stopp-knappen og aktiver start-knappen document.getElementById('startRecordingButton').disabled = false; document.getElementById('stopRecordingButton').disabled = true; }
// Koble til knapper og filinput document.getElementById('loadFilesButton').addEventListener('click', loadFilesFromStorage); document.getElementById('clearStorageButton').addEventListener('click', clearStorage); document.getElementById('fileInput').addEventListener('change', handleFileUpload); document.getElementById('startRecordingButton').addEventListener('click', startRecording); document.getElementById('stopRecordingButton').addEventListener('click', stopRecording);
// Last inn lagrede filer ved oppstart loadFilesFromStorage(); </script> </body> </html>
Mvh, Ole