I went through quite a few design revisions to get to the pipeline architecture I described yesterday. Some ideas I tried out and then abandoned:
- Giving the filters the responsibility of keeping the data they needed.
- Filters telling other filters how many samples they should consume or produce.
- A FilterGraph object which held all the buffers and which had methods to make and break connections.
- All the reader and writer methods being on the buffers.
- Lookahead reader methods for filters.
- Filters encapsulating other filters that they communicate with.
- Having separate consume() and produce() methods.
- Having the Reader and Writer functionality as part of the Consumer and Producer classes (this introduced a surprisingly significant overhead)
- A Connection object to encapsulate the buffer.
It's rather difficult to tell what's going to work well and what isn't until you actually write some code. And then it takes some trial and error work to hit upon the right pattern. Assumptions must be called into question. Prejudices must be discarded. Darlings must be killed. But you know when you've got it right because the rest then practically writes itself.