PDA

Visualizza la versione completa : Creare waveform audio


techno
26-05-2021, 11:27
Ciao a tutti.
Ho preso questo script da css-tricks.com per visualizzare un onda audio dei file mp3




// Set up audio context
window.AudioContext = window.AudioContext || window.webkitAudioContext;
const audioContext = new AudioContext();


/**
* Retrieves audio from an external source, the initializes the drawing function
* @param {String} url the url of the audio we'd like to fetch
*/
const drawAudio = url => {
fetch(url)
.then(response => response.arrayBuffer())
.then(arrayBuffer => audioContext.decodeAudioData(arrayBuffer))
.then(audioBuffer => draw(normalizeData(filterData(audioBuffer))));
};


/**
* Filters the AudioBuffer retrieved from an external source
* @param {AudioBuffer} audioBuffer the AudioBuffer from drawAudio()
* @returns {Array} an array of floating point numbers
*/
const filterData = audioBuffer => {
const rawData = audioBuffer.getChannelData(0); // We only need to work with one channel of data
const samples = 70; // Number of samples we want to have in our final data set
const blockSize = Math.floor(rawData.length / samples); // the number of samples in each subdivision
const filteredData = [];
for (let i = 0; i < samples; i++) {
let blockStart = blockSize * i; // the location of the first sample in the block
let sum = 0;
for (let j = 0; j < blockSize; j++) {
sum = sum + Math.abs(rawData[blockStart + j]); // find the sum of all the samples in the block
}
filteredData.push(sum / blockSize); // divide the sum by the block size to get the average
}
return filteredData;
};


/**
* Normalizes the audio data to make a cleaner illustration
* @param {Array} filteredData the data from filterData()
* @returns {Array} an normalized array of floating point numbers
*/
const normalizeData = filteredData => {
const multiplier = Math.pow(Math.max(...filteredData), -1);
return filteredData.map(n => n * multiplier);
}


/**
* Draws the audio file into a canvas element.
* @param {Array} normalizedData The filtered array returned from filterData()
* @returns {Array} a normalized array of data
*/
const draw = normalizedData => {
// set up the canvas
const canvas = document.querySelector(".waveform");
const dpr = window.devicePixelRatio || 1;
const padding = 20;
canvas.width = canvas.offsetWidth * dpr;
canvas.height = (canvas.offsetHeight + padding * 2) * dpr;
const ctx = canvas.getContext("2d");
ctx.scale(dpr, dpr);
ctx.translate(0, canvas.offsetHeight / 2 + padding); // set Y = 0 to be in the middle of the canvas


// draw the line segments
const width = canvas.offsetWidth / normalizedData.length;
for (let i = 0; i < normalizedData.length; i++) {
const x = width * i;
let height = normalizedData[i] * canvas.offsetHeight - padding;
if (height < 0) {
height = 0;
} else if (height > canvas.offsetHeight / 2) {
height = height > canvas.offsetHeight / 2;
}
drawLineSegment(ctx, x, height, width, (i + 1) % 2);
}
};


/**
* A utility function for drawing our line segments
* @param {AudioContext} ctx the audio context
* @param {number} x the x coordinate of the beginning of the line segment
* @param {number} height the desired height of the line segment
* @param {number} width the desired width of the line segment
* @param {boolean} isEven whether or not the segmented is even-numbered
*/
const drawLineSegment = (ctx, x, height, width, isEven) => {
ctx.lineWidth = 1; // how thick the line is
ctx.strokeStyle = "#fff"; // what color our line is
ctx.beginPath();
height = isEven ? height : -height;
ctx.moveTo(x, 0);
ctx.lineTo(x, height);
ctx.arc(x + width / 2, height, width / 2, Math.PI, 0, isEven);
ctx.lineTo(x + width, 0);
ctx.stroke();
};

drawAudio('https://s3-us-west-2.amazonaws.com/s.cdpn.io/3/shoptalk-clip.mp3');



ma mi da i seguenti errori:
SyntaxError: Identifier 'drawAudio' has already been declared

e

Uncaught (in promise) ReferenceError: audioContext is not defin

eppure faccio un copia ed incolla mah

ninja72
26-05-2021, 15:28
Esistono molte librerie gratuite per il tuo scopo, ti mando le prime due che ho trovato.
Audiomotion-analyzer e Wavesurfer.



<!DOCTYPE html>
<html lang="it-IT">

<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
canvas {
width: 300px;
height: 65px;
}

.audioblock {
width: 300px;
}

#waveform {
width: 300px;
}
</style>
</head>

<body>

<div class="audioblock">
<div id="container"></div>
<audio src="Alpha.mp3" id="audio" controls crossorigin></audio>
</div>

<div id="waveform"></div>
<button id="playpause">Play / Pause</button>

<script src="https://unpkg.com/wavesurfer.js/dist/wavesurfer.js"></script>

<script type="module">
// load module from Skypack CDN
import AudioMotionAnalyzer from 'https://cdn.skypack.dev/audiomotion-analyzer?min'

