author | František Kučera <franta-hg@frantovo.cz> |
Mon, 04 Jan 2021 13:38:08 +0100 | |
branch | v_0 |
changeset 11 | 5b351628a377 |
parent 10 | 4d95b089457d |
child 12 | 15d87fdd6e6c |
permissions | -rw-r--r-- |
0 | 1 |
/** |
2 |
* DJM-Fix |
|
3 |
* Copyright © 2020 František Kučera (Frantovo.cz, GlobalCode.info) |
|
4 |
* |
|
5 |
* This program is free software: you can redistribute it and/or modify |
|
6 |
* it under the terms of the GNU General Public License as published by |
|
7 |
* the Free Software Foundation, version 3 of the License. |
|
8 |
* |
|
9 |
* This program is distributed in the hope that it will be useful, |
|
10 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 |
* GNU General Public License for more details. |
|
13 |
* |
|
14 |
* You should have received a copy of the GNU General Public License |
|
15 |
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
16 |
*/ |
|
17 |
||
1 | 18 |
#include <memory> |
19 |
#include <iostream> |
|
2
f34476ab597f
background thread + AlsaBridge skeleton
František Kučera <franta-hg@frantovo.cz>
parents:
1
diff
changeset
|
20 |
#include <chrono> |
f34476ab597f
background thread + AlsaBridge skeleton
František Kučera <franta-hg@frantovo.cz>
parents:
1
diff
changeset
|
21 |
#include <thread> |
f34476ab597f
background thread + AlsaBridge skeleton
František Kučera <franta-hg@frantovo.cz>
parents:
1
diff
changeset
|
22 |
#include <csignal> |
5
ef8f4023e32e
sending and receiving MIDI messages through ALSA (the dirty way)
František Kučera <franta-hg@frantovo.cz>
parents:
2
diff
changeset
|
23 |
#include <atomic> |
1 | 24 |
|
25 |
#include "DJMFix.h" |
|
2
f34476ab597f
background thread + AlsaBridge skeleton
František Kučera <franta-hg@frantovo.cz>
parents:
1
diff
changeset
|
26 |
#include "AlsaBridge.h" |
f34476ab597f
background thread + AlsaBridge skeleton
František Kučera <franta-hg@frantovo.cz>
parents:
1
diff
changeset
|
27 |
|
5
ef8f4023e32e
sending and receiving MIDI messages through ALSA (the dirty way)
František Kučera <franta-hg@frantovo.cz>
parents:
2
diff
changeset
|
28 |
static std::atomic<bool> run{true}; |
2
f34476ab597f
background thread + AlsaBridge skeleton
František Kučera <franta-hg@frantovo.cz>
parents:
1
diff
changeset
|
29 |
|
f34476ab597f
background thread + AlsaBridge skeleton
František Kučera <franta-hg@frantovo.cz>
parents:
1
diff
changeset
|
30 |
void interrupt(int signal) { |
f34476ab597f
background thread + AlsaBridge skeleton
František Kučera <franta-hg@frantovo.cz>
parents:
1
diff
changeset
|
31 |
run = false; |
f34476ab597f
background thread + AlsaBridge skeleton
František Kučera <franta-hg@frantovo.cz>
parents:
1
diff
changeset
|
32 |
std::cerr << "interrupt()" << std::endl; // TODO: do not mess STDIO |
f34476ab597f
background thread + AlsaBridge skeleton
František Kučera <franta-hg@frantovo.cz>
parents:
1
diff
changeset
|
33 |
} |
1 | 34 |
|
10 | 35 |
/** |
36 |
* The support for Pioneer DJ DJM-250MK2 (an external USB sound card / mixer) was added to the Linux (kernel) by these patches: |
|
37 |
* |
|
38 |
* - https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/sound/usb?id=73d8c94084341e2895169a0462dbc18167f01683 (playback) |
|
39 |
* - https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/sound/usb?id=14335d8b9e1a2bf006f9d969a103f9731cabb210 (recording) |
|
40 |
* - https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/sound/usb?id=cdc01a1558dedcee3daee7e1802d0349a07edb87 (mixer setup) |
|
41 |
* |
|
42 |
* These patches are enough for playback and for recording from post CH faders. |
|
43 |
* |
|
44 |
* However this mixer is somehow incapacitated and if we want to record the raw signal from the PHONO or LINE channels, |
|
45 |
* we only get silence. This feature is important for DVS (Digital Vinyl Systems) setups where |
|
46 |
* the timecode signal from special control vinyls flows from mixer to the computer |
|
47 |
* where it is interpreted in a software like MIXXX and used for controlling the playback of files on our computer. |
|
48 |
* The signal (usually music) from these files flows back to the mixer and then to speakers and headphones. |
|
49 |
* |
|
50 |
* To make this work and enjoy all the features of the device we have bought, we need to tell the mixer that we |
|
51 |
* want the signal instead of silence on given channels. And this is the purpose of the djm-fix utility and |
|
52 |
* it is done by sending some magic packet to the mixer. |
|
53 |
* |
|
54 |
* Implementation of this magic in the AlsaBridge.cpp file is based on publicly available documentation |
|
55 |
* that can be found at <https://mixb.me/CDJHidProtocol/hid-analysis/handshake.html>. |
|
56 |
* This page pointed me to the proper hash function (according to the constants, it is bit uncommon but publicly known Fowler–Noll–Vo hash function, FNV) |
|
57 |
* and some magic bits. I wrote this standalone C++ program that talks with the mixer over MIDI SysEx messages and does the magic. |
|
58 |
* |
|
59 |
* When this program is started, it finds the mixer and makes it fully working. |
|
60 |
* It needs to be running all the time, otherwise we will get silence on the PHONO/LINE channels again. |
|
61 |
* |
|
62 |
* Install dependencies: |
|
63 |
* apt install mercurial make pkg-config g++ libasound2-dev # in Debian or Ubuntu (it will be similar in other distributions) |
|
64 |
* |
|
65 |
* Download djm-fix: |
|
66 |
* hg clone https://hg.frantovo.cz/midi/djm-fix/ # primary source |
|
67 |
* hg clone https://hg.globalcode.info/midi/djm-fix/ # or we can use this mirror |
|
68 |
* |
|
69 |
* Compile: |
|
70 |
* make # we can skip this step, it will be compiled on the first run |
|
71 |
* |
|
72 |
* Run: |
|
11
5b351628a377
Find card by a name pattern (regular expression) instead using hardcoded name.
František Kučera <franta-hg@frantovo.cz>
parents:
10
diff
changeset
|
73 |
* make run # in most cases |
5b351628a377
Find card by a name pattern (regular expression) instead using hardcoded name.
František Kučera <franta-hg@frantovo.cz>
parents:
10
diff
changeset
|
74 |
* build/djm-fix 'Pioneer DJ.*' # or provide custom name pattern (regular expression) to select the proper card |
10 | 75 |
* |
76 |
* Stop: |
|
77 |
* press Ctrl+C |
|
11
5b351628a377
Find card by a name pattern (regular expression) instead using hardcoded name.
František Kučera <franta-hg@frantovo.cz>
parents:
10
diff
changeset
|
78 |
* |
5b351628a377
Find card by a name pattern (regular expression) instead using hardcoded name.
František Kučera <franta-hg@frantovo.cz>
parents:
10
diff
changeset
|
79 |
* Look for updates in the Mercurial repositories and at <https://blog.frantovo.cz/c/387/>. |
10 | 80 |
*/ |
81 |
||
0 | 82 |
int main(int argc, char**argv) { |
11
5b351628a377
Find card by a name pattern (regular expression) instead using hardcoded name.
František Kučera <franta-hg@frantovo.cz>
parents:
10
diff
changeset
|
83 |
try { |
5b351628a377
Find card by a name pattern (regular expression) instead using hardcoded name.
František Kučera <franta-hg@frantovo.cz>
parents:
10
diff
changeset
|
84 |
std::string cardNamePattern = argc == 2 ? argv[1] : "Pioneer DJ.*"; |
10 | 85 |
|
11
5b351628a377
Find card by a name pattern (regular expression) instead using hardcoded name.
František Kučera <franta-hg@frantovo.cz>
parents:
10
diff
changeset
|
86 |
signal(SIGINT, interrupt); |
5b351628a377
Find card by a name pattern (regular expression) instead using hardcoded name.
František Kučera <franta-hg@frantovo.cz>
parents:
10
diff
changeset
|
87 |
std::unique_ptr<djmfix::DJMFix> djmFix(djmfix::create()); |
5b351628a377
Find card by a name pattern (regular expression) instead using hardcoded name.
František Kučera <franta-hg@frantovo.cz>
parents:
10
diff
changeset
|
88 |
std::unique_ptr<djmfix::alsa::AlsaBridge> alsaBridge(djmfix::alsa::create(djmFix.get(), cardNamePattern)); |
1 | 89 |
|
11
5b351628a377
Find card by a name pattern (regular expression) instead using hardcoded name.
František Kučera <franta-hg@frantovo.cz>
parents:
10
diff
changeset
|
90 |
alsaBridge->start(); |
5b351628a377
Find card by a name pattern (regular expression) instead using hardcoded name.
František Kučera <franta-hg@frantovo.cz>
parents:
10
diff
changeset
|
91 |
while (run) std::this_thread::sleep_for(std::chrono::milliseconds(100)); |
5b351628a377
Find card by a name pattern (regular expression) instead using hardcoded name.
František Kučera <franta-hg@frantovo.cz>
parents:
10
diff
changeset
|
92 |
alsaBridge->stop(); |
1 | 93 |
|
11
5b351628a377
Find card by a name pattern (regular expression) instead using hardcoded name.
František Kučera <franta-hg@frantovo.cz>
parents:
10
diff
changeset
|
94 |
return 0; |
5b351628a377
Find card by a name pattern (regular expression) instead using hardcoded name.
František Kučera <franta-hg@frantovo.cz>
parents:
10
diff
changeset
|
95 |
} catch (const std::exception& e) { |
5b351628a377
Find card by a name pattern (regular expression) instead using hardcoded name.
František Kučera <franta-hg@frantovo.cz>
parents:
10
diff
changeset
|
96 |
std::cerr << "ERROR: " << e.what() << std::endl; // TODO: do not mess STDIO |
5b351628a377
Find card by a name pattern (regular expression) instead using hardcoded name.
František Kučera <franta-hg@frantovo.cz>
parents:
10
diff
changeset
|
97 |
} |
0 | 98 |
} |