Working with the other fourMs packages
ambiscape handles sound. When a question involves bodies, video or music corpora, another package owns it, and the packages are meant to meet at file boundaries rather than by importing one another.
Who owns what
| Package | Owns | Weight |
|---|---|---|
ambiscape |
spatial audio in, soundscape features out | numpy, scipy, soundfile, matplotlib |
micromotion |
motion time series: mocap, IMU, force plate | numpy, scipy, pandas |
musicalgestures (MGT) |
video in, visual features out | ~282 MB — opencv, librosa, numba, scikit-image, ffmpeg |
musiscape |
music collections and long music recordings; its tagging module segments a concert from ambiscape.ml.tag_frames posteriors |
+ librosa, micromotion |
avsegmenter |
whole concert and lecture recordings: ml.tag_frames for the segment classes, extract_take/segmentation for level and novelty, then players and archival metadata |
+ MGT, musiscape, torch |
The dependency arrow points from the heavy packages to the light ones. ambiscape does not import
MGT, micromotion or musiscape; MGT's _soundscape.py consumes ambiscape's output and adapts it at
the seam. It stays that way because someone analysing a field recording should not have to install a
computer-vision stack, and someone analysing accelerometer data should not have to install an audio
one.
The file boundary
Where the packages hand audio to one another, two conventions carry what the audio itself cannot.
A leading YYYYMMDD_HHMMSS in the filename, in local wall-clock time.
open_session takes a recording's start from its BWF timestamp if there is
one, else from this stamp, else from the file's modification time --- and
that last fallback silently dates a segment to whenever it was written
rather than to when it was recorded. Anything writing audio for another tool
should write the stamp; io.export_segment does.
FLAC for exchanged audio that is not archival. Lossless, roughly half the size of WAV, and read natively on every side. WAV keeps its place for bit-exact excerpts, where the BWF chunk and the source's own PCM subtype are the point.
Crossing to micromotion
One function does not merely cross, it defers. Since 0.40.0
ambiscape.circstats.circ_corr is a re-export of
micromotion.circular.circ_corr, because micromotion owns circular statistics
in this family. It returns that package's dict, so callers want
circ_corr(a, b)["r"] and gain a p the old local copy never offered. The
import is lazy and the dependency is the circular extra
(pip install ambiscape[circular]), so ambiscape still installs on its own ---
only entrain.directional_correlation needs micromotion present. The two had
carried the same Jammalamadaka--SenGupta formula under one name and returned
different types, which is the failure a shared name is supposed to prevent.
The common case is a recording where a body and its surroundings were captured together, and the question is whether they relate. ambiscape produces the per-second sound side; micromotion produces the per-second motion side; the join happens in your own analysis on a shared clock.
Two things that have cost real time on exactly this join:
Clocks are not shared just because the recordings are simultaneous. Devices started separately drift, and phone apps in particular can suspend and lose time from the timeline entirely rather than leaving a gap. See micromotion's formats guide for what Physics Toolbox does to its own timestamps. Align on a physical event that appears in both signals, such as a tap that registers in the accelerometer and the microphone, rather than on file timestamps.
A cross-modal null needs a positive control. If motion does not track sound, the honest question is whether the pipeline could have detected it. Correlating two environmental channels, say ambiscape's loudness against a visual-change trace, gives that control cheaply: if they track each other and the body tracks neither, the null is about the body.
Crossing to MGT
MGT reads the video that ambiscape's session folder usually sits beside, whether that is 360
recordings, action cameras or room video. For GoPro .360 and similar, MGT's flatten_gopro360
handles the projection.
A GoPro MAX carries four audio channels which can be read as pseudo-ambisonics giving horizontal direction, so a session with no dedicated ambisonic recorder may still have a usable sound field. That is worth checking before writing a day off as audio-less.
When the overlap is real
Some functionality genuinely exists in more than one package. Prefer the package whose domain the question belongs to, and say in your analysis which implementation produced a number, since two implementations of "the same" measure rarely agree exactly, and a figure without its provenance cannot be reproduced or compared.
Outside the fourMs family
Two packages in the wider toolbox landscape meet this one at a DataFrame. Kinetics Toolkit keeps data, time and events in a TimeSeries with to_dataframe and from_dataframe; read a C3D there, convert, and hand the frame to this package's functions. mopipe composes motion-capture processing as typed nodes over pandas; a function from this package can be wrapped as one node, since every function here takes and returns arrays or frames and holds no state.