Files
kichikuou_xsystem35-sdl2/shell/cdda.ts
T
2017-04-16 00:23:42 +09:00

111 lines
3.8 KiB
TypeScript

/// <reference path="util.ts" />
/// <reference path="volume.ts" />
namespace xsystem35 {
export class CDPlayer {
private audio = <HTMLAudioElement>$('audio');
private blobs: Blob[];
private currentTrack: number;
private isVolumeSupported: boolean;
private unmute: () => void; // Non-null if emulating mute by pause
waiting: boolean;
constructor(private imageLoader: ImageLoader, volumeControl: VolumeControl) {
// Volume control of <audio> is not supported in iOS
this.audio.volume = 0.5;
this.isVolumeSupported = this.audio.volume !== 1;
this.blobs = [];
volumeControl.addEventListener(this.onVolumeChanged.bind(this));
this.audio.volume = volumeControl.volume();
this.audio.addEventListener('error', this.onAudioError.bind(this));
this.waiting = false;
this.removeUserGestureRestriction();
if (!this.isVolumeSupported) {
volumeControl.hideSlider();
if (this.audio.volume === 0)
this.unmute = () => {};
}
}
play(track: number, loop: number) {
this.currentTrack = track;
if (this.unmute) {
this.unmute = () => { this.play(track, loop); };
return;
}
this.waiting = true;
if (this.blobs[track]) {
this.startPlayback(this.blobs[track], loop);
return;
}
this.imageLoader.getCDDA(track).then((blob) => {
this.blobs[track] = blob;
this.startPlayback(blob, loop);
});
}
stop() {
this.audio.pause();
this.currentTrack = null;
if (this.unmute)
this.unmute = () => {};
}
getPosition(): number {
if (!this.currentTrack)
return 0;
let time = Math.round(this.audio.currentTime * 75);
if (this.unmute || this.audio.error)
time += 750; // unblock Kichikuou OP
return this.currentTrack | time << 8;
}
private startPlayback(blob: Blob, loop: number) {
this.audio.setAttribute('src', URL.createObjectURL(blob));
this.audio.loop = (loop !== 0);
this.audio.load();
this.audio.play();
this.waiting = false;
}
private onVolumeChanged(evt: CustomEvent) {
if (this.isVolumeSupported) {
this.audio.volume = evt.detail;
return;
}
let muted = evt.detail === 0;
if (!!this.unmute === muted)
return;
if (muted) {
this.audio.pause();
this.unmute = () => { this.audio.play(); };
} else {
let unmute = this.unmute;
this.unmute = null;
unmute();
}
}
private onAudioError(err: ErrorEvent) {
let clone = document.importNode((<HTMLTemplateElement>$('#cdda-error')).content, true);
let toast = xsystem35.shell.addToast(clone, 'danger');
toast.querySelector('.cdda-reload-button').addEventListener('click', () => {
this.imageLoader.reloadImage().then(() => {
this.play(this.currentTrack, this.audio.loop ? 1 : 0);
(<HTMLElement>toast.querySelector('.btn-clear')).click();
});
});
}
private removeUserGestureRestriction() {
let hanlder = () => {
this.audio.load();
console.log('CDDA unlocked');
window.removeEventListener('touchend', hanlder);
};
window.addEventListener('touchend', hanlder);
}
}
}