2012-07-26 92 views
2

我從一首歌曲中將原始44,1 kHz音頻數據作爲Javascript數組,並且我想創建一個可縮放的時間軸。在Javascript中繪製可縮放的音頻波形時間軸

實例從時間軸無畏:

Sample waveform from Audacity

由於有幾百萬的時間點的普通的JavaScript圖形庫可能不會削減它:我想,不知道,正常的圖形庫將在此多人死亡時間點。但是,是否存在用於JS的這種可視化的庫?畫布,webGL,SVG都是可以接受的解決方案。

解決方案最好帶有縮放和平移。

請注意,這發生嚴格的客戶端和服務器端解決方案不可接受。

+0

您不能扔你的振幅值成圖形庫,並希望簡單地解決這個問題它會處理它。您需要創建縮小數據的「概覽」或「預覽」。 – 2012-07-26 20:35:19

+0

因此,我在問這樣的解決方案是否已經存在?我很清楚目前的圖形庫無法處理它。 – 2012-07-27 07:46:27

+0

創建概述並不是一件困難的事情。這樣的圖書館可能存在,但大部分麻煩在於將數據存入圖書館或從圖書館出庫,而不是實際創建概覽。 – 2012-07-27 14:42:28

回答

3

我已經相當廣泛地研究了這個相同的問題。據我所知,唯一現有的項目接近你想要的是wavesurfer.js。我沒有使用它,但屏幕截圖和描述聽起來很有希望。請參閱this question

祝你好運。

0

我已經在瀏覽器中使用了RaphaelJS進行SVG渲染,它的表現非常好。這是我會去的。希望SVG能夠勝任這項任務。

0

您不能簡單地取出波形數據並渲染所有數據點,這是非常低效的。

變量解釋:

  • 寬度:以像素爲單位繪製區域寬度,max是屏幕寬度
  • 高度:同的寬度,但然後繪圖區的高度
  • :每個像素的採樣數,這是您的縮放級別
  • 分辨率:數字o f採樣取像素採樣範圍,調整性能與準確性。
  • 滾動:您將需要表現的虛擬滾動,這是PX滾動位置
  • 數據:原始音頻數據陣列,大概幾百萬個樣本長
  • drawData:本減少了聲音用於繪製的數據

您將不得不僅從音頻數據中獲取視口中的樣本並減少這些樣本。當然,這會產生2 *寬度的數據集,您可以使用該數據集來渲染圖像。 縮小增加spp,放大縮小它。改變滾動值可以改變它。

下面的代碼具有O(RN)複雜性,其中N是寬度,R是分辨率。最大精度在spp < =分辨率。

代碼看起來像這樣,這會得到峯值,你也可以做rms或平均值。

let reduceAudioPeak = function(data, spp, scroll, width, resolution) { 
    let drawData = new Array(width); 
    let startSample = scroll * spp; 
    let skip = Math.ceil(spp/resolution); 

    // For each pixel in draw area 
    for (let i = 0; i < width; i++) { 
     let min = 0; // minimum value in sample range 
     let max = 0; // maximum value in sample range 
     let pixelStartSample = startSample + (i * spp); 

     // Iterate over the sample range for this pixel (spp) 
     // and find the min and max values. 
     for(let j = 0; j < spp; j += skip) { 
      const index = pixelStartSample + j; 
      if(index < data.length) { 
       let val = data[index]; 
       if (val > max) { 
        max = val; 
       } else if (val < min) { 
        min = val; 
       } 
      } 
     } 

     drawData[i] = [min, max]; 
    } 
    return drawData; 
} 

有了這些數據,你可以畫出像這樣,你可以使用線條,SVG等:

let drawWaveform = function(canvas, drawData, width, height) { 
    let ctx = canvas.getContext('2d'); 
    let drawHeight = height/2; 

    // clear canvas incase there is already something drawn 
    ctx.clearRect(0, 0, width, height); 
    for(let i = 0; i < width; i++) { 
     // transform data points to pixel height and move to centre 
     let minPixel = drawData[i][0] * drawHeigth + drawHeight; 
     let maxPixel = drawData[i][1] * drawHeight + drawHeight; 
     let pixelHeight = maxPixel - minPixel; 

     ctx.fillRect(i, minPixel, 1, pixelHeight); 
    } 
}