Skip to content
Open
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
31 changes: 18 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@

<div align="center"><img style="display:inline-block" width='150' src="./assets/logo.png"/><p>
<span style="font-size: 14px">Version: 0.4.9</span><br>
<span style="font-size: 14px">Version: 0.5.0</span><br>
<span>"A Simple Beat Time Marks Generator"</span><br>
<span style="font-size: 12px;color= #95dafc">-- Created by <a>Kevin T. Lee</a> --</span>
</p>
<a href="./LICENSE"><img alt="MIT" src="https://img.shields.io/github/license/mashape/apistatus.svg?&url=LICENSE&longCache=true&style=for-the-badge"></a>
<a href="http://lidengju.com"><img alt="Code" src="https://img.shields.io/badge/Code%20with-Love-red.svg?longCache=true&style=for-the-badge"></a>
<a href="https://github.com/kevinleeex/dj-beat/"><img alt="Version" src="https://img.shields.io/badge/Version-0.4.9-blue.svg?longCache=true&style=for-the-badge"></a>
<a href="https://github.com/kevinleeex/dj-beat/"><img alt="Version" src="https://img.shields.io/badge/Version-0.5.0-blue.svg?longCache=true&style=for-the-badge"></a>
</div>

# DJ-beat
Expand All @@ -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**:

Expand All @@ -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
```

Expand All @@ -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
Expand All @@ -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

```
Expand Down
3 changes: 1 addition & 2 deletions djbeat/bases.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
Cython==0.29.6
numpy==1.14.3
numpy>=1.22
39 changes: 28 additions & 11 deletions djbeat/djbeat.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,14 @@
# author: Kevin T. Lee<[email protected]>
# 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
Expand All @@ -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):
Expand All @@ -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\'.')
Expand All @@ -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):
Expand Down Expand Up @@ -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,
Expand Down
15 changes: 8 additions & 7 deletions djbeat/requirements.txt
Original file line number Diff line number Diff line change
@@ -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
17 changes: 9 additions & 8 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down