I can successfully create a 16-bit wav file, but when creating a 24-bit file, all I hear is white noise. I'm setting 24-bit signed integer data chunks. Do I have to set some special audio format at byte 20 in the wav file header? I'm currently using format 1.
Edit #1
The wBitsPerSample
field is set to 24. The wAvgBytesPerSec
(byte rate) field is set to
// 44100 * (2 * 3)
sampleRate * blockAlign
and wBlockAlign
is set to
// 2 * 3
numChannels * bytesPerSampe
Assuming you already did, the data itself needs to be 24-bit butt-to-butt (requires bit-shifting and masking unless the data already is from a 24-bit byte source). Or put differently: each sample will take 3 bytes. And as with 16-bit the byte-order matters.
I don't know if I got this part right, though.
My data comes in the form of Float32 that goes from -1 to 1 (AudioBuffer.getChannelData()
). I then convert it to Int24:
function floatTo24BitPCM(output, offset, input) {
for (var i = 0; i < input.length; i++, offset += 3) {
var s = Math.floor(input[i] * 8388608 + 0.5)
output.setInt24(offset, s, true)
}
}
and
DataView.prototype.setInt24 = function(pos, val, littleEndian) {
this.setInt16(pos, val >> 8, littleEndian);
this.setInt8(pos+2, val & ~4294967040, littleEndian); // this "magic number" masks off the first 16 bits
}
Does this process respect the specification (it seems like I'm doit bit shifting and masking in setInt24
)?
Edit #2
Modifying
DataView.prototype.setInt24 = function(pos, val, littleEndian) {
this.setInt16(pos, val >> 8, littleEndian);
this.setInt8(pos+2, val & ~4294967040, littleEndian); // this "magic number" masks off the first 16 bits
}
to
DataView.prototype.setUint24 = function(pos, val, littleEndian) {
this.setUint8(pos, val & ~4294967040, littleEndian); // this "magic number" masks off the first 16 bits
this.setUint16(pos + 1, val >> 8, littleEndian);
}
did the trick. I assume that the byte-order was incorrect? I'm confused as to why taking the last byte and putting it before the first two bytes is the correct order.
I also suggest that this question is re-opened as it is narrow enough to not be considered as "broad" anymore.
From the limited context in the post -
The field wBitsPerSample
(inside fmt->fmt-ck
format specific chunk, using 1 (PCM) for wFormatTag
is fine) must reflect number of bits per sample, ie. 24 in this case.
Assuming you already did, the data itself needs to be 24-bit butt-to-butt (requires bit-shifting and masking unless the data already is from a 24-bit byte source). Or put differently: each sample will take 3 bytes. And as with 16-bit the byte-order matters.
wAvgBytesPerSec
and wBlockAlign
are calculated as before just with the new bit size.