如何从多个音频文件中获取总音频持续时间
How to get total audio duration from multiple audio files
我正在尝试从一组音频路径中获取音频的总持续时间。
这是数组的样子:
var sound_paths = ["1.mp3","2.mp3",...]
我看过这个 post,这对我有帮助:
但是,我不知道如何在数组上实现它。这个想法是我想遍历每个音频文件,获取它的持续时间,并将它添加到“sum_duration”变量。
我似乎无法想出一种通过 for 循环执行此操作的方法。我尝试过 Promises(诚然我是新手):(注意函数来自 class)
getDuration(src,cb){
// takes a source audio file and a callback function
var audio = new Audio();
audio.addEventListener("loadedmetadata",()=>{
cb(audio.duration);
});
audio.src = src;
}
getAudioArrayDuration(aud_path_arr){
// takes in an array of audio paths, finds the total audio duration
// in seconds
return new Promise((resolve)=>{
var duration = 0;
for(const aud_path in aud_path_arr){
var audio = new Audio();
audio.src = aud_path;
audio.onloadedmetadata = ()=>{
console.log(audio.duration);
duration += audio.duration;
}
resolve(duration);
}
});
}
但是,这显然是行不通的,只会return持续时间值为0。
如何遍历音频文件并return每个文件的总音频持续时间?
我很快就把它拼凑在一起了,所以你必须根据你的函数结构调整它,但这是一个有效的代码片段,应该会让你朝着正确的方向前进。
只需跟踪已加载的音频文件,如果与查询的音频文件数相匹配,则调用总持续时间的回调。
您还应该将失败的请求考虑在内,这样如果 loadedmetadata
事件从未触发,您可以做出相应的反应(通过将该文件回退到 0 持续时间,或抛出异常等。 ).
const cb = function(duration) {
console.log(`Total duration: ${duration}`);
};
let sound_paths = ["https://rawcdn.githack.com/anars/blank-audio/92f06aaa1f1f4cae365af4a256b04cf9014de564/5-seconds-of-silence.mp3","https://rawcdn.githack.com/anars/blank-audio/92f06aaa1f1f4cae365af4a256b04cf9014de564/2-seconds-of-silence.mp3"];
let totalDuration = 0;
let loadedSounds = [];
sound_paths.map(src => {
const audio = new Audio();
audio.addEventListener("loadedmetadata", ()=>{
totalDuration += audio.duration;
loadedSounds.push(audio);
if ( loadedSounds.length === sound_paths.length ) {
cb( totalDuration );
}
});
audio.src = src;
});
我认为,在这种情况下,使用 promise 是正确的方法,是时候适应它们了 ;) 请记住,promise 将在不久的将来实现您的愿望。让你的问题更难的是你有一组文件要检查,每个文件都需要单独由它自己的 Promise 覆盖,这样你的程序就可以知道它们何时都已填满。
我总是称我的 'promised' 吸气剂为 'fetch...',这样我就知道它会 return 一个承诺而不是一个直接值。
function fetchDuration(path) {
return new Promise((resolve) => {
const audio = new Audio();
audio.src = path;
audio.addEventListener(
'loadedmetadata',
() => {
// To keep a promise maintainable, only do 1
// asynchronous activity for each promise you make
resolve(audio.duration)
},
);
})
}
function fetchTotalDuration(paths) {
// Create an array of promises and wait until all have completed
return Promise.all(paths.map((path) => fetchDuration(path)))
// Reduce the results back to a single value
.then((durations) => durations.reduce(
(acc, duration) => acc + duration,
0,
))
;
}
在某些时候,您的代码将不得不处理这些异步内容,老实说,我相信 Promises 是执行此操作的最简单方法。这需要一点时间来适应,但最终是值得的。以上内容可以在您的代码中使用:
window.addEventListener('DOMContentLoaded', () => {
fetchTotalDuration(["1.mp3","2.mp3",...])
.then((totalDuration) => {
document.querySelector('.player__total-duration').innerHTML = totalDuration;
})
;
});
我正在尝试从一组音频路径中获取音频的总持续时间。
这是数组的样子:
var sound_paths = ["1.mp3","2.mp3",...]
我看过这个 post,这对我有帮助:
但是,我不知道如何在数组上实现它。这个想法是我想遍历每个音频文件,获取它的持续时间,并将它添加到“sum_duration”变量。
我似乎无法想出一种通过 for 循环执行此操作的方法。我尝试过 Promises(诚然我是新手):(注意函数来自 class)
getDuration(src,cb){
// takes a source audio file and a callback function
var audio = new Audio();
audio.addEventListener("loadedmetadata",()=>{
cb(audio.duration);
});
audio.src = src;
}
getAudioArrayDuration(aud_path_arr){
// takes in an array of audio paths, finds the total audio duration
// in seconds
return new Promise((resolve)=>{
var duration = 0;
for(const aud_path in aud_path_arr){
var audio = new Audio();
audio.src = aud_path;
audio.onloadedmetadata = ()=>{
console.log(audio.duration);
duration += audio.duration;
}
resolve(duration);
}
});
}
但是,这显然是行不通的,只会return持续时间值为0。
如何遍历音频文件并return每个文件的总音频持续时间?
我很快就把它拼凑在一起了,所以你必须根据你的函数结构调整它,但这是一个有效的代码片段,应该会让你朝着正确的方向前进。
只需跟踪已加载的音频文件,如果与查询的音频文件数相匹配,则调用总持续时间的回调。
您还应该将失败的请求考虑在内,这样如果 loadedmetadata
事件从未触发,您可以做出相应的反应(通过将该文件回退到 0 持续时间,或抛出异常等。 ).
const cb = function(duration) {
console.log(`Total duration: ${duration}`);
};
let sound_paths = ["https://rawcdn.githack.com/anars/blank-audio/92f06aaa1f1f4cae365af4a256b04cf9014de564/5-seconds-of-silence.mp3","https://rawcdn.githack.com/anars/blank-audio/92f06aaa1f1f4cae365af4a256b04cf9014de564/2-seconds-of-silence.mp3"];
let totalDuration = 0;
let loadedSounds = [];
sound_paths.map(src => {
const audio = new Audio();
audio.addEventListener("loadedmetadata", ()=>{
totalDuration += audio.duration;
loadedSounds.push(audio);
if ( loadedSounds.length === sound_paths.length ) {
cb( totalDuration );
}
});
audio.src = src;
});
我认为,在这种情况下,使用 promise 是正确的方法,是时候适应它们了 ;) 请记住,promise 将在不久的将来实现您的愿望。让你的问题更难的是你有一组文件要检查,每个文件都需要单独由它自己的 Promise 覆盖,这样你的程序就可以知道它们何时都已填满。
我总是称我的 'promised' 吸气剂为 'fetch...',这样我就知道它会 return 一个承诺而不是一个直接值。
function fetchDuration(path) {
return new Promise((resolve) => {
const audio = new Audio();
audio.src = path;
audio.addEventListener(
'loadedmetadata',
() => {
// To keep a promise maintainable, only do 1
// asynchronous activity for each promise you make
resolve(audio.duration)
},
);
})
}
function fetchTotalDuration(paths) {
// Create an array of promises and wait until all have completed
return Promise.all(paths.map((path) => fetchDuration(path)))
// Reduce the results back to a single value
.then((durations) => durations.reduce(
(acc, duration) => acc + duration,
0,
))
;
}
在某些时候,您的代码将不得不处理这些异步内容,老实说,我相信 Promises 是执行此操作的最简单方法。这需要一点时间来适应,但最终是值得的。以上内容可以在您的代码中使用:
window.addEventListener('DOMContentLoaded', () => {
fetchTotalDuration(["1.mp3","2.mp3",...])
.then((totalDuration) => {
document.querySelector('.player__total-duration').innerHTML = totalDuration;
})
;
});