Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,26 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [1.7.1] — 2026-08-05

### Fixed
- The committed API pages published a band this package no longer uses. They showed
`group_qom(points, fs, lo=0.3, hi=15.0)` and deep-linked into `musicalgestures/_qom.py` at line
numbers that stopped existing when those functions moved to `micromotion` on 2026-07-29. The
pages are regenerated from the current source.
- `docs/user-guide/pose-tracking.md` and `docs/user-guide/sound-movement-toolkit.md` said the band
is 0.3–5 Hz and passed `lo=0.3, hi=15.0`. It is `micromotion.BAND`, 0.2–5 Hz. The regeneration
script does not touch hand-written pages, so these were corrected by hand.
- The `micromotion` floor was `>=0.3`. No such release exists on PyPI below 0.6, and the functions
re-exported here arrived far later, so the constraint permitted installations in which
`from musicalgestures import group_qom` fails. It is now `>=0.15.2`, which is also the floor that
makes the committed API pages true, since they are generated from that package's docstrings.

### Changed
- The three re-export shims now point at <https://fourms.github.io/micromotion/> for the API
reference. Their generated pages describe the shim rather than the functions, which is correct
but left a reader with nowhere to go.

## [1.7.0] — 2026-08-03

### Added
Expand Down
4 changes: 4 additions & 0 deletions docs/MODULES.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,17 @@ Full list of [Mgt-python](README.md#mgt-python) project modules.
- [Posture](musicalgestures/_posture.md#posture)
- [Pulse](musicalgestures/_pulse.md#pulse)
- [Qom](musicalgestures/_qom.md#qom)
- [Remap360](musicalgestures/_remap360.md#remap360)
- [Show](musicalgestures/_show.md#show)
- [Show Window](musicalgestures/_show_window.md#show-window)
- [Sonification](musicalgestures/_sonification.md#sonification)
- [Soundscape](musicalgestures/_soundscape.md#soundscape)
- [Spacetime](musicalgestures/_spacetime.md#spacetime)
- [Ssm](musicalgestures/_ssm.md#ssm)
- [Stream](musicalgestures/_stream.md#stream)
- [Subtract](musicalgestures/_subtract.md#subtract)
- [Sync](musicalgestures/_sync.md#sync)
- [Timecode](musicalgestures/_timecode.md#timecode)
- [Utils](musicalgestures/_utils.md#utils)
- [Video](musicalgestures/_video.md#video)
- [Videoadjust](musicalgestures/_videoadjust.md#videoadjust)
Expand Down
126 changes: 123 additions & 3 deletions docs/musicalgestures/_360video.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,15 @@
- [Mgt-python](../README.md#mgt-python) / [Modules](../MODULES.md#mgt-python-modules) / [Musicalgestures](index.md#musicalgestures) / 360video
- [Mg360Video](#mg360video)
- [Mg360Video().convert_projection](#mg360videoconvert_projection)
- [Mg360Video.from_dual_fisheye](#mg360videofrom_dual_fisheye)
- [Projection](#projection)
- [calibrate_dual_fisheye_fov](#calibrate_dual_fisheye_fov)
- [make_seam_mask](#make_seam_mask)
- [stitch_dual_fisheye](#stitch_dual_fisheye)

## Mg360Video

[[find in source code]](https://github.com/fourMs/MGT-python/blob/master/musicalgestures/_360video.py#L94)
[[find in source code]](https://github.com/fourMs/MGT-python/blob/master/musicalgestures/_360video.py#L255)

```python
class Mg360Video(MgVideo):
Expand All @@ -30,7 +34,7 @@ Class for 360 videos.

### Mg360Video().convert_projection

[[find in source code]](https://github.com/fourMs/MGT-python/blob/master/musicalgestures/_360video.py#L126)
[[find in source code]](https://github.com/fourMs/MGT-python/blob/master/musicalgestures/_360video.py#L299)

```python
def convert_projection(
Expand All @@ -53,12 +57,128 @@ options (Dict[str, str], optional): Options for the conversion. Defaults to None

- [Projection](#projection)

### Mg360Video.from_dual_fisheye

[[find in source code]](https://github.com/fourMs/MGT-python/blob/master/musicalgestures/_360video.py#L287)

```python
@classmethod
def from_dual_fisheye(
front_file,
back_file,
camera: str = None,
**stitch_kwargs,
):
```

Stitch a dual-fisheye pair (e.g. the `_00_`/`_10_` .insv files of an
Insta360 camera) into an equirectangular video and open it as an
Mg360Video. See [stitch_dual_fisheye](#stitch_dual_fisheye) for the stitching options
(`fov=None` auto-calibrates the lens FOV on a probe frame).

## Projection

[[find in source code]](https://github.com/fourMs/MGT-python/blob/master/musicalgestures/_360video.py#L11)
[[find in source code]](https://github.com/fourMs/MGT-python/blob/master/musicalgestures/_360video.py#L13)

```python
class Projection(Enum):
```

same as https://ffmpeg.org/ffmpeg-filters.html#v360.

## calibrate_dual_fisheye_fov

[[find in source code]](https://github.com/fourMs/MGT-python/blob/master/musicalgestures/_360video.py#L131)

```python
def calibrate_dual_fisheye_fov(
front_file,
back_file,
time_s: float = 1.0,
candidates=None,
print_result: bool = False,
):
```

Estimate the effective lens field of view of a dual-fisheye pair
(e.g. the two .insv files of an Insta360 camera) by projecting one frame
of each lens to equirectangular at candidate FOVs and measuring the
photometric mismatch in the seam bands at longitude ±90°.

#### Arguments

- `front_file` *str* - Video of the front lens.
- `back_file` *str* - Video of the back lens.
- `time_s` *float* - Timestamp of the probe frame.
- `candidates` *list* - FOVs (degrees) to try. Default 185–205.

#### Returns

- `float` - The FOV with the smallest seam mismatch.

## make_seam_mask

[[find in source code]](https://github.com/fourMs/MGT-python/blob/master/musicalgestures/_360video.py#L106)

```python
def make_seam_mask(width: int, height: int, feather_deg: float = 8.0):
```

Column mask for feather-blending two hemispheres on an equirectangular
canvas: 0 where the front lens (yaw 0) should be used, 255 for the back
lens (yaw 180), with a linear ramp of ±feather_deg around the seams at
longitude ±90°.

#### Arguments

- `width` *int* - Mask width in pixels (full 360° canvas).
- `height` *int* - Mask height in pixels.
- `feather_deg` *float* - Half-width of the blend ramp in degrees.

#### Returns

- `np.ndarray` - uint8 mask of shape (height, width).

## stitch_dual_fisheye

[[find in source code]](https://github.com/fourMs/MGT-python/blob/master/musicalgestures/_360video.py#L188)

```python
def stitch_dual_fisheye(
front_file,
back_file,
target_name: str = None,
fov: float = None,
feather_deg: float = 8.0,
width: int = None,
height: int = None,
crf: int = 21,
preset: str = 'fast',
print_cmd: bool = False,
):
```

Stitch a dual-fisheye pair (two single-lens files, e.g. Insta360
`_00_`/`_10_` .insv) into one equirectangular video with a feathered
seam blend. Each lens is projected to equirectangular separately
(back lens at yaw 180) and the two are merged with a soft column mask,
which avoids the hard seams of a plain `v360=dfisheye` conversion.
Audio is taken from the front-lens file when present.
Also fits Garmin VIRB 360 RAW-mode recordings, which store the two
~200-degree hemispheres as separate files.

#### Arguments

- `front_file` *str* - Video of the front lens.
- `back_file` *str* - Video of the back lens.
- `target_name` *str* - Output path. Defaults to `<front>_equirect.mp4`.
- `fov` *float* - Lens FOV in degrees. None runs
[calibrate_dual_fisheye_fov](#calibrate_dual_fisheye_fov) on a probe frame first.
- `feather_deg` *float* - Half-width of the seam blend in degrees.
width, height (int): Output size. Defaults to lens height × 2 by
lens height (2:1 equirectangular).
crf (int), preset (str): x264 rate control.

#### Returns

- `str` - Path of the stitched video.
6 changes: 3 additions & 3 deletions docs/musicalgestures/_alignment.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ five camera angles' motion envelopes.
def envelope_lag(x, y, rate, max_lag_s=1.5):
```

Lag (s) of `y` relative to `x` maximising their correlation. Positive
Lag (s) of `y` relative to `x` maximizing their correlation. Positive
lag = `y` happens after `x`. Thin wrapper around [xcorr_lag](#xcorr_lag), kept as
the ro study's interface for envelope-to-envelope lags (e.g. voice
envelope vs motion envelope).
Expand Down Expand Up @@ -254,11 +254,11 @@ def xcorr_lag(x, y, fs, max_lag=1.5):
```

Canonical lead/lag estimate between two signals by vectorized
cross-correlation: the lag of `y` relative to `x` that maximises their
cross-correlation: the lag of `y` relative to `x` that maximizes their
correlation, searched within +/- `max_lag` seconds. Positive lag means
`y` happens after `x`.

Both signals are mean-removed and the correlation is normalised to a
Both signals are mean-removed and the correlation is normalized to a
Pearson-like coefficient over the full window. Among near-tied maxima
(common for periodic envelopes, where peaks recur at +/- one period),
the smallest-magnitude lag is returned rather than an arbitrary aliased
Expand Down
16 changes: 8 additions & 8 deletions docs/musicalgestures/_audio.md
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ Renders a figure of plots showing spectral/loudness descriptors, including RMS e
- `n_mels` *int, optional* - The number of mel filters to use for filtering the frequency domain. Affects the vertical resolution (sharpness) of the spectrogram. NB: Too high values with relatively small window sizes can result in artifacts (typically black lines) in the resulting image. Defaults to 128.
- `fmin` *float, optional* - Lowest frequency (in Hz). Defaults to 0.0.
- `fmax` *float, optional* - Highest frequency (in Hz). Defaults to None, use fmax = sr / 2.0
- `power` *float, optional* - The steepness of the curve for the colour mapping. Defaults to 2.
- `power` *float, optional* - The steepness of the curve for the color mapping. Defaults to 2.
- `dpi` *int, optional* - Image quality of the rendered figure in DPI. Defaults to 300.
- `autoshow` *bool, optional* - Whether to show the resulting figure automatically. Defaults to True.
- `original_time` *bool, optional* - Whether to plot original time or not. This parameter can be useful if the file has been shortened beforehand (e.g. skip). Defaults to False.
Expand Down Expand Up @@ -337,7 +337,7 @@ Renders a figure showing the mel-scaled spectrogram of the video/audio file.
- `n_mels` *int, optional* - The number of filters to use for filtering the frequency domain. Affects the vertical resolution (sharpness) of the spectrogram. NB: Too high values with relatively small window sizes can result in artifacts (typically black lines) in the resulting image. Defaults to 128.
- `fmin` *float, optional* - Lowest frequency (in Hz). Defaults to 0.0.
- `fmax` *float, optional* - Highest frequency (in Hz). Defaults to None, use fmax = sr / 2.0.
- `power` *float, optional* - The steepness of the curve for the colour mapping. Defaults to 2.
- `power` *float, optional* - The steepness of the curve for the color mapping. Defaults to 2.
- `top_db` *float, optional* - threshold the output at top_db below the peak: max(20 * log10(S/ref)) - top_db. Defaults to 80.0.
- `dpi` *int, optional* - Image quality of the rendered figure in DPI. Defaults to 300.
- `autoshow` *bool, optional* - Whether to show the resulting figure automatically. Defaults to True.
Expand Down Expand Up @@ -468,12 +468,12 @@ Renders a figure showing the waveform of the video/audio file.
- `dpi` *int, optional* - Image quality of the rendered figure in DPI. Defaults to 300.
- `autoshow` *bool, optional* - Whether to show the resulting figure automatically. Defaults to True.
- `raw` *bool, optional* - Whether to show labels and ticks on the plot. Defaults to False.
- `colored` *bool, optional* - Whether to create a coloured waveform image (freesound-style) from an audio input file. Defauts to False.
- `image_width` *int, optional* - Number of pixels for the coloured waveform image width. Defaults to 2500.
- `image_height` *int, optional* - Number of pixels for the coloured waveform image height. Defaults to 500.
- `fmin` *int, optional* - Minimum frequency for computing spectral centroid for the coloured waveform image. Defaults to 500.
- `fmax` *int, optional* - Maximum frequency for computing spectral centroid for the coloured waveform image. Defaults to None (i.e. Nyquist frequency).
- `cmap` *str, optional* - Colormap used for colouring the waveform, all colormaps included with matplotlib can be used. Defaults to 'freesound'.
- `colored` *bool, optional* - Whether to create a colored waveform image (freesound-style) from an audio input file. Defauts to False.
- `image_width` *int, optional* - Number of pixels for the colored waveform image width. Defaults to 2500.
- `image_height` *int, optional* - Number of pixels for the colored waveform image height. Defaults to 500.
- `fmin` *int, optional* - Minimum frequency for computing spectral centroid for the colored waveform image. Defaults to 500.
- `fmax` *int, optional* - Maximum frequency for computing spectral centroid for the colored waveform image. Defaults to None (i.e. Nyquist frequency).
- `cmap` *str, optional* - Colormap used for coloring the waveform, all colormaps included with matplotlib can be used. Defaults to 'freesound'.
- `original_time` *bool, optional* - Whether to plot original time or not. This parameter can be useful if the video file has been shortened beforehand (e.g. skip). Defaults to True.
- `title` *str, optional* - Optionally add title to the figure. Possible to set the filename as the title using the string 'filename'. Defaults to None.
- `target_name` *str, optional* - The name of the output image. Defaults to None (which assumes that the input filename with the suffix "_waveform.png" should be used).
Expand Down
10 changes: 5 additions & 5 deletions docs/musicalgestures/_audio_video.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
> Auto-generated documentation for [musicalgestures._audio_video](https://github.com/fourMs/MGT-python/blob/master/musicalgestures/_audio_video.py) module.

Audio–movement comparison reports for a single performer: tools to reveal how a dancer's
movement relates to the sound, through phase synchrony, structural similarity, per-body-part coupling,
movement relates to the sound phase synchrony, structural similarity, per-body-part coupling,
and energy/dynamics coupling.

- [Mgt-python](../README.md#mgt-python) / [Modules](../MODULES.md#mgt-python-modules) / [Musicalgestures](index.md#musicalgestures) / Audio Video
Expand Down Expand Up @@ -36,8 +36,8 @@ def mg_body_audio_coupling(
Map which body parts are most rhythmically coupled to the music.

For every pose marker the per-frame speed is correlated with the audio onset-strength
envelope (sampled at the video frame rate). The result is shown as a body mapthe average
pose with each marker coloured by its correlationplus a sorted bar chart, and a CSV of the
envelope (sampled at the video frame rate). The result is shown as a body mapthe average
pose with each marker coloured by its correlationplus a sorted bar chart, and a CSV of the
per-marker correlations. Uses cached pose keypoints when available, otherwise runs ``pose()``
first (``**pose_kwargs`` are forwarded).

Expand All @@ -60,7 +60,7 @@ def mg_dynamics_coupling(
) -> 'MgFigure':
```

Compare audio **loudness** with movement **quantity**. Does the dancer move more when the
Compare audio **loudness** with movement **quantity** — does the dancer move more when the
music is louder?

Aligns the audio RMS-loudness envelope with the quantity-of-motion envelope and reports their
Expand Down Expand Up @@ -118,7 +118,7 @@ Compare the temporal **structure** of the audio with that of the movement.

Builds a self-similarity matrix (SSM) of the audio (from MFCC frames) and of the video
(from low-resolution frame appearance), resampled to the same ``n`` time points, and shows
them side by side with their absolute **difference map**. Bright regions in the difference
them side by side with their absolute **difference map** — bright regions in the difference
are where the musical structure and the movement structure diverge.

Returns an MgFigure (mean structural agreement in ``.data``), or None if the video has no audio.
20 changes: 12 additions & 8 deletions docs/musicalgestures/_audiofeatures.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ Sources: cymbal-comparison study and Westney-comparisons study (Jensenius).

## attack_spectral_centroid

[[find in source code]](https://github.com/fourMs/MGT-python/blob/master/musicalgestures/_audiofeatures.py#L207)
[[find in source code]](https://github.com/fourMs/MGT-python/blob/master/musicalgestures/_audiofeatures.py#L209)

```python
def attack_spectral_centroid(
Expand All @@ -43,8 +43,10 @@ centroid over the first `attack` seconds after the RMS-envelope peak.
Discriminates, e.g., strike placement and damping on a cymbal.

The constants (120 ms attack, 2048-sample Hann window, 512 hop) are
PROVISIONAL defaults reimplemented from the cymbal-comparison paper's
method description.
validated against the original cymbal dataset (Zenodo 21360429, 2026
revalidation); revalidation found centroids ~15-25% lower than archived
results with ordering preserved (implementation detail differences,
ordering-safe); tune per dataset as needed.

Source: cymbal-comparison study (Jensenius).

Expand Down Expand Up @@ -78,8 +80,8 @@ relative to the per-file peak, with a minimum inter-onset interval.

Reliable for discrete strokes; over-fragments sustained rolls/tremolo
and can trigger on near-noise material. The default constants
(0.15 x peak, 0.06 s) are PROVISIONAL defaults reimplemented from the
cymbal-comparison paper's method description.
(0.15 x peak, 0.06 s) are validated against the original cymbal dataset
(Zenodo 21360429, 2026 revalidation); tune per dataset as needed.

Source: cymbal-comparison study (Jensenius).

Expand Down Expand Up @@ -130,7 +132,7 @@ def spectral_flux(y, sr, nperseg=2048, noverlap=1536):
```

Spectral-flux onset-detection function: the positive first difference of
the STFT magnitude, summed over frequency and normalised to a maximum of
the STFT magnitude, summed over frequency and normalized to a maximum of
1. Rises sharply at note/percussion onsets.

Source: Westney-comparisons study (Jensenius).
Expand Down Expand Up @@ -210,8 +212,10 @@ falling back to -5 to -25 dB (T20, x3) when the deeper level is not
reached.

The constants (20 ms window, -5/-35 with -5/-25 fallback, 6 dB re-rise
stop) are PROVISIONAL defaults reimplemented from the cymbal-comparison
paper's method description.
stop) are validated against the original cymbal dataset (Zenodo 21360429,
2026 revalidation); revalidation found 1-6% agreement overall (one damped
exemplar +77% difference, likely an implementation detail); tune per
dataset as needed.

Source: cymbal-comparison study (Jensenius) -- instrument decay of
damped vs undamped cymbal strokes.
Expand Down
4 changes: 2 additions & 2 deletions docs/musicalgestures/_blurfaces.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,11 @@ Credits: `centerface.onnx` (original) and `centerface.py` are based on https://g
- `ellipse` *bool, optional* - Mask faces with blurred ellipses. Defaults to True.
- `draw_heatmap` *bool, optional* - Draw heatmap of the detected faces using the centroid of the face mask. Defaults to False.
- `neighbours` *int, optional* - Number of neighbours for smoothing the heatmap image. Defaults to 32.
- `resolution` *int, optional* - Number of pixel resolution for the heatmap visualisation. Defaults to 250.
- `resolution` *int, optional* - Number of pixel resolution for the heatmap visualization. Defaults to 250.
- `draw_scores` *bool, optional* - Draw detection faceness scores onto outputs (a score between 0 and 1 that roughly corresponds to the detector's confidence that something is a face). Defaults to False.
- `save_data` *bool, optional* - Whether to save the scaled coordinates of the face mask (time (ms), x1, y1, x2, y2) for each frame to a file. Defaults to True.
- `data_format` *str, optional* - Specifies format of blur_faces-data. Accepted values are 'csv', 'tsv' and 'txt'. For multiple output formats, use list, e.g. ['csv', 'txt']. Defaults to 'csv'.
- `color` *tuple, optional* - Customized colour of the rectangle boxes. Defaults to black (0, 0, 0).
- `color` *tuple, optional* - Customized color of the rectangle boxes. Defaults to black (0, 0, 0).
- `use_gpu` *bool, optional* - Whether to attempt GPU (CUDA) acceleration for face detection. Falls back to CPU automatically if CUDA is unavailable. Defaults to False.
- `target_name` *str, optional* - Target output name. Defaults to None (which assumes that the input filename with the suffix "_blurred" should be used).
- `overwrite` *bool, optional* - Whether to allow overwriting existing files or to automatically increment target filenames to avoid overwriting. Defaults to True.
Expand Down
Loading
Loading