日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

您的位置:首頁(yè)技術(shù)文章
文章詳情頁(yè)

JS實(shí)現(xiàn)audio音頻剪裁剪切復(fù)制播放與上傳(步驟詳解)

瀏覽:254日期:2024-04-28 13:37:25

JS實(shí)現(xiàn)audio音頻剪裁剪切復(fù)制播放與上傳(步驟詳解)

背景是這樣的,用戶上傳音頻文件,可能只需要幾十秒就夠了,但是常規(guī)的音樂都要3~5分鐘,80%的流量都是不需要的,要是就這么傳上去,其實(shí)是流量的浪費(fèi),如果可以在前端就進(jìn)行剪裁,也就是只取前面一段時(shí)間的音頻,豈不是可以給公司省很多流量費(fèi)用,前端的業(yè)務(wù)價(jià)值就體現(xiàn)了。

關(guān)鍵如何實(shí)現(xiàn)呢?

下面,就以“截取用戶上傳音頻前3秒內(nèi)容”的需求示意下如何借助Web Audio API實(shí)現(xiàn)音頻的部分復(fù)制與播放功能。

一、不嗶嗶,直接正題

實(shí)現(xiàn)步驟如下。

1. File對(duì)象轉(zhuǎn)ArrayBuffer

在Web網(wǎng)頁(yè)中,用戶選擇的文件是個(gè)file對(duì)象,我們可以將這個(gè)文件對(duì)象轉(zhuǎn)換成Blob、ArrayBuffer或者Base64。

在音頻處理這里,都是使用ArrayBuffer這個(gè)數(shù)據(jù)類型。

代碼如下所示,假設(shè)file類型的文件選擇框的id是 ’file’ 。

file.onchange = function (event) { var file = event.target.files[0]; // 開始識(shí)別 var reader = new FileReader(); reader.onload = function (event) { var arrBuffer = event.target.result; // arrBuffer就是包含音頻數(shù)據(jù)的ArrayBuffer對(duì)象 }); reader.readAsArrayBuffer(file);};

使用的是 readAsArrayBuffer() 方法,無論是MP3格式、OGG格式還是WAV格式,都可以轉(zhuǎn)換成ArrayBuffer類型。

2. ArrayBuffer轉(zhuǎn)AudioBuffer

這里的ArrayBuffer相對(duì)于把音頻文件數(shù)組化了,大家可以理解為把音頻文件分解成一段一段的,塞進(jìn)了一個(gè)一個(gè)有地址的小屋子里,在計(jì)算機(jī)領(lǐng)域稱為“緩沖區(qū)”,就是單詞Buffer的意思。

所謂音頻的剪裁,其實(shí)就是希望可以復(fù)制音頻前面一段時(shí)間的內(nèi)容。

但是問題來了,ArrayBuffer里面的數(shù)據(jù)并沒有分類,統(tǒng)一分解了,想要準(zhǔn)確提取某一截音頻數(shù)據(jù),提取不出來。

所以,才需要轉(zhuǎn)換成AudioBuffer,純粹的音頻數(shù)據(jù),方便提取。

AudioBuffer是一個(gè)僅僅包含音頻數(shù)據(jù)的數(shù)據(jù)對(duì)象,是Web Audio API中的一個(gè)概念。

既然說到了Web Audio API,那我們就順便……順便……,想了想,還是不展開,因?yàn)樘嬰s了,這Web Audio API至少比Web Animation API復(fù)雜了10倍,API之多,體量之大,世間罕見,想要完全吃透了,沒有三年五載,啃不下來。

如果大家不是想要立志成為音視頻處理專家,僅僅是臨時(shí)解決一點(diǎn)小毛小病的問題,則不必深入,否則腦坑疼,使用MDN文檔中的一些案例東拼西湊,基本的效果也能弄出來。

扯遠(yuǎn)了,回到這里。

