Skip to content
GitHub

Multimedia Beat (lexigram-multimedia-beat)

Audio tempo/beat analysis for the Lexigram Framework — analyzes an audio MediaAsset and returns tempo (BPM) and beat timestamps for driving beat-synced cut timing.


lexigram-multimedia-beat analyzes an audio clip and returns a BeatAnalysisResult (tempo_bpm + beat_timestamps). Two backends are available: librosa (default, runs in-process, no reference server) and madmom (optional, deep-learning-based, reference-server pattern — better on syncopated or tempo-changing material).

Full documentation: docs.lexigram.dev

Terminal window
uv add lexigram-multimedia-beat
# Optional extras
uv add "lexigram-multimedia-beat[librosa]" # librosa in-process backend
uv add "lexigram-multimedia-beat[madmom-server]" # madmom reference server
from lexigram import Application
from lexigram.di.module import Module, module
from lexigram.multimedia.beat import BeatAnalysisModule
from lexigram.contracts.multimedia.protocols import BeatAnalysisProvider
from lexigram.contracts.multimedia.types import BeatAnalysisRequest, MediaAsset
@module(imports=[BeatAnalysisModule.configure()])
class AppModule(Module):
pass
async def main() -> None:
async with Application.boot(modules=[AppModule]) as app:
beat = await app.container.resolve(BeatAnalysisProvider)
asset = MediaAsset(mime_type="audio/mp3", provider="local", bytes_data=b"<mp3>")
result = await beat.analyze(BeatAnalysisRequest(asset=asset))
if result.is_ok():
analysis = result.unwrap() # BeatAnalysisResult — tempo_bpm + beat_timestamps
print(analysis.tempo_bpm)
if __name__ == "__main__":
import asyncio
asyncio.run(main())

Zero-config usage: Call BeatAnalysisModule.configure() with no arguments to use the in-process librosa backend.

application.yaml
multimedia_beat:
backend: "librosa"
librosa_sample_rate: 44100

Option 2 — Profiles + Environment Variables

Section titled “Option 2 — Profiles + Environment Variables”
Terminal window
export LEX_PROFILE=production
export LEX_MULTIMEDIA_BEAT__BACKEND=madmom
export LEX_MULTIMEDIA_BEAT__LIBROSA_SAMPLE_RATE=44100
from lexigram.multimedia.beat import BeatAnalysisModule
from lexigram.multimedia.beat.config import BeatAnalysisConfig
BeatAnalysisModule.configure(
config=BeatAnalysisConfig(backend="librosa", librosa_sample_rate=44100)
)
FieldDefaultEnv varDescription
backend"librosa"LEX_MULTIMEDIA_BEAT__BACKENDlibrosa (in-process), madmom (reference server)
librosa_sample_rate22050LEX_MULTIMEDIA_BEAT__LIBROSA_SAMPLE_RATESample rate for the librosa backend
madmom_base_url"http://localhost:5600"LEX_MULTIMEDIA_BEAT__MADMOM_BASE_URLMadmom server URL
timeout30.0LEX_MULTIMEDIA_BEAT__TIMEOUTRequest timeout in seconds
MethodDescription
BeatAnalysisModule.configure(config)Configure with explicit beat-analysis config
BeatAnalysisModule.stub()No-op module for unit testing (uses librosa)
  • Two backendslibrosa (in-process, default, no reference server) and madmom (deep-learning, reference-server pattern)
  • No blob persistence — returns a BeatAnalysisResult (tempo + beat timestamps), not a MediaAsset; no queued task handler
  • Beat-synced editing — drive cut timing in the calling application
  • Reference serverlexigram-beat-madmom-serve console script runs the madmom model server
  • Result-basedanalyze() -> Result[BeatAnalysisResult, MultimediaError]; errors are domain values, not exceptions
from lexigram import Application
from lexigram.multimedia.beat import BeatAnalysisModule
async def test_boot():
async with Application.boot(modules=[BeatAnalysisModule.stub()]) as app:
assert app.container is not None
FileWhat it contains
src/lexigram/multimedia/beat/module.pyBeatAnalysisModule.configure() and .stub()
src/lexigram/multimedia/beat/config.pyBeatAnalysisConfig
src/lexigram/multimedia/beat/di/provider.pyBeatAnalysisGenerationProvider — registers BeatAnalysisProvider
src/lexigram/multimedia/beat/providers/Backend implementations (librosa, madmom)
src/lexigram/multimedia/beat/servers/Reference-server entry point (lexigram-beat-madmom-serve)
src/lexigram/multimedia/beat/exceptions.pyBeatAnalysisError hierarchy