马黑黑 发表于 2022-12-8 10:43

无需跨域获取音频波形数据(初稿)

本帖最后由 马黑黑 于 2022-12-8 22:10 编辑 <br /><br /><style>
#papa { margin: auto; padding: 10px; width: 740px; background: #fff; border: 1px solid #ccc; box-shadow: 2px 4px 6px #000; position: relative; }
#papa h2 { margin: 8px 0; font: bold 2em sans-serif; text-align: center; text-shadow: 2px 2px 2px #000; color: lightgreen; }
#papa input { display: none; }
#mplayer { margin: auto; position: relative; width: 100%; height: 160px; bottom: 0; display: flex; justify-content: center; align-items: flex-end;}
#rec { margin: auto; width: 95%; height: 260px; display: block; padding: 4px; outline: none; position: relative;}
#select { margin: 0 0 0 20px; cursor: pointer; }
#copytip { border: none; outline: none; user-select: none; cursor: default; }
.mLine { position: relative; margin: 0 2px 0 0; width: 4px; height: 10px; background: gray linear-gradient(to top,darkgreen,green,lightgreen); }
.mLine::after { position: absolute; content: ''; width: 100%; height: 3px; background: pink; top: -4px; }
</style>

<div id="papa">
        <h2>获取音频波形数据</h2>
        <p>
                <input id="select" type="button" value="选择音乐" />
                <input type="file" id="mfile" accept=".mp3, .ogg, .wav, .acc, .webm"/>
                <input id="copy" type="button" value="复制" />
                <input id="copytip" type="text" value="" /><br><br>
        </p>
        <p><textarea id="rec" placeholder="尚未准备就绪..."></textarea></p>
        <div id="mplayer"></div>
</div>
<audio id="aud"></audio>

<script>
let total = Math.ceil(mplayer.offsetWidth / 6);
let aa = 0;
for(j=0; j<total; j++) {
        let el = document.createElement('span');
        el.className = 'mLine';
        mplayer.appendChild(el);
}
let lines = document.querySelectorAll('.mLine');

let context = new AudioContext;
let source = context.createMediaElementSource(aud);
let analyser = context.createAnalyser();
source.connect(analyser);
analyser.connect(context.destination);
let output = new Uint8Array(total);
let ybAr = [];

(function update() {
        analyser.getByteFrequencyData(output);
        let mid = total % 2 === 0 ? total / 2 - 1 : Math.floor(total / 2);
        for(j = 0; j < total ; j++) {
                let k = j <= mid ? (mid - j) * 2 : (j - mid) * 2 - 1;
                lines.style.height = output/2 + 'px';
        }
        window.requestAnimationFrame(update);
})();

aud.addEventListener('timeupdate', () => {
        ybAr.push(output);
        rec.value = 'ypData = [' + ybAr + '];';
        rec.scrollTop = rec.scrollHeight;
        aa ++;
});

aud.addEventListener('ended',() => {
        select.disabled = false;
});

copy.onclick = () => {
        rec.select();
        document.execCommand('copy');
        copytip.value = '内容已复制到剪切板';
        setTimeout("copytip.value=''",3000);
}

select.onclick = () => {
        mfile.click();
        select.disabled = true;
}

mfile.onchange = () => {
        let filelist = mfile.files;
        if(filelist.length === 0) return;
        aud.src = URL.createObjectURL(filelist);
        aud.play();
        rec.placeholder = '音频数据处理中 ...';
}

</script>

马黑黑 发表于 2022-12-8 10:48

本帖最后由 马黑黑 于 2022-12-8 11:06 编辑

文档下载:

这是初稿,应该存在诸多问题,但经测试,实现功能的核心代码是正常的

小辣椒 发表于 2022-12-8 10:57

还可以这样啊{:4_178:}

小辣椒 发表于 2022-12-8 10:57

黑黑太强悍了{:4_178:}

小辣椒 发表于 2022-12-8 10:59

可惜现在手机{:4_198:}不能马上试

马黑黑 发表于 2022-12-8 11:00

通过 input 提交的本地音频文件,解码后所得到的URL与web页运行同域,因此不再存在跨域问题!

