From 775eaf61211fb549a0bca76b927e2d1848f8be2d Mon Sep 17 00:00:00 2001 From: Jeremy Fievet Date: Mon, 15 Sep 2025 13:11:25 +0200 Subject: [PATCH] feat: Apple Silicon support via librosa fallback; optional madmom; add m4a support; bump to 0.5.0; refresh deps + README --- README.md | 31 ++++++++++++++++++------------- djbeat/bases.txt | 3 +-- djbeat/djbeat.py | 39 ++++++++++++++++++++++++++++----------- djbeat/requirements.txt | 15 ++++++++------- setup.py | 17 +++++++++-------- 5 files changed, 64 insertions(+), 41 deletions(-) diff --git a/README.md b/README.md index d9fdc16..926f026 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,12 @@

- Version: 0.4.9
+ Version: 0.5.0
"A Simple Beat Time Marks Generator"
-- Created by Kevin T. Lee --

MIT Code - Version + Version
# DJ-beat @@ -19,7 +19,7 @@ Dj-beat is an easy-to-use generator that automatically detects audio beats and g A good music-driven video requires a perfect combination of sound and picture. Think about you're using the video editing software like Final Cut Pro X, you need to manually mark the place on the soundtrack that denotes the beat. Now, you have the **DJ-beat**, which can help you handle such a boring thing, mark, mark, mark...While it may do better than us. -Dj-beat is a simple tool developed based on python3 and madmom library, supports operating via command line and graphical interface*. The principle of the tool is the music beat tracking (based on multi-LSTM models and Dynamic Bayesian Network), then the tool output the XML file, which the FCPX and PRE can read. +Dj-beat is a simple tool developed based on python3 and audio ML libraries, supports operating via command line and graphical interface*. As of 0.5.0 it is Apple Silicon (arm64) friendly: it uses librosa by default for beat tracking and will use madmom when available for parity with older versions. Learn more about **beat tracking**: @@ -32,18 +32,20 @@ Learn more about **beat tracking**: ![preview](./assets/preview.png) ## :beer: Installation -### Requirements -Cython==0.29.6 -numpy==1.14.3 -> You may need to install the above two libs before you install the dj-beat. - -madmom==0.16.1 -tqdm==4.31.1 -librosa==0.6.3 +### Requirements (0.5.0+) +- numpy>=1.22 +- scipy>=1.10 +- librosa>=0.10 +- audioread>=3.0.0 +- tqdm>=4.60 +- pyfiglet>=0.8 +- urllib3>=1.26 + +Optional for legacy accuracy parity: +- madmom (if installed, will be used automatically) ```bash cd ./djbeat -pip install -r bases.txt pip install -r requirements.txt ``` @@ -59,7 +61,7 @@ pip install dj-beat ```bash $ git clone https://github.com/kevinleeex/dj-beat.git $ cd dj-beat -$ pip setup.py install +$ pip install . ``` ## :star2: Usage @@ -70,6 +72,9 @@ $ pip setup.py install $ djbeat -f ./test/treasure-trimed.wav -r 30 ``` +Supported input formats: wav, mp3, m4a +Note: On some systems, m4a decoding requires a system codec (e.g., ffmpeg). On macOS, CoreAudio usually handles it out of the box. + #### Arguments ``` diff --git a/djbeat/bases.txt b/djbeat/bases.txt index ec63a2b..860993f 100644 --- a/djbeat/bases.txt +++ b/djbeat/bases.txt @@ -1,2 +1 @@ -Cython==0.29.6 -numpy==1.14.3 \ No newline at end of file +numpy>=1.22 diff --git a/djbeat/djbeat.py b/djbeat/djbeat.py index 92de190..1db884f 100644 --- a/djbeat/djbeat.py +++ b/djbeat/djbeat.py @@ -2,9 +2,14 @@ # author: Kevin T. Lee # description: DJ-beat is available to detect the beat from the audio and generate time marks for FCPX and premiere. -__version__ = '0.4.9' +__version__ = '0.5.0' + +# Try to use madmom if available (original algorithm). Fallback to librosa otherwise +try: + import madmom # type: ignore +except Exception: # pragma: no cover - optional dependency + madmom = None -import madmom import librosa import argparse import sys @@ -20,8 +25,8 @@ class DJbeat(object): - # supported format list - ext_list = ['mp3', 'wav'] + # supported format list (case-insensitive) + ext_list = ['mp3', 'wav', 'm4a'] def __init__(self, filepath, fps=100, frame_rate=30, show_time=False): if not os.path.exists(filepath): @@ -34,7 +39,7 @@ def __init__(self, filepath, fps=100, frame_rate=30, show_time=False): self.fileext = '' if '.' in self.filename: self.file_name = self.filename.split('.')[0] - self.fileext = self.filename.split('.')[-1] + self.fileext = self.filename.split('.')[-1].lower() if self.fileext not in DJbeat.ext_list: raise Exception( 'Not supported file format, please use \'.mp3\', or \'.wav\'.') @@ -51,15 +56,27 @@ def __init__(self, filepath, fps=100, frame_rate=30, show_time=False): def proc_data(self): print('[Start processing the audio...It may take a while]') # y: original audio, sr: sample rate - self.y, self.audio_sr = librosa.load(self.filepath) + # mono=True for consistent beat tracking; librosa will downmix internally + self.y, self.audio_sr = librosa.load(self.filepath, mono=True) self.file_time = (1.0 * len(self.y) / self.audio_sr) self.file_real_length = int(self.file_time * 1000) self.file_length = int(self.file_time) * 1000 - proc = madmom.features.beats.DBNBeatTrackingProcessor(look_ahead=0.4, fps=self.fps) - act = madmom.features.beats.RNNBeatProcessor()(self.filepath) - - beat_times = proc(act) + # Prefer original madmom pipeline when available + if madmom is not None: + try: + proc = madmom.features.beats.DBNBeatTrackingProcessor(look_ahead=0.4, fps=self.fps) + act = madmom.features.beats.RNNBeatProcessor()(self.filepath) + beat_times = proc(act) + return beat_times + except Exception: + # Fall through to librosa-based tracker on any failure + print('[madmom backend unavailable; falling back to librosa beat tracker]') + + # librosa fallback (Apple Silicon friendly) + # Estimate tempo and beat positions, return beat times in seconds + tempo, beat_frames = librosa.beat.beat_track(y=self.y, sr=self.audio_sr) + beat_times = librosa.frames_to_time(beat_frames, sr=self.audio_sr) return beat_times def gen_fcpxml(self): @@ -114,7 +131,7 @@ def main(): parser = argparse.ArgumentParser( description='DJ-beat, automatically mark the beat of your music for FCPX and PRE.') parser.add_argument('-f', '--filepath', default='', type=str, - help='The filepath of the input audio, support wav and mp3.') + help='The filepath of the input audio; supports wav, mp3, m4a (m4a may require a system decoder such as ffmpeg on some systems).') parser.add_argument('-r', '--frame_rate', default='30', choices=['23.98', '24', '25', '29.97', '30', '50', '60'], help='The frame rate of your video setting.') parser.add_argument('-s', '--fps', default=100, type=int, diff --git a/djbeat/requirements.txt b/djbeat/requirements.txt index 831fe7b..0bf50a1 100644 --- a/djbeat/requirements.txt +++ b/djbeat/requirements.txt @@ -1,7 +1,8 @@ -Cython==0.29.6 -numpy==1.14.3 -tqdm==4.31.1 -madmom==0.16.1 -librosa==0.6.3 -pyfiglet==0.8.post1 -urllib3>=1.24.2 +# Minimal runtime deps for Apple Silicon (madmom optional) +numpy>=1.22 +scipy>=1.10 +tqdm>=4.60 +librosa>=0.10 +audioread>=3.0.0 +pyfiglet>=0.8 +urllib3>=1.26 diff --git a/setup.py b/setup.py index 301f3bd..010c800 100644 --- a/setup.py +++ b/setup.py @@ -15,17 +15,18 @@ entry_points={ "console_scripts": ['djbeat = djbeat.djbeat:main'] }, - version='0.4.9', + version='0.5.0', description="A simple CLI tool for generating beat marks of music for FCPX and PRE", license="MIT", install_requires=[ - 'Cython', - 'numpy', - 'tqdm', - 'madmom', - 'librosa', - 'pyfiglet', - 'urllib3' + # Keep dependencies Apple Silicon friendly; madmom is now optional + 'numpy>=1.22', + 'scipy>=1.10', + 'tqdm>=4.60', + 'librosa>=0.10', + 'audioread>=3.0.0', + 'pyfiglet>=0.8', + 'urllib3>=1.26' ], # long_description=long_descr, include_package_data=True,