26 KiB
DJ workstation — feature/dj_workstation
The main window has two tabs: Karaoke Studio and DJ Studio. Playback, MIDI handling and selections persist when switching. Native tab pages hide or detach inactive drop destinations so karaoke cannot intercept DJ drops. The DJ library fills the remaining window height. The DJ Queue button opens the queue and Automix controls in a modal, with a live waiting-track count. The two bottom status messages and the DJ Settings, Audio Routing and MIDI header buttons have been removed. Settings… (Command-comma) stays available in either workspace and opens the matching Karaoke or DJ scope; choose Devices or MIDI there. Existing singer, venue, rotation, video, background music and recursive directory import features remain available. Background music is a compact strip above karaoke transport. Each tab opens its own settings scope.
Using the decks
- Use the DJ browser’s Import Files / Folder button for DJ music. It has its own
DJ/Library.sqlite,DJ/Mediaand playlists under the app support folder. It starts empty; existing karaoke songs are not migrated. The tested recursive importer is reused with audio-only import, without CDG graphics. MP3, WAV, M4A, MP4/M4V/MOV audio, AIFF/AIF, CAF, FLAC and AAC extensions are accepted; decoding depends on macOS format support. Imports support progress, cancellation and duplicate detection. - Select a DJ library row and use Load A/B, use the row’s A/B buttons or right-click Load into Deck A/B, or drag a DJ library song onto a deck. Loading is paused, with no brief autoplay. Finder audio files can also be dropped onto either deck’s header, platter area or centre waveform. Back-to-back drops are queued while a copy/import is running; re-dropping existing media still loads the selected deck. Dropping onto a playing deck asks for confirmation before importing or replacing anything; Cancel preserves playback and Replace & Load explicitly overrides protection. Library loads also respect the active-deck protection preference.
- Cyan identifies A; amber identifies B. Each platter’s angle follows actual source playback time, including tempo changes, pauses and seeks. Drag around a platter to jog two source seconds per revolution. This is seek-based jogging, not vinyl scratching.
- Waveforms come from decoded audio and reuse existing waveform caches. Drag outside an active loop to seek. Green IN/OUT grips resize the loop; dragging inside its region moves it without changing its length. Shift-drag creates a loop in either waveform. Native mouse tracking supports scrubbing in the overview and scrolling spectrum while paused or playing. In the large spectrum, hold the left mouse button and drag left to advance or right to rewind, relative to the initial position without a click jump; the waveform follows the hand. The overview remains an absolute position selector. The scrolling viewport freezes during a drag and resumes following playback afterwards. Waveform scrolling, playheads and platter rotation use the audio clock at up to 60 display frames per second, with interpolated waveform amplitudes.
- High/mid/low EQ and the bipolar filter are beside each platter. Gain and level knobs have been removed from the on-screen decks. Drag a knob vertically; double-click to reset. Knobs expose adjustable accessibility actions and current values. EQ uses the existing three-band filters; filter is low-pass left, bypass centre, high-pass right.
- Play/pause, stop-to-start, set/return cue and four set/jump hot cues are per deck. Right-click a hot cue to clear it. Use the cue-time editor to set an exact cue in seconds or capture the current playhead without moving playback. Loop ✎ opens exact start/end fields with millisecond display and Use Playhead buttons; Activate Loop validates and applies the region without pausing playback. Manual IN/OUT loops do not need BPM. Beat loops require an estimated, entered or tapped BPM; choose 1–32 beats. Loop toggles off on a second press and continues correctly at the end of a track. Changing the loop size resizes an active loop immediately, preserving its start and continuing playback; the end is clamped to track duration.
- Loading estimates BPM conservatively from up to the first 90 seconds of audio, searching 70–180 BPM; silence and steady tones remain unknown. Estimates show BPM~ and can be replaced by entering source BPM (40–240) or tapping at least three beats. Sync buttons start grey and unlit. Clicking A makes B follow A’s effective BPM; clicking B makes A follow B’s effective BPM. Both buttons then show active. Press either again to unlink and restore both original tempos. Sync follows changes to the clicked leader’s tempo; it does not align beat phase or detect a beat grid. Use the jog/nudge buttons to align beats. Tempo adjustment preserves pitch, using AVAudioUnitTimePitch.
- The crossfader and DJ output headroom affect only DJ playback. Equal-power and linear crossfader curves are selectable. The karaoke master and saved singer preferences are independent. The wing meters show individual deck peaks, not a summed master meter. There is no master limiter; use gain/levels appropriately.
- Karaoke and DJ music can play simultaneously. The existing background-to-singer interlock is preserved, but it does not automatically duck the new DJ decks.
Library and playlists
The DJ browser supports title/artist/album search and paginates in groups of 50. DJ playlists are stored independently from karaoke. Create, rename or delete them from the folder menu; right-click a song to add it to a playlist, remove it, or move it earlier/later. Karaoke library drag references are rejected by the DJ decks; import the source music using the DJ importer. DRM subscription streaming is not added.
DJ queue and Automix — first feature stage
The DJ queue is independent of karaoke and DJ playlists. Add a song with its + button, use Add to DJ Queue in its context menu, add the current filtered library/playlist with the queue button, or drag from the DJ library into the queue. Duplicate songs are allowed. Reorder with the arrow buttons, remove entries, shuffle or clear. Queue order, fade duration and BPM-match preference save in DJ/DJQueue.json; relaunch never starts playback automatically.
Start Automix uses an already playing deck, or loads the first queued song into A. It preloads the next song paused on the silent deck, regardless of the load-autoplay preference. Near the current track’s end, it starts the next deck and moves the real crossfader over the selected 0–30 seconds. Zero seconds is a cut; short tracks shorten the fade. Mix Now begins the transition immediately. BPM matching optionally adjusts the incoming tempo when both BPM values are available and the ratio fits the selected tempo range. This is timed crossfading, not djay’s AI phrase selection or beat-phase alignment; see djay’s Automix workflow for the reference feature set.
Automix requires Internal mixer mode and starts only when at most one deck is playing. It waits for active loops, skips missing/unreadable queue entries, stops at the end of the final track, and yields to manual loading, transport, tempo/jog or crossfader control. Stop Automix relinquishes automatic control while playback remains available to the operator. Both DJ decks are used by automation; karaoke remains independent.
Audio routing
DJ Settings → Devices lists routable CoreAudio outputs and every reported stereo pair, including ch 1–2 and ch 3–4 on the four-channel Numark. Explicit native channel menus apply selections immediately. Routing persists in DJ/DJAudioRouting.json; valid device/pair changes preserve playing/paused state and source position. Channel-only changes use a live HAL update where supported, while a physical-device switch can require a brief engine restart. Active headphone preview is re-routed rather than discarded. Conflicting intermediate edits leave the last valid route active and show an inline explanation. There is no Apply step.
Use the named controller preset button to configure its pairs. Switching to External sets up the two deck pairs and disables cue if those pairs are both public outputs. The detected-device list shows input/output counts and all stereo pairs; input-only devices are identified separately. Device connection notifications and a refresh loop while settings are open keep the list current.
- Internal: both decks use Main Output. Pre-Cueing can use another device or a non-overlapping pair on the same multichannel interface. On Mixtrack Go, choose Numark MixTrack Go Audio, main ch 1–2 and pre-cue ch 3–4.
- External: decks A and B have independent device/pair selectors. The software crossfader is bypassed; use an external mixer. Decks cannot share the same device/pair, and cue cannot overlap either public output.
- Headphone preview is independent playback starting from the selected deck’s position and current tempo/EQ/filter. Later changes are not followed; restart preview to refresh. One deck can be previewed at a time. Cue overlap is rejected before public audio is sent. Karaoke has its own routing; background music follows the existing output.
Actual AUHAL channel-map readback on the attached four-channel Numark interface verified [0,1,-1,-1] for main 1–2 and [-1,-1,0,1] for cue 3–4. This is an API-level check; audible socket isolation and physical monitoring still need listening verification. Implementation follows Apple’s channel-map property.
Not implemented: booth/microphone/recording input, phase-locked PFL, aggregate-device creation, automatic failover and calibrated round-trip latency.
Controllers
The confirmed model is Numark Mixtrack Go. Its preset was independently implemented from the protocol addresses in the supplied Mixxx mapping. Numark’s product page documents USB class compliance and Bluetooth MIDI.
The 210 supplied .djayMidiMapping files are included as XML property lists under KJamsClone/MIDIMappings. In DJ Settings → MIDI, search/select a profile, view its Compatibility Report, then Apply XML Profile. Import XML accepts additional .xml, .plist and .djayMidiMapping files. Inputs and applied profiles are saved per source ID.
Automatic detection is enabled by default. It matches exact endpoint names and aliases from the supplied files, chooses a unique supported source, and restores a saved input after relaunch/reconnection. Ambiguous matches require manual selection. Not connected disables automatic detection until re-enabled. Custom MIDI Learn remains available.
The generic adapter handles standard note/CC and 14-bit pitch-bend bindings for available two-deck transport, cue/hot cues 1–4, loops, EQ/filter/gain, channel volume, crossfader, master/cue level, load and browse actions. It respects inversion, signed/offset relative encoders and soft takeover for supported absolute controls. Common play/cue/sync/headphone/loop/hot-cue LED outputs support explicit addresses, min/max values and inversion. Conflicting, conditional, modifier, HID or unsupported assignments are disabled and reported. djay custom processors, arbitrary predicates, displays, four-deck operation, proprietary scripts and rotary acceleration curves are not reproduced.
Mixtrack Go uses a dedicated native adapter when its supplied XML profile is selected or detected. This enables its 14-bit split-CC tempo, relative jog, channel faders, filter/low switch, browsing/loading, transport/shared Sync, headphone controls, hot-cue/loop pad modes and corresponding LED feedback. Apply Mixtrack Go Preset remains available as a direct alternative. Initialization sends identity and controller-state requests and refreshes LEDs after two seconds, because the startup demo can clear early LED state. Deck B pad mode uses XML address 95/00. Supported transport, mode, load, shifted transport and pad LEDs are driven from app state. App shutdown cancels initialization, clears the LEDs and pad-mode state, and ignores later feedback; selecting a saved direct preset repeats its startup handshake on reconnect.
Limitations: stems, sampler, FX modes, touch scratching, HID, motor feedback and controller certification are not implemented. Unsupported pad modes report the limitation. Tests exercised actual CoreMIDI output to a receiving virtual destination, including delayed LED refresh. The attached Numark MIDI endpoints and audio device were discovered, and its channel maps were checked; physical knob/button behaviour, visible LED appearance, Bluetooth delivery and audible socket isolation still need hands-on verification.
Continuous console and separate preferences
The deck area is now one continuous console following the supplied reference: track headers and overview waveforms above; mirrored tempo/platter/EQ/filter wings; stacked, source-timed eight-second scrolling waveforms in the centre; and a shared bottom transport strip with a centred rectangular-cap crossfader. Native vertical tempo faders have visible scale marks, keyboard/accessibility support and a tested control-to-binding action. Play, Cue, loop size, headphones and hot cues remain available. No on-screen gain or channel-level knobs are shown. Track headers show embedded artwork or a nearby JPG/JPEG/PNG, prioritising a matching track name or cover/folder/front/artwork image. Platters have a clear rotating radial marker. Musical key analysis is not implemented.
Settings now use an icon-category toolbar with separate Karaoke and DJ selectors. DJ Settings opens directly in DJ scope; Audio Routing and MIDI open the corresponding DJ categories. Karaoke device routing applies only to the singer deck. DJ General, Sound, Library, Appearance and Advanced preferences are persisted independently in DJ/DJSettings.json. Working options include paused/automatic load, active-deck protection, reset EQ/filter on load, ±8/16/50% tempo range and inversion, equal-power/linear crossfade curves, output headroom, waveform colours/window/grid, rotating marker, inactive-deck dimming, library font/row height and optional hot-cue autoplay. MIDI learning is cancelled when leaving its settings category. Singer Web is available only in Karaoke settings, with its existing server controls preserved.
Waveform beat guides use BPM and source time zero, with stronger yellow marks and numbered guides every four beats; they are not analysed downbeats. Active loops have green regions and IN/OUT boundary markers. DVS, Neural Mix, booth/microphone input, recording, Spotify and cloud sync are not implemented.
Import integrity
Media imports stream into a staging file, verify SHA-256, and atomically rename the result. Source permissions, ACLs and protected security-scope metadata are not copied. Failed or cancelled transfers remove staging files. Empty existing destinations are repaired on retry, and empty playback files show a reimport instruction. Original media and library records are preserved.
Verification — 5 November 2026
The full macOS suite covers karaoke, recursive CDG/audio import, independent DJ imports/playlists, rotation, background handoff, media repair, real audio loops, live loop resizing, linked Sync, cue editing, waveform/BPM guides, Finder override, artwork, real knob double-clicks, native faders, XML profiles, automatic controller detection/reconnection, actual CoreMIDI output and delayed LED initialization/shutdown. Native workspace tab switching preserves simultaneous playback. Automix tests exercise timed transitions, both playing decks during a fade, manual takeover, loop waiting, unavailable files and queue persistence without launch autoplay.
Attached-interface checks verify available output devices and AUHAL stereo channel maps when the hardware is connected; that check skips when the interface is unavailable. Physical button response, visible LEDs and audible socket isolation still require hands-on verification. Builds compile for arm64 and x86_64; tests execute on Apple silicon. Temporary builds, logs, captures and scripts are kept in task directories under /private/tmp, including kjmix-xml-mappings and kjmix-loop-edit.
Latest validation: 147 tests executed, zero failures, one attached-interface check skipped because the user confirmed the Numark was unplugged. Earlier attached-interface runs verified the four-channel AUHAL maps; native menu selection and live binding changes are also tested independently of hardware.
Spectrum scrolling caches source-aligned image sections and translates them by fractional pixels as playback advances. On macOS 14+ a view display link schedules refreshes with the current display; macOS 13 uses a timer. Beat and loop markers stay aligned to the same audio-clock position. Cached images are rebuilt after waveform analysis, resize, zoom or colour changes.
DJ imports show a live progress panel with a coloured progress bar, imported/skipped/remaining totals, the current file and a selectable, copyable log. DJ imports, including Finder drops, offer Run in Background; View Progress reopens the panel, and View Log shows the completed report. Scanning, hashing, copying and metadata reads run on a utility background worker with a separate database connection; interface progress updates are throttled to about ten per second. Cancelling retains completed tracks. Duplicate detection reuses existing track IDs, including identical files renamed or selected from another folder; a repeated drop can still load that track into either deck. Different songs are never considered duplicates solely because their titles match.
Karaoke Studio imports run in the background without the DJ import modal; import failures use the existing error alert.
Both studios finish importing and publish their library tracks first, then submit saved waveform preparation to a separate utility-priority queue. Further imports can continue while this queue is busy. A non-modal background status shows generated/reused/issue counts and Cancel. Manual Generate/Regenerate retains the existing progress dialog. DJ decks reuse the DJ waveform cache; waveform failures never undo an imported track. Karaoke waveform batch jobs show a coloured progress bar and percentage ring, with generated/reused/skipped/issue counts and cancellation.
Each deck has a vertical channel-level fader beside its EQ/filter controls. The DJ library search uses the same compact rounded field as Karaoke Studio.
DJ library rows include the same gold favourite star as Karaoke Studio. Favourites are saved independently in the DJ library, with a Favourites filter and a right-click toggle.
Dragging a DJ waveform previews short audio grains through that deck’s EQ, level and output routing while paused; releasing stops the preview and retains the selected position. Scrubbing a playing deck continues playback. This is audio preview seeking, rather than reverse vinyl scratching.
The DJ library advances to the next page when a user scroll reaches the bottom. Page changes return the list to the top and select the first track. Right-click a DJ track and choose Waveforms to generate its cache, prepare loaded decks or the entire DJ library, or force regeneration. Batch analysis runs on a utility worker with saved-cache reuse, progress and cancellation.
DJ waveform generation opens a modal with a coloured progress bar, percentage ring, counts and Cancel. The results stay visible until Done; any analysis issues are listed in the modal.
DJ library selection supports Command-click for separate tracks, Shift-click for ranges, and Command-A or right-click Select All Songs for all matching tracks across pages. The queue toolbar action adds the selected tracks in library order. Right-click selected tracks to generate or regenerate their saved waveforms or add the selection to the DJ queue.
Library and audio responsiveness
DJ tracks appear in a native table with resizable Title, Artist, Album, Time and Rating columns. Favourite stars and five-star ratings are independent and saved in the DJ library. Right-click Song Info / Artist to edit metadata, or Reinterpret Selected Names to use the same preview/template tools as Karaoke Studio; Undo restores the last DJ name change.
Both studios use the same search field with a clear X. Filtered DJ rows are cached until search/library/playlist/favourites change; fader events do not rebuild the library table. Unchanged drag titles no longer redraw on every selection update. Platters use native display callbacks instead of SwiftUI frame-by-frame animation.
Waveform analysis processes contiguous bin segments rather than doing division for every sample. Batches admit at most two background workers, dropping to one while any player is playing; existing workers finish their current files, and decode blocks yield during playback. Original cache validity and cancellation rules remain. A local bundled-WAV benchmark measured about 3× faster analysis, with matching levels; this is not a guarantee for other media or drives.
Equaliser opens a shared ten-band graphic EQ for both DJ decks and headphone preview. Flat, Rock, Pop, Jazz, Vocal, Bass Boost and Treble Boost presets are editable, with bypass and automatic persistence. Gain changes apply without restarting playback.
Each deck also has a microphone toggle beside its level fader for basic centre-vocal reduction. It runs in the audio render path and can be switched during playback. Centred instruments are reduced too; mono is passed through, and stereo vocals may remain. This is centre cancellation, not AI source separation.
Ordinary loops are prepared on a worker and scheduled with the audio node's looping buffer, rather than restarting from a UI timer. Source display time wraps on that same audio clock. Loop buffers are capped at 64 MB; longer manual loops retain the streaming/timer fallback. At normal speed with no pitch shift the time-pitch unit is bypassed to reduce processing overhead. During scrubbing, the waveform follows accepted audio positions, rather than showing a newer mouse target before that audio is scheduled.
The waveform/BPM admission limit is shared across imports, on-load analysis and batch jobs, so separate analysis paths cannot each start their own pair of workers. Playing audio reduces that global limit to one; reads yield between blocks. Neutral time-pitch processing is bypassed.
Loop Off returns to normal file playback through the audio-clock handoff described below. The TV/video view presents original decoded frames directly in a display-resolution-backed layer with aspect-fit scaling, and opens at 1280×720 by default. CDG source graphics remain their original fixed resolution; scaling cannot recover missing HD detail. Settings uses a non-wrapping studio selector; the Karaoke Studio toolbar omits the Settings button.
External DJ storage
DJ Settings → Library → Move Media and Waveforms selects a destination folder, including an external drive. Imported audio is stored in its Media subfolder and saved waveforms in Waveforms. Transfers run on a utility worker with progress and cancellation; both decks and headphone preview must be stopped. Every copied file is verified before its original is removed. Waveform keys are updated for relocated audio, so saved analysis remains reusable. Folder access is remembered across launches; missing external drives are reported instead of silently creating substitute folders. The database, playlists, favourites, ratings, MIDI setup and settings stay on this Mac. Cancellation retains verified transfers and remaining originals; rerun the move to finish an interrupted transfer.
Changes to a playing loop's length are queued with the audio node at a loop boundary, avoiding a node restart. A three-millisecond seam blend reduces edge clicks without changing the loop's frame count. Loop Off switches back to the source file through the same overlap.
Move progress is presented by the DJ settings pane that observes the move directly. Discovery reports progress before file matching begins, skips empty cache folders and checks each audio stamp once. Cancel responds during scanning, hashing and streaming copy; copies use 1 MB chunks and remove incomplete staging files. Large file verification/copy phases report byte counts instead of leaving the interface unchanged.
Referenced imports and library cleanup
New DJ imports default to referencing their original files, avoiding a second media copy. Choose Copy files into DJ storage under DJ Settings → Library → Import Mode when a managed copy is wanted. The mode is remembered. Selected files/folders retain access bookmarks; keep their source drive connected. Saved waveforms are still generated. ZIP audio must be extracted into managed storage. Existing copied tracks are unchanged automatically.
Right-click selected DJ tracks to remove their library entries. DJ Settings → Library also has Clear DJ Library and Clean Unused Files. Removal requires confirmation and keeps media files. Cleanup scans on a worker, previews count/size/paths, and requires confirmation before moving unreferenced hash-named managed media and stale waveform caches to Trash. Referenced originals and unrecognised personal files are excluded. The cleanup preview is rechecked before use; files newly referenced or changed are skipped. Waveform cleanup is deferred when source-file availability prevents cache validation. Clearing the DJ library also clears its queue/favourites while leaving original files and empty playlist definitions.
Both library toolbars share coloured, rounded action buttons and matching search fields. DJ Library groups its heading/selection/actions above filters/search/page navigation: cyan Import, green Add to Queue, purple Playlists and amber Favourites. Filter/library changes prune stale selections and clamp pagination to the current results.
Loop activation and cancellation prepare an idle transport node while the audible node keeps running. Both feed the same effects chain. A shared host-clock start (up to 50 ms lookahead) and per-sample 12 ms complementary envelopes overlap the streams before retiring the outgoing node. The first partial loop pass uses the same processed seam as subsequent passes. Regression checks measure silent runs and adjacent-sample jumps across repeated start/stop operations, including two playing decks and changed tempos, as well as actual loop content and natural end-of-track completion.