Categories
Sonitus

Coding by Toilet Breaks

I just had a revelation while sitting on the can: the generation of the “I need another source because this one is empty” event happens in the wrong place. The MultiSource will of course detect the end almost immediately after a source file is decoded which can happen in just a few seconds (even if your MP3 file yields seven minutes worth of music) so obviously (obviously!) it should not send the event; instead the final sink of the pipeline should tell somebody that the source of the pipeline needs new data. Now I only need to figure out which sink I should listen to in case I have several sinks in a pipeline (e.g. one for a streaming server, one for local audio output).

Categories
Sonitus

Needs Moar Signals

Great, I’m back at the initial problem: the beginning of the pipeline needs to know when the end of the pipeline has processed all the data that the beginning of the pipeline has produced. Unfortunately, with external decoders, that is not done easily or reliably. At least I can not think of a way that does not involve “waiting until x ms have gone by without getting data.”

Categories
Sonitus

Getting Rid of Things…

Turns out I had not really introduced a bug. It was all the fault of the predicate filter which — with the new approach of how to create pipelines with changing formats — can simply be thrown out.

Categories
Sonitus

Consolidation

I made good on what I said yesterday: I scrapped all those fancy interfaces that I had and merged them all into Filter. The resulting simplification of some parts of the code was noticable, the commit added 681 lines but removed 906.

I introduced a small metadata handling bug that I will take care of right after finishing this post and I still need to create a filter that can contain several filters so that I can simply attach a pipeline (consisting of e. g. a stream source and an mp3 decoder) to a multi source filter. That should fix all my format-metadata-changing problems.

Categories
Sonitus

A New Plan Is Forming…

Apparently the real problem is to get the metadata of a filter’s input to the output generated by that exact input. So by some magical means I have to wait for a filter plugin to have generated all data that it will generate for the input it has been fed, and we’re potentially talking about dozens of milliseconds! This is an outrage!

Categories
Bit Manipulation Java

Bit Fiddlery

Recently I tried to parse FLAC headers. In the STREAMINFO block there are several fields that have a width of non-multiple-of-8 bits so I had to create a function that could read a number of bits starting at an arbitrary bit.

/**
 * Reads numberOfBits bits from the given buffer, starting at the given byte
 * and bit offsets. Bits are assumed to be numbered MSB-first, i.e. the
 * highest bit in a byte (0x80) is considered bit 0.
 * 
 * Example UUID: B24E931F-FFC5-4F3C-A6FF-E667BDB5F062
 */
long parseBits(byte[] data, int byteOffset, int bitOffset, int numberOfBits) {
  long value = 0;
  int currentByteOffset = byteOffset;
  int currentBitOffset = bitOffset;
  int bitsRemaining = numberOfBits;

  /* while we still need some bits... */
  while (bitsRemaining > 0) {

    /* shift the current value by the number of bits we still need
     * to make room for them at the end. at most a byte, though. */
    value <<= Math.min(8, remainingBits);

    /* extract all the bits remaining in the current byte. */
    int bitsWeNeed = (data[currentByteOffset] & (0xff >>> currentBitOffset));

    /* shift them so that only the number of bits we need remains. */
    bitsWeNeed <<= (8 - currentBitOffset - Math.min(bitsRemaining, 8 - currentBitOffset));

    /* now combine the values. */
    value |= bitsWeNeed;

    /* reduce number of bits we still need. */
    bitsRemaining -= Math.min(bitsRemaining, 8 - currentBitOffset);

    /* the current byte is now depleted of bits we need. even if it isn’t
     * it doesn’t matter because if we needed less bits than we had this
     * routine is now finished. */
    currentBitOffset = 0;
    currentByteOffset++;
  }

  return value;
}