mirror of
https://github.com/kichikuou/xsystem35-sdl2.git
synced 2026-10-05 13:18:08 +03:00
Apply tslint
This commit is contained in:
+120
-117
@@ -2,113 +2,6 @@
|
||||
/// <reference path="volume.ts" />
|
||||
|
||||
namespace xsystem35 {
|
||||
abstract class PCMSound {
|
||||
protected context: AudioContext;
|
||||
protected gain: GainNode;
|
||||
protected duration_: number;
|
||||
protected startTime: number;
|
||||
|
||||
constructor(protected dst: AudioNode) {
|
||||
this.context = dst.context;
|
||||
this.gain = this.context.createGain();
|
||||
this.gain.connect(dst);
|
||||
}
|
||||
abstract start(loop: number): void;
|
||||
abstract stop(): void;
|
||||
setGain(gain: number) {
|
||||
this.gain.gain.value = gain;
|
||||
}
|
||||
fadeout(msec: number) {
|
||||
this.gain.gain.linearRampToValueAtTime(0, this.context.currentTime + msec / 1000);
|
||||
}
|
||||
getPosition(): number {
|
||||
if (!this.startTime)
|
||||
return 0;
|
||||
return this.context.currentTime - this.startTime;
|
||||
}
|
||||
isPlaying(): boolean {
|
||||
return !!this.startTime;
|
||||
}
|
||||
get duration(): number {
|
||||
return this.duration_;
|
||||
}
|
||||
}
|
||||
|
||||
class PCMSoundSimple extends PCMSound {
|
||||
private node: AudioBufferSourceNode;
|
||||
|
||||
constructor(dst: AudioNode, buf: AudioBuffer) {
|
||||
super(dst);
|
||||
this.node = this.context.createBufferSource();
|
||||
this.node.buffer = buf;
|
||||
this.node.connect(this.gain);
|
||||
this.node.onended = this.onended.bind(this);
|
||||
this.duration_ = buf.duration;
|
||||
}
|
||||
|
||||
start(loop: number) {
|
||||
if (loop == 0)
|
||||
this.node.loop = true;
|
||||
else if (loop != 1)
|
||||
console.warn('Unsupported PCM loop count ' + loop);
|
||||
this.node.start();
|
||||
this.startTime = this.context.currentTime;
|
||||
}
|
||||
|
||||
stop() {
|
||||
if (this.startTime) {
|
||||
this.node.stop();
|
||||
this.startTime = null;
|
||||
}
|
||||
}
|
||||
|
||||
private onended() {
|
||||
this.startTime = null;
|
||||
}
|
||||
}
|
||||
|
||||
class PCMSoundMixLR extends PCMSound {
|
||||
private lsrc: AudioBufferSourceNode;
|
||||
private rsrc: AudioBufferSourceNode;
|
||||
private endCount = 0;
|
||||
|
||||
constructor(dst: AudioNode, lbuf: AudioBuffer, rbuf: AudioBuffer) {
|
||||
super(dst);
|
||||
this.lsrc = this.context.createBufferSource();
|
||||
this.rsrc = this.context.createBufferSource();
|
||||
this.lsrc.buffer = lbuf;
|
||||
this.rsrc.buffer = rbuf;
|
||||
var merger = this.context.createChannelMerger(2);
|
||||
merger.connect(this.gain);
|
||||
this.lsrc.connect(merger, 0, 0);
|
||||
this.rsrc.connect(merger, 0, 1);
|
||||
this.lsrc.onended = this.rsrc.onended = this.onended.bind(this);
|
||||
this.duration_ = Math.max(lbuf.duration, rbuf.duration);
|
||||
}
|
||||
|
||||
start(loop: number) {
|
||||
if (loop != 1)
|
||||
console.warn('PCMSoundMixLR: loop is not supported ' + loop);
|
||||
this.lsrc.start();
|
||||
this.rsrc.start();
|
||||
this.startTime = this.context.currentTime;
|
||||
}
|
||||
|
||||
stop() {
|
||||
if (this.startTime) {
|
||||
this.lsrc.stop();
|
||||
this.rsrc.stop();
|
||||
this.startTime = null;
|
||||
}
|
||||
}
|
||||
|
||||
private onended() {
|
||||
this.endCount++;
|
||||
if (this.endCount == 2)
|
||||
this.startTime = null;
|
||||
}
|
||||
}
|
||||
|
||||
declare var webkitAudioContext: any;
|
||||
export class AudioManager {
|
||||
private context: AudioContext;
|
||||
@@ -134,8 +27,8 @@ namespace xsystem35 {
|
||||
}
|
||||
|
||||
private removeUserGestureRestriction() {
|
||||
var hanlder = () => {
|
||||
var src = this.context.createBufferSource();
|
||||
let hanlder = () => {
|
||||
let src = this.context.createBufferSource();
|
||||
src.buffer = this.context.createBuffer(1, 1, 22050);
|
||||
src.connect(this.context.destination);
|
||||
src.start();
|
||||
@@ -146,11 +39,11 @@ namespace xsystem35 {
|
||||
}
|
||||
|
||||
private load(no: number): Promise<AudioBuffer> {
|
||||
var buf = this.getWave(no);
|
||||
let buf = this.getWave(no);
|
||||
if (!buf)
|
||||
return Promise.reject('Failed to open wave ' + no);
|
||||
|
||||
var decoded: Promise<AudioBuffer>;
|
||||
let decoded: Promise<AudioBuffer>;
|
||||
if (this.isSafari) {
|
||||
decoded = new Promise((resolve, reject) => {
|
||||
this.context.decodeAudioData(buf, resolve, reject);
|
||||
@@ -165,12 +58,12 @@ namespace xsystem35 {
|
||||
}
|
||||
|
||||
private getWave(no: number): ArrayBuffer {
|
||||
var dfile = _ald_getdata(2 /* DRIFILE_WAVE */, no - 1);
|
||||
let dfile = _ald_getdata(2 /* DRIFILE_WAVE */, no - 1);
|
||||
if (!dfile)
|
||||
return null;
|
||||
var ptr = Module.getValue(dfile + 8, '*');
|
||||
var size = Module.getValue(dfile, 'i32');
|
||||
var buf = Module.HEAPU8.buffer.slice(ptr, ptr + size);
|
||||
let ptr = Module.getValue(dfile + 8, '*');
|
||||
let size = Module.getValue(dfile, 'i32');
|
||||
let buf = Module.HEAPU8.buffer.slice(ptr, ptr + size);
|
||||
_ald_freedata(dfile);
|
||||
return buf;
|
||||
}
|
||||
@@ -196,7 +89,7 @@ namespace xsystem35 {
|
||||
this.slots[slot] = new PCMSoundMixLR(this.masterGain, this.buffers[noL], this.buffers[noR]);
|
||||
return resume();
|
||||
}
|
||||
var ps = [];
|
||||
let ps = [];
|
||||
if (!this.buffers[noL]) ps.push(this.load(noL));
|
||||
if (!this.buffers[noR]) ps.push(this.load(noR));
|
||||
Promise.all(ps).then(() => {
|
||||
@@ -258,4 +151,114 @@ namespace xsystem35 {
|
||||
this.masterGain.gain.value = evt.detail;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
abstract class PCMSound {
|
||||
protected context: AudioContext;
|
||||
protected gain: GainNode;
|
||||
protected startTime: number;
|
||||
|
||||
constructor(protected dst: AudioNode) {
|
||||
this.context = dst.context;
|
||||
this.gain = this.context.createGain();
|
||||
this.gain.connect(dst);
|
||||
}
|
||||
abstract start(loop: number): void;
|
||||
abstract stop(): void;
|
||||
setGain(gain: number) {
|
||||
this.gain.gain.value = gain;
|
||||
}
|
||||
fadeout(msec: number) {
|
||||
this.gain.gain.linearRampToValueAtTime(0, this.context.currentTime + msec / 1000);
|
||||
}
|
||||
getPosition(): number {
|
||||
if (!this.startTime)
|
||||
return 0;
|
||||
return this.context.currentTime - this.startTime;
|
||||
}
|
||||
isPlaying(): boolean {
|
||||
return !!this.startTime;
|
||||
}
|
||||
abstract get duration(): number;
|
||||
}
|
||||
|
||||
class PCMSoundSimple extends PCMSound {
|
||||
private node: AudioBufferSourceNode;
|
||||
|
||||
constructor(dst: AudioNode, buf: AudioBuffer) {
|
||||
super(dst);
|
||||
this.node = this.context.createBufferSource();
|
||||
this.node.buffer = buf;
|
||||
this.node.connect(this.gain);
|
||||
this.node.onended = this.onended.bind(this);
|
||||
}
|
||||
|
||||
start(loop: number) {
|
||||
if (loop === 0)
|
||||
this.node.loop = true;
|
||||
else if (loop !== 1)
|
||||
console.warn('Unsupported PCM loop count ' + loop);
|
||||
this.node.start();
|
||||
this.startTime = this.context.currentTime;
|
||||
}
|
||||
|
||||
stop() {
|
||||
if (this.startTime) {
|
||||
this.node.stop();
|
||||
this.startTime = null;
|
||||
}
|
||||
}
|
||||
|
||||
get duration() {
|
||||
return this.node.buffer.duration;
|
||||
}
|
||||
|
||||
private onended() {
|
||||
this.startTime = null;
|
||||
}
|
||||
}
|
||||
|
||||
class PCMSoundMixLR extends PCMSound {
|
||||
private lsrc: AudioBufferSourceNode;
|
||||
private rsrc: AudioBufferSourceNode;
|
||||
private endCount = 0;
|
||||
|
||||
constructor(dst: AudioNode, lbuf: AudioBuffer, rbuf: AudioBuffer) {
|
||||
super(dst);
|
||||
this.lsrc = this.context.createBufferSource();
|
||||
this.rsrc = this.context.createBufferSource();
|
||||
this.lsrc.buffer = lbuf;
|
||||
this.rsrc.buffer = rbuf;
|
||||
let merger = this.context.createChannelMerger(2);
|
||||
merger.connect(this.gain);
|
||||
this.lsrc.connect(merger, 0, 0);
|
||||
this.rsrc.connect(merger, 0, 1);
|
||||
this.lsrc.onended = this.rsrc.onended = this.onended.bind(this);
|
||||
}
|
||||
|
||||
start(loop: number) {
|
||||
if (loop !== 1)
|
||||
console.warn('PCMSoundMixLR: loop is not supported ' + loop);
|
||||
this.lsrc.start();
|
||||
this.rsrc.start();
|
||||
this.startTime = this.context.currentTime;
|
||||
}
|
||||
|
||||
stop() {
|
||||
if (this.startTime) {
|
||||
this.lsrc.stop();
|
||||
this.rsrc.stop();
|
||||
this.startTime = null;
|
||||
}
|
||||
}
|
||||
|
||||
get duration() {
|
||||
return Math.max(this.lsrc.buffer.duration, this.rsrc.buffer.duration);
|
||||
}
|
||||
|
||||
private onended() {
|
||||
this.endCount++;
|
||||
if (this.endCount === 2)
|
||||
this.startTime = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+4
-4
@@ -13,7 +13,7 @@ namespace xsystem35 {
|
||||
volumeControl.addEventListener(this.onVolumeChanged.bind(this));
|
||||
this.audio.volume = volumeControl.volume();
|
||||
this.waiting = false;
|
||||
this.removeUserGestureRestriction()
|
||||
this.removeUserGestureRestriction();
|
||||
}
|
||||
|
||||
play(track: number, loop: number) {
|
||||
@@ -37,13 +37,13 @@ namespace xsystem35 {
|
||||
getPosition(): number {
|
||||
if (!this.currentTrack)
|
||||
return 0;
|
||||
var time = Math.round(this.audio.currentTime * 75);
|
||||
let time = Math.round(this.audio.currentTime * 75);
|
||||
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.loop = (loop !== 0);
|
||||
this.audio.load();
|
||||
this.audio.play();
|
||||
this.waiting = false;
|
||||
@@ -54,7 +54,7 @@ namespace xsystem35 {
|
||||
}
|
||||
|
||||
private removeUserGestureRestriction() {
|
||||
var hanlder = () => {
|
||||
let hanlder = () => {
|
||||
this.audio.load();
|
||||
console.log('CDDA unlocked');
|
||||
window.removeEventListener('touchend', hanlder);
|
||||
|
||||
+23
-19
@@ -5,7 +5,7 @@ namespace xsystem35 {
|
||||
private worker: Worker;
|
||||
private cddaCallback: (wab: Blob) => void;
|
||||
|
||||
constructor(private runMain: ()=>void) {
|
||||
constructor(private runMain: () => void) {
|
||||
this.initWorker();
|
||||
$('#fileselect').addEventListener('change', this.handleFileSelect.bind(this), false);
|
||||
document.body.ondragover = this.handleDragOver.bind(this);
|
||||
@@ -13,7 +13,7 @@ namespace xsystem35 {
|
||||
}
|
||||
|
||||
getCDDA(track: number, callback: (wav: Blob) => void) {
|
||||
this.send({ command: 'getTrack', track: track });
|
||||
this.send({ command: 'getTrack', track });
|
||||
this.cddaCallback = callback;
|
||||
}
|
||||
|
||||
@@ -35,13 +35,14 @@ namespace xsystem35 {
|
||||
}
|
||||
|
||||
private populateFiles(files: any, volumeLabel: string) {
|
||||
var grGenerator = new GameResourceGenerator();
|
||||
for (var name in files) {
|
||||
var data: ArrayBuffer = files[name];
|
||||
let grGenerator = new GameResourceGenerator();
|
||||
for (let name in files) {
|
||||
let data: ArrayBuffer = files[name];
|
||||
// Store contents in the emscripten heap, so that it can be mmap-ed without copying
|
||||
var ptr = Module.getMemory(data.byteLength);
|
||||
let ptr = Module.getMemory(data.byteLength);
|
||||
Module.HEAPU8.set(new Uint8Array(data), ptr);
|
||||
FS.writeFile(name, Module.HEAPU8.subarray(ptr, ptr + data.byteLength), { encoding: 'binary', canOwn: true });
|
||||
FS.writeFile(name, Module.HEAPU8.subarray(ptr, ptr + data.byteLength),
|
||||
{ encoding: 'binary', canOwn: true });
|
||||
grGenerator.addFile(name);
|
||||
}
|
||||
FS.writeFile('xsystem35.gr', grGenerator.generate());
|
||||
@@ -51,9 +52,9 @@ namespace xsystem35 {
|
||||
}
|
||||
|
||||
private handleFileSelect(evt: Event) {
|
||||
var input = <HTMLInputElement>evt.target;
|
||||
var files = input.files;
|
||||
for (var i = 0; i < files.length; i++)
|
||||
let input = <HTMLInputElement>evt.target;
|
||||
let files = input.files;
|
||||
for (let i = 0; i < files.length; i++)
|
||||
this.setFile(files[i]);
|
||||
input.value = '';
|
||||
}
|
||||
@@ -67,13 +68,13 @@ namespace xsystem35 {
|
||||
private handleDrop(evt: DragEvent) {
|
||||
evt.stopPropagation();
|
||||
evt.preventDefault();
|
||||
var files = evt.dataTransfer.files;
|
||||
for (var i = 0; i < files.length; i++)
|
||||
let files = evt.dataTransfer.files;
|
||||
for (let i = 0; i < files.length; i++)
|
||||
this.setFile(files[i]);
|
||||
}
|
||||
|
||||
private setFile(file: File) {
|
||||
this.send({ command: 'setFile', file: file });
|
||||
this.send({ command: 'setFile', file });
|
||||
}
|
||||
|
||||
private startInstall() {
|
||||
@@ -101,6 +102,8 @@ namespace xsystem35 {
|
||||
case 'error':
|
||||
console.log(evt.data.message);
|
||||
break;
|
||||
default:
|
||||
throw('unknown command: ' + evt.data.command);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,27 +113,28 @@ namespace xsystem35 {
|
||||
}
|
||||
|
||||
class GameResourceGenerator {
|
||||
static resourceType: { [ch: string]: string } = { s: 'Scenario', g: 'Graphics', w: 'Wave', d: 'Data', r: 'Resource', m: 'Midi' };
|
||||
static resourceType: { [ch: string]: string } =
|
||||
{ s: 'Scenario', g: 'Graphics', w: 'Wave', d: 'Data', r: 'Resource', m: 'Midi' };
|
||||
private basename: string;
|
||||
private lines: string[] = [];
|
||||
|
||||
addFile(name: string) {
|
||||
var type = name.charAt(name.length - 6).toLowerCase();
|
||||
var id = name.charAt(name.length - 5);
|
||||
let type = name.charAt(name.length - 6).toLowerCase();
|
||||
let id = name.charAt(name.length - 5);
|
||||
this.basename = name.slice(0, -6);
|
||||
this.lines.push(GameResourceGenerator.resourceType[type] + id.toUpperCase() + ' ' + name);
|
||||
}
|
||||
|
||||
generate(): string {
|
||||
for (var i = 0; i < 26; i++) {
|
||||
var id = String.fromCharCode(65 + i);
|
||||
for (let i = 0; i < 26; i++) {
|
||||
let id = String.fromCharCode(65 + i);
|
||||
this.lines.push('Save' + id + ' save/' + this.basename + 's' + id.toLowerCase() + '.asd');
|
||||
}
|
||||
return this.lines.join('\n') + '\n';
|
||||
}
|
||||
|
||||
isEmpty(): boolean {
|
||||
return this.lines.length == 0;
|
||||
return this.lines.length === 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+9
-9
@@ -10,10 +10,10 @@ namespace xsystem35 {
|
||||
export const xsys35rc = [
|
||||
'font_device: ttf',
|
||||
'ttfont_mincho: ' + Font.fname,
|
||||
'ttfont_gothic: ' + Font.fname, ''
|
||||
'ttfont_gothic: ' + Font.fname, '',
|
||||
].join('\n');
|
||||
export var cdPlayer: CDPlayer;
|
||||
export var audio: AudioManager;
|
||||
export let cdPlayer: CDPlayer;
|
||||
export let audio: AudioManager;
|
||||
|
||||
class System35Shell {
|
||||
private imageLoader: ImageLoader;
|
||||
@@ -46,15 +46,15 @@ namespace xsystem35 {
|
||||
FS.mkdir('/save');
|
||||
FS.mount(IDBFS, {}, '/save');
|
||||
Module.addRunDependency('syncfs');
|
||||
FS.syncfs(true, (err) => { Module.removeRunDependency('syncfs') });
|
||||
}
|
||||
FS.syncfs(true, (err) => { Module.removeRunDependency('syncfs'); });
|
||||
},
|
||||
];
|
||||
this.volumeControl = new VolumeControl();
|
||||
xsystem35.cdPlayer = new CDPlayer(this.imageLoader, this.volumeControl);
|
||||
this.zoom = new ZoomManager();
|
||||
this.antialiasCheckbox = <HTMLInputElement>$('#antialias');
|
||||
this.antialiasCheckbox.addEventListener('change', this.antialiasChanged.bind(this));
|
||||
this.antialiasCheckbox.checked = localStorage.getItem('antialias') != 'false';
|
||||
this.antialiasCheckbox.checked = localStorage.getItem('antialias') !== 'false';
|
||||
xsystem35.audio = new AudioManager(this.volumeControl);
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ namespace xsystem35 {
|
||||
this.fsyncTimer = window.setTimeout(() => {
|
||||
FS.syncfs(false, (err) => {
|
||||
if (err)
|
||||
console.log("FS.syncfs error: ", err);
|
||||
console.log('FS.syncfs error: ', err);
|
||||
});
|
||||
}, 100);
|
||||
}
|
||||
@@ -94,7 +94,7 @@ namespace xsystem35 {
|
||||
}
|
||||
|
||||
private addRightClickEmulation() {
|
||||
var emulatingRightClick = false;
|
||||
let emulatingRightClick = false;
|
||||
document.body.addEventListener('touchstart', (e) => {
|
||||
if (e.target !== document.body)
|
||||
return;
|
||||
@@ -110,5 +110,5 @@ namespace xsystem35 {
|
||||
}
|
||||
}
|
||||
|
||||
export var shell = new System35Shell();
|
||||
export let shell = new System35Shell();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"extends": "tslint:recommended",
|
||||
"rules": {
|
||||
"curly": false,
|
||||
"interface-name": false,
|
||||
"max-classes-per-file": false,
|
||||
"member-access": false,
|
||||
"member-ordering": false,
|
||||
"no-bitwise": false,
|
||||
"no-empty": false,
|
||||
"no-namespace": false,
|
||||
"no-reference": false,
|
||||
"only-arrow-functions": ["allow-declarations", "allow-named-functions"],
|
||||
"prefer-for-of": false,
|
||||
"quotemark": [true, "single", "avoid-escape"],
|
||||
"whitespace": [
|
||||
true,
|
||||
"check-branch",
|
||||
"check-decl",
|
||||
"check-operator",
|
||||
"check-separator",
|
||||
"check-type"
|
||||
],
|
||||
|
||||
"no-console": false
|
||||
}
|
||||
}
|
||||
+6
-5
@@ -1,4 +1,4 @@
|
||||
var $: (selector:string)=>HTMLElement = document.querySelector.bind(document);
|
||||
let $: (selector: string) => HTMLElement = document.querySelector.bind(document);
|
||||
|
||||
// xsystem35 exported functions
|
||||
declare function _musfade_setvolval_all(vol: number): void;
|
||||
@@ -8,10 +8,10 @@ declare function _ald_getdata(type: number, no: number): number;
|
||||
declare function _ald_freedata(data: number): void;
|
||||
|
||||
declare namespace Module {
|
||||
var noInitialRun: boolean;
|
||||
let noInitialRun: boolean;
|
||||
|
||||
// Undocumented methods / attributes
|
||||
var canvas: HTMLElement;
|
||||
let canvas: HTMLElement;
|
||||
function setStatus(status: string): void;
|
||||
function monitorRunDependencies(left: number): void;
|
||||
function callMain(): void;
|
||||
@@ -19,9 +19,10 @@ declare namespace Module {
|
||||
}
|
||||
|
||||
declare namespace FS {
|
||||
function writeFile(path: string, data: ArrayBufferView | string, opts?: {encoding?: string; flags?: string; canOwn?: boolean}): void;
|
||||
function writeFile(path: string, data: ArrayBufferView | string,
|
||||
opts?: {encoding?: string; flags?: string; canOwn?: boolean}): void;
|
||||
}
|
||||
|
||||
declare namespace EmterpreterAsync {
|
||||
function handle(asyncOp: (resume:()=>void) => void): void;
|
||||
function handle(asyncOp: (resume: () => void) => void): void;
|
||||
}
|
||||
|
||||
+3
-3
@@ -23,7 +23,7 @@ namespace xsystem35 {
|
||||
}
|
||||
|
||||
volume(): number {
|
||||
return this.muted ? 0 : parseInt(this.slider.value) / 100;
|
||||
return this.muted ? 0 : parseInt(this.slider.value, 10) / 100;
|
||||
}
|
||||
|
||||
addEventListener(handler: (evt: CustomEvent) => any) {
|
||||
@@ -45,7 +45,7 @@ namespace xsystem35 {
|
||||
}
|
||||
|
||||
private onSliderValueChanged(e: Event) {
|
||||
this.vol = parseInt(this.slider.value) / 100;
|
||||
this.vol = parseInt(this.slider.value, 10) / 100;
|
||||
if (this.vol > 0 && this.muted) {
|
||||
this.muted = false;
|
||||
this.icon.classList.remove('fa-volume-off');
|
||||
@@ -59,7 +59,7 @@ namespace xsystem35 {
|
||||
}
|
||||
|
||||
private dispatchEvent() {
|
||||
var event = new CustomEvent('volumechange', { detail: this.volume() });
|
||||
let event = new CustomEvent('volumechange', { detail: this.volume() });
|
||||
this.elem.dispatchEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
+5
-5
@@ -13,21 +13,21 @@ namespace xsystem35 {
|
||||
this.zoomSelect.value = localStorage.getItem('zoom') || '1';
|
||||
this.smoothingCheckbox = <HTMLInputElement>$('#smoothing');
|
||||
this.smoothingCheckbox.addEventListener('change', this.handleSmoothing.bind(this));
|
||||
if (localStorage.getItem('smoothing') == 'false') {
|
||||
if (localStorage.getItem('smoothing') === 'false') {
|
||||
this.smoothingCheckbox.checked = false;
|
||||
this.handleSmoothing();
|
||||
}
|
||||
}
|
||||
|
||||
handleZoom() {
|
||||
var value = this.zoomSelect.value;
|
||||
let value = this.zoomSelect.value;
|
||||
localStorage.setItem('zoom', value);
|
||||
var contentsStyle = $('.contents').style;
|
||||
if (value == 'fit') {
|
||||
let contentsStyle = $('.contents').style;
|
||||
if (value === 'fit') {
|
||||
contentsStyle.maxWidth = 'none';
|
||||
contentsStyle.width = this.canvas.style.width = '100%';
|
||||
} else {
|
||||
var ratio = Number(value);
|
||||
let ratio = Number(value);
|
||||
contentsStyle.maxWidth = 'none';
|
||||
contentsStyle.width = this.canvas.style.width = this.canvas.width * ratio + 'px';
|
||||
}
|
||||
|
||||
+92
-89
@@ -5,7 +5,7 @@ class ISO9660FileSystem {
|
||||
|
||||
constructor(private sectorReader: CDImageReader) {
|
||||
this.pvd = new PVD(sectorReader.readSector(0x10));
|
||||
if (this.pvd.type != 1)
|
||||
if (this.pvd.type !== 1)
|
||||
throw('PVD not found');
|
||||
}
|
||||
|
||||
@@ -17,25 +17,26 @@ class ISO9660FileSystem {
|
||||
return this.pvd.rootDirEnt();
|
||||
}
|
||||
|
||||
getDirEnt(name:string, parent:DirEnt): DirEnt {
|
||||
getDirEnt(name: string, parent: DirEnt): DirEnt {
|
||||
name = name.toLowerCase();
|
||||
for (var e of this.readDir(parent)) {
|
||||
if (e.name.toLowerCase() == name)
|
||||
for (let e of this.readDir(parent)) {
|
||||
if (e.name.toLowerCase() === name)
|
||||
return e;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
readDir(dirent:DirEnt): DirEnt[] {
|
||||
var sector = dirent.sector;
|
||||
var position = 0;
|
||||
var length = dirent.size;
|
||||
var entries:DirEnt[] = [];
|
||||
readDir(dirent: DirEnt): DirEnt[] {
|
||||
let sector = dirent.sector;
|
||||
let position = 0;
|
||||
let length = dirent.size;
|
||||
let entries: DirEnt[] = [];
|
||||
let buf: ArrayBuffer;
|
||||
while (position < length) {
|
||||
if (position == 0)
|
||||
var buf = this.sectorReader.readSector(sector);
|
||||
var child = new DirEnt(buf, position);
|
||||
if (child.length == 0) {
|
||||
if (position === 0)
|
||||
buf = this.sectorReader.readSector(sector);
|
||||
let child = new DirEnt(buf, position);
|
||||
if (child.length === 0) {
|
||||
// Padded end of sector
|
||||
position = 2048;
|
||||
} else {
|
||||
@@ -44,7 +45,7 @@ class ISO9660FileSystem {
|
||||
}
|
||||
if (position > 2048)
|
||||
throw('dirent across sector boundary');
|
||||
if (position == 2048) {
|
||||
if (position === 2048) {
|
||||
sector++;
|
||||
position = 0;
|
||||
length -= 2048;
|
||||
@@ -53,21 +54,21 @@ class ISO9660FileSystem {
|
||||
return entries;
|
||||
}
|
||||
|
||||
readFile(dirent:DirEnt): Uint8Array[] {
|
||||
readFile(dirent: DirEnt): Uint8Array[] {
|
||||
return this.sectorReader.readSequentialSectors(dirent.sector, dirent.size);
|
||||
}
|
||||
}
|
||||
|
||||
class PVD {
|
||||
private view:DataView;
|
||||
constructor(private buf:ArrayBuffer) {
|
||||
private view: DataView;
|
||||
constructor(private buf: ArrayBuffer) {
|
||||
this.view = new DataView(buf);
|
||||
}
|
||||
get type(): number {
|
||||
return this.view.getUint8(0);
|
||||
}
|
||||
volumeLabel(): string {
|
||||
var decoder = new TextDecoder('shift_jis');
|
||||
let decoder = new TextDecoder('shift_jis');
|
||||
return decoder.decode(new DataView(this.buf, 40, 32)).trim();
|
||||
}
|
||||
rootDirEnt(): DirEnt {
|
||||
@@ -76,8 +77,8 @@ class PVD {
|
||||
}
|
||||
|
||||
class DirEnt {
|
||||
private view:DataView;
|
||||
constructor(private buf:ArrayBuffer, private offset:number) {
|
||||
private view: DataView;
|
||||
constructor(private buf: ArrayBuffer, private offset: number) {
|
||||
this.view = new DataView(buf, offset);
|
||||
}
|
||||
get length(): number {
|
||||
@@ -90,35 +91,35 @@ class DirEnt {
|
||||
return this.view.getUint32(10, true);
|
||||
}
|
||||
get isDirectory(): boolean {
|
||||
return (this.view.getUint8(25) & 2) != 0;
|
||||
return (this.view.getUint8(25) & 2) !== 0;
|
||||
}
|
||||
get name(): string {
|
||||
var len = this.view.getUint8(32);
|
||||
var decoder = new TextDecoder('shift_jis');
|
||||
return decoder.decode(new DataView(this.buf, this.offset+33, len)).split(';')[0];
|
||||
let len = this.view.getUint8(32);
|
||||
let decoder = new TextDecoder('shift_jis');
|
||||
return decoder.decode(new DataView(this.buf, this.offset + 33, len)).split(';')[0];
|
||||
}
|
||||
}
|
||||
|
||||
interface CDImageReader {
|
||||
readSector(sector:number): ArrayBuffer;
|
||||
readSector(sector: number): ArrayBuffer;
|
||||
readSequentialSectors(startSector: number, length: number): Uint8Array[];
|
||||
maxTrack(): number;
|
||||
extractTrack(track:number): Blob;
|
||||
extractTrack(track: number): Blob;
|
||||
}
|
||||
|
||||
class ImageReaderBase {
|
||||
constructor(public image:File) {}
|
||||
constructor(public image: File) {}
|
||||
|
||||
readSequential(startOffset:number,
|
||||
bytesToRead:number,
|
||||
blockSize:number,
|
||||
sectorSize:number,
|
||||
sectorOffset:number): Uint8Array[] {
|
||||
var sectors = Math.ceil(bytesToRead / sectorSize);
|
||||
var blob = this.image.slice(startOffset, startOffset + sectors * blockSize);
|
||||
var buf = new FileReaderSync().readAsArrayBuffer(blob);
|
||||
var bufs:Uint8Array[] = [];
|
||||
for (var i = 0; i < sectors; i++) {
|
||||
readSequential(startOffset: number,
|
||||
bytesToRead: number,
|
||||
blockSize: number,
|
||||
sectorSize: number,
|
||||
sectorOffset: number): Uint8Array[] {
|
||||
let sectors = Math.ceil(bytesToRead / sectorSize);
|
||||
let blob = this.image.slice(startOffset, startOffset + sectors * blockSize);
|
||||
let buf = new FileReaderSync().readAsArrayBuffer(blob);
|
||||
let bufs: Uint8Array[] = [];
|
||||
for (let i = 0; i < sectors; i++) {
|
||||
bufs.push(new Uint8Array(buf, i * blockSize + sectorOffset, Math.min(bytesToRead, sectorSize)));
|
||||
bytesToRead -= sectorSize;
|
||||
}
|
||||
@@ -127,16 +128,16 @@ class ImageReaderBase {
|
||||
}
|
||||
|
||||
class ImgCueReader extends ImageReaderBase implements CDImageReader {
|
||||
private tracks:{ type:string; index:string[]; }[];
|
||||
private tracks: Array<{ type: string; index: string[]; }>;
|
||||
|
||||
constructor(img:File, cue:File) {
|
||||
constructor(img: File, cue: File) {
|
||||
super(img);
|
||||
this.parseCue(cue);
|
||||
}
|
||||
|
||||
readSector(sector:number): ArrayBuffer {
|
||||
var start = sector * 2352 + 16;
|
||||
var end = start + 2048;
|
||||
readSector(sector: number): ArrayBuffer {
|
||||
let start = sector * 2352 + 16;
|
||||
let end = start + 2048;
|
||||
return new FileReaderSync().readAsArrayBuffer(this.image.slice(start, end));
|
||||
}
|
||||
|
||||
@@ -144,115 +145,117 @@ class ImgCueReader extends ImageReaderBase implements CDImageReader {
|
||||
return this.readSequential(startSector * 2352, length, 2352, 2048, 16);
|
||||
}
|
||||
|
||||
private parseCue(cueFile:File) {
|
||||
var lines = new FileReaderSync().readAsText(cueFile).split('\n');
|
||||
private parseCue(cueFile: File) {
|
||||
let lines = new FileReaderSync().readAsText(cueFile).split('\n');
|
||||
this.tracks = [];
|
||||
var currentTrack:number = null;
|
||||
for (var line of lines) {
|
||||
var fields = line.trim().split(/\s+/);
|
||||
let currentTrack: number = null;
|
||||
for (let line of lines) {
|
||||
let fields = line.trim().split(/\s+/);
|
||||
switch (fields[0]) {
|
||||
case 'TRACK':
|
||||
currentTrack = Number(fields[1]);
|
||||
this.tracks[currentTrack] = {type:fields[2], index:[]};
|
||||
this.tracks[currentTrack] = {type: fields[2], index: []};
|
||||
break;
|
||||
case 'INDEX':
|
||||
if (currentTrack)
|
||||
this.tracks[currentTrack].index[Number(fields[1])] = fields[2];
|
||||
break;
|
||||
default:
|
||||
; // Do nothing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
maxTrack():number {
|
||||
maxTrack(): number {
|
||||
return this.tracks.length - 1;
|
||||
}
|
||||
|
||||
extractTrack(track:number): Blob {
|
||||
if (!this.tracks[track] || this.tracks[track].type != 'AUDIO')
|
||||
extractTrack(track: number): Blob {
|
||||
if (!this.tracks[track] || this.tracks[track].type !== 'AUDIO')
|
||||
return;
|
||||
|
||||
var start = this.indexToSector(this.tracks[track].index[1]) * 2352;
|
||||
var end:number;
|
||||
if (this.tracks[track+1]) {
|
||||
var index = this.tracks[track+1].index[0] || this.tracks[track+1].index[1];
|
||||
let start = this.indexToSector(this.tracks[track].index[1]) * 2352;
|
||||
let end: number;
|
||||
if (this.tracks[track + 1]) {
|
||||
let index = this.tracks[track + 1].index[0] || this.tracks[track + 1].index[1];
|
||||
end = this.indexToSector(index) * 2352;
|
||||
} else {
|
||||
end = this.image.size;
|
||||
}
|
||||
var size = end - start;
|
||||
let size = end - start;
|
||||
return new Blob([createWaveHeader(size), this.image.slice(start, start + size)], {type : 'audio/wav'});
|
||||
}
|
||||
|
||||
private indexToSector(index:string):number {
|
||||
var msf = index.split(':').map(Number);
|
||||
return msf[0]*60*75 + msf[1]*75 + msf[2];
|
||||
private indexToSector(index: string): number {
|
||||
let msf = index.split(':').map(Number);
|
||||
return msf[0] * 60 * 75 + msf[1] * 75 + msf[2];
|
||||
}
|
||||
}
|
||||
|
||||
enum MdsTrackMode { Audio = 0xa9, Mode1 = 0xaa };
|
||||
|
||||
class MdfMdsReader extends ImageReaderBase implements CDImageReader {
|
||||
private tracks:{ mode:number; sectorSize:number; offset:number; sectors:number; }[];
|
||||
private tracks: Array<{ mode: number; sectorSize: number; offset: number; sectors: number; }>;
|
||||
|
||||
constructor(mdf:File, mds:File) {
|
||||
constructor(mdf: File, mds: File) {
|
||||
super(mdf);
|
||||
this.parseMds(mds);
|
||||
}
|
||||
|
||||
private parseMds(mdsFile:File) {
|
||||
var buf = new FileReaderSync().readAsArrayBuffer(mdsFile);
|
||||
private parseMds(mdsFile: File) {
|
||||
let buf = new FileReaderSync().readAsArrayBuffer(mdsFile);
|
||||
|
||||
var signature = new TextDecoder().decode(new DataView(buf, 0, 16));
|
||||
if (signature != 'MEDIA DESCRIPTOR')
|
||||
let signature = new TextDecoder().decode(new DataView(buf, 0, 16));
|
||||
if (signature !== 'MEDIA DESCRIPTOR')
|
||||
throw mdsFile.name + ': not a mds file';
|
||||
|
||||
var header = new DataView(buf, 0, 0x70);
|
||||
var entries = header.getUint8(0x62);
|
||||
let header = new DataView(buf, 0, 0x70);
|
||||
let entries = header.getUint8(0x62);
|
||||
|
||||
this.tracks = [];
|
||||
for (var i = 0; i < entries; i++) {
|
||||
var trackData = new DataView(buf, 0x70 + i * 0x50, 0x50);
|
||||
var extraData = new DataView(buf, 0x70 + entries * 0x50 + i * 8, 8);
|
||||
var mode = trackData.getUint8(0x00);
|
||||
var track = trackData.getUint8(0x04);
|
||||
var sectorSize = trackData.getUint16(0x10, true);
|
||||
var offset = trackData.getUint32(0x28, true); // >4GB offset is not supported.
|
||||
var sectors = extraData.getUint32(0x4, true);
|
||||
for (let i = 0; i < entries; i++) {
|
||||
let trackData = new DataView(buf, 0x70 + i * 0x50, 0x50);
|
||||
let extraData = new DataView(buf, 0x70 + entries * 0x50 + i * 8, 8);
|
||||
let mode = trackData.getUint8(0x00);
|
||||
let track = trackData.getUint8(0x04);
|
||||
let sectorSize = trackData.getUint16(0x10, true);
|
||||
let offset = trackData.getUint32(0x28, true); // >4GB offset is not supported.
|
||||
let sectors = extraData.getUint32(0x4, true);
|
||||
if (track < 100)
|
||||
this.tracks[track] = {mode:mode, sectorSize:sectorSize, offset:offset, sectors:sectors};
|
||||
this.tracks[track] = {mode, sectorSize, offset, sectors};
|
||||
}
|
||||
if (this.tracks[1].mode != MdsTrackMode.Mode1)
|
||||
if (this.tracks[1].mode !== MdsTrackMode.Mode1)
|
||||
throw 'track 1 is not mode1';
|
||||
}
|
||||
|
||||
readSector(sector:number): ArrayBuffer {
|
||||
var start = sector * this.tracks[1].sectorSize + 16;
|
||||
var end = start + 2048;
|
||||
readSector(sector: number): ArrayBuffer {
|
||||
let start = sector * this.tracks[1].sectorSize + 16;
|
||||
let end = start + 2048;
|
||||
return new FileReaderSync().readAsArrayBuffer(this.image.slice(start, end));
|
||||
}
|
||||
|
||||
readSequentialSectors(startSector: number, length: number): Uint8Array[] {
|
||||
var track = this.tracks[1];
|
||||
let track = this.tracks[1];
|
||||
return this.readSequential(track.offset + startSector * track.sectorSize, length, track.sectorSize, 2048, 16);
|
||||
}
|
||||
|
||||
maxTrack():number {
|
||||
maxTrack(): number {
|
||||
return this.tracks.length - 1;
|
||||
}
|
||||
|
||||
extractTrack(track:number): Blob {
|
||||
if (!this.tracks[track] || this.tracks[track].mode != MdsTrackMode.Audio)
|
||||
extractTrack(track: number): Blob {
|
||||
if (!this.tracks[track] || this.tracks[track].mode !== MdsTrackMode.Audio)
|
||||
return;
|
||||
|
||||
var size = this.tracks[track].sectors * 2352;
|
||||
var chunks = this.readSequential(this.tracks[track].offset, size, this.tracks[track].sectorSize, 2352, 0);
|
||||
let size = this.tracks[track].sectors * 2352;
|
||||
let chunks = this.readSequential(this.tracks[track].offset, size, this.tracks[track].sectorSize, 2352, 0);
|
||||
return new Blob([<any>createWaveHeader(size)].concat(chunks), {type : 'audio/wav'});
|
||||
}
|
||||
}
|
||||
|
||||
function createWaveHeader(size:number):ArrayBuffer {
|
||||
var buf = new ArrayBuffer(44);
|
||||
var view = new DataView(buf);
|
||||
function createWaveHeader(size: number): ArrayBuffer {
|
||||
let buf = new ArrayBuffer(44);
|
||||
let view = new DataView(buf);
|
||||
view.setUint32(0, 0x52494646, false); // 'RIFF'
|
||||
view.setUint32(4, size + 36, true); // filesize - 8
|
||||
view.setUint32(8, 0x57415645, false); // 'WAVE'
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
importScripts('cdimage.js');
|
||||
|
||||
declare function postMessage(data: any, transfers:any): void;
|
||||
declare function postMessage(data: any, transfers: any): void;
|
||||
|
||||
class Installer {
|
||||
private imgFile:File;
|
||||
private cueFile:File;
|
||||
private imageReader:CDImageReader;
|
||||
private imgFile: File;
|
||||
private cueFile: File;
|
||||
private imageReader: CDImageReader;
|
||||
|
||||
constructor() {
|
||||
addEventListener('message', this.onMessage.bind(this));
|
||||
@@ -15,9 +15,9 @@ class Installer {
|
||||
switch (evt.data.command) {
|
||||
case 'setFile':
|
||||
this.setFile(evt.data.file);
|
||||
var imgName = this.imgFile && this.imgFile.name;
|
||||
var cueName = this.cueFile && this.cueFile.name;
|
||||
postMessage({command:'readyState', img:imgName, cue:cueName});
|
||||
let imgName = this.imgFile && this.imgFile.name;
|
||||
let cueName = this.cueFile && this.cueFile.name;
|
||||
postMessage({command: 'readyState', img: imgName, cue: cueName});
|
||||
break;
|
||||
case 'extractFiles':
|
||||
if (this.ready())
|
||||
@@ -27,11 +27,13 @@ class Installer {
|
||||
if (this.ready())
|
||||
this.getTrack(evt.data.track);
|
||||
break;
|
||||
default:
|
||||
throw('unknown command: ' + evt.data.command);
|
||||
}
|
||||
}
|
||||
|
||||
private setFile(file:File) {
|
||||
var name = file.name.toLowerCase();
|
||||
private setFile(file: File) {
|
||||
let name = file.name.toLowerCase();
|
||||
if (name.endsWith('.img') || name.endsWith('.mdf'))
|
||||
this.imgFile = file;
|
||||
else if (name.endsWith('.cue') || name.endsWith('.mds'))
|
||||
@@ -49,25 +51,25 @@ class Installer {
|
||||
}
|
||||
|
||||
private extractFiles() {
|
||||
var isofs = new ISO9660FileSystem(this.imageReader);
|
||||
//this.walk(isofs, isofs.rootDir(), '/');
|
||||
var gamedata = isofs.getDirEnt('gamedata', isofs.rootDir());
|
||||
let isofs = new ISO9660FileSystem(this.imageReader);
|
||||
// this.walk(isofs, isofs.rootDir(), '/');
|
||||
let gamedata = isofs.getDirEnt('gamedata', isofs.rootDir());
|
||||
if (!gamedata) {
|
||||
postMessage({command:'error', message:'インストールできません。GAMEDATAフォルダが見つかりません。'});
|
||||
postMessage({command: 'error', message: 'インストールできません。GAMEDATAフォルダが見つかりません。'});
|
||||
return;
|
||||
}
|
||||
var files: any = {};
|
||||
var transfers = [];
|
||||
for (var e of isofs.readDir(gamedata)) {
|
||||
let files: any = {};
|
||||
let transfers = [];
|
||||
for (let e of isofs.readDir(gamedata)) {
|
||||
if (e.name.toLowerCase().endsWith('.ald')) {
|
||||
var buffer = new ArrayBuffer(e.size);
|
||||
var uint8 = new Uint8Array(buffer);
|
||||
var ptr = 0;
|
||||
for (var buf of isofs.readFile(e)) {
|
||||
let buffer = new ArrayBuffer(e.size);
|
||||
let uint8 = new Uint8Array(buffer);
|
||||
let ptr = 0;
|
||||
for (let buf of isofs.readFile(e)) {
|
||||
uint8.set(buf, ptr);
|
||||
ptr += buf.byteLength;
|
||||
}
|
||||
if (ptr != e.size)
|
||||
if (ptr !== e.size)
|
||||
throw('expected ' + e.size + ' bytes, but read ' + ptr + 'bytes');
|
||||
files[e.name] = buffer;
|
||||
transfers.push(buffer);
|
||||
@@ -75,12 +77,12 @@ class Installer {
|
||||
}
|
||||
postMessage({command: 'extractFiles',
|
||||
volumeLabel: isofs.volumeLabel(),
|
||||
files: files}, transfers);
|
||||
files}, transfers);
|
||||
}
|
||||
|
||||
private walk(isofs:ISO9660FileSystem, dir:DirEnt, dirname:string) {
|
||||
for (var e of isofs.readDir(dir)) {
|
||||
if (e.name != '\0' && e.name != '\x01') {
|
||||
private walk(isofs: ISO9660FileSystem, dir: DirEnt, dirname: string) {
|
||||
for (let e of isofs.readDir(dir)) {
|
||||
if (e.name !== '\0' && e.name !== '\x01') {
|
||||
console.log(dirname + e.name);
|
||||
if (e.isDirectory)
|
||||
this.walk(isofs, e, dirname + e.name + '/');
|
||||
@@ -88,10 +90,10 @@ class Installer {
|
||||
}
|
||||
}
|
||||
|
||||
private getTrack(track:number) {
|
||||
var blob = this.imageReader.extractTrack(track);
|
||||
postMessage({command:'complete', track:track, wav:blob});
|
||||
private getTrack(track: number) {
|
||||
let blob = this.imageReader.extractTrack(track);
|
||||
postMessage({command: 'complete', track, wav: blob});
|
||||
}
|
||||
}
|
||||
|
||||
var installer = new Installer();
|
||||
let installer = new Installer();
|
||||
|
||||
@@ -2,8 +2,8 @@ class FallbackTextDecoder {
|
||||
constructor(utfLabel?: string) {}
|
||||
|
||||
decode(buffer: DataView): string {
|
||||
var out = '';
|
||||
for (var i = 0; i < buffer.byteLength; i++) {
|
||||
let out = '';
|
||||
for (let i = 0; i < buffer.byteLength; i++) {
|
||||
let c = buffer.getUint8(i);
|
||||
if (c < 128)
|
||||
out += String.fromCharCode(c);
|
||||
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
../shell/tslint.json
|
||||
Reference in New Issue
Block a user