| // Copyright 2021 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| import {$} from 'chrome://resources/js/util.m.js'; |
| |
| import {AudioSample, OutputPage} from './output_page.js'; |
| import {PageNavigator} from './page.js'; |
| |
| export class AudioPlayer extends HTMLElement { |
| private sampleIdx: number; |
| private audioDiv: HTMLDivElement; |
| private audioPlay: HTMLButtonElement; |
| private audioContext: AudioContext|null; |
| private audioQuery: HTMLDivElement; |
| private audioNameTag: HTMLParagraphElement; |
| private audioExpectation: HTMLParagraphElement; |
| private prevLink: HTMLButtonElement; |
| private timerId: number|null; |
| constructor(private audioSamples: AudioSample[]) { |
| super(); |
| this.sampleIdx = 0; |
| this.audioContext = null; |
| this.timerId = null; |
| const clone = ($('audioPlayer-template') as HTMLTemplateElement) |
| .content.cloneNode(true); |
| this.audioDiv = (clone as HTMLElement).querySelector('div')!; |
| this.audioPlay = |
| this.audioDiv.querySelector('#play-btn') as HTMLButtonElement; |
| this.audioQuery = |
| this.audioDiv.querySelector('#output-qs') as HTMLDivElement; |
| this.audioNameTag = this.audioDiv.querySelectorAll('p')[0]!; |
| this.audioExpectation = this.audioDiv.querySelectorAll('p')[1]!; |
| this.prevLink = this.audioDiv.querySelector('#back') as HTMLButtonElement; |
| this.prevLink.textContent = '< Back'; |
| this.prevLink.addEventListener('click', () => { |
| this.handleBackClick(); |
| }); |
| |
| this.setUpAudioPlayer(); |
| this.setButtons(); |
| this.appendChild(this.audioDiv); |
| } |
| |
| private get current() { |
| return this.audioSamples[this.sampleIdx]; |
| } |
| |
| setUpAudioPlayer() { |
| this.audioNameTag.innerHTML = `Playing: ${this.current!.description}`; |
| this.setAudioExpectation(); |
| } |
| |
| setAudioExpectation() { |
| if (this.current!.pan == -1) { |
| this.audioExpectation.innerHTML = |
| 'Should hear audio coming from the left channel.'; |
| } else if (this.current!.pan == 1) { |
| this.audioExpectation.innerHTML = |
| 'Should hear audio coming from the right channel.'; |
| } else { |
| this.audioExpectation.innerHTML = |
| 'Should hear audio of a single pitch from all channels.'; |
| } |
| } |
| |
| setButtons() { |
| const yesLink = |
| this.audioQuery.querySelector('#output-yes') as HTMLButtonElement; |
| const noLink = |
| this.audioQuery.querySelector('#output-no') as HTMLButtonElement; |
| |
| yesLink.addEventListener('click', () => this.handleResponse(true)); |
| noLink.addEventListener('click', () => this.handleResponse(false)); |
| |
| this.audioPlay.addEventListener('click', () => { |
| if (this.audioContext?.state === 'running') { |
| this.audioContext.suspend(); |
| } |
| |
| this.audioContext = |
| new AudioContext({sampleRate: this.current!.sampleRate}); |
| const oscNode = this.audioContext.createOscillator(); |
| oscNode.type = 'sine'; |
| oscNode.channelCount = this.current!.channelCount; |
| oscNode.frequency.value = this.current!.freqency; |
| if (this.current!.channelCount == 2) { |
| const panNode = this.audioContext.createStereoPanner(); |
| panNode.pan.value = this.current!.pan; |
| oscNode.connect(panNode); |
| panNode.connect(this.audioContext.destination); |
| } else { |
| oscNode.connect(this.audioContext.destination); |
| } |
| if (this.timerId) { |
| window.clearTimeout(this.timerId); |
| } |
| this.timerId = window.setTimeout(() => { |
| this.audioContext?.suspend(); |
| this.audioQuery.hidden = false; |
| this.timerId = null; |
| }, 3000); |
| oscNode.start(); |
| }); |
| } |
| |
| createButton(buttonName: string, buttonText: string) { |
| const button = document.createElement('button'); |
| const buttonClassName = buttonName + '-btn'; |
| button.setAttribute('class', buttonClassName); |
| button.textContent = buttonText; |
| this.audioDiv.appendChild(button); |
| return button; |
| } |
| |
| handleBackClick() { |
| this.sampleIdx -= 1; |
| this.audioContext?.suspend(); |
| if (this.timerId) { |
| window.clearTimeout(this.timerId); |
| this.timerId = null; |
| } |
| this.setUpAudioPlayer(); |
| this.prevLink.hidden = this.sampleIdx == 0; |
| this.audioQuery.hidden = true; |
| } |
| |
| handleResponse(response: boolean) { |
| OutputPage.getInstance().setOutputMapEntry(this.current!, response); |
| if (this.sampleIdx + 1 == this.audioSamples.length) { |
| PageNavigator.getInstance().showPage('feedback'); |
| } else { |
| this.sampleIdx += 1; |
| this.setUpAudioPlayer(); |
| this.audioQuery.hidden = true; |
| this.prevLink.hidden = this.sampleIdx == 0; |
| } |
| } |
| } |
| customElements.define('audio-player', AudioPlayer); |