Patcher: arnoldasr's mods as extended_bpm, phasemeter, rgb_waveform
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
7dbb4ec6f8
commit
429c9ab8fc
3 files changed
+19
-20
No files matched your search
@@ -12,8 +12,8 @@ python cdj900nxs_patcher.py --list
|
|||||||
|
|
||||||
In the list: **arrow keys** move, **space** ticks or unticks, **a** ticks all
|
In the list: **arrow keys** move, **space** ticks or unticks, **a** ticks all
|
||||||
or none, **enter** builds, **q** quits. Ticking a mod ticks what it needs;
|
or none, **enter** builds, **q** quits. Ticking a mod ticks what it needs;
|
||||||
unticking one unticks what needs it (`utility` needs `code`, `hotcuekeys`
|
unticking one unticks what needs it (`hotcuekeys` needs `cuecolours`,
|
||||||
needs `cuecolours`). A mod with known faults starts unticked.
|
`beatjump` needs `hotcuekeys`). A mod with known faults starts unticked.
|
||||||
|
|
||||||
Before anything is built the patcher shows a disclaimer that must be
|
Before anything is built the patcher shows a disclaimer that must be
|
||||||
accepted by typing `yes` (or with `--accept`, where no one can type): the
|
accepted by typing `yes` (or with `--accept`, where no one can type): the
|
||||||
@@ -54,9 +54,9 @@ From the emulator checkout `../CDJ900NXSVirtual` (`--repo` for another place):
|
|||||||
|
|
||||||
| mod | what it does |
|
| mod | what it does |
|
||||||
|---|---|
|
|---|---|
|
||||||
| `code` | arnoldasr: BPM with two decimals, two-line phase meter, RGB waveform |
|
| `extended_bpm` | arnoldasr: BPM with two decimals (tenths as a small digit above) |
|
||||||
| `utility` | arnoldasr: UTILITY > PHASE METER switch (needs `code`) |
|
| `phasemeter` | arnoldasr: two-line phase meter, chosen in UTILITY > PHASE METER (was SLIP FLASHING) |
|
||||||
| `overview` | arnoldasr: overview waveform colour gradient |
|
| `rgb_waveform` | arnoldasr: big waveform in RGB colours, overview as a red-to-white gradient |
|
||||||
| `beatjump` | TRACK SEARCH jumps 1/2/4/8 beats, UTILITY > BEAT JUMP (needs `hotcuekeys`), see below |
|
| `beatjump` | TRACK SEARCH jumps 1/2/4/8 beats, UTILITY > BEAT JUMP (needs `hotcuekeys`), see below |
|
||||||
| `cuecolours` | memory cues in their rekordbox colours, hot cues shown |
|
| `cuecolours` | memory cues in their rekordbox colours, hot cues shown |
|
||||||
| `hotcuekeys` | hot cues A-C on the BEAT DIVIDE keys (needs `cuecolours`), see below |
|
| `hotcuekeys` | hot cues A-C on the BEAT DIVIDE keys (needs `cuecolours`), see below |
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ choose, as a new C900NXS.UPD for the player's own USB update.
|
|||||||
|
|
||||||
The mods come from the CDJ900NXSVirtual checkout next to this folder
|
The mods come from the CDJ900NXSVirtual checkout next to this folder
|
||||||
(--repo): mods/patch_cdj900nxs.py, which also needs arnoldasr's checkout in
|
(--repo): mods/patch_cdj900nxs.py, which also needs arnoldasr's checkout in
|
||||||
mods/cdj900nxs/upstream for his mods (code, utility, overview).
|
mods/cdj900nxs/upstream for his mods (extended_bpm, phasemeter, rgb_waveform).
|
||||||
"""
|
"""
|
||||||
import argparse
|
import argparse
|
||||||
import os
|
import os
|
||||||
@@ -38,9 +38,8 @@ sys.path.insert(0, HERE)
|
|||||||
import upd # noqa: E402
|
import upd # noqa: E402
|
||||||
|
|
||||||
DEFAULT_REPO = os.path.join(os.path.dirname(HERE), 'CDJ900NXSVirtual')
|
DEFAULT_REPO = os.path.join(os.path.dirname(HERE), 'CDJ900NXSVirtual')
|
||||||
UPSTREAM_MODS = ('code', 'utility', 'overview')
|
UPSTREAM_MODS = ('extended_bpm', 'phasemeter', 'rgb_waveform')
|
||||||
NEEDS = {'utility': 'code', # the PHASE METER switch chooses the code mod's meter
|
NEEDS = {'hotcuekeys': 'cuecolours', # the hot cues the keys play are read by cuecolours
|
||||||
'hotcuekeys': 'cuecolours', # the hot cues the keys play are read by cuecolours
|
|
||||||
'beatjump': 'hotcuekeys'} # hotcuekeys' engine makes the jumps
|
'beatjump': 'hotcuekeys'} # hotcuekeys' engine makes the jumps
|
||||||
LABEL = '1.32'
|
LABEL = '1.32'
|
||||||
# not ticked at the start of the list, and why
|
# not ticked at the start of the list, and why
|
||||||
@@ -148,7 +147,7 @@ def choose(mods):
|
|||||||
for i, (name, what, ok, why) in enumerate(mods):
|
for i, (name, what, ok, why) in enumerate(mods):
|
||||||
mark = '[x]' if name in chosen else ('[ ]' if ok else ' - ')
|
mark = '[x]' if name in chosen else ('[ ]' if ok else ' - ')
|
||||||
cursor = '>' if i == at else ' '
|
cursor = '>' if i == at else ' '
|
||||||
text = '%s %s %-11s %s' % (cursor, mark, name, what if ok else why)
|
text = '%s %s %-13s %s' % (cursor, mark, name, what if ok else why)
|
||||||
sys.stdout.write('\x1b[2K' + ('\x1b[7m%s\x1b[0m' % text if i == at else text)[:200] + '\n')
|
sys.stdout.write('\x1b[2K' + ('\x1b[7m%s\x1b[0m' % text if i == at else text)[:200] + '\n')
|
||||||
need = ', '.join('%s needs %s' % kv for kv in NEEDS.items())
|
need = ', '.join('%s needs %s' % kv for kv in NEEDS.items())
|
||||||
sys.stdout.write('\x1b[2K (%s)\n\x1b[2K\n' % need)
|
sys.stdout.write('\x1b[2K (%s)\n\x1b[2K\n' % need)
|
||||||
@@ -181,7 +180,7 @@ def choose_by_number(mods):
|
|||||||
print('\n Mods (all usable ones without known faults are ticked):')
|
print('\n Mods (all usable ones without known faults are ticked):')
|
||||||
for i, (name, what, ok, why) in enumerate(mods, 1):
|
for i, (name, what, ok, why) in enumerate(mods, 1):
|
||||||
mark = '[x]' if name in chosen else ('[ ]' if ok else ' - ')
|
mark = '[x]' if name in chosen else ('[ ]' if ok else ' - ')
|
||||||
print(' %d %s %-11s %s' % (i, mark, name, what if ok else why))
|
print(' %d %s %-13s %s' % (i, mark, name, what if ok else why))
|
||||||
answer = input(' Numbers to tick/untick (e.g. 1 3), enter to go on, q to quit: ').strip()
|
answer = input(' Numbers to tick/untick (e.g. 1 3), enter to go on, q to quit: ').strip()
|
||||||
if not answer:
|
if not answer:
|
||||||
break
|
break
|
||||||
@@ -264,7 +263,7 @@ def main(argv=None):
|
|||||||
mods = available(patcher, args.repo)
|
mods = available(patcher, args.repo)
|
||||||
if args.list:
|
if args.list:
|
||||||
for name, what, ok, why in mods:
|
for name, what, ok, why in mods:
|
||||||
print('%-11s %s%s' % (name, what, '' if ok else ' (%s)' % why))
|
print('%-13s %s%s' % (name, what, '' if ok else ' (%s)' % why))
|
||||||
return 0
|
return 0
|
||||||
if not args.stock:
|
if not args.stock:
|
||||||
ap.error('give the official C900NXS.UPD')
|
ap.error('give the official C900NXS.UPD')
|
||||||
|
|||||||
+8
-8
@@ -95,20 +95,20 @@ def test_boot_area_tampering_caught():
|
|||||||
upd.verify(bad, stock, stock.application)
|
upd.verify(bad, stock, stock.application)
|
||||||
|
|
||||||
|
|
||||||
MODS = [('code', '', True, ''), ('utility', '', True, ''), ('overview', '', True, ''),
|
MODS = [('extended_bpm', '', True, ''), ('phasemeter', '', True, ''), ('rgb_waveform', '', True, ''),
|
||||||
('beatjump', '', True, ''), ('cuecolours', '', True, ''), ('hotcuekeys', '', True, '')]
|
('beatjump', '', True, ''), ('cuecolours', '', True, ''), ('hotcuekeys', '', True, '')]
|
||||||
|
|
||||||
|
|
||||||
def test_every_mod_can_be_unticked():
|
def test_every_mod_can_be_unticked():
|
||||||
chosen = {m[0] for m in MODS}
|
chosen = {m[0] for m in MODS}
|
||||||
cli._toggle(chosen, 'code', MODS)
|
cli._toggle(chosen, 'extended_bpm', MODS)
|
||||||
assert 'code' not in chosen and 'utility' not in chosen # what needs it goes with it
|
assert 'extended_bpm' not in chosen and 'phasemeter' in chosen # each on its own
|
||||||
cli._toggle(chosen, 'cuecolours', MODS)
|
cli._toggle(chosen, 'cuecolours', MODS)
|
||||||
assert 'cuecolours' not in chosen and 'hotcuekeys' not in chosen
|
assert 'cuecolours' not in chosen and 'hotcuekeys' not in chosen
|
||||||
cli._toggle(chosen, 'hotcuekeys', MODS)
|
cli._toggle(chosen, 'hotcuekeys', MODS)
|
||||||
assert {'hotcuekeys', 'cuecolours'} <= chosen # and ticking brings what it needs
|
assert {'hotcuekeys', 'cuecolours'} <= chosen # and ticking brings what it needs
|
||||||
cli._toggle(chosen, 'overview', MODS)
|
cli._toggle(chosen, 'rgb_waveform', MODS)
|
||||||
assert 'overview' not in chosen
|
assert 'rgb_waveform' not in chosen
|
||||||
cli._toggle(chosen, 'cuecolours', MODS)
|
cli._toggle(chosen, 'cuecolours', MODS)
|
||||||
assert not {'cuecolours', 'hotcuekeys', 'beatjump'} & chosen # and what needs that
|
assert not {'cuecolours', 'hotcuekeys', 'beatjump'} & chosen # and what needs that
|
||||||
cli._toggle(chosen, 'beatjump', MODS)
|
cli._toggle(chosen, 'beatjump', MODS)
|
||||||
@@ -133,9 +133,9 @@ def test_disclaimer_without_a_terminal(monkeypatch):
|
|||||||
|
|
||||||
def test_credit_can_be_unticked():
|
def test_credit_can_be_unticked():
|
||||||
import types
|
import types
|
||||||
mods = cli.available(types.SimpleNamespace(MODS={"code": "c", "credit": "x"}), cli.DEFAULT_REPO)
|
mods = cli.available(types.SimpleNamespace(MODS={"extended_bpm": "c", "credit": "x"}), cli.DEFAULT_REPO)
|
||||||
assert [m[0] for m in mods] == ['code', 'credit']
|
assert [m[0] for m in mods] == ['extended_bpm', 'credit']
|
||||||
chosen = {m[0] for m in mods if m[0] not in cli.KNOWN_FAULTS}
|
chosen = {m[0] for m in mods if m[0] not in cli.KNOWN_FAULTS}
|
||||||
assert 'credit' in chosen # ticked at the start
|
assert 'credit' in chosen # ticked at the start
|
||||||
cli._toggle(chosen, 'credit', mods)
|
cli._toggle(chosen, 'credit', mods)
|
||||||
assert chosen == {'code'}
|
assert chosen == {'extended_bpm'}
|
||||||
Reference in new issue
Block a user