2
0

audio.ts 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. namespace audio {
  2. export class AudioManager {
  3. context: AudioContext;
  4. volume: GainNode;
  5. output: AudioNode;
  6. constructor() {
  7. this.context = new AudioContext();
  8. this.volume = this.context.createGain();
  9. this.volume.connect(this.context.destination);
  10. this.output = this.volume;
  11. }
  12. getTime(): number {
  13. return this.context.currentTime;
  14. }
  15. loadTrack(url: string): Promise<Track> {
  16. return window.fetch(url)
  17. .then(response => response.arrayBuffer())
  18. .then(buffer => this.context.decodeAudioData(buffer))
  19. .then(audioBuffer => new Track(this, audioBuffer))
  20. }
  21. loadTrackFromFile(file: File): Promise<Track> {
  22. let promise = new Promise<ArrayBuffer>((resolve, reject) => {
  23. let reader = new FileReader();
  24. reader.onload = () => resolve(reader.result as ArrayBuffer);
  25. reader.readAsArrayBuffer(file);
  26. });
  27. return promise
  28. .then(buffer => this.context.decodeAudioData(buffer))
  29. .then(audioBuffer => new Track(this, audioBuffer))
  30. }
  31. loadTrackWithProgress(url: string, listener: (event: ProgressEvent) => any): Promise<Track> {
  32. let promise = new Promise<ArrayBuffer>((resolve, reject) => {
  33. let xhr = new XMLHttpRequest();
  34. xhr.open('GET', url);
  35. xhr.responseType = 'arraybuffer';
  36. xhr.onprogress = listener;
  37. xhr.onload = () => resolve(xhr.response);
  38. xhr.onerror = () => reject();
  39. xhr.send();
  40. });
  41. return promise
  42. .then(buffer => this.context.decodeAudioData(buffer))
  43. .then(audioBuffer => new Track(this, audioBuffer))
  44. }
  45. }
  46. export class Track {
  47. manager: AudioManager;
  48. buffer: AudioBuffer;
  49. source: AudioBufferSourceNode | null;
  50. playStartTime: number;
  51. resumeTime: number;
  52. hasStarted: boolean;
  53. isFinished: boolean;
  54. constructor(manager: AudioManager, buffer: AudioBuffer) {
  55. this.manager = manager;
  56. this.buffer = buffer;
  57. this.source = null;
  58. this.playStartTime = 0;
  59. this.resumeTime = 0;
  60. this.hasStarted = false;
  61. this.isFinished = true;
  62. }
  63. play(): void {
  64. this.source = this.manager.context.createBufferSource();
  65. this.source.buffer = this.buffer;
  66. this.source.connect(this.manager.output);
  67. this.playStartTime = this.manager.getTime();
  68. this.isFinished = false;
  69. this.hasStarted = true;
  70. this.source.start();
  71. }
  72. start(duration?: number): void {
  73. this.source = this.manager.context.createBufferSource();
  74. this.source.buffer = this.buffer;
  75. this.source.connect(this.manager.output);
  76. this.source.onended = (event) => {
  77. if (this.source == event.target) {
  78. this.isFinished = true;
  79. this.resumeTime = this.manager.getTime() - this.playStartTime;
  80. if (this.resumeTime > this.getDuration()) {
  81. this.resumeTime = 0;
  82. }
  83. }
  84. }
  85. this.isFinished = false;
  86. this.hasStarted = true;
  87. this.playStartTime = this.manager.getTime() - this.resumeTime;
  88. this.source.start(0, this.resumeTime, duration);
  89. }
  90. pause(): void {
  91. if (this.isFinished) return;
  92. this.resumeTime = this.manager.getTime() - this.playStartTime;
  93. this.isFinished = true;
  94. if (this.source) {
  95. this.source.stop();
  96. }
  97. }
  98. stop(): void {
  99. this.resumeTime = 0;
  100. this.isFinished = true;
  101. if (this.source) {
  102. this.source.stop();
  103. }
  104. }
  105. isPlaying(): boolean {
  106. return this.hasStarted && !this.isFinished;
  107. }
  108. getTime(): number {
  109. if (!this.hasStarted) {
  110. return 0;
  111. }
  112. else if (this.isFinished) {
  113. if (this.resumeTime > 0) {
  114. return this.resumeTime;
  115. } else {
  116. return this.getDuration();
  117. }
  118. } else {
  119. return this.manager.getTime() - this.playStartTime;
  120. }
  121. }
  122. getDuration(): number {
  123. return this.buffer.duration;
  124. }
  125. }
  126. }