window.addEventListener('DOMContentLoaded', () => {
// audio source
const audioEl = document.getElementById('audio')

// instantiate analyzer
const audioMotion = new AudioMotionAnalyzer(
document.getElementById('container'),
{
source: audioEl,
height: window.innerHeight - 50,
mode: 5,
gradient: 'prism', //classic / prism / rainbow
lineWidth: 2,
fillAlpha: .5,
barSpace: .5,
showLeds: false
}
)

// Init wavesurfer
let wavesurfer = WaveSurfer.create({
container: '#waveform',
waveColor: '#A8DBA8',
progressColor: '#3B8686',
backend: 'MediaElement',
barWidth: 2,
barHeight: 1, // the height of the wave
barGap: null
});
// error console
wavesurfer.on('error', function (e) {
console.warn(e);
});
// Load audio from URL
wavesurfer.load('./Abba.mp3');
// event button
document.getElementById('playpause')
.addEventListener('click', () => {
wavesurfer.playPause();
})
})

</script>

</body>

</html>

linoma
26-05-2021, 18:42
Cm se venisse caricato 2 volte lo script. Ovviamente funziona su browser che supporti html5. X quanto possa funzionare credo che sia inutile visualizzare un treno di impulsi, anche in media perdendo significativita, su uno schermo da 4k ;)

techno
27-05-2021, 00:53
Esistono molte librerie gratuite per il tuo scopo, ti mando le prime due che ho trovato.
Audiomotion-analyzer e Wavesurfer.



<!DOCTYPE html>
<html lang="it-IT">

<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
canvas {
width: 300px;
height: 65px;
}

.audioblock {
width: 300px;
}

#waveform {
width: 300px;
}
</style>
</head>

<body>

<div class="audioblock">
<div id="container"></div>
<audio src="Alpha.mp3" id="audio" controls crossorigin></audio>
</div>

<div id="waveform"></div>
<button id="playpause">Play / Pause</button>

<script src="https://unpkg.com/wavesurfer.js/dist/wavesurfer.js"></script>

<script type="module">
// load module from Skypack CDN
import AudioMotionAnalyzer from 'https://cdn.skypack.dev/audiomotion-analyzer?min'

window.addEventListener('DOMContentLoaded', () => {
// audio source
const audioEl = document.getElementById('audio')

// instantiate analyzer
const audioMotion = new AudioMotionAnalyzer(
document.getElementById('container'),
{
source: audioEl,
height: window.innerHeight - 50,
mode: 5,
gradient: 'prism', //classic / prism / rainbow
lineWidth: 2,
fillAlpha: .5,
barSpace: .5,
showLeds: false
}
)

// Init wavesurfer
let wavesurfer = WaveSurfer.create({
container: '#waveform',
waveColor: '#A8DBA8',
progressColor: '#3B8686',
backend: 'MediaElement',
barWidth: 2,
barHeight: 1, // the height of the wave
barGap: null
});
// error console
wavesurfer.on('error', function (e) {
console.warn(e);
});
// Load audio from URL
wavesurfer.load('./Abba.mp3');
// event button
document.getElementById('playpause')
.addEventListener('click', () => {
wavesurfer.playPause();
})
})

</script>

</body>

</html>


Wavesurcer.Js lo uso gia da un po di yempo ma mi fa un waveform solo e siccome io ho una lista di audio vorrei che ogni audio visualizzasse il suo waveform

linoma
27-05-2021, 10:21
Su ff funziona benissimo.Qualche secondo di attesa

techno
27-05-2021, 11:21
Su ff funziona benissimo.Qualche secondo di attesa


Quale quello che ho postato io?
Perche lo provato su chrome e mi da quelli errori

techno
27-05-2021, 11:58
ok ora funziona anche a me avevo dimenticato d dichiarare AudioContext()

ninja72
27-05-2021, 12:04
Wavesurcer.Js lo uso gia da un po di yempo ma mi fa un waveform solo e siccome io ho una lista di audio vorrei che ogni audio visualizzasse il suo waveform

Wavesurfer-js permette di gestire le multi view anche se da codice custom, il discorso vedere quale sia il miglior approccio per ci che devi realizzare.
Se devi caricare diversi brani dalla durata di svariati minuti, penso che la cosa migliore sia utilizzare un sistema playlist come mostrato nel loro esempio https://wavesurfer-js.org/example/playlist/index.html
(https://wavesurfer-js.org/example/playlist/index.html)(tipo quello di beatport per capirci).

Questo per non rallentare di molto il caricamento della pagina, diversamente potresti realizzare un funzione custom che prende un id e un url e ritorni un elemento DOM con relativi bottoni play / stop per esempio.

techno
27-05-2021, 17:24
Wavesurfer-js permette di gestire le multi view anche se da codice custom, il discorso vedere quale sia il miglior approccio per ci che devi realizzare.
Se devi caricare diversi brani dalla durata di svariati minuti, penso che la cosa migliore sia utilizzare un sistema playlist come mostrato nel loro esempio https://wavesurfer-js.org/example/playlist/index.html
(https://wavesurfer-js.org/example/playlist/index.html)(tipo quello di beatport per capirci).

Questo per non rallentare di molto il caricamento della pagina, diversamente potresti realizzare un funzione custom che prende un id e un url e ritorni un elemento DOM con relativi bottoni play / stop per esempio.

Avevo gia visto la playlist di wavesurf ma non quello che voglio fare io qui ce una playlist ma ce solo un waveform a me serve fare per ogni brano visualizzato il suo waveform tipo ad esempio come soundcloud.com che nella lista dei brani dell'artista ad ogni brano ce il rispettivo waveform ecco a me questo serve.

Loading