2012-07-16 48 views
8

Tôi thường đọc rằng không thể tạm dừng/tiếp tục các tệp âm thanh với Web Audio API.
Nhưng bây giờ tôi đã thấy một số example nơi họ thực sự có thể tạm dừng và tiếp tục lại. Tôi cố gắng tìm hiểu xem họ đã làm thế nào. Tôi nghĩ có lẽ source.looping = false là chìa khóa, nhưng không phải vậy.
Hiện tại, âm thanh của tôi luôn phát lại từ đầu.API âm thanh web tiếp tục từ tạm dừng

Đây là mã hiện tại của tôi

var context = new (window.AudioContext || window.webkitAudioContext)(); 

function AudioPlayer() { 
    this.source = context.createBufferSource(); 
    this.analyser = context.createAnalyser(); 
    this.stopped = true; 
} 

AudioPlayer.prototype.setBuffer = function(buffer) { 
    this.source.buffer = buffer; 
    this.source.looping = false; 
}; 

AudioPlayer.prototype.play = function() { 
    this.source.connect(this.analyser); 
    this.analyser.connect(context.destination); 

    this.source.noteOn(0); 
    this.stopped = false; 
}; 

AudioPlayer.prototype.stop = function() { 
    this.analyser.disconnect(); 
    this.source.disconnect(); 
    this.stopped = true; 
}; 

Có ai biết phải làm gì, để làm cho nó hoạt động?

Trả lời

5

Nếu không chi tiêu bất cứ lúc nào kiểm tra nguồn gốc của ví dụ của bạn, tôi muốn nói rằng bạn sẽ muốn sử dụng phương pháp noteGrainOn của AudioBufferSourceNode (https://dvcs.w3.org/hg/audio/raw-file/tip/webaudio/specification.html#methodsandparams-AudioBufferSourceNode)

Chỉ cần theo dõi bao xa vào bộ đệm bạn là khi bạn gọi là noteOff, và sau đó làm noteGrainOn từ đó khi tiếp tục trên một AudioBufferSourceNode mới.

Điều đó có hợp lý không?

EDIT: Xem nhận xét bên dưới để biết các cuộc gọi API được cập nhật.

+0

Vâng, anh ta không sử dụng 'noteGrainOn()' trong ví dụ (mặc dù vậy vẫn không thể biết được anh ta làm thế nào). Nhưng dù sao, điều này hoạt động như một sự quyến rũ, vì vậy tôi sẽ coi đây là một câu trả lời được chấp nhận. Cảm ơn bạn :) –

+1

noteGrainOn() hiện đã được đổi tên trong spec, như có noteOn() - cả hai đều đang chơi(), có hoặc không có đối số bù đắp hạt. Tuy nhiên, chưa thấy điều này được hỗ trợ. – LeeGee

+1

nó thực sự là 'bắt đầu' (có hoặc không có đối số' bắt đầu (howSoonRelativeToCurrentTime, fromSecondInBuffer, forDuration) ') và có vẻ như hoạt động trong Chrome Canary –

15

Câu trả lời của Oskar và nhận xét của ayke rất hữu ích, nhưng tôi đã thiếu một ví dụ về mã. Vì vậy, tôi đã viết một: http://jsfiddle.net/v3syS/2/ Tôi hy vọng nó sẽ giúp.

var url = 'http://thelab.thingsinjars.com/web-audio-tutorial/hello.mp3'; 

var ctx = new webkitAudioContext(); 
var buffer; 
var sourceNode; 

var startedAt; 
var pausedAt; 
var paused; 

function load(url) { 
    var request = new XMLHttpRequest(); 
    request.open('GET', url, true); 
    request.responseType = 'arraybuffer'; 
    request.onload = function() { 
     ctx.decodeAudioData(request.response, onBufferLoad, onBufferError); 
    }; 
    request.send(); 
}; 

