mirror of
https://github.com/curioustorvald/tsvm.git
synced 2026-03-07 19:51:51 +09:00
playwav now dithers the audio
This commit is contained in:
@@ -3,10 +3,8 @@
|
|||||||
let HW_SAMPLING_RATE = 30000
|
let HW_SAMPLING_RATE = 30000
|
||||||
let filename = exec_args[1]
|
let filename = exec_args[1]
|
||||||
const port = _TVDOS.DRV.FS.SERIAL._toPorts("A")[0]
|
const port = _TVDOS.DRV.FS.SERIAL._toPorts("A")[0]
|
||||||
function printdbg(s) {
|
function printdbg(s) { if (0) serial.println(s) }
|
||||||
if (0) serial.println(s)
|
function printvis(s) { if (0) println(s) }
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//println("Reading...")
|
//println("Reading...")
|
||||||
//serial.println("!!! READING")
|
//serial.println("!!! READING")
|
||||||
@@ -189,8 +187,27 @@ const uNybToSnyb = [0,1,2,3,4,5,6,7,-8,-7,-6,-5,-4,-3,-2,-1]
|
|||||||
// returns: [unsigned high, unsigned low, signed high, signed low]
|
// returns: [unsigned high, unsigned low, signed high, signed low]
|
||||||
function getNybbles(b) { return [b >> 4, b & 15, uNybToSnyb[b >> 4], uNybToSnyb[b & 15]] }
|
function getNybbles(b) { return [b >> 4, b & 15, uNybToSnyb[b >> 4], uNybToSnyb[b & 15]] }
|
||||||
function s8Tou8(i) { return i + 128 }
|
function s8Tou8(i) { return i + 128 }
|
||||||
function s16Tou8(i) { return ((i >>> 8)) + 128 }
|
function s16Tou8(i) {
|
||||||
|
// return s8Tou8((i >> 8) & 255)
|
||||||
|
// apply dithering
|
||||||
|
let ufval = (i / 65536.0) + 0.5
|
||||||
|
let ival = randomRound(ufval * 256.0)
|
||||||
|
return ival|0
|
||||||
|
}
|
||||||
function u16Tos16(i) { return (i > 32767) ? i - 65536 : i }
|
function u16Tos16(i) { return (i > 32767) ? i - 65536 : i }
|
||||||
|
function sampleToVisual(i) {
|
||||||
|
let rawstr = Math.abs(i).toString(2)
|
||||||
|
if (i < 0) rawstr = rawstr.padStart(16, '0')
|
||||||
|
else rawstr = rawstr.padEnd(16, '0')
|
||||||
|
|
||||||
|
let strPiece = rawstr.substring(0, Math.ceil(Math.abs(i) / 2048))
|
||||||
|
if (i == 0)
|
||||||
|
return ' ][ '
|
||||||
|
if (i < 0)
|
||||||
|
return strPiece.padStart(16, ' ') + ' '
|
||||||
|
else
|
||||||
|
return ' ' + strPiece.padEnd(16, ' ')
|
||||||
|
}
|
||||||
function checkIfPlayable() {
|
function checkIfPlayable() {
|
||||||
if (pcmType != 1 && pcmType != 2) return `PCM Type not LPCM/ADPCM (${pcmType})`
|
if (pcmType != 1 && pcmType != 2) return `PCM Type not LPCM/ADPCM (${pcmType})`
|
||||||
if (pcmType == 2 && nChannels > 2) return `Audio not mono/stereo but instead has ${nChannels} channels`
|
if (pcmType == 2 && nChannels > 2) return `Audio not mono/stereo but instead has ${nChannels} channels`
|
||||||
@@ -203,8 +220,15 @@ function decodeLPCM(inPtr, outPtr, inputLen) {
|
|||||||
|
|
||||||
if (2 == bytes) {
|
if (2 == bytes) {
|
||||||
if (HW_SAMPLING_RATE == samplingRate) {
|
if (HW_SAMPLING_RATE == samplingRate) {
|
||||||
for (let k = 0; k < inputLen / 2; k++) {
|
for (let k = 0; k < inputLen / 2; k+=2) {
|
||||||
sys.poke(outPtr + k, s8Tou8(sys.peek(inPtr + k*2 + 1)))
|
let sample = [
|
||||||
|
u16Tos16(sys.peek(inPtr + k*2 + 0) | (sys.peek(inPtr + k*2 + 1) << 8)),
|
||||||
|
u16Tos16(sys.peek(inPtr + k*2 + 2) | (sys.peek(inPtr + k*2 + 3) << 8))
|
||||||
|
]
|
||||||
|
sys.poke(outPtr + k, s16Tou8(sample[0]))
|
||||||
|
sys.poke(outPtr + k + 1, s16Tou8(sample[1]))
|
||||||
|
// soothing visualiser(????)
|
||||||
|
printvis(`${sampleToVisual(sample[0])} | ${sampleToVisual(sample[1])}`)
|
||||||
}
|
}
|
||||||
return inputLen / 2
|
return inputLen / 2
|
||||||
}
|
}
|
||||||
@@ -245,7 +269,7 @@ function decodeLPCM(inPtr, outPtr, inputLen) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
// soothing visualiser(????)
|
// soothing visualiser(????)
|
||||||
// let ls = sample[0].toString(2);if (sample[0] < 0) ls = ls.padStart(16, ' ') + ' '; else ls = ' ' + ls.padEnd(16, ' ');let rs = sample[1].toString(2);if (sample[1] < 0) rs = rs.padStart(16, ' ') + ' '; else rs = ' ' + rs.padEnd(16, ' ');println(`${ls} | ${rs}`)
|
printvis(`${sampleToVisual(sample[0])} | ${sampleToVisual(sample[1])}`)
|
||||||
|
|
||||||
// writeout
|
// writeout
|
||||||
sys.poke(outPtr + sendoutLength, s16Tou8(sample[channel]))
|
sys.poke(outPtr + sendoutLength, s16Tou8(sample[channel]))
|
||||||
@@ -264,6 +288,12 @@ function decodeLPCM(inPtr, outPtr, inputLen) {
|
|||||||
throw Error(`24-bit or 32-bit PCM not supported (bits per sample: ${bitsPerSample})`)
|
throw Error(`24-bit or 32-bit PCM not supported (bits per sample: ${bitsPerSample})`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
function randomRound(k) {
|
||||||
|
if (Math.random() < (k - (k|0)))
|
||||||
|
return Math.ceil(k)
|
||||||
|
else
|
||||||
|
return Math.floor(k)
|
||||||
|
}
|
||||||
// @see https://wiki.multimedia.cx/index.php/Microsoft_ADPCM
|
// @see https://wiki.multimedia.cx/index.php/Microsoft_ADPCM
|
||||||
// @see https://github.com/videolan/vlc/blob/master/modules/codec/adpcm.c#L423
|
// @see https://github.com/videolan/vlc/blob/master/modules/codec/adpcm.c#L423
|
||||||
function decodeMS_ADPCM(inPtr, outPtr, blockSize) {
|
function decodeMS_ADPCM(inPtr, outPtr, blockSize) {
|
||||||
@@ -294,7 +324,7 @@ function decodeMS_ADPCM(inPtr, outPtr, blockSize) {
|
|||||||
sys.poke(outPtr + 2, s16Tou8(samL1))
|
sys.poke(outPtr + 2, s16Tou8(samL1))
|
||||||
sys.poke(outPtr + 3, s16Tou8(samR1))
|
sys.poke(outPtr + 3, s16Tou8(samR1))
|
||||||
|
|
||||||
// println(`isamp\t${samL2}\t${samR2}\t${samL1}\t${samR1}`)
|
// printvis(`isamp\t${samL2}\t${samR2}\t${samL1}\t${samR1}`)
|
||||||
|
|
||||||
let bytesSent = 4
|
let bytesSent = 4
|
||||||
// start delta-decoding
|
// start delta-decoding
|
||||||
@@ -317,13 +347,13 @@ function decodeMS_ADPCM(inPtr, outPtr, blockSize) {
|
|||||||
if (deltaR < 16) deltaR = 16
|
if (deltaR < 16) deltaR = 16
|
||||||
|
|
||||||
// another soothing numbers wheezg-by(?)
|
// another soothing numbers wheezg-by(?)
|
||||||
// println(`b ${(''+byte).padStart(3,' ')} nb ${(''+unybL).padStart(2,' ')} ${(''+unybR).padStart(2,' ')} pred${(''+predictorL).padStart(9,' ')}${(''+predictorR).padStart(9,' ')}\tdelta\t${deltaL}\t${deltaR}`)
|
printvis(`b ${(''+byte).padStart(3,' ')} nb ${(''+unybL).padStart(2,' ')} ${(''+unybR).padStart(2,' ')} pred${(''+predictorL).padStart(9,' ')}${(''+predictorR).padStart(9,' ')}\tdelta\t${deltaL}\t${deltaR}`)
|
||||||
|
// printvis(`${sampleToVisual(predictorL)} | ${sampleToVisual(predictorR)}`)
|
||||||
|
|
||||||
// sendout
|
// sendout
|
||||||
sys.poke(outPtr + bytesSent, s16Tou8(predictorL));bytesSent += 1;
|
sys.poke(outPtr + bytesSent, s16Tou8(predictorL));bytesSent += 1;
|
||||||
sys.poke(outPtr + bytesSent, s16Tou8(predictorR));bytesSent += 1;
|
sys.poke(outPtr + bytesSent, s16Tou8(predictorR));bytesSent += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return bytesSent
|
return bytesSent
|
||||||
}
|
}
|
||||||
else if (1 == nChannels) {
|
else if (1 == nChannels) {
|
||||||
@@ -339,7 +369,7 @@ function decodeMS_ADPCM(inPtr, outPtr, blockSize) {
|
|||||||
sys.poke(outPtr + 2, s16Tou8(samL1))
|
sys.poke(outPtr + 2, s16Tou8(samL1))
|
||||||
sys.poke(outPtr + 3, s16Tou8(samL1))
|
sys.poke(outPtr + 3, s16Tou8(samL1))
|
||||||
|
|
||||||
// println(`isamp\t${samL2}\t${samL1}`)
|
// printvis(`isamp\t${samL2}\t${samL1}`)
|
||||||
|
|
||||||
let bytesSent = 4
|
let bytesSent = 4
|
||||||
// start delta-decoding
|
// start delta-decoding
|
||||||
@@ -359,7 +389,7 @@ function decodeMS_ADPCM(inPtr, outPtr, blockSize) {
|
|||||||
if (deltaL < 16) deltaL = 16
|
if (deltaL < 16) deltaL = 16
|
||||||
|
|
||||||
// another soothing numbers wheezg-by(?)
|
// another soothing numbers wheezg-by(?)
|
||||||
// println(`b ${(''+byte).padStart(3,' ')} nb ${(''+unybL).padStart(2,' ')} pred${(''+predictorL).padStart(9,' ')}\tdelta\t${deltaL}`)
|
printvis(`b ${(''+byte).padStart(3,' ')} nb ${(''+unybL).padStart(2,' ')} pred${(''+predictorL).padStart(9,' ')}\tdelta\t${deltaL}`)
|
||||||
|
|
||||||
// sendout
|
// sendout
|
||||||
sys.poke(outPtr + bytesSent, s16Tou8(predictorL));bytesSent += 1;
|
sys.poke(outPtr + bytesSent, s16Tou8(predictorL));bytesSent += 1;
|
||||||
@@ -377,7 +407,7 @@ function decodeMS_ADPCM(inPtr, outPtr, blockSize) {
|
|||||||
if (deltaL < 16) deltaL = 16
|
if (deltaL < 16) deltaL = 16
|
||||||
|
|
||||||
// another soothing numbers wheezg-by(?)
|
// another soothing numbers wheezg-by(?)
|
||||||
// println(`b ${(''+byte).padStart(3,' ')} nb ${(''+unybR).padStart(2,' ')} pred${(''+predictorL).padStart(9,' ')}\tdelta\t${deltaL}`)
|
printvis(`b ${(''+byte).padStart(3,' ')} nb ${(''+unybR).padStart(2,' ')} pred${(''+predictorL).padStart(9,' ')}\tdelta\t${deltaL}`)
|
||||||
|
|
||||||
// sendout
|
// sendout
|
||||||
sys.poke(outPtr + bytesSent, s16Tou8(predictorL));bytesSent += 1;
|
sys.poke(outPtr + bytesSent, s16Tou8(predictorL));bytesSent += 1;
|
||||||
Reference in New Issue
Block a user