AudioBuffer大家可以理解為音樂數(shù)據(jù),那為什么叫AudioBuffer,不叫AudioData呢?

因?yàn)锽uffer是個(gè)專有名詞,直譯為緩沖區(qū),大家可以理解為高速公路,AudioBuffer處理數(shù)據(jù)更快,而且還有很多延伸的API,就像是高速公路上的服務(wù)區(qū),有吃有喝還有加油的地方。

AudioData一看名字就是鄉(xiāng)下土鱉,雖然接地氣,但是,處理好幾兆的數(shù)據(jù)的時(shí)候,就有些帶不動(dòng)了,就好像騎小電驢,在公速公路和鄉(xiāng)道縣道沒多大區(qū)別,但是如果是開跑車,嘖嘖,鄉(xiāng)下路就帶不動(dòng)了。

如何才能轉(zhuǎn)換成AudioBuffer呢?

使用AudioContext對(duì)象的 decodeAudioData() 方法,代碼如下:

var audioCtx = new AudioContext();audioCtx.decodeAudioData(arrBuffer, function(audioBuffer) { // audioBuffer就是AudioBuffer});

3. 復(fù)制AudioBuffer前3秒數(shù)據(jù)

AudioBuffer對(duì)象是一個(gè)音頻專用Buffer對(duì)象,包含很多音頻信息,包括:

durationnumberOfChannelssampleRate

等。

包括一些音頻聲道數(shù)據(jù)處理方法,例如:

getChannelData()copyFromChannel()copyToChannel()

文檔見這里: https://developer.mozilla.org/en-US/docs/Web/API/AudioBuffer

所以,實(shí)現(xiàn)的原理很簡(jiǎn)單,創(chuàng)建一個(gè)空的AudioBuffer,復(fù)制現(xiàn)有的通道數(shù)據(jù)前3秒的數(shù)據(jù),然后復(fù)制的內(nèi)容寫入到這個(gè)空的AudioBuffer,于是我們就得到了一個(gè)剪裁后的音頻Buffer數(shù)據(jù)了。

代碼如下:

// 聲道數(shù)量和采樣率var channels = audioBuffer.numberOfChannels;var rate = audioBuffer.sampleRate;// 截取前3秒var startOffset = 0;var endOffset = rate * 3;// 3秒對(duì)應(yīng)的幀數(shù)var frameCount = endOffset - startOffset;// 創(chuàng)建同樣采用率、同樣聲道數(shù)量,長(zhǎng)度是前3秒的空的AudioBuffervar newAudioBuffer = new AudioContext().createBuffer(channels, endOffset - startOffset, rate);// 創(chuàng)建臨時(shí)的Array存放復(fù)制的buffer數(shù)據(jù)var anotherArray = new Float32Array(frameCount);// 聲道的數(shù)據(jù)的復(fù)制和寫入var offset = 0;for (var channel = 0; channel < channels; channel++) { audioBuffer.copyFromChannel(anotherArray, channel, startOffset); newAudioBuffer.copyToChannel(anotherArray, channel, offset);}// newAudioBuffer就是全新的復(fù)制的3秒長(zhǎng)度的AudioBuffer對(duì)象

上面JavaScript代碼中的變量 newAudioBuffer 就是全新的復(fù)制的3秒長(zhǎng)度的AudioBuffer對(duì)象。

4. 使用newAudioBuffer做點(diǎn)什么?

其實(shí)應(yīng)該是有了AudioBuffer對(duì)象后我們可以做點(diǎn)什么。

能做很多事情。

1) 如果希望直接播放

我們可以直接把AudioBuffer的數(shù)據(jù)作為音頻數(shù)據(jù)進(jìn)行播放

// 創(chuàng)建AudioBufferSourceNode對(duì)象var source = audioCtx.createBufferSource();// 設(shè)置AudioBufferSourceNode對(duì)象的buffer為復(fù)制的3秒AudioBuffer對(duì)象source.buffer = newAudioBuffer;// 這一句是必須的,表示結(jié)束,沒有這一句沒法播放,沒有聲音// 這里直接結(jié)束,實(shí)際上可以對(duì)結(jié)束做一些特效處理source.connect(audioCtx.destination);// 資源開始播放source.start();

2) 如果希望在<audio>元素中播放