function play() { 
    sourceNode = ctx.createBufferSource(); 
    sourceNode.connect(ctx.destination); 
    sourceNode.buffer = buffer; 
    paused = false; 

    if (pausedAt) { 
     startedAt = Date.now() - pausedAt; 
     sourceNode.start(0, pausedAt/1000); 
    } 
    else { 
     startedAt = Date.now(); 
     sourceNode.start(0); 
    } 
}; 

function stop() { 
    sourceNode.stop(0); 
    pausedAt = Date.now() - startedAt; 
    paused = true; 
}; 

function onBufferLoad(b) { 
    buffer = b; 
    play(); 
}; 

function onBufferError(e) { 
    console.log('onBufferError', e); 
}; 

document.getElementById("toggle").onclick = function() { 
    if (paused) play(); 
    else stop(); 
}; 

load(url); 
0

Việc thiếu chức năng tạm dừng cài sẵn trong API WebAudio có vẻ như là sự giám sát lớn đối với tôi. Có thể, trong tương lai nó sẽ có thể thực hiện điều này bằng cách sử dụng MediaElementSource đã lên kế hoạch, điều này sẽ cho phép bạn kết nối một phần tử (hỗ trợ tạm dừng) với Web Audio. Hiện tại, hầu hết các cách giải quyết dường như dựa trên việc ghi nhớ thời gian phát lại (như được mô tả trong câu trả lời của imbrizi). Cách giải quyết như vậy có vấn đề khi lặp lại âm thanh (vòng lặp thực hiện không có khoảng trống hay không?) Và khi bạn cho phép thay đổi tự động phát lại âm thanh (vì cả hai đều ảnh hưởng đến thời gian). Một cách giải quyết, không kém hack-ish và về mặt kỹ thuật không chính xác, nhưng đơn giản hơn nhiều, bạn có thể sử dụng là:

source.playbackRate = paused?0.0000001:1; 

Thật không may, 0 không phải là một giá trị hợp lệ cho playbackRate (mà thực sự sẽ tạm dừng các âm thanh). Tuy nhiên, đối với nhiều mục đích thực tế, một số giá trị rất thấp, như 0.000001, là đủ gần, và nó sẽ không tạo ra bất kỳ đầu ra âm thanh nào.

+0

+10 để hack nhanh :-) – Sam

+0

Đây không phải là một ý tưởng tuyệt vời vì bạn sẽ ngăn trình duyệt xóa bất kỳ bộ đệm âm thanh không sử dụng nào. Đó là một chút clunky để làm việc với các API như nó được, nhưng nó được thiết kế theo cách đó vì lý do hiệu suất và hiệu quả bộ nhớ. Một thư viện bao bọc nhỏ như trong câu hỏi OPs là một cách tiếp cận tốt hơn. –

0

CẬP NHẬT: Tính năng này chỉ hợp lệ cho Chrome. Firefox (v29) chưa triển khai thuộc tính MediaElementAudioSourceNode.mediaElement.

Giả sử bạn đã có tham chiếu AudioContext và nguồn phương tiện của mình (ví dụ: qua AudioContext.createMediaElementSource() gọi phương thức), bạn có thể gọi MediaElement.play()MediaElement.pause() trên nguồn của mình, ví dụ:

source.mediaElement.pause(); 
source.mediaElement.play(); 

Không cần hack và giải pháp, nó được hỗ trợ. Nếu bạn đang làm việc với một thẻ <audio> làm nguồn của mình, bạn không nên tạm dừng cuộc gọi trực tiếp trên phần tử âm thanh trong JavaScript của bạn, điều này sẽ dừng phát lại.

9

Trong các trình duyệt hiện nay (Chrome 43, Firefox 40) có doanh nghiệp 'đình chỉ' và 'tiếp tục' phương pháp có sẵn cho AudioContext:

