export function PCMPlayer(option)
|
{
|
this.init(option);
|
}
|
|
PCMPlayer.prototype.init=function(option)
|
{
|
var defaults={
|
encoding: '16bitInt',
|
channels:1,
|
sampleRate:8000,
|
flushingTime:1000
|
};
|
this.option=Object.assign({},defaults,option);
|
this.samples=new Float32Array();
|
this.flush=this.flush.bind(this);
|
this.interval=setInterval(this.flush,this.option.flushingTime);
|
this.maxValue=this.getMaxValue();
|
this.typedArray=this.getTypedArray();
|
this.createContext();
|
};
|
|
PCMPlayer.prototype.getMaxValue=function()
|
{
|
var encodings={
|
'8bitInt': 128,
|
'16bitInt':32768,
|
'32bitInt':2147483648,
|
'32bitFloat':1
|
}
|
|
return encodings[this.option.encoding]?encodings[this.option.encoding]:encodings['16bitInt'];
|
};
|
|
PCMPlayer.prototype.getTypedArray=function()
|
{
|
var typedArrays={
|
'8bitInt': Int8Array,
|
'16bitInt':Int16Array,
|
'32bitInt':Int32Array,
|
'32bitFloat':Float32Array
|
}
|
|
return typedArrays[this.option.encoding]?typedArrays[this.option.encoding]:typedArrays['16bitInt'];
|
};
|
|
PCMPlayer.prototype.createContext=function()
|
{
|
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;
|
};
|
|
PCMPlayer.prototype.isTypedArray=function(data)
|
{
|
return (data.byteLength&&data.buffer&&data.buffer.constructor==ArrayBuffer);
|
};
|
|
PCMPlayer.prototype.feed=function(data)
|
{
|
if(!this.isTypedArray(data)) return;
|
data=this.getFormatedValue(data);
|
var tmp=new Float32Array(this.samples.length+data.length);
|
tmp.set(this.samples,0);
|
tmp.set(data,this.samples.length);
|
this.samples=tmp;
|
};
|
|
PCMPlayer.prototype.getFormatedValue=function(data)
|
{
|
var data=new this.typedArray(data.buffer),
|
float32=new Float32Array(data.length),
|
i;
|
|
for(i=0; i<data.length; i++)
|
{
|
float32[i]=data[i]/this.maxValue;
|
}
|
return float32;
|
};
|
|
PCMPlayer.prototype.volume=function(volume)
|
{
|
this.gainNode.gain.value=volume;
|
};
|
|
PCMPlayer.prototype.destroy=function()
|
{
|
if(this.interval)
|
{
|
clearInterval(this.interval);
|
}
|
this.samples=null;
|
this.audioCtx.close();
|
this.audioCtx=null;
|
};
|
|
PCMPlayer.prototype.flush=function()
|
{
|
if(!this.samples.length) return;
|
var bufferSource=this.audioCtx.createBufferSource(),
|
length=this.samples.length/this.option.channels,
|
audioBuffer=this.audioCtx.createBuffer(this.option.channels,length,this.option.sampleRate),
|
audioData,
|
channel,
|
offset,
|
i,
|
decrement;
|
|
for(channel=0; channel<this.option.channels; channel++)
|
{
|
audioData=audioBuffer.getChannelData(channel);
|
offset=channel;
|
decrement=50;
|
for(i=0; i<length; i++)
|
{
|
audioData[i]=this.samples[offset];
|
/* fadein */
|
if(i<50)
|
{
|
audioData[i]=(audioData[i]*i)/50;
|
}
|
/* fadeout*/
|
if(i>=(length-51))
|
{
|
audioData[i]=(audioData[i]*decrement--)/50;
|
}
|
offset+=this.option.channels;
|
}
|
}
|
|
if(this.startTime<this.audioCtx.currentTime)
|
{
|
this.startTime=this.audioCtx.currentTime;
|
}
|
//console.log('start vs current '+this.startTime+' vs '+this.audioCtx.currentTime+' duration: '+audioBuffer.duration);
|
bufferSource.buffer=audioBuffer;
|
bufferSource.connect(this.gainNode);
|
bufferSource.start(this.startTime);
|
this.startTime+=audioBuffer.duration;
|
this.samples=new Float32Array();
|
};
|
|
PCMPlayer.prototype.getTimestamp=function()
|
{
|
if(this.audioCtx)
|
{
|
return this.audioCtx.currentTime;
|
}
|
else
|
{
|
return 0;
|
}
|
};
|
|
PCMPlayer.prototype.play=function(data)
|
{
|
if(!this.isTypedArray(data))
|
{
|
return;
|
}
|
|
data=this.getFormatedValue(data);
|
if(!data.length)
|
{
|
return;
|
}
|
|
var bufferSource=this.audioCtx.createBufferSource(),
|
length=data.length/this.option.channels,
|
audioBuffer=this.audioCtx.createBuffer(this.option.channels,length,this.option.sampleRate),
|
audioData,
|
channel,
|
offset,
|
i,
|
decrement;
|
|
for(channel=0; channel<this.option.channels; channel++)
|
{
|
audioData=audioBuffer.getChannelData(channel);
|
offset=channel;
|
decrement=50;
|
for(i=0; i<length; i++)
|
{
|
audioData[i]=data[offset];
|
/* fadein */
|
if(i<50)
|
{
|
audioData[i]=(audioData[i]*i)/50;
|
}
|
/* fadeout*/
|
if(i>=(length-51))
|
{
|
audioData[i]=(audioData[i]*decrement--)/50;
|
}
|
offset+=this.option.channels;
|
}
|
}
|
|
if(this.startTime<this.audioCtx.currentTime)
|
{
|
this.startTime=this.audioCtx.currentTime;
|
}
|
//console.log('start vs current '+this.startTime+' vs '+this.audioCtx.currentTime+' duration: '+audioBuffer.duration);
|
bufferSource.buffer=audioBuffer;
|
bufferSource.connect(this.gainNode);
|
bufferSource.start(this.startTime);
|
this.startTime+=audioBuffer.duration;
|
};
|
|
PCMPlayer.prototype.pause=function()
|
{
|
if(this.audioCtx.state==='running')
|
{
|
this.audioCtx.suspend()
|
}
|
}
|
|
PCMPlayer.prototype.resume=function()
|
{
|
if(this.audioCtx.state==='suspended')
|
{
|
this.audioCtx.resume()
|
}
|
}
|