diff --git a/library/jy4340132-aaa/adpcm.js b/library/jy4340132-aaa/adpcm.js new file mode 100644 index 00000000..cd2b0a10 --- /dev/null +++ b/library/jy4340132-aaa/adpcm.js @@ -0,0 +1,61 @@ + + +class Adpcm extends AudioCoder +{ + constructor(wasm, importObj) + { + super(wasm, importObj); + this._indexDe = Adpcm._currentIndex; + this._indexEn = Adpcm._currentIndex + 1; + Adpcm._currentIndex = (Adpcm._currentIndex + 2) & 0x3F; + this._wasm.instance.exports._initAdpcmState(this._indexDe); + this._wasm.instance.exports._initAdpcmState(this._indexEn); + } + + resetDecodeState(state) + { + this._wasm.instance.exports._resetAdpcmState(this._indexDe, state.valprev, state.index); + } + + resetEncodeState(state) + { + this._wasm.instance.exports._resetAdpcmState(this._indexEn, state.valprev, state.index); + } + + getDecodeState() + { + this._wasm.instance.exports._getAdpcmState(this._indexDe, 10236, 10238); + return new Adpcm.State(this._memory[10236] + (this._memory[10237] << 8), this._memory[10238]); + } + + getEncodeState() + { + this._wasm.instance.exports._getAdpcmState(this._indexEn, 10236, 10238); + return new Adpcm.State(this._memory[10236] + (this._memory[10237] << 8), this._memory[10238]); + } + + decode(data) + { + this._copyToMemory(data); + this._wasm.instance.exports._decodeAdpcm(this._indexDe, 0, 10240, data.byteLength << 1); + return new Int16Array(this._memory.buffer, 10240, data.byteLength << 1); + } + + encode(data) + { + this._copyToMemory(data); + this._wasm.instance.exports._encodeAdpcm(this._indexEn, 0, 10240, data.byteLength >>> 1); + return new Uint8Array(this._memory.buffer, 10240, data.byteLength >>> 2); + } +} + +Adpcm._currentIndex = 0; + +Adpcm.State = class +{ + constructor(valprev, index) + { + this.valprev = valprev; + this.index = index; + } +} diff --git a/library/jy4340132-aaa/adpcm.wasm b/library/jy4340132-aaa/adpcm.wasm new file mode 100644 index 00000000..6591605c Binary files /dev/null and b/library/jy4340132-aaa/adpcm.wasm differ diff --git a/library/jy4340132-aaa/pcm_player.js b/library/jy4340132-aaa/pcm_player.js new file mode 100644 index 00000000..ebe152ed --- /dev/null +++ b/library/jy4340132-aaa/pcm_player.js @@ -0,0 +1,80 @@ + +class PCMPlayer +{ + constructor(channels, sampleRate) + { + this._samples = new Float32Array(); + this._flushingTime = 200; + this._channels = channels; + this._sampleRate = sampleRate; + this._flush = this._flush.bind(this); + this._audioCtx = new (window.AudioContext || window.webkitAudioContext)(); + this._gainNode = this._audioCtx.createGain(); + this._gainNode.gain.value = 1; + this._gainNode.connect(this._audioCtx.destination); + this._startTime = this._audioCtx.currentTime; + this._interval = setInterval(this._flush, this._flushingTime); + } + + setVolume(volume) + { + this._gainNode.gain.value = volume; + } + + close() + { + if(this._interval) + { + clearInterval(this._interval); + } + this._audioCtx.close(); + }; + + feed(data) + { + let tmp = new Float32Array(this._samples.length + data.length); + tmp.set(this._samples, 0); + tmp.set(data, this._samples.length); + this._samples = tmp; + }; + + _flush() + { + if(!this._channels || !this._sampleRate || !this._samples.length) + { + return; + } + let bufferSource = this._audioCtx.createBufferSource(); + let length = this._samples.length / this._channels; + let audioBuffer = this._audioCtx.createBuffer(this._channels, length, this._sampleRate); + for (let channel = 0; channel != this._channels; ++channel) + { + let audioData = audioBuffer.getChannelData(channel); + let offset = channel; + let decrement = 50; + for (let i = 0; i != length; ++i) + { + audioData[i] = this._samples[offset]; + if (i < 50) + { + audioData[i] = (audioData[i] * i) / 50; + } + if (i >= (length - 51)) + { + audioData[i] = (audioData[i] * decrement--) / 50; + } + offset += this._channels; + } + } + + if (this._startTime < this._audioCtx.currentTime) + { + this._startTime = this._audioCtx.currentTime; + } + bufferSource.buffer = audioBuffer; + bufferSource.connect(this._gainNode); + bufferSource.start(this._startTime); + this._startTime += audioBuffer.duration; + this._samples = new Float32Array(); + } +} diff --git a/library/jy4340132-aaa/std.js b/library/jy4340132-aaa/std.js new file mode 100644 index 00000000..1c1e3f23 --- /dev/null +++ b/library/jy4340132-aaa/std.js @@ -0,0 +1,171 @@ + +class Std +{ + constructor() + {} + + static memmem(data1, data1Offset, data2) + { + for (let i = 0; i <= data1.byteLength - data2.byteLength - data1Offset; ++i) + { + let j = 0; + for (; j != data2.byteLength; ++j) + { + if(data1[i + j + data1Offset] != data2[j]) + { + break; + } + } + if(j >= data2.byteLength) + { + return i + data1Offset; + } + } + return -1; + } + + static memcmp(data1, data1Offset, data2) + { + for(let i = 0; i != data2.byteLength; ++i) + { + if(data1[i + data1Offset] != data2[i]) + { + return -1; + } + } + return 0; + } + + static memcpy(data1, data1Offset, data2, data2Begin, data2End) + { + data1.set(data2.subarray(data2Begin, data2End), data1Offset); + } + + static milliSecondTime() + { + return new Date().getTime(); + } + + static shortToFloatData(input) + { + let inputSamples = input.length; + let output = new Float32Array(inputSamples); + for(let i = 0; i != inputSamples; ++i) + { + output[i] = input[i] / 32768; + } + return output; + } + + static floatToShortData(input) + { + let inputSamples = input.length; + let output = new Int16Array(inputSamples); + for(let i = 0; i != inputSamples; ++i) + { + output[i] = input[i] * 32768; + } + return output; + } + + static downsampleBuffer(buffer, rate, sampleRate) + { + if(rate == sampleRate) + { + return buffer; + } + else if(rate > sampleRate) + { + throw "rate > sampleRate error !!"; + } + let sampleRateRatio = sampleRate / rate; + let newLength = Math.ceil(buffer.length / sampleRateRatio) & 0xFFFC; + let result = new Float32Array(newLength); + let offsetResult = 0; + let offsetBuffer = 0; + while (offsetResult != result.length) + { + let nextOffsetBuffer = offsetBuffer + sampleRateRatio; + let accum = 0; + let count = 0; + let currentOffset = Math.ceil(offsetBuffer); + let currentNextOffset = Math.ceil(nextOffsetBuffer); + for (let i = currentOffset; i != currentNextOffset && i != buffer.length; ++i) + { + accum += buffer[i]; + ++count; + } + result[offsetResult] = accum / count; + ++offsetResult; + offsetBuffer = nextOffsetBuffer; + } + return result; + } +} + +class Result +{ + constructor(data, type, time, errorCode, duration = 20) + { + this.data = data; + this.type = type; + this.time = time; + this.duration = duration; + this.errorCode = errorCode; + } + + static makeErrorResult(errorCode) + { + return new Result(null, -1, -1, errorCode); + } +} + +Result.ErrorCode = class +{ + constructor() + {} +} + +Result.ErrorCode.SUCCESS = 0; +Result.ErrorCode.PARAM_ERROR = 1000; +Result.ErrorCode.PARAM_CHANGE = 2000; +Result.ErrorCode.FAIL = 3000; +Result.ErrorCode.NO_INIT_ERROR = Result.ErrorCode.FAIL + 1; +Result.ErrorCode.CACHE_MAX_ERROR = Result.ErrorCode.FAIL + 2; + +Result.Type = class +{ + constructor() + {} +} + +Result.Type.H264_I_FRAME = 0; +Result.Type.H264_P_FRAME = 1; +Result.Type.H264_B_FRAME = 2; +Result.Type.AUDIO = 3; +Result.Type.TRANS_DATA = 4; +Result.Type.FMP4_HEAD = 5; +Result.Type.FMP4_BODY = 6; + +class AudioCoder +{ + constructor(wasm, importObj) + { + if(importObj.memoryBase < 102400) + { + throw new Error("too small"); + } + this._importObj = importObj; + this._wasm = wasm; + this._memory = new Uint8Array(this._importObj.env.memory.buffer); + } + + _copyToMemory(data) + { + if(data.byteLength > (this._importObj.env.memoryBase >>> 6)) + { + throw new Error("overflow"); + } + this._memory.set(new Uint8Array(data.buffer, data.byteOffset, data.byteLength)); + } +} diff --git a/multi.html b/multi.html index 22b2fc98..f42d8f95 100644 --- a/multi.html +++ b/multi.html @@ -14,6 +14,11 @@ + + + + + + + + + + + + + + +