var audioCtx = new AudioContext(); 
susresBtn.onclick = function() { 
    if(audioCtx.state === 'running') { 
    audioCtx.suspend().then(function() { 
     susresBtn.textContent = 'Resume context'; 
    }); 
    } else if(audioCtx.state === 'suspended') { 
    audioCtx.resume().then(function() { 
     susresBtn.textContent = 'Suspend context'; 
    }); 
    } 
} 

(sửa đổi mã ví dụ từ https://developer.mozilla.org/en-US/docs/Web/API/AudioContext/suspend)

3

Thực web -audio API có thể thực hiện tác vụ tạm dừng và phát cho bạn. Nó biết tình trạng hiện tại của bối cảnh âm thanh (chạy hoặc bị đình chỉ), vì vậy bạn có thể làm điều này một cách đơn giản này:

susresBtn.onclick = function() { 
 
    if(audioCtx.state === 'running') { 
 
    audioCtx.suspend() 
 
    } else if(audioCtx.state === 'suspended') { 
 
    audioCtx.resume() 
 
    } 
 
}

Tôi hy vọng điều này có thể giúp đỡ.

0

Năm 2017, sử dụng ctx.currentTime hoạt động tốt để theo dõi điểm trong bài hát. Đoạn mã dưới đây sử dụng một nút (trackStartPause) để chuyển đổi giữa nút phát & tạm dừng. Tôi đã sử dụng các biến toàn cầu vì mục đích đơn giản. Biến musicStartPoint theo dõi thời gian bạn đang ở trong bài hát. Nhạc api theo dõi thời gian tính bằng giây.

Đặt musicStartPoint ban đầu của bạn ở mức 0 (đầu của bài hát)

var ctx = new webkitAudioContext(); 
var buff, src; 
var musicLoaded = false; 
var musicStartPoint = 0; 
var songOnTime, songEndTime; 
var songOn = false; 

songStartPause.onclick = function() { 

    if(!songOn) { 
    if(!musicLoaded) { 
     loadAndPlay(); 
     musicLoaded = true; 
    } else { 
     play(); 
    } 

    songOn = true; 
    songStartPause.innerHTML = "||" //a fancy Pause symbol 

    } else { 
    songOn = false; 
    src.stop(); 
    setPausePoint(); 
    songStartPause.innerHTML = ">" //a fancy Play symbol 
    } 
} 

Sử dụng ctx.currentTime trừ thời gian bài hát kết thúc từ khi nó bắt đầu, và thêm lượng thời gian này để tuy nhiên đến nay bạn đã trong bài hát ban đầu.

function setPausePoint() { 
    songEndTime = ctx.currentTime; 
    musicStartPoint += (songEndTime - songOnTime); 
} 

Chức năng tải/phát.

function loadAndPlay() { 
    var req = new XMLHttpRequest(); 
    req.open("GET", "//mymusic.com/unity.mp3") 
    req.responseType = "arraybuffer"; 
    req.onload = function() { 
    ctx.decodeAudioData(req.response, function(buffer) { 
     buff = buffer; 
     play(); 
    }) 
    } 
    req.send(); 
} 

function createBuffer() { 
     src = ctx.createBufferSource(); 
     src.buffer = buff; 
    } 


function connectNodes() { 
    src.connect(ctx.destination); 
} 

Cuối cùng, chức năng phát yêu cầu bài hát bắt đầu tại nhạc được chỉ địnhStartPoint (và phát ngay) và cũng đặt biến songOnTime.

function play(){ 
    createBuffer() 
    connectNodes(); 
    songOnTime = ctx.currentTime; 
    src.start(0, musicStartPoint); 
} 

* Phụ chú: Tôi biết nó có thể trông sạch hơn để thiết lập songOnTime lên trong hàm nhấp chuột, nhưng tôi hình dung nó làm cho tinh thần để lấy mã thời gian càng gần càng tốt để src.start, giống như cách chúng tôi lấy thời gian tạm dừng càng gần src.stop càng tốt.

Các vấn đề liên quan