waveform audio file format encoder logic

encoder[from AudioBuffer]/downencoder[32, 24, 16 ,8]を使用可能。

encoder/downencoder

define AudioBuffer.prototype

1. throw
none

2. declare values, value, blockAlign
const vs=Array(14),v=b>>>3,blockAlign=this.numberOfChannels*v

3. declare call
,c=32===b?(v,i)=>(i=>v.subarray(i,4+i))(i<<2):(c=>{
    if(24===b)c=v=>(0>v?0x800000*v:0x7fffff*v).to3Array()
    else if(16===b)c=v=>(0>v?0x8000*v:0x7fff*v).to2Array()
    else if(8===b)c=v=>[0x80+(0>v?0x80*v:0x7f*v)]
    else throw Error()
    return(v,i)=>c(v[i].limit(false,-1).limit(true,1))
})()

4. set values
vs[0]=ids[0]
vs[2]=ids[1]
vs[3]=ids[2]
vs[4]=new Uint8Array([0x10,0,0,0])
vs[5]=new Uint8Array([32===b?3:1,0])
vs[6]=this.numberOfChannels.to2Array()
vs[7]=this.sampleRate.to4Array()
vs[8]=(this.sampleRate*blockAlign).to4Array()
vs[9]=blockAlign.to2Array()
vs[10]=b.to2Array()
vs[11]=ids[3]
vs[13]=(c=>{
    const vs=Array(this.numberOfChannels)
    if(32===b)forEach(false,this.numberOfChannels,(_,i)=>vs[i]=new Uint8Array(this.getChannelData(i).buffer))
    else forEach(false,this.numberOfChannels,(_,i)=>vs[i]=this.getChannelData(i))
    return 24===b?define(0b01,numberToArray(true,3),()=>c(vs)):c(vs)
})(vs=>{
    const data=new Uint8Array(this.length*blockAlign)
    forEach(false,this.length,(_,y)=>forEach(false,this.numberOfChannels,(_,x)=>data.set(c(vs[x],y),x*v+y*blockAlign)))
    return data
})
vs[1]=(36+vs[13].length).to4Array()
vs[12]=vs[13].length.to4Array()

5. return
return new Blob(vs,{type:`audio/wav`})

define Uint8Array.prototype

1. throw
if(ids[0]!==this.toNumberFrom4(0))throw Error()
if(ids[1]!==this.toNumberFrom4(8))throw Error()

2. declare index, value, call
let i=12,v,c

3. declare values
const vs=Array(4)

4. set values
vs[0]=this.subarray(0,i)
while(i<this.length){
    const id=this.toNumberFrom4(i),size=this.toNumberFrom4(i+=4)
    i+=4
    if(ids[2]===id){
        v=this.toNumberFrom2(14+i)
        if(32===v)c=(c=>{
            if(24===b)c=v=>(0>v?0x800000*v:0x7fffff*v).to3Array()
            else if(16===b)c=v=>(0>v?0x8000*v:0x7fff*v).to2Array()
            else if(8===b)c=v=>[0x80+(0>v?0x80*v:0x7f*v)]
            else throw Error()
            return(v,i)=>c(v[i].limit(false,-1).limit(true,1))
        })()
        else if(24===v)c=(c=>{
            if(16===b)c=v=>(0>v?0x8000*v/0x800000:0x7fff*v/0x7fffff).to2Array()
            else if(8===b)c=v=>[0x80+(0>v?0x80*v/0x800000:0x7f*v/0x7fffff)]
            else throw Error()
            return(v,i)=>c((v.toNumberFrom3(i*3)<<8)>>8)
        })()
        else if(16===v)c=(c=>{
            if(8===b)c=v=>[0x80+(0>v?0x80*v/0x8000:0x7f*v/0x7fff)]
            else throw Error()
            return(v,i)=>c((v[i]<<16)>>16)
        })()
        else throw Error()
        this.set((16).to4Array(),i-4)
        this.set((1).to2Array(),i)
        this.set((this.toNumberFrom4(8+i)*b/v).to4Array(),8+i)
        this.set((this.toNumberFrom2(12+i)*b/v).to2Array(),12+i)
        this.set(b.to2Array(),14+i)
        vs[1]=this.subarray(i-8,i+size)
    }else if(ids[3]===id){
        if(!c)throw Error()  
        vs[2]=this.subarray(i-8,i)
        vs[3]=(c=>{
            const vs=this.slice(i,i+size)
            if(32===v)return(vs=>24===b?define(0b01,numberToArray(true,3),()=>c(vs)):c(vs))(new Float32Array(vs.buffer))
            else if(24===v)return(vs=>define(0b01,uint8ArrayToNumber(true,3),()=>c(vs)))(vs)
            else return(vs=>c(vs))(new Uint16Array(vs.buffer))
        })(vs=>{
            const length=size/(v>>>3),data=new Uint8Array(length*(v=b>>>3))
            this.set((36+data.length).to4Array(),4)
            this.set(data.length.to4Array(),i-4)
            forEach(false,length,(_,x)=>data.set(c(vs,x),x*v))
            return data
        })
    }
    i+=size
}

5. return
return new Blob(vs,{type:`audio/wav`})