diff options
| author | dvs1 | 2024-10-17 20:46:35 +1000 |
|---|---|---|
| committer | dvs1 | 2024-10-17 20:46:35 +1000 |
| commit | 3ebed4e4f7cda7da2af3a63a80aeecbec45514db (patch) | |
| tree | a6796438586e3637eca766679a46863282694021 /jackonall | |
| parent | Correct docs about where to put the aataaj.lua script (diff) | |
| download | JackOnAllDevices-3ebed4e4f7cda7da2af3a63a80aeecbec45514db.zip JackOnAllDevices-3ebed4e4f7cda7da2af3a63a80aeecbec45514db.tar.gz JackOnAllDevices-3ebed4e4f7cda7da2af3a63a80aeecbec45514db.tar.bz2 JackOnAllDevices-3ebed4e4f7cda7da2af3a63a80aeecbec45514db.tar.xz | |
Delete excess files, now I've combined them.
Diffstat (limited to 'jackonall')
| -rwxr-xr-x | jackonall | 237 |
1 files changed, 0 insertions, 237 deletions
diff --git a/jackonall b/jackonall deleted file mode 100755 index e786188..0000000 --- a/jackonall +++ /dev/null | |||
| @@ -1,237 +0,0 @@ | |||
| 1 | #!/usr/bin/env luajit | ||
| 2 | |||
| 3 | --[[ | ||
| 4 | This is part of the JackOnAllDevices project, JOAD for short. | ||
| 5 | |||
| 6 | NOTE - Seems both ALSA and JACK are per user. | ||
| 7 | |||
| 8 | ]] | ||
| 9 | |||
| 10 | |||
| 11 | -- CHANGE these to suit. | ||
| 12 | --local GUI = 'qjackctl' | ||
| 13 | local GUI = 'catia' | ||
| 14 | local alias = { | ||
| 15 | {name='Screen', dev='HDMI9'}, | ||
| 16 | } | ||
| 17 | |||
| 18 | |||
| 19 | -- This APT stuff was copied from apt-panopticon. | ||
| 20 | local APT = {} | ||
| 21 | |||
| 22 | APT.readCmd = function(cmd) | ||
| 23 | local result = {} | ||
| 24 | local output = io.popen(cmd) | ||
| 25 | if nil ~= output then | ||
| 26 | for l in output:lines() do | ||
| 27 | table.insert(result, l) | ||
| 28 | end | ||
| 29 | end | ||
| 30 | return result | ||
| 31 | end | ||
| 32 | |||
| 33 | |||
| 34 | APT.exe = function(c) | ||
| 35 | local exe = {status = 0, result = '', lines = {}, log = true, cmd = c .. ' ', command = c} | ||
| 36 | |||
| 37 | function exe:log() | ||
| 38 | self.log = true | ||
| 39 | return self | ||
| 40 | end | ||
| 41 | function exe:Nice(c) | ||
| 42 | if nil == c then | ||
| 43 | self.cmd = 'ionice -c3 nice -n 19 ' .. self.cmd | ||
| 44 | else | ||
| 45 | self.cmd = self.cmd .. 'ionice -c3 nice -n 19 ' .. c .. ' ' | ||
| 46 | end | ||
| 47 | return self | ||
| 48 | end | ||
| 49 | function exe:timeout(c) | ||
| 50 | -- timeout returns a status of - command status if --preserve-status; "128+9" (actually 137) if --kill-after ends up being done; 124 if it had to TERM; command status if all went well. | ||
| 51 | -- --kill-after means "send KILL after TERM fails. | ||
| 52 | if nil == c then | ||
| 53 | self.cmd = 'timeout --kill-after=10.0 --foreground 42.0s ' .. self.cmd | ||
| 54 | else | ||
| 55 | self.cmd = 'timeout --kill-after=10.0 --foreground ' .. c .. ' ' .. self.cmd | ||
| 56 | end | ||
| 57 | return self | ||
| 58 | end | ||
| 59 | function exe:also(c) | ||
| 60 | if nil == c then c = '' else c = ' ' .. c end | ||
| 61 | self.cmd = self.cmd .. ';' .. c .. ' ' | ||
| 62 | return self | ||
| 63 | end | ||
| 64 | function exe:And(c) | ||
| 65 | if nil == c then c = '' else c = ' ' .. c end | ||
| 66 | self.cmd = self.cmd .. '&&' .. c .. ' ' | ||
| 67 | return self | ||
| 68 | end | ||
| 69 | function exe:Or(c) | ||
| 70 | if nil == c then c = '' end | ||
| 71 | self.cmd = self.cmd .. '|| ' .. c .. ' ' | ||
| 72 | return self | ||
| 73 | end | ||
| 74 | function exe:noErr() | ||
| 75 | self.cmd = self.cmd .. '2>/dev/null ' | ||
| 76 | return self | ||
| 77 | end | ||
| 78 | function exe:wait(w) | ||
| 79 | self.cmd = self.cmd .. '&& touch ' .. w .. ' ' | ||
| 80 | return self | ||
| 81 | end | ||
| 82 | function exe:Do() | ||
| 83 | --[[ "The condition expression of a control structure can return any | ||
| 84 | value. Both false and nil are considered false. All values different | ||
| 85 | from nil and false are considered true (in particular, the number 0 | ||
| 86 | and the empty string are also true)." | ||
| 87 | says the docs, I beg to differ.]] | ||
| 88 | if true == self.log then D(" executing - <code>" .. self.cmd .. "</code>") end | ||
| 89 | --[[ Damn os.execute() | ||
| 90 | Lua 5.1 says it returns "a status code, which is system-dependent" | ||
| 91 | Lua 5.2 says it returns true/nil, "exit"/"signal", the status code. | ||
| 92 | I'm getting 7168 or 0. No idea what the fuck that is. | ||
| 93 | local ok, rslt, status = os.execute(s) | ||
| 94 | ]] | ||
| 95 | local f = APT.readCmd(self.cmd, 'r') | ||
| 96 | -- The last line will be the command's returned status, collect everything else in result. | ||
| 97 | self.status = '' -- Otherwise the result starts with 0. | ||
| 98 | self.result = '\n' | ||
| 99 | self.lines = f | ||
| 100 | for i,l in ipairs(f) do | ||
| 101 | self.result = self.result .. l .. "\n" | ||
| 102 | end | ||
| 103 | f = APT.readCmd('echo "$?"', 'r') | ||
| 104 | for i,l in ipairs(f) do | ||
| 105 | self.status = tonumber(l) | ||
| 106 | if (137 == self.status) or (124 == self.status) then | ||
| 107 | print("timeout killed " .. self.status .. ' ' .. self.command) | ||
| 108 | E("timeout killed " .. self.status .. ' ' .. self.command) | ||
| 109 | elseif (0 ~= self.status) then | ||
| 110 | print("status |" .. self.status .. '| ' .. self.command) | ||
| 111 | E("status |" .. self.status .. '| ' .. self.command) | ||
| 112 | end | ||
| 113 | end | ||
| 114 | return self | ||
| 115 | end | ||
| 116 | function exe:fork(host) | ||
| 117 | if nil ~= host then self.cmd = self.cmd .. '; r=$?; if [ $r -ge 124 ]; then echo "$r ' .. host .. ' failed forked command ' .. string.gsub(self.cmd, '"', "'") .. '"; fi' end | ||
| 118 | self.cmd = '{ ' .. self.cmd .. '; } &' | ||
| 119 | if true == self.log then D(" forking - <code>" .. self.cmd .. "</code>") end | ||
| 120 | os.execute(self.cmd) | ||
| 121 | return self | ||
| 122 | end | ||
| 123 | return exe | ||
| 124 | end | ||
| 125 | |||
| 126 | |||
| 127 | |||
| 128 | local Cards = {} | ||
| 129 | |||
| 130 | print('Scanning for audio devices.') | ||
| 131 | local cards = APT.exe('ls -d1 /proc/asound/card[0-9]*'):noErr():Do() | ||
| 132 | for i,l in ipairs(cards.lines) do | ||
| 133 | local f, e = io.open(l .. '/id', "r") | ||
| 134 | if nil == f then print("Could not open " .. l .. '/id') else | ||
| 135 | Cards[l] = {path = l, name = f:read("*a"):sub(1, -2), devs = {}, captureDevs = {}, playbackDevs = {}} | ||
| 136 | if "Loopback" ~= Cards[l]['name'] then | ||
| 137 | Cards[l]['capture'] = APT.exe('ls -d1 ' .. l .. '/pcm[0-9]*c*'):noErr():Do() | ||
| 138 | for j,c in ipairs(Cards[l]['capture'].lines) do | ||
| 139 | local n = c:match(".*pcm(%d+).*") | ||
| 140 | Cards[l]['captureDevs'][j] = n | ||
| 141 | Cards[l]['devs'][n] = n | ||
| 142 | print("\tFound capture device: " .. Cards[l]['name'] .. "\tDEVICE: " .. Cards[l]['captureDevs'][j] .. ' ' .. n) | ||
| 143 | end | ||
| 144 | Cards[l]['playback'] = APT.exe('ls -d1 ' .. l .. '/pcm[0-9]*p*'):noErr():Do() | ||
| 145 | for j,p in ipairs(Cards[l]['playback'].lines) do | ||
| 146 | local n = p:match(".*pcm(%d+).*") | ||
| 147 | Cards[l]['playbackDevs'][j] = n | ||
| 148 | Cards[l]['devs'][n] = n | ||
| 149 | print("\tFound playback device: " .. Cards[l]['name'] .. "\tDEVICE: " .. Cards[l]['playbackDevs'][j] .. ' ' .. n) | ||
| 150 | end | ||
| 151 | end | ||
| 152 | end | ||
| 153 | end | ||
| 154 | |||
| 155 | |||
| 156 | print('') | ||
| 157 | print("Start up JACK and friends.") | ||
| 158 | print("jack_control") | ||
| 159 | APT.exe('jack_control start'):Do() | ||
| 160 | APT.exe('jack_control ds alsa'):Do() | ||
| 161 | --jack_control dps device hw:RIG,0 | ||
| 162 | print("sleep 5") | ||
| 163 | APT.exe('sleep 5'):Do() | ||
| 164 | if nil ~= GUI then | ||
| 165 | print(GUI) | ||
| 166 | APT.exe(GUI):fork() | ||
| 167 | end | ||
| 168 | print("jack-plumbing") | ||
| 169 | APT.exe('jack-plumbing -q 2>/dev/null'):fork() | ||
| 170 | -- Bridge ALSA ports to JACK ports. Only handles MIDI. | ||
| 171 | -- MIDI via a2jmidid. The --ehw enables hardware ports as well, equal to using the seq MIDI drivare according to https://freeshell.de/~murks/posts/ALSA_and_JACK_MIDI_explained_(by_a_dummy_for_dummies)/ | ||
| 172 | --a2j_control actually starts a2jmidid. | ||
| 173 | ----a2jmidid -e -u & | ||
| 174 | -- I think the jack_control start and my current alsa config means a2jmidid gets started anyway. But seem to need this bit to get the joystick covered. | ||
| 175 | print("a2j_control") | ||
| 176 | APT.exe('a2j_control --ehw && a2j_control --start'):Do() | ||
| 177 | print("sleep 2") | ||
| 178 | APT.exe('sleep 2'):Do() | ||
| 179 | print("") | ||
| 180 | |||
| 181 | |||
| 182 | --local AIN = "alsa_in" | ||
| 183 | local AIN = "zita-a2j" | ||
| 184 | --local AOUT = "alsa_out" | ||
| 185 | local AOUT = "zita-j2a" | ||
| 186 | |||
| 187 | print("Basic ALSA sound devices converted to JACK.") | ||
| 188 | for i,C in pairs(alias) do | ||
| 189 | print('HW playback: ' .. C['name'] .. '\tDEVICE: ' .. C['dev']) | ||
| 190 | APT.exe('alsa_out -j ' .. C['name'] .. ' -d ' .. C['dev']):fork() | ||
| 191 | APT.exe('sleep 1'):Do() | ||
| 192 | end | ||
| 193 | print("HW playback: cloop\tDEVICE: cloop") | ||
| 194 | -- No idea why, cloop wont work with zita-a2j. | ||
| 195 | APT.exe('alsa_in -j cloop -d cloop'):fork() | ||
| 196 | APT.exe('sleep 1'):Do() | ||
| 197 | APT.exe('jack_connect cloop:capture_1 system:playback_1'):Do() | ||
| 198 | APT.exe('jack_connect cloop:capture_2 system:playback_2'):Do() | ||
| 199 | print("HW playback: ploop\tDEVICE: ploop") | ||
| 200 | APT.exe('alsa_out -j ploop -d ploop'):fork() | ||
| 201 | APT.exe('sleep 1'):Do() | ||
| 202 | APT.exe('jack_connect system:capture_1 ploop:playback_1'):Do() | ||
| 203 | APT.exe('jack_connect system:capture_2 ploop:playback_2'):Do() | ||
| 204 | |||
| 205 | |||
| 206 | print("") | ||
| 207 | |||
| 208 | print("Rest of ALSA sound devices converted to JACK.") | ||
| 209 | for i,C in pairs(Cards) do | ||
| 210 | for j,c in ipairs(C['playbackDevs']) do | ||
| 211 | print("HW playback: " .. C['name'] .. "\tDEVICE: " .. C['playbackDevs'][j]) | ||
| 212 | APT.exe(AOUT .. ' -j ' .. C['name'] .. "_" .. C['playbackDevs'][j] .. '-in -d ' .. C['name'] .. C['playbackDevs'][j]):fork() | ||
| 213 | -- APT.exe('sleep 1'):Do() | ||
| 214 | end | ||
| 215 | for j,c in ipairs(C['captureDevs']) do | ||
| 216 | print("HW capture: " .. C['name'] .. "\tDEVICE: " .. C['captureDevs'][j]) | ||
| 217 | APT.exe(AIN .. ' -j ' .. C['name'] .. "_" .. C['captureDevs'][j] .. '-out -d ' .. C['name'] .. C['captureDevs'][j]):fork() | ||
| 218 | -- APT.exe('sleep 1'):Do() | ||
| 219 | end | ||
| 220 | end | ||
| 221 | print("") | ||
| 222 | |||
| 223 | print("Scanning for joysticks.") | ||
| 224 | local sticks = APT.exe('ls -1 /dev/input/js[0-9]*'):noErr():Do() | ||
| 225 | for i,l in ipairs(sticks.lines) do | ||
| 226 | print("aseqjoy " .. l) | ||
| 227 | -- Buttons switch to that numbered MIDI channel, defaults to 1. | ||
| 228 | -- Axis are mapped to MIDI controllers 10 - 15 | ||
| 229 | -- -r means to use high resolution MIDI values. | ||
| 230 | APT.exe('aseqjoy -d ' .. l:sub(-1,-1) .. ' -r'):fork() | ||
| 231 | -- print("sleep 1") | ||
| 232 | -- APT.exe('sleep 1'):Do() | ||
| 233 | end | ||
| 234 | print("") | ||
| 235 | |||
| 236 | |||
| 237 | |||