這個(gè)還挺麻煩的。

從 <audio> 的src屬性獲取音頻資源,再進(jìn)行處理是簡(jiǎn)單的,網(wǎng)上的案例也很多。

但是,想要處理后的AudioBuffer再變成src讓 <audio> 元素播放,嘿嘿,就沒那么容易了。

我 (張?chǎng)涡瘢?找了一圈,沒有看到Web Audio API中有專門的“逆轉(zhuǎn)錄”方法。

唯一可行的路數(shù)就是根據(jù)AudioBuffer數(shù)據(jù),重新構(gòu)建原始的音頻數(shù)據(jù)。研究了一番,轉(zhuǎn)成WAV格式相對(duì)容易,想要轉(zhuǎn)換成MP3格式比較麻煩,這里有個(gè)項(xiàng)目: https://github.com/higuma/mp3-lame-encoder-js 不過自己沒驗(yàn)證過,不過看代碼量,還挺驚人的。

因此,我們的目標(biāo)還是轉(zhuǎn)到WAV音頻文件生成上吧,下面這段方法是從網(wǎng)上找的AudioBuffer轉(zhuǎn)WAV文件的方法,以Blob數(shù)據(jù)格式返回。

// Convert AudioBuffer to a Blob using WAVE representationfunction bufferToWave(abuffer, len) { var numOfChan = abuffer.numberOfChannels, length = len * numOfChan * 2 + 44, buffer = new ArrayBuffer(length), view = new DataView(buffer), channels = [], i, sample, offset = 0, pos = 0; // write WAVE header // 'RIFF' setUint32(0x46464952); // file length - 8 setUint32(length - 8); // 'WAVE' setUint32(0x45564157); // 'fmt ' chunk setUint32(0x20746d66); // length = 16 setUint32(16); // PCM (uncompressed) setUint16(1); setUint16(numOfChan); setUint32(abuffer.sampleRate); // avg. bytes/sec setUint32(abuffer.sampleRate * 2 * numOfChan); // block-align setUint16(numOfChan * 2); // 16-bit (hardcoded in this demo) setUint16(16); // 'data' - chunk setUint32(0x61746164); // chunk length setUint32(length - pos - 4); // write interleaved data for(i = 0; i < abuffer.numberOfChannels; i++) channels.push(abuffer.getChannelData(i)); while(pos < length) { // interleave channels for(i = 0; i < numOfChan; i++) { // clamp sample = Math.max(-1, Math.min(1, channels[i][offset])); // scale to 16-bit signed int sample = (0.5 + sample < 0 ? sample * 32768 : sample * 32767)|0; // write 16-bit sample view.setInt16(pos, sample, true); pos += 2; } // next source sample offset++ } // create Blob return new Blob([buffer], {type: 'audio/wav'}); function setUint16(data) { view.setUint16(pos, data, true); pos += 2; } function setUint32(data) { view.setUint32(pos, data, true); pos += 4; }}

WAV格式的兼容性還是很6的,如下圖所示:

JS實(shí)現(xiàn)audio音頻剪裁剪切復(fù)制播放與上傳(步驟詳解)

凡事支持Web Audio API的瀏覽器都支持WAV格式,所以,技術(shù)上完全可行。

下面這段JS可以得到剪裁后的WAV音頻的Blob數(shù)據(jù)格式:

var blob = bufferToWave(newAudioBuffer, frameCount);

有了Blob數(shù)據(jù),接下來事情就簡(jiǎn)單了。

