Hey, thanks all for the input.
So here is a more fuller description of what I am thinking about.
I am involved with a project that requires audio monitoring of birdsong. We are building up a library of recordings of ambient noise, and will provide an interface to extract selected parts of very long records for detailed analysis.
I want to replace the LSB of audio samples in with metadata about the stream - time, date, GPS location, sample rates, recording device, channel, recording gain and so on. This way the metadata can be included in standard lossless audio file formats (like WAV files), and it can be played with standard media players (of course anything that manipulates the samples will cause the loss of this data, but that isn't my problem).
Eventually this process won't actually involve much data loss as we will be capturing using a 24-bit audio codec, and bit-shifting to keep the 15 bits of useful data. The bit-shift factor will then be included in the block metadata allowing the original dynamic range to be restored. (Of course for playback by standard media players all the blocks in the same file will need to use the same bit-shift factor)
The main reason I don't want to use separate metadata file or embedded metadata blocks in the file is that it needs to have a stream of location, front-end gain, and a reference clock signal (e.g. UTC time) all of which change over time, and we need to be able to randomly access sections of the recordings.
The metadata is a 256-bit block (including a CRC), which is scrambled using the bit stream from a 16-bit LFSR. To allow the state state of the LFSR to be recovered the first 16 bits of the block are zeros. Basically it looks like a single bit of random noise. If you have 511 samples, you can then sync up with the LFSR, and find out when, where and who and how the samples were obtained.
I am now pondering how to merge this data in with the audio samples. One option is to just replace the least significant bit of the sample with the metadata bit
out[i] = (in[i] & 0xFFFE) | metadata_bit[i]
The other option is to flip those LSBs that don't match what I need them to be:
out[i] = in[i];
if((out[i]&1) != metadata_bit) {
out[i] &= 0x1;
}
Which is the same as just replacing the LSB
I'm now thinking I might treat it as a dither:
dither = 1;
...
out[i] = in[i];
if(out[i]&1 != metadata_bit) {
out[i] += dither;
dither = -dither;
}
Hum... so many options. The last one sort of feels right.
I'm trying to work out which makes the most sense before I commit to anything.