|  | @@ -1,387 +0,0 @@
 | 
	
		
			
				|  |  | -import * as audio from './audio';
 | 
	
		
			
				|  |  | -import * as level from './level';
 | 
	
		
			
				|  |  | -import * as util from './util';
 | 
	
		
			
				|  |  | -import * as youtube from './youtube';
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -export class Editor {
 | 
	
		
			
				|  |  | -  audioManager: audio.AudioManager;
 | 
	
		
			
				|  |  | -  urlElement: HTMLInputElement;
 | 
	
		
			
				|  |  | -  loadElement: HTMLButtonElement;
 | 
	
		
			
				|  |  | -  audioElement: HTMLInputElement;
 | 
	
		
			
				|  |  | -  barElement: HTMLElement;
 | 
	
		
			
				|  |  | -  markerListElement: HTMLElement;
 | 
	
		
			
				|  |  | -  intervalListElement: HTMLElement;
 | 
	
		
			
				|  |  | -  kanaElement: HTMLTextAreaElement;
 | 
	
		
			
				|  |  | -  kanjiElement: HTMLTextAreaElement;
 | 
	
		
			
				|  |  | -  displayElement: HTMLElement;
 | 
	
		
			
				|  |  | -  jsonElement: HTMLInputElement;
 | 
	
		
			
				|  |  | -  waveFormContainer: HTMLDivElement;
 | 
	
		
			
				|  |  | -  track: audio.Track | null = null;
 | 
	
		
			
				|  |  | -  markers: Marker[] = [];
 | 
	
		
			
				|  |  | -  waveForm: WaveForm;
 | 
	
		
			
				|  |  | -  currentMarker: Marker | null = null;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  constructor() {
 | 
	
		
			
				|  |  | -    this.audioManager = new audio.AudioManager();
 | 
	
		
			
				|  |  | -    this.urlElement = util.getElement(document, '#url');
 | 
	
		
			
				|  |  | -    this.loadElement = util.getElement(document, '#load');
 | 
	
		
			
				|  |  | -    this.loadElement.addEventListener('click', (event) => {
 | 
	
		
			
				|  |  | -      this.loadAudio();
 | 
	
		
			
				|  |  | -    });
 | 
	
		
			
				|  |  | -    this.audioElement = util.getElement(document, '#audio');
 | 
	
		
			
				|  |  | -    this.audioElement.addEventListener('change', (event) => {
 | 
	
		
			
				|  |  | -      this.urlElement.value = '';
 | 
	
		
			
				|  |  | -      this.loadAudio();
 | 
	
		
			
				|  |  | -    });
 | 
	
		
			
				|  |  | -    this.barElement = util.getElement(document, '.bar-overlay');
 | 
	
		
			
				|  |  | -    this.markerListElement = util.getElement(document, '.markers');
 | 
	
		
			
				|  |  | -    this.intervalListElement = util.getElement(document, '#intervals');
 | 
	
		
			
				|  |  | -    this.kanaElement = util.getElement(document, '#kana');
 | 
	
		
			
				|  |  | -    this.kanjiElement = util.getElement(document, '#kanji');
 | 
	
		
			
				|  |  | -    this.displayElement = util.getElement(document, '#display');
 | 
	
		
			
				|  |  | -    this.jsonElement = util.getElement(document, '#json');
 | 
	
		
			
				|  |  | -    this.waveFormContainer = util.getElement(document, '.waveform-container');
 | 
	
		
			
				|  |  | -    this.waveForm = new WaveForm(
 | 
	
		
			
				|  |  | -      util.getElement(document, '#waveform'),
 | 
	
		
			
				|  |  | -      util.getElement(document, '#waveform-overlay'),
 | 
	
		
			
				|  |  | -      (time: number) => this.play(time)
 | 
	
		
			
				|  |  | -    );
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    this.markerListElement.addEventListener('click', (event: MouseEvent) =>
 | 
	
		
			
				|  |  | -      this.markersClick(event)
 | 
	
		
			
				|  |  | -    );
 | 
	
		
			
				|  |  | -    document
 | 
	
		
			
				|  |  | -      .querySelector('#play')!
 | 
	
		
			
				|  |  | -      .addEventListener('click', () => this.play());
 | 
	
		
			
				|  |  | -    document
 | 
	
		
			
				|  |  | -      .querySelector('#pause')!
 | 
	
		
			
				|  |  | -      .addEventListener('click', () => this.pause());
 | 
	
		
			
				|  |  | -    document
 | 
	
		
			
				|  |  | -      .querySelector('#insert-marker')!
 | 
	
		
			
				|  |  | -      .addEventListener('click', () => this.insertMarker());
 | 
	
		
			
				|  |  | -    document
 | 
	
		
			
				|  |  | -      .querySelector<HTMLElement>('.bar')!
 | 
	
		
			
				|  |  | -      .addEventListener('click', (event: MouseEvent) =>
 | 
	
		
			
				|  |  | -        this.scrubberClick(event)
 | 
	
		
			
				|  |  | -      );
 | 
	
		
			
				|  |  | -    document
 | 
	
		
			
				|  |  | -      .querySelector('#import')!
 | 
	
		
			
				|  |  | -      .addEventListener('click', () => this.import());
 | 
	
		
			
				|  |  | -    document
 | 
	
		
			
				|  |  | -      .querySelector('#export')!
 | 
	
		
			
				|  |  | -      .addEventListener('click', () => this.export());
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    this.update();
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  loadAudio(): void {
 | 
	
		
			
				|  |  | -    const url = this.urlElement.value;
 | 
	
		
			
				|  |  | -    if (url != '') {
 | 
	
		
			
				|  |  | -      const videoId = youtube.getVideoId(url);
 | 
	
		
			
				|  |  | -      if (videoId !== null) {
 | 
	
		
			
				|  |  | -        const element = util.getElement(document, '#youtube');
 | 
	
		
			
				|  |  | -        this.audioManager
 | 
	
		
			
				|  |  | -          .loadTrackFromYoutube(videoId, element, () => {})
 | 
	
		
			
				|  |  | -          .then((t) => {
 | 
	
		
			
				|  |  | -            this.track = t;
 | 
	
		
			
				|  |  | -            this.waveForm.clear();
 | 
	
		
			
				|  |  | -            this.waveFormContainer.style.display = 'none';
 | 
	
		
			
				|  |  | -          });
 | 
	
		
			
				|  |  | -        return;
 | 
	
		
			
				|  |  | -      }
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    let file = this.audioElement.files![0];
 | 
	
		
			
				|  |  | -    if (file != null) {
 | 
	
		
			
				|  |  | -      if (this.track != null) {
 | 
	
		
			
				|  |  | -        this.track.stop();
 | 
	
		
			
				|  |  | -      }
 | 
	
		
			
				|  |  | -      this.clearMarkers();
 | 
	
		
			
				|  |  | -      this.audioManager.loadTrackFromFile(file).then((t) => {
 | 
	
		
			
				|  |  | -        this.track = t;
 | 
	
		
			
				|  |  | -        this.waveForm.setTrack(t);
 | 
	
		
			
				|  |  | -        this.waveFormContainer.style.display = 'block';
 | 
	
		
			
				|  |  | -      });
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  update(): void {
 | 
	
		
			
				|  |  | -    if (this.track != null) {
 | 
	
		
			
				|  |  | -      let percentage = (this.track.getTime() / this.track.getDuration()) * 100;
 | 
	
		
			
				|  |  | -      this.barElement.style.width = `${percentage}%`;
 | 
	
		
			
				|  |  | -      if (this.track instanceof audio.FileTrack) {
 | 
	
		
			
				|  |  | -        this.waveForm.update(this.markers);
 | 
	
		
			
				|  |  | -      }
 | 
	
		
			
				|  |  | -      if (this.currentMarker) {
 | 
	
		
			
				|  |  | -        this.currentMarker.liElement.className = '';
 | 
	
		
			
				|  |  | -      }
 | 
	
		
			
				|  |  | -      let index = this.markers.findIndex((m) => m.time > this.track!.getTime());
 | 
	
		
			
				|  |  | -      if (index < 0) index = 0;
 | 
	
		
			
				|  |  | -      this.currentMarker = this.markers[index - 1];
 | 
	
		
			
				|  |  | -      if (this.currentMarker) {
 | 
	
		
			
				|  |  | -        this.currentMarker.liElement.className = 'highlight';
 | 
	
		
			
				|  |  | -      }
 | 
	
		
			
				|  |  | -      let text = this.kanjiElement.value.split('\n')[index] || '';
 | 
	
		
			
				|  |  | -      this.displayElement.textContent = text;
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -    requestAnimationFrame(() => this.update());
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  scrubberClick(event: MouseEvent): void {
 | 
	
		
			
				|  |  | -    let pos = event.clientX - 10;
 | 
	
		
			
				|  |  | -    console.log(pos);
 | 
	
		
			
				|  |  | -    let percentage = pos / this.markerListElement.clientWidth;
 | 
	
		
			
				|  |  | -    let targetTime = percentage * this.track!.getDuration();
 | 
	
		
			
				|  |  | -    this.play(targetTime);
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  markersClick(event: MouseEvent): void {
 | 
	
		
			
				|  |  | -    let pos = event.clientX - 10;
 | 
	
		
			
				|  |  | -    let percentage = pos / this.markerListElement.clientWidth;
 | 
	
		
			
				|  |  | -    let targetTime = percentage * this.track!.getDuration();
 | 
	
		
			
				|  |  | -    this.insertMarker(targetTime);
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  insertMarker(time?: number): void {
 | 
	
		
			
				|  |  | -    let marker = new Marker(
 | 
	
		
			
				|  |  | -      this.track!.getDuration(),
 | 
	
		
			
				|  |  | -      (marker: Marker) => this.removeMarker(marker),
 | 
	
		
			
				|  |  | -      (marker: Marker) => this.playMarker(marker)
 | 
	
		
			
				|  |  | -    );
 | 
	
		
			
				|  |  | -    if (time !== undefined) {
 | 
	
		
			
				|  |  | -      marker.time = time;
 | 
	
		
			
				|  |  | -    } else {
 | 
	
		
			
				|  |  | -      marker.time = this.track!.getTime();
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -    let insertIndex = this.markers.findIndex((m) => m.time > marker.time);
 | 
	
		
			
				|  |  | -    if (insertIndex >= 0) {
 | 
	
		
			
				|  |  | -      this.markers.splice(insertIndex, 0, marker);
 | 
	
		
			
				|  |  | -    } else {
 | 
	
		
			
				|  |  | -      this.markers.push(marker);
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -    this.markerListElement.appendChild(marker.markerElement);
 | 
	
		
			
				|  |  | -    if (insertIndex >= 0) {
 | 
	
		
			
				|  |  | -      this.intervalListElement.insertBefore(
 | 
	
		
			
				|  |  | -        marker.liElement,
 | 
	
		
			
				|  |  | -        this.markers[insertIndex + 1].liElement
 | 
	
		
			
				|  |  | -      );
 | 
	
		
			
				|  |  | -    } else {
 | 
	
		
			
				|  |  | -      this.intervalListElement.appendChild(marker.liElement);
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  play(start?: number, duration?: number): void {
 | 
	
		
			
				|  |  | -    this.track!.pause();
 | 
	
		
			
				|  |  | -    this.track!.start(start, duration);
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  pause(): void {
 | 
	
		
			
				|  |  | -    this.track!.pause();
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  playMarker(marker: Marker): void {
 | 
	
		
			
				|  |  | -    let start = marker.time;
 | 
	
		
			
				|  |  | -    let end = this.track!.getDuration();
 | 
	
		
			
				|  |  | -    let index = this.markers.findIndex((m) => m == marker);
 | 
	
		
			
				|  |  | -    if (index < this.markers.length - 1) {
 | 
	
		
			
				|  |  | -      end = this.markers[index + 1].time;
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -    let duration = end - start;
 | 
	
		
			
				|  |  | -    this.play(start, duration);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    this.highlightLine(this.kanjiElement, index + 1);
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  removeMarker(marker: Marker): void {
 | 
	
		
			
				|  |  | -    let index = this.markers.findIndex((m) => m == marker);
 | 
	
		
			
				|  |  | -    this.markers.splice(index, 1);
 | 
	
		
			
				|  |  | -    this.markerListElement.removeChild(marker.markerElement);
 | 
	
		
			
				|  |  | -    this.intervalListElement.removeChild(marker.liElement);
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  clearMarkers(): void {
 | 
	
		
			
				|  |  | -    this.markers.forEach((m) => {
 | 
	
		
			
				|  |  | -      this.markerListElement.removeChild(m.markerElement);
 | 
	
		
			
				|  |  | -      this.intervalListElement.removeChild(m.liElement);
 | 
	
		
			
				|  |  | -    });
 | 
	
		
			
				|  |  | -    this.markers = [];
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  highlightLine(element: HTMLTextAreaElement, line: number) {
 | 
	
		
			
				|  |  | -    let text = element.value;
 | 
	
		
			
				|  |  | -    let index = 0;
 | 
	
		
			
				|  |  | -    for (let i = 0; i < line; ++i) {
 | 
	
		
			
				|  |  | -      index = text.indexOf('\n', index + 1);
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -    let endIndex = text.indexOf('\n', index + 1);
 | 
	
		
			
				|  |  | -    element.focus();
 | 
	
		
			
				|  |  | -    element.setSelectionRange(index, endIndex);
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  import(): void {
 | 
	
		
			
				|  |  | -    this.clearMarkers();
 | 
	
		
			
				|  |  | -    let lines: level.Line[] = JSON.parse(this.jsonElement.value);
 | 
	
		
			
				|  |  | -    let kanji = '';
 | 
	
		
			
				|  |  | -    let kana = '';
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    lines.forEach((line) => {
 | 
	
		
			
				|  |  | -      kanji += line.kanji + '\n';
 | 
	
		
			
				|  |  | -      kana += line.kana + '\n';
 | 
	
		
			
				|  |  | -      if (line.end != undefined) {
 | 
	
		
			
				|  |  | -        this.insertMarker(line.end);
 | 
	
		
			
				|  |  | -      }
 | 
	
		
			
				|  |  | -    });
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    this.kanjiElement.value = kanji;
 | 
	
		
			
				|  |  | -    this.kanaElement.value = kana;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  export(): void {
 | 
	
		
			
				|  |  | -    let kanji = this.kanjiElement.value.split('\n');
 | 
	
		
			
				|  |  | -    let kana = this.kanaElement.value.split('\n');
 | 
	
		
			
				|  |  | -    let length = Math.max(kanji.length, kana.length, this.markers.length - 1);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    let lines = [];
 | 
	
		
			
				|  |  | -    let lastStart = 0;
 | 
	
		
			
				|  |  | -    for (let i = 0; i < length; ++i) {
 | 
	
		
			
				|  |  | -      let data: level.Line = {
 | 
	
		
			
				|  |  | -        kanji: kanji[i] || '@',
 | 
	
		
			
				|  |  | -        kana: kana[i] || '@',
 | 
	
		
			
				|  |  | -      };
 | 
	
		
			
				|  |  | -      if (this.markers[i]) {
 | 
	
		
			
				|  |  | -        data.start = lastStart;
 | 
	
		
			
				|  |  | -        data.end = this.markers[i].time;
 | 
	
		
			
				|  |  | -        lastStart = data.end;
 | 
	
		
			
				|  |  | -      }
 | 
	
		
			
				|  |  | -      lines.push(data);
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    this.jsonElement.value = JSON.stringify(lines);
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  start(): void {
 | 
	
		
			
				|  |  | -    this.loadAudio();
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -class Marker {
 | 
	
		
			
				|  |  | -  markerElement: HTMLElement;
 | 
	
		
			
				|  |  | -  liElement: HTMLElement;
 | 
	
		
			
				|  |  | -  inputElement: HTMLInputElement;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  constructor(
 | 
	
		
			
				|  |  | -    readonly duration: number,
 | 
	
		
			
				|  |  | -    readonly remove: (marker: Marker) => void,
 | 
	
		
			
				|  |  | -    readonly play: (marker: Marker) => void
 | 
	
		
			
				|  |  | -  ) {
 | 
	
		
			
				|  |  | -    this.markerElement = document.createElement('div');
 | 
	
		
			
				|  |  | -    this.markerElement.className = 'marker';
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    let fragment = util.loadTemplate(document, 'interval');
 | 
	
		
			
				|  |  | -    this.liElement = util.getElement(fragment, '*');
 | 
	
		
			
				|  |  | -    this.inputElement = util.getElement(fragment, '.interval');
 | 
	
		
			
				|  |  | -    this.inputElement.addEventListener('change', () => {
 | 
	
		
			
				|  |  | -      this.time = parseFloat(this.inputElement.value);
 | 
	
		
			
				|  |  | -    });
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    fragment
 | 
	
		
			
				|  |  | -      .querySelector('.play-section')!
 | 
	
		
			
				|  |  | -      .addEventListener('click', () => play(this));
 | 
	
		
			
				|  |  | -    fragment
 | 
	
		
			
				|  |  | -      .querySelector('.remove-section')!
 | 
	
		
			
				|  |  | -      .addEventListener('click', () => remove(this));
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  get time(): number {
 | 
	
		
			
				|  |  | -    return parseFloat(this.inputElement.value);
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  set time(t: number) {
 | 
	
		
			
				|  |  | -    this.inputElement.value = t.toFixed(1);
 | 
	
		
			
				|  |  | -    let percentage = (t * 100) / this.duration;
 | 
	
		
			
				|  |  | -    this.markerElement.style.left = `${percentage}%`;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -class WaveForm {
 | 
	
		
			
				|  |  | -  ctx: CanvasRenderingContext2D;
 | 
	
		
			
				|  |  | -  overlayCtx: CanvasRenderingContext2D;
 | 
	
		
			
				|  |  | -  track: audio.FileTrack | null = null;
 | 
	
		
			
				|  |  | -  data: Float32Array | null = null;
 | 
	
		
			
				|  |  | -  stride: number = 0;
 | 
	
		
			
				|  |  | -  currentSection: number = -1;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  constructor(
 | 
	
		
			
				|  |  | -    readonly canvas: HTMLCanvasElement,
 | 
	
		
			
				|  |  | -    readonly overlay: HTMLCanvasElement,
 | 
	
		
			
				|  |  | -    readonly setTime: (time: number) => void
 | 
	
		
			
				|  |  | -  ) {
 | 
	
		
			
				|  |  | -    canvas.height = canvas.clientHeight;
 | 
	
		
			
				|  |  | -    canvas.width = canvas.clientWidth;
 | 
	
		
			
				|  |  | -    overlay.height = overlay.clientHeight;
 | 
	
		
			
				|  |  | -    overlay.width = overlay.clientWidth;
 | 
	
		
			
				|  |  | -    this.ctx = canvas.getContext('2d')!;
 | 
	
		
			
				|  |  | -    this.overlayCtx = overlay.getContext('2d')!;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    this.overlayCtx.fillStyle = 'rgba(255, 0, 0, 0.5)';
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    this.overlay.addEventListener('click', (event: MouseEvent) => {
 | 
	
		
			
				|  |  | -      let pos = event.clientX - this.overlay.offsetLeft;
 | 
	
		
			
				|  |  | -      let percentage = pos / this.overlay.width;
 | 
	
		
			
				|  |  | -      let time = this.currentSection * 5 + percentage * 5;
 | 
	
		
			
				|  |  | -      this.setTime(time);
 | 
	
		
			
				|  |  | -    });
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  clear(): void {
 | 
	
		
			
				|  |  | -    this.track = null;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  setTrack(track: audio.FileTrack): void {
 | 
	
		
			
				|  |  | -    this.track = track;
 | 
	
		
			
				|  |  | -    this.stride = Math.floor(
 | 
	
		
			
				|  |  | -      (this.track.buffer.sampleRate / this.canvas.width) * 5
 | 
	
		
			
				|  |  | -    );
 | 
	
		
			
				|  |  | -    this.currentSection = -1;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  timeToX(time: number): number {
 | 
	
		
			
				|  |  | -    return ((time - this.currentSection * 5) / 5) * this.canvas.width;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  update(markers: Marker[]): void {
 | 
	
		
			
				|  |  | -    let section = Math.floor(this.track!.getTime() / 5);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    let height = this.canvas.height;
 | 
	
		
			
				|  |  | -    if (this.currentSection != section) {
 | 
	
		
			
				|  |  | -      this.data = this.track!.buffer.getChannelData(0);
 | 
	
		
			
				|  |  | -      this.ctx.clearRect(0, 0, this.canvas.width, height);
 | 
	
		
			
				|  |  | -      this.ctx.beginPath();
 | 
	
		
			
				|  |  | -      this.ctx.moveTo(0, height / 2);
 | 
	
		
			
				|  |  | -      let offset = section * this.canvas.width * this.stride;
 | 
	
		
			
				|  |  | -      for (let i = 0; i < this.canvas.width; ++i) {
 | 
	
		
			
				|  |  | -        let index = offset + i * this.stride;
 | 
	
		
			
				|  |  | -        let value = height / 2 + (height / 2) * this.data[index];
 | 
	
		
			
				|  |  | -        this.ctx.lineTo(i, value);
 | 
	
		
			
				|  |  | -      }
 | 
	
		
			
				|  |  | -      this.ctx.stroke();
 | 
	
		
			
				|  |  | -      this.currentSection = section;
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    let marker = this.timeToX(this.track!.getTime());
 | 
	
		
			
				|  |  | -    this.overlayCtx.clearRect(0, 0, this.canvas.width, height);
 | 
	
		
			
				|  |  | -    this.overlayCtx.fillRect(0, 0, marker, height);
 | 
	
		
			
				|  |  | -    markers.forEach((m) => {
 | 
	
		
			
				|  |  | -      if (m.time > section * 5 && m.time <= section * 5 + 5) {
 | 
	
		
			
				|  |  | -        let x = this.timeToX(m.time);
 | 
	
		
			
				|  |  | -        this.overlayCtx.beginPath();
 | 
	
		
			
				|  |  | -        this.overlayCtx.moveTo(x, 0);
 | 
	
		
			
				|  |  | -        this.overlayCtx.lineTo(x, height);
 | 
	
		
			
				|  |  | -        this.overlayCtx.stroke();
 | 
	
		
			
				|  |  | -      }
 | 
	
		
			
				|  |  | -    });
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -let e = new Editor();
 | 
	
		
			
				|  |  | -e.start();
 |