我們可以直接把Blob數(shù)據(jù)轉(zhuǎn)換成URL,可以使用 URL.createObjectURL() 生成一個(gè)Blob鏈接。

假設(shè)頁(yè)面上有如下HTML代碼:

<audio controls=''></audio>

則如下設(shè)置,就可以點(diǎn)擊上面的 <audio> 元素進(jìn)行播放了。

audio.src = URL.createObjectURL(blob);

如果要轉(zhuǎn)換成Base64地址,可以這么處理:

var reader2 = new FileReader();reader2.onload = function(event){ audio.src = event.target.result;};reader2.readAsDataURL(blob);

3) 如果希望上傳剪裁的音頻

有了Blob數(shù)據(jù),上傳還不是灑灑水的事情。

可以使用FormData進(jìn)行傳輸,例如:

var formData = new FormData();formData.append(’audio’, blob);// 請(qǐng)求走起var xhr = new XMLHttpRequest();xhr.open(’POST’, this.cgiGetImg, true);// 請(qǐng)求成功xhr.onload = function () {};// 發(fā)送數(shù)據(jù)xhr.send(formData);

有demo可以進(jìn)行效果體驗(yàn)的,您可以狠狠地點(diǎn)擊這里: 用戶上傳的MP3音頻剪裁并播放demo

使用截圖示意如下:

JS實(shí)現(xiàn)audio音頻剪裁剪切復(fù)制播放與上傳(步驟詳解)

本文地址: https://www.zhangxinxu.com/wordpress/?p=9505

到此這篇關(guān)于JS實(shí)現(xiàn)audio音頻剪裁剪切復(fù)制播放與上傳的文章就介紹到這了,更多相關(guān)js audio音頻剪裁內(nèi)容請(qǐng)搜索好吧啦網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持好吧啦網(wǎng)!