下载二楼提供的源码,任何能运行现代浏览器的客户端都可以正常运行,当然,嫌麻烦的话也可以在线制作波形数据。

源码中的 audio 控件的 timeupdate 监听事件选取 第二个声音数组元素:

aud.addEventListener('timeupdate', () => {
        ybAr.push(output);
        rec.value = 'ypData = [' + ybAr + '];';
        rec.scrollTop = rec.scrollHeight;
        aa ++;
});

如果需要第一个元素的数据,ybAr.push(output); 中的 1 改为 0,要第二个,改为 2,其他依此类推。

马黑黑 发表于 2022-12-8 11:02

小辣椒 发表于 2022-12-8 10:59
可惜现在手机不能马上试

{:4_173:}

马黑黑 发表于 2022-12-8 11:04

小辣椒 发表于 2022-12-8 10:57
黑黑太强悍了

这是初稿,还有一些细节问题尚未处理,应该也存在诸多臭虫

马黑黑 发表于 2022-12-8 11:26

小辣椒 发表于 2022-12-8 10:57
还可以这样啊

昨天拖地板的时候思考了一阵子,觉得可以:不就是跨域吗?我不跨还不行吗?

不跨就需要同域。别的招数木有,但可以在线解码呀,这不就解决了?

在线解码,意味着播放客户端的音频,早前在这里发过这方面的帖子,解码没问题。

解码的方式至少有两种处理思路,我用了最简单的:用 input file ,省事。

马黑黑 发表于 2022-12-8 11:27

小辣椒 发表于 2022-12-8 10:59
可惜现在手机不能马上试

手机也可以操作的。不过手机下,频谱是倒过来的{:4_170:}

梦缘 发表于 2022-12-8 15:27

感谢老师的无私分享,问好!

红影 发表于 2022-12-8 15:33

黑黑又制作了工具书一样的帖子,真好。{:4_187:}

红影 发表于 2022-12-8 15:37

一边听着音乐,一边看着波形数据被一个个加载,真神奇{:4_199:}

红影 发表于 2022-12-8 15:40

选了个乐曲,刚开始出来的单音的时候,很多频谱还没升起来,看着很多空挡的地方。哇,一首曲子听完了,竟有这么多波形数据,太智能了{:4_173:}

红影 发表于 2022-12-8 15:41

呀,我接着又听一个曲子,没把原来的清除掉,那些波形数据就接着延伸下去了{:4_172:}

红影 发表于 2022-12-8 15:42

这倒也好,要是多曲播放的帖子,不用另外做波形数据了{:4_173:}

亚伦影音工作室 发表于 2022-12-8 17:31

本帖最后由 亚伦影音工作室 于 2022-12-8 17:33 编辑

黑黑老师不抓去频谱数字用你转过来的任意数组,放上去,然后MP3任意使用,这样频谱不标准,但可解燃眉之急。我转了一个MP3数组但放上去不动!

马黑黑 发表于 2022-12-8 18:14

亚伦影音工作室 发表于 2022-12-8 17:31
黑黑老师不抓去频谱数字用你转过来的任意数组,放上去,然后MP3任意使用,这样频谱不标准,但可解燃眉之急 ...

可能是数组名称的问题,我有一个示范名称误写成了 ybData,现在这个生成的波形数据是 ypData,检查一下名称前后是否一致。

也可能是其他问题所导致,需要核查代码。

马黑黑 发表于 2022-12-8 18:16

红影 发表于 2022-12-8 15:41
呀,我接着又听一个曲子,没把原来的清除掉,那些波形数据就接着延伸下去了

初稿,发完后我也发现这个问题了,但作为预览,先这样,定稿版正在核验中,估计我喝完酒后就可以发出来了

马黑黑 发表于 2022-12-8 18:17

红影 发表于 2022-12-8 15:42
这倒也好,要是多曲播放的帖子,不用另外做波形数据了

估计不行,衔接会有问题
页: [1] 2 3 4 5 6 7 8 9 10
查看完整版本: 无需跨域获取音频波形数据(初稿)