autopilot
autopilot copied to clipboard
Sound Output Calibration
Long time coming! Need to be able to calibrate sound output!
We have a bit of a (relatively undocumented) calibration system, where hardware objects have a calibration
property that saves/loads on get/set, so this can likely patch into that.
Process
- One pi vs. multiple? Usually the pi doesn't have sound input, and some sound cards (like the amp2) don't have it either, so you might need another soundcard than the one you're calibrating in order to actually record the sound output. It makes sense to me to decouple the recording part from the sound emitting part so one pi can record the audio and then send it back to the original pi which then estimates the inverse filter, but it also should be possible to do it on the same pi if you have a card with sound input.
- Initiated by the pilot vs. the terminal? Moving towards making each agent more self-sufficient, so it should be possible to trigger it from the terminal as well as from the pilot. In line with thinking of a more systematic relationship between agent capabilities than we have now, for example the water reward calibration routine is (badly) split between the pilot https://github.com/wehr-lab/autopilot/blob/e408c08e76df8d8c930edfb4ba58e31cd1ec4d87/autopilot/core/pilot.py#L364-L446 , the gui https://github.com/wehr-lab/autopilot/blob/e408c08e76df8d8c930edfb4ba58e31cd1ec4d87/autopilot/core/gui.py#L2153-L2217 and the terminal https://github.com/wehr-lab/autopilot/blob/e408c08e76df8d8c930edfb4ba58e31cd1ec4d87/autopilot/core/terminal.py#L832-L863
Calibration Types
- Inverse filter: this seems like the most straightforward to me? But instead of needing to do filter design it's easier for me to think about it in the time domain where we measure some impulse response and then convolve it over the generated sound samples.
- sounds to use?: I had written something using dynamic ripples before, using single tones is fine but it's slow and doesn't estimate nonlinear effects of the speaker/amplifier. Kip has also given me some fancy golay-code based filtering but i was never able to make it work.
Implementation Questions
- Where should calibration happen? should it happen in the Sound classes during sample generation, or should it happen at the output device? The latter makes more sense to me, but might be a little harder to implement because the sound is played in chunks, and so we would need to filter every chunk on the fly. We already have the notion of a base sound class that carries logic inherent to one particular sound backend, so it seems like it should be possible to implement it within the sound classes rather than the audio server, but in doing so we also need to make the parameterization of the audio system more explicit: currently the prefs just have the
JACKDSTRING
which carries an implicit reference to the output card, but maybe this is the time to build another think with the wiki so you can specify which speaker/amplifier combination you're using and potentially upload the calibration results to the wiki to start making a library of them? - Implementing audio input with jack! Very possible! basically an inverse operation to passing arrays into the buffer of the jack client, but need to clean up the entire process of declaring and starting the server and this might be a good time to do that.
•we should definitely have the option of a frequency look-up table for pure tones, in addition to any Inverse filter. An inverse filter is more general but requires tradeoffs and will never be ideal. In contrast a look-up table can be ideal if all you're doing is delivering pure tones (especially if you calibrate at the exact frequencies you intend to use). •I've always applied calibration at sample generation time, which has worked well and seems the most bulletproof to me.
would a calibration routine that can use a sound/array of sounds make sense then? eg. would implement dynamic ripples as a sound class and specify that as the test sound. and then a sound can have a default type of calibration as a class attribute, but the calibration method can take a calibration method as an arg?