標(biāo)簽: JavaScript
相關(guān)文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
国际精品欧美精品| 日韩视频一二区| 日韩av二区在线播放| 日本不卡不码高清免费观看| 日韩av一区二区三区四区| 九九九精品视频| 国产欧美在线| 欧美偷窥清纯综合图区| 国内精品福利| 久久久久一区| 国产精品香蕉| 免费人成网站在线观看欧美高清| 综合国产视频| 国产亚洲欧美日韩在线观看一区二区| 日韩成人精品一区二区三区 | 日韩亚洲精品在线观看| 婷婷五月色综合香五月| 国产色噜噜噜91在线精品| 久久久久九九精品影院| 国产精品99久久精品| 91精品一区国产高清在线gif| 福利在线免费视频| 极品日韩av| 亚州精品视频| 精品国产亚洲一区二区三区在线 | 国产欧美91| 欧美日韩免费观看一区=区三区| 天海翼精品一区二区三区| 亚洲美女久久| 天堂va蜜桃一区二区三区| 免费视频久久| 最新国产精品久久久| 亚洲最大av| 欧美亚洲国产日韩| 牛牛精品成人免费视频| 日韩区欧美区| 99成人在线视频| 国产探花一区二区| 亚洲v在线看| 亚洲精品日本| www在线观看黄色| 麻豆精品网站| 国产一区二区三区免费在线| 国产一区二区高清| 国产美女一区| 国产精品sss在线观看av| 久久久人人人| 欧美中文高清| 香蕉精品久久| 国产精品亚洲二区| 99久久精品网| 欧美日韩亚洲三区| 色爱综合av| 国产日韩欧美中文在线| 亚洲第一区色| 日本aⅴ亚洲精品中文乱码| 麻豆精品在线观看| 久久精品1区| 亚洲开心激情| 欧美日韩xxxx| 国产99久久| 亚洲精品欧洲| 欧美激情另类| 久久亚洲影院| 成人免费网站www网站高清| 99在线|亚洲一区二区| 久久99性xxx老妇胖精品| 99国产精品久久久久久久| 欧美国产不卡| 免费看日韩精品| 欧美成人基地| 国产精品久久久久77777丨| 国产亚洲福利| 欧美sss在线视频| 日韩在线黄色| 欧美日韩视频免费观看| 国产日韩精品视频一区二区三区| 极品日韩av| 久久久久久网| 国产精品igao视频网网址不卡日韩 | 午夜在线精品偷拍| 欧美一区久久久| 国产精品亚洲一区二区三区在线观看| 亚洲一区久久| 精品五月天堂| 丝袜亚洲精品中文字幕一区| 啪啪亚洲精品| 国内精品福利| 国产劲爆久久| 久久性天堂网| 四虎国产精品免费观看| 亚洲精品乱码久久久久久蜜桃麻豆 | 日韩精品一二三四| 免费一级欧美片在线观看网站| 91成人超碰| 久久激情综合网| 黄色成人91| 色婷婷亚洲mv天堂mv在影片| 噜噜噜躁狠狠躁狠狠精品视频 | 国产精品日韩精品中文字幕| 婷婷激情综合| 美女av一区| 蜜臀a∨国产成人精品| 中文在线а√在线8| 中文字幕av一区二区三区四区| 久久婷婷国产| 日韩高清成人在线| 在线亚洲激情| 日韩一区自拍| 欧美1区2区3| 中文字幕免费一区二区| 久久蜜桃av| 精品久久网站| 国产精品国码视频| 日本视频在线一区| 亚洲欧美视频| 日韩在线免费| 精品不卡一区| 国产精品s色| 蜜桃视频免费观看一区| 99久久夜色精品国产亚洲1000部| 国产精品地址| 97精品久久| 亚洲综合小说| 日韩一区二区免费看| 久久精品亚洲人成影院 | 蜜臀91精品一区二区三区| 99精品一区| 天堂а√在线最新版中文在线| 日韩中文字幕| 亚洲精品第一| 视频一区二区欧美| 婷婷久久免费视频| 97se亚洲| 国产精品草草| 国产成人免费精品| 久久久天天操| 丝袜脚交一区二区| 日本不卡一区二区三区| 欧美伊人影院| 国产va免费精品观看精品视频| 精品美女在线视频| 欧美gv在线| 午夜欧美理论片| 亚洲ab电影| 久久久精品区| 视频小说一区二区| 在线一区免费观看| 91亚洲无吗| 日本久久精品| 欧美va天堂在线| 免费人成精品欧美精品| 欧美亚洲综合视频| 欧美韩日一区| 亚洲在线电影| 国产丝袜一区| 欧美日韩精品免费观看视欧美高清免费大片| 国精品一区二区| 日本不卡高清视频| 高清一区二区三区| 日韩午夜精品| 欧美天堂在线| 国产精品字幕| 日韩午夜视频在线| 黄色aa久久| 中文字幕一区二区三区日韩精品| 国产精品亚洲综合色区韩国| 色婷婷狠狠五月综合天色拍| 天使萌一区二区三区免费观看| 久久黄色影视| 99久久精品费精品国产| 日韩欧美美女在线观看| 日韩成人精品一区| 一区二区电影| 日韩免费视频| 青草av.久久免费一区| 黑人精品一区| 亚洲精品福利| 蜜桃精品在线| 欧美在线首页| 成人av二区| 久久精品国产99国产| 亚洲综合日韩| 91视频一区| 日韩成人一级| 免费观看不卡av| 国产精品入口久久| 亚洲国产一区二区三区在线播放| 国产精品激情| 视频一区视频二区中文字幕| 国内不卡的一区二区三区中文字幕| 蜜臀av免费一区二区三区| 国产精品v亚洲精品v日韩精品| 在线视频精品| 国产va在线视频| 久久国产乱子精品免费女| 欧美日韩视频| 国产精品麻豆久久| 日本午夜精品一区二区三区电影| 欧美中文一区二区|