pcm_player.js 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. class PCMPlayer
  2. {
  3. constructor(channels, sampleRate)
  4. {
  5. this._samples = new Float32Array();
  6. this._flushingTime = 200;
  7. this._channels = channels;
  8. this._sampleRate = sampleRate;
  9. this._flush = this._flush.bind(this);
  10. this._audioCtx = new (window.AudioContext || window.webkitAudioContext)();
  11. this._gainNode = this._audioCtx.createGain();
  12. this._gainNode.gain.value = 1;
  13. this._gainNode.connect(this._audioCtx.destination);
  14. this._startTime = this._audioCtx.currentTime;
  15. this._interval = setInterval(this._flush, this._flushingTime);
  16. }
  17. setVolume(volume)
  18. {
  19. this._gainNode.gain.value = volume;
  20. }
  21. close()
  22. {
  23. if(this._interval)
  24. {
  25. clearInterval(this._interval);
  26. }
  27. this._audioCtx.close();
  28. };
  29. feed(data)
  30. {
  31. let tmp = new Float32Array(this._samples.length + data.length);
  32. tmp.set(this._samples, 0);
  33. tmp.set(data, this._samples.length);
  34. this._samples = tmp;
  35. };
  36. _flush()
  37. {
  38. if(!this._channels || !this._sampleRate || !this._samples.length)
  39. {
  40. return;
  41. }
  42. let bufferSource = this._audioCtx.createBufferSource();
  43. let length = this._samples.length / this._channels;
  44. let audioBuffer = this._audioCtx.createBuffer(this._channels, length, this._sampleRate);
  45. for (let channel = 0; channel != this._channels; ++channel)
  46. {
  47. let audioData = audioBuffer.getChannelData(channel);
  48. let offset = channel;
  49. let decrement = 50;
  50. for (let i = 0; i != length; ++i)
  51. {
  52. audioData[i] = this._samples[offset];
  53. if (i < 50)
  54. {
  55. audioData[i] = (audioData[i] * i) / 50;
  56. }
  57. if (i >= (length - 51))
  58. {
  59. audioData[i] = (audioData[i] * decrement--) / 50;
  60. }
  61. offset += this._channels;
  62. }
  63. }
  64. if (this._startTime < this._audioCtx.currentTime)
  65. {
  66. this._startTime = this._audioCtx.currentTime;
  67. }
  68. bufferSource.buffer = audioBuffer;
  69. bufferSource.connect(this._gainNode);
  70. bufferSource.start(this._startTime);
  71. this._startTime += audioBuffer.duration;
  72. this._samples = new Float32Array();
  73. }
  74. }