A state-by-event read of audioroute (Splitter, SplitterTap, MidSide, Port), audiomixer (Mixer, MixerVoice) and RawSample at v0.6.3rc3. Items marked measured were run on the CPython twin, on desktop MicroPython and on desktop CircuitPython. The rest come from reading the code.
The twin and the native nodes disagree
- Mixer level gate (measured). The native mixer forces a voice's gate open at the end of every inner chunk, and a chunk is capped by the source's buffer (
Mixer.c:587-591). The twin forces it once per block (audiomixer.py:215-240). With a fresh voice, DC 4000 and 100-frame source buffers into a 256-frame block, the twin plays nothing in block 0 and both native builds go non-zero at frame 100. The same applies to any level or pan move. Every mixer test feeds sources at least as big as the block, so none sees it.
- Mono SplitterTap (measured). The native mono tap hands out an inline buffer it refills on every pull (
SplitterTap.c:294-299); the twin hands out a fresh copy (_audiodsp.c:935-955). A voice primed from a mono tap, then the tap pulled directly: native mixes the overtaken block, the twin mixes the snapshot. A class run has already hit this.
Mixer.deinit(). Native keeps every voice's source referenced (Mixer.c:99-109); the twin releases them (audiomixer.py:159-162). The test that asserts the release runs on CPython only.
- Splitter with a source block that is not whole frames. Native drops the block silently after taking it (
Splitter.c:75-77); the twin raises, keeps the bad bytes, and raises on every later pull.
MidSide.stop() and playing exist on the twin only, and a test exercises them.
Audio lost
MidSide.reset_buffer and MidSide.play() drop the source frames the node holds (MidSide.c:178-188, :99-103): 256 frames with 512-frame buffers. Tested only through one class.
- Mono buffers with an odd number of frames lose their last frame on every buffer in the mixer (
Mixer.c:386).
Mixer.reset_buffer's priming fetch consumes a block of the source.
No test at all
Housekeeping
MixerVoice's constructor sets three fields and relies on zero-fill for the rest (MixerVoice.c:146-150), while Port.c:103-104 says the allocator does not zero. One of the two is wrong.
- The CircuitPython coverage binary writes gcov profile files into the shared build tree on every run.
See #176 and #177 for the same read of the other nodes.
A state-by-event read of
audioroute(Splitter, SplitterTap, MidSide, Port),audiomixer(Mixer, MixerVoice) andRawSampleat v0.6.3rc3. Items marked measured were run on the CPython twin, on desktop MicroPython and on desktop CircuitPython. The rest come from reading the code.The twin and the native nodes disagree
Mixer.c:587-591). The twin forces it once per block (audiomixer.py:215-240). With a fresh voice, DC 4000 and 100-frame source buffers into a 256-frame block, the twin plays nothing in block 0 and both native builds go non-zero at frame 100. The same applies to any level or pan move. Every mixer test feeds sources at least as big as the block, so none sees it.SplitterTap.c:294-299); the twin hands out a fresh copy (_audiodsp.c:935-955). A voice primed from a mono tap, then the tap pulled directly: native mixes the overtaken block, the twin mixes the snapshot. A class run has already hit this.Mixer.deinit(). Native keeps every voice's source referenced (Mixer.c:99-109); the twin releases them (audiomixer.py:159-162). The test that asserts the release runs on CPython only.Splitter.c:75-77); the twin raises, keeps the bad bytes, and raises on every later pull.MidSide.stop()andplayingexist on the twin only, and a test exercises them.Audio lost
MidSide.reset_bufferandMidSide.play()drop the source frames the node holds (MidSide.c:178-188,:99-103): 256 frames with 512-frame buffers. Tested only through one class.Mixer.c:386).Mixer.reset_buffer's priming fetch consumes a block of the source.No test at all
RawSample.MidSide.set()twice before a pull;MidSide.set()takes no pump lock (same family as audioconvolve.Convolver: synthesize() and load() write the impulse without the pump lock, and load() still resets mid-stream #166).Porthas no node test that runs on CPython, and is not in the deinit probe's list.Housekeeping
MixerVoice's constructor sets three fields and relies on zero-fill for the rest (MixerVoice.c:146-150), whilePort.c:103-104says the allocator does not zero. One of the two is wrong.See #176 and #177 for the same read of the other nodes.