cuepoint 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
cuepoint-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Ena Otuokon
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,167 @@
1
+ Metadata-Version: 2.4
2
+ Name: cuepoint
3
+ Version: 0.1.0
4
+ Summary: What to play next, and exactly where to bring it in. Reads a rekordbox collection, read-only.
5
+ Author-email: Ena Otuokon <otuokonhelena@gmail.com>
6
+ License: MIT
7
+ Keywords: dj,rekordbox,mixing,harmonic-mixing,music
8
+ Classifier: Environment :: Console
9
+ Classifier: Intended Audience :: End Users/Desktop
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Topic :: Multimedia :: Sound/Audio :: Analysis
12
+ Requires-Python: >=3.9
13
+ Description-Content-Type: text/markdown
14
+ License-File: LICENSE
15
+ Requires-Dist: numpy>=1.21
16
+ Requires-Dist: scipy>=1.7
17
+ Dynamic: license-file
18
+
19
+ # Cuepoint
20
+
21
+ Cuepoint answers one question: **this record is playing — what comes next, and
22
+ where exactly do I bring it in?**
23
+
24
+ Every other tool stops at tempo and key. Two records can share both and still
25
+ wreck: the kicks land on different sixteenths, or both singers arrive at once.
26
+ Cuepoint listens to the parts that actually decide it.
27
+
28
+ It reads a local rekordbox collection strictly read-only. It never writes into
29
+ rekordbox's own files.
30
+
31
+ ## Why it can do this
32
+
33
+ rekordbox has already analysed the collection — beat grid, downbeats, and the
34
+ phrase structure (intro / build / peak / breakdown / outro). That analysis sits
35
+ in the clear in `networkAnalyze6.db` and the `.DAT`/`.EXT` files beside it, so
36
+ none of it has to be recomputed. Cuepoint parses it, then decodes each track
37
+ once to measure what the analysis does not carry:
38
+
39
+ | feature | what it settles |
40
+ |---|---|
41
+ | `groove_low` | where the kick sits in the bar — the clash you can't hear coming |
42
+ | `groove_full` | whether the overall feel matches, swung against straight |
43
+ | `chroma` | harmonic agreement, from the actual spectrum rather than a key label |
44
+ | `vocal` | is somebody singing here |
45
+ | `energy_db` | does the incoming record hold the level |
46
+ | `kick_hz` | do the two kick fundamentals beat against each other |
47
+
48
+ Grooves are measured against rekordbox's own grid and expressed as 24 slots of
49
+ one bar, so two records at different tempos compare directly.
50
+
51
+ ## How a blend is scored
52
+
53
+ A recommendation is never just a track — it is a phrase of the outgoing record,
54
+ a phrase of the incoming one, and the number of bars they run together. Seven
55
+ components, each 0..1:
56
+
57
+ tempo 0.15 can the pitch fader reach it (also half and double time)
58
+ groove 0.22 do the two bars agree about where the weight falls
59
+ vocal 0.18 two vocals at once, the most audible mistake there is
60
+ harmonic 0.15 do the pitch classes agree
61
+ energy 0.12 does the level hold or lift
62
+ role 0.13 is this a sensible place to leave, and to arrive
63
+ sub 0.05 do the kick fundamentals fight in the bottom octave
64
+
65
+ Thresholds are measured, not guessed. Two phrases picked at random correlate at
66
+ 0.14 in the low band while two phrases of the *same* record correlate at 0.81,
67
+ and the ramps are set across gaps like that one. Where a refinement failed to
68
+ earn its place it was removed and the reason left in the source — see
69
+ `harmonic_fit` in [`mix.py`](cuepoint/mix.py).
70
+
71
+ ## Install
72
+
73
+ Requires **Python 3.9+**, **ffmpeg** on `PATH`, and a **rekordbox** collection
74
+ that has been analysed. numpy and scipy come in with the package.
75
+
76
+ pip install cuepoint # or: pipx install cuepoint
77
+ cuepoint doctor # checks ffmpeg, rekordbox, and where data lives
78
+ cuepoint setup # scan, measure, then open the UI
79
+
80
+ `setup` is the whole first run. It reads the rekordbox collection, decodes each
81
+ track once to measure what the analysis does not carry, and opens the web UI on
82
+ localhost:8765. Expect a few minutes for a few hundred tracks; the measurement
83
+ is cached per track, so later runs only touch what changed.
84
+
85
+ Everything Cuepoint derives lives in one folder, away from wherever you happen
86
+ to be standing:
87
+
88
+ macOS ~/Library/Application Support/Cuepoint
89
+ Windows %LOCALAPPDATA%\Cuepoint
90
+ Linux ~/.local/share/cuepoint
91
+
92
+ Set `CUEPOINT_HOME` to move it, or `CUEPOINT_REKORDBOX` if your collection is
93
+ not where rekordbox usually puts it. A directory that already contains a
94
+ `cuepoint.db` keeps using it, so nothing is stranded by upgrading.
95
+
96
+ ## Use
97
+
98
+ After the first run, the individual steps are there when you need them:
99
+
100
+ cuepoint build # re-read rekordbox (after moving or adding music)
101
+ cuepoint extract # measure new tracks
102
+ cuepoint serve # the web UI
103
+
104
+ Run those three in that order whenever you move files or add music -- each one
105
+ feeds the next.
106
+
107
+ From the command line:
108
+
109
+ cuepoint tracks eleven # search
110
+ cuepoint show "Ten to Eleven" # structure, key, per-phrase detail
111
+ cuepoint next "Ten to Eleven" # what to play next
112
+ cuepoint set "Ten to Eleven" -n 10 # chain a whole set
113
+
114
+ `next` prints the mix points and the full score breakdown:
115
+
116
+ 1. #########. 0.92 Find Your Corner
117
+ 126.0 BPM C (8B)
118
+ out at 2:17 (peak) -> in at 0:30 (build) 4 bars pitch +0.0%
119
+ tempo 1.00 groove 1.00 vocal 0.98 harmonic 1.00 energy 0.99 ...
120
+
121
+ The web UI draws the same thing: both records on one time axis, aligned at the
122
+ bar where one becomes the other, plus a compatible-track filter -- pitch range
123
+ and Camelot key, the way a DJ browser works.
124
+
125
+ ## Live mode
126
+
127
+ Not currently wired in. `fingerprint.py` and `listen.py` still build a
128
+ recognition index and follow the room, and `cuepoint index` / `cuepoint listen`
129
+ still run -- but the live capture path degrades chroma badly enough that the
130
+ matcher will not commit, so it is out of the UI until that is fixed. A track
131
+ matched from its file scores 0.998; the same audio captured live scores 0.94
132
+ with almost no margin over the runner-up.
133
+
134
+ ## Layout
135
+
136
+ anlz.py parser for rekordbox's .DAT/.EXT analysis files
137
+ library.py builds cuepoint.db from the collection (read-only)
138
+ audio.py ffmpeg decode, spectrogram, onset envelope, grid alignment
139
+ features.py per-phrase groove / chroma / vocal / energy
140
+ extract.py runs features.py across the library, in parallel, cached
141
+ mix.py the scorer: what follows what, and where
142
+ fingerprint.py chroma index + closed-set recognition and playhead search
143
+ listen.py audio capture, hypothesis tracking, live state
144
+ server.py local web UI
145
+ paths.py where the database, features and index live, per platform
146
+ static/ the UI itself, and the two typefaces it sets (SIL OFL 1.1),
147
+ self-hosted so a booth with no wifi still looks right
148
+
149
+ Deliberately no librosa — everything used here is a few dozen lines of numpy.
150
+
151
+ ## Caveats
152
+
153
+ `vocal` is a heuristic (harmonic/percussive separation plus a band-limited
154
+ energy ratio), not a trained detector. It separates "instrumental" from
155
+ "someone is singing", which is what the scorer needs; it will not catch a
156
+ heavily processed vocal chop.
157
+
158
+ Phrase roles come from rekordbox and inherit its mistakes — occasional two-bar
159
+ fragments are segmentation noise, and are skipped as mix points.
160
+
161
+ Live recognition assumes keylock is on, which is the modern default. With
162
+ keylock off, a large pitch move shifts energy across chroma bins and match
163
+ confidence will fall.
164
+
165
+ Streaming catalogues (Beatport, Beatsource, TIDAL) are not integrated. The
166
+ Beatport v4 API is OAuth behind an approved-partner portal and in-app streaming
167
+ needs a commercial LINK agreement, so it is not reachable without a deal.
@@ -0,0 +1,149 @@
1
+ # Cuepoint
2
+
3
+ Cuepoint answers one question: **this record is playing — what comes next, and
4
+ where exactly do I bring it in?**
5
+
6
+ Every other tool stops at tempo and key. Two records can share both and still
7
+ wreck: the kicks land on different sixteenths, or both singers arrive at once.
8
+ Cuepoint listens to the parts that actually decide it.
9
+
10
+ It reads a local rekordbox collection strictly read-only. It never writes into
11
+ rekordbox's own files.
12
+
13
+ ## Why it can do this
14
+
15
+ rekordbox has already analysed the collection — beat grid, downbeats, and the
16
+ phrase structure (intro / build / peak / breakdown / outro). That analysis sits
17
+ in the clear in `networkAnalyze6.db` and the `.DAT`/`.EXT` files beside it, so
18
+ none of it has to be recomputed. Cuepoint parses it, then decodes each track
19
+ once to measure what the analysis does not carry:
20
+
21
+ | feature | what it settles |
22
+ |---|---|
23
+ | `groove_low` | where the kick sits in the bar — the clash you can't hear coming |
24
+ | `groove_full` | whether the overall feel matches, swung against straight |
25
+ | `chroma` | harmonic agreement, from the actual spectrum rather than a key label |
26
+ | `vocal` | is somebody singing here |
27
+ | `energy_db` | does the incoming record hold the level |
28
+ | `kick_hz` | do the two kick fundamentals beat against each other |
29
+
30
+ Grooves are measured against rekordbox's own grid and expressed as 24 slots of
31
+ one bar, so two records at different tempos compare directly.
32
+
33
+ ## How a blend is scored
34
+
35
+ A recommendation is never just a track — it is a phrase of the outgoing record,
36
+ a phrase of the incoming one, and the number of bars they run together. Seven
37
+ components, each 0..1:
38
+
39
+ tempo 0.15 can the pitch fader reach it (also half and double time)
40
+ groove 0.22 do the two bars agree about where the weight falls
41
+ vocal 0.18 two vocals at once, the most audible mistake there is
42
+ harmonic 0.15 do the pitch classes agree
43
+ energy 0.12 does the level hold or lift
44
+ role 0.13 is this a sensible place to leave, and to arrive
45
+ sub 0.05 do the kick fundamentals fight in the bottom octave
46
+
47
+ Thresholds are measured, not guessed. Two phrases picked at random correlate at
48
+ 0.14 in the low band while two phrases of the *same* record correlate at 0.81,
49
+ and the ramps are set across gaps like that one. Where a refinement failed to
50
+ earn its place it was removed and the reason left in the source — see
51
+ `harmonic_fit` in [`mix.py`](cuepoint/mix.py).
52
+
53
+ ## Install
54
+
55
+ Requires **Python 3.9+**, **ffmpeg** on `PATH`, and a **rekordbox** collection
56
+ that has been analysed. numpy and scipy come in with the package.
57
+
58
+ pip install cuepoint # or: pipx install cuepoint
59
+ cuepoint doctor # checks ffmpeg, rekordbox, and where data lives
60
+ cuepoint setup # scan, measure, then open the UI
61
+
62
+ `setup` is the whole first run. It reads the rekordbox collection, decodes each
63
+ track once to measure what the analysis does not carry, and opens the web UI on
64
+ localhost:8765. Expect a few minutes for a few hundred tracks; the measurement
65
+ is cached per track, so later runs only touch what changed.
66
+
67
+ Everything Cuepoint derives lives in one folder, away from wherever you happen
68
+ to be standing:
69
+
70
+ macOS ~/Library/Application Support/Cuepoint
71
+ Windows %LOCALAPPDATA%\Cuepoint
72
+ Linux ~/.local/share/cuepoint
73
+
74
+ Set `CUEPOINT_HOME` to move it, or `CUEPOINT_REKORDBOX` if your collection is
75
+ not where rekordbox usually puts it. A directory that already contains a
76
+ `cuepoint.db` keeps using it, so nothing is stranded by upgrading.
77
+
78
+ ## Use
79
+
80
+ After the first run, the individual steps are there when you need them:
81
+
82
+ cuepoint build # re-read rekordbox (after moving or adding music)
83
+ cuepoint extract # measure new tracks
84
+ cuepoint serve # the web UI
85
+
86
+ Run those three in that order whenever you move files or add music -- each one
87
+ feeds the next.
88
+
89
+ From the command line:
90
+
91
+ cuepoint tracks eleven # search
92
+ cuepoint show "Ten to Eleven" # structure, key, per-phrase detail
93
+ cuepoint next "Ten to Eleven" # what to play next
94
+ cuepoint set "Ten to Eleven" -n 10 # chain a whole set
95
+
96
+ `next` prints the mix points and the full score breakdown:
97
+
98
+ 1. #########. 0.92 Find Your Corner
99
+ 126.0 BPM C (8B)
100
+ out at 2:17 (peak) -> in at 0:30 (build) 4 bars pitch +0.0%
101
+ tempo 1.00 groove 1.00 vocal 0.98 harmonic 1.00 energy 0.99 ...
102
+
103
+ The web UI draws the same thing: both records on one time axis, aligned at the
104
+ bar where one becomes the other, plus a compatible-track filter -- pitch range
105
+ and Camelot key, the way a DJ browser works.
106
+
107
+ ## Live mode
108
+
109
+ Not currently wired in. `fingerprint.py` and `listen.py` still build a
110
+ recognition index and follow the room, and `cuepoint index` / `cuepoint listen`
111
+ still run -- but the live capture path degrades chroma badly enough that the
112
+ matcher will not commit, so it is out of the UI until that is fixed. A track
113
+ matched from its file scores 0.998; the same audio captured live scores 0.94
114
+ with almost no margin over the runner-up.
115
+
116
+ ## Layout
117
+
118
+ anlz.py parser for rekordbox's .DAT/.EXT analysis files
119
+ library.py builds cuepoint.db from the collection (read-only)
120
+ audio.py ffmpeg decode, spectrogram, onset envelope, grid alignment
121
+ features.py per-phrase groove / chroma / vocal / energy
122
+ extract.py runs features.py across the library, in parallel, cached
123
+ mix.py the scorer: what follows what, and where
124
+ fingerprint.py chroma index + closed-set recognition and playhead search
125
+ listen.py audio capture, hypothesis tracking, live state
126
+ server.py local web UI
127
+ paths.py where the database, features and index live, per platform
128
+ static/ the UI itself, and the two typefaces it sets (SIL OFL 1.1),
129
+ self-hosted so a booth with no wifi still looks right
130
+
131
+ Deliberately no librosa — everything used here is a few dozen lines of numpy.
132
+
133
+ ## Caveats
134
+
135
+ `vocal` is a heuristic (harmonic/percussive separation plus a band-limited
136
+ energy ratio), not a trained detector. It separates "instrumental" from
137
+ "someone is singing", which is what the scorer needs; it will not catch a
138
+ heavily processed vocal chop.
139
+
140
+ Phrase roles come from rekordbox and inherit its mistakes — occasional two-bar
141
+ fragments are segmentation noise, and are skipped as mix points.
142
+
143
+ Live recognition assumes keylock is on, which is the modern default. With
144
+ keylock off, a large pitch move shifts energy across chroma bins and match
145
+ confidence will fall.
146
+
147
+ Streaming catalogues (Beatport, Beatsource, TIDAL) are not integrated. The
148
+ Beatport v4 API is OAuth behind an approved-partner portal and in-app streaming
149
+ needs a commercial LINK agreement, so it is not reachable without a deal.
File without changes