aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordvs12024-10-17 20:46:35 +1000
committerdvs12024-10-17 20:46:35 +1000
commit3ebed4e4f7cda7da2af3a63a80aeecbec45514db (patch)
treea6796438586e3637eca766679a46863282694021
parentCorrect docs about where to put the aataaj.lua script (diff)
downloadJackOnAllDevices-3ebed4e4f7cda7da2af3a63a80aeecbec45514db.zip
JackOnAllDevices-3ebed4e4f7cda7da2af3a63a80aeecbec45514db.tar.gz
JackOnAllDevices-3ebed4e4f7cda7da2af3a63a80aeecbec45514db.tar.bz2
JackOnAllDevices-3ebed4e4f7cda7da2af3a63a80aeecbec45514db.tar.xz
Delete excess files, now I've combined them.
-rwxr-xr-xjackoffall146
-rwxr-xr-xjackonall237
-rwxr-xr-xjackscanall326
3 files changed, 0 insertions, 709 deletions
diff --git a/jackoffall b/jackoffall
deleted file mode 100755
index 6c7cec2..0000000
--- a/jackoffall
+++ /dev/null
@@ -1,146 +0,0 @@
1#!/usr/bin/env luajit
2
3
4local APT = {}
5
6
7APT.readCmd = function(cmd)
8 local result = {}
9 local output = io.popen(cmd)
10 if nil ~= output then
11 for l in output:lines() do
12 table.insert(result, l)
13 end
14 end
15 return result
16end
17
18
19APT.exe = function(c)
20 local exe = {status = 0, result = '', log = true, cmd = c .. ' ', command = c}
21
22 function exe:log()
23 self.log = true
24 return self
25 end
26 function exe:Nice(c)
27 if nil == c then
28 self.cmd = 'ionice -c3 nice -n 19 ' .. self.cmd
29 else
30 self.cmd = self.cmd .. 'ionice -c3 nice -n 19 ' .. c .. ' '
31 end
32 return self
33 end
34 function exe:timeout(c)
35 -- 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.
36 -- --kill-after means "send KILL after TERM fails.
37 if nil == c then
38 self.cmd = 'timeout --kill-after=10.0 --foreground 42.0s ' .. self.cmd
39 else
40 self.cmd = 'timeout --kill-after=10.0 --foreground ' .. c .. ' ' .. self.cmd
41 end
42 return self
43 end
44 function exe:also(c)
45 if nil == c then c = '' else c = ' ' .. c end
46 self.cmd = self.cmd .. ';' .. c .. ' '
47 return self
48 end
49 function exe:And(c)
50 if nil == c then c = '' else c = ' ' .. c end
51 self.cmd = self.cmd .. '&&' .. c .. ' '
52 return self
53 end
54 function exe:Or(c)
55 if nil == c then c = '' end
56 self.cmd = self.cmd .. '|| ' .. c .. ' '
57 return self
58 end
59 function exe:noErr()
60 self.cmd = self.cmd .. '2>/dev/null '
61 return self
62 end
63 function exe:wait(w)
64 self.cmd = self.cmd .. '&& touch ' .. w .. ' '
65 return self
66 end
67 function exe:Do()
68 --[[ "The condition expression of a control structure can return any
69 value. Both false and nil are considered false. All values different
70 from nil and false are considered true (in particular, the number 0
71 and the empty string are also true)."
72 says the docs, I beg to differ.]]
73 if true == self.log then D(" executing - &nbsp; <code>" .. self.cmd .. "</code>") end
74 --[[ Damn os.execute()
75 Lua 5.1 says it returns "a status code, which is system-dependent"
76 Lua 5.2 says it returns true/nil, "exit"/"signal", the status code.
77 I'm getting 7168 or 0. No idea what the fuck that is.
78 local ok, rslt, status = os.execute(s)
79 ]]
80 local f = APT.readCmd(self.cmd, 'r')
81 -- The last line will be the command's returned status, collect everything else in result.
82 self.status = '' -- Otherwise the result starts with 0.
83 self.result = '\n'
84 for i,l in ipairs(f) do
85 self.result = self.result .. l .. "\n"
86 end
87 f = APT.readCmd('echo "$?"', 'r')
88 for i,l in ipairs(f) do
89 self.status = tonumber(l)
90 if (137 == self.status) or (124 == self.status) then
91 print("timeout killed " .. self.status .. ' ' .. self.command)
92 E("timeout killed " .. self.status .. ' ' .. self.command)
93 elseif (0 ~= self.status) then
94 print("status |" .. self.status .. '| ' .. self.command)
95 E("status |" .. self.status .. '| ' .. self.command)
96 end
97 end
98 return self
99 end
100 function exe:fork(host)
101 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
102 self.cmd = '{ ' .. self.cmd .. '; } &'
103 if true == self.log then D(" forking - &nbsp; <code>" .. self.cmd .. "</code>") end
104 os.execute(self.cmd)
105 return self
106 end
107 return exe
108end
109
110
111APT.exe("a2j_control --stop"):Do()
112APT.exe("sleep 2"):Do()
113APT.exe("a2j_control --exit"):Do()
114APT.exe("sleep 2"):Do()
115APT.exe("killall -TERM alsa_out"):Do()
116APT.exe("killall -TERM alsa_in"):Do()
117APT.exe("killall -TERM zita-a2j"):Do()
118APT.exe("killall -TERM zita-j2a"):Do()
119APT.exe("killall -TERM aseqjoy"):Do()
120APT.exe("killall -TERM jack-plumbing"):Do()
121APT.exe("sleep 2"):Do()
122APT.exe("jack_control stop"):Do()
123APT.exe("sleep 2"):Do()
124APT.exe("jack_control exit"):Do()
125APT.exe("sleep 2"):Do()
126--APT.exe("a2j_control --stop; a2j_control --exit"):Do()
127--APT.exe("sleep 2"):Do()
128APT.exe("killall -TERM jmcore"):Do()
129APT.exe("pkill -TERM jackdbus; pkill -TERM a2jmidid"):Do()
130APT.exe("killall -TERM a2jmidid"):Do()
131APT.exe("killall -KILL jackdbus"):Do()
132APT.exe("sleep 2"):Do()
133APT.exe("killall -KILL a2jmidid"):Do()
134APT.exe("pkill -KILL jackdbus; pkill -KILL a2jmidid"):Do()
135APT.exe("sleep 2"):Do()
136APT.exe("killall -KILL a2jmidid"):Do()
137APT.exe("killall -KILL jackdbus"):Do()
138APT.exe("sleep 2"):Do()
139APT.exe("killall -KILL a2jmidid"):Do()
140APT.exe("killall -KILL jackdbus"):Do()
141APT.exe("sleep 2"):Do()
142APT.exe("pkill -KILL jackdbus; pkill -KILL a2jmidid"):Do()
143APT.exe("killall -TERM qjackctl"):Do()
144
145-- Catia is python, and no easy way to kill it.
146APT.exe("ps auxw | grep python"):Do()
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--[[
4This is part of the JackOnAllDevices project, JOAD for short.
5
6NOTE - Seems both ALSA and JACK are per user.
7
8]]
9
10
11-- CHANGE these to suit.
12--local GUI = 'qjackctl'
13local GUI = 'catia'
14local alias = {
15 {name='Screen', dev='HDMI9'},
16 }
17
18
19-- This APT stuff was copied from apt-panopticon.
20local APT = {}
21
22APT.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
31end
32
33
34APT.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 - &nbsp; <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 - &nbsp; <code>" .. self.cmd .. "</code>") end
120 os.execute(self.cmd)
121 return self
122 end
123 return exe
124end
125
126
127
128local Cards = {}
129
130print('Scanning for audio devices.')
131local cards = APT.exe('ls -d1 /proc/asound/card[0-9]*'):noErr():Do()
132for 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
153end
154
155
156print('')
157print("Start up JACK and friends.")
158print("jack_control")
159APT.exe('jack_control start'):Do()
160APT.exe('jack_control ds alsa'):Do()
161--jack_control dps device hw:RIG,0
162print("sleep 5")
163APT.exe('sleep 5'):Do()
164if nil ~= GUI then
165 print(GUI)
166 APT.exe(GUI):fork()
167end
168print("jack-plumbing")
169APT.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.
175print("a2j_control")
176APT.exe('a2j_control --ehw && a2j_control --start'):Do()
177print("sleep 2")
178APT.exe('sleep 2'):Do()
179print("")
180
181
182--local AIN = "alsa_in"
183local AIN = "zita-a2j"
184--local AOUT = "alsa_out"
185local AOUT = "zita-j2a"
186
187print("Basic ALSA sound devices converted to JACK.")
188for 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()
192end
193print("HW playback: cloop\tDEVICE: cloop")
194-- No idea why, cloop wont work with zita-a2j.
195APT.exe('alsa_in -j cloop -d cloop'):fork()
196APT.exe('sleep 1'):Do()
197APT.exe('jack_connect cloop:capture_1 system:playback_1'):Do()
198APT.exe('jack_connect cloop:capture_2 system:playback_2'):Do()
199print("HW playback: ploop\tDEVICE: ploop")
200APT.exe('alsa_out -j ploop -d ploop'):fork()
201APT.exe('sleep 1'):Do()
202APT.exe('jack_connect system:capture_1 ploop:playback_1'):Do()
203APT.exe('jack_connect system:capture_2 ploop:playback_2'):Do()
204
205
206print("")
207
208print("Rest of ALSA sound devices converted to JACK.")
209for 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
220end
221print("")
222
223print("Scanning for joysticks.")
224local sticks = APT.exe('ls -1 /dev/input/js[0-9]*'):noErr():Do()
225for 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()
233end
234print("")
235
236
237
diff --git a/jackscanall b/jackscanall
deleted file mode 100755
index 24d87df..0000000
--- a/jackscanall
+++ /dev/null
@@ -1,326 +0,0 @@
1#!/usr/bin/env luajit
2
3--[[
4This is part of the JackOnAllDevices project, JOAD for short.
5
6The purpose is to scan for all ALSA / asound audio devices, and hook them
7all up to JACK. Then it starts up JACK, and hooks up any joysticks it
8finds as MIDI controllers.
9
10
11Alas ~/.asoundrc doesn't understand ~ or $HOME, or even "try the current
12directory" it seems. So you have to hard cade the path. Make sure your
13~/.asoundrc or /etc/asoundrc includes something like this -
14
15</var/lib/JOAD/asoundrc>
16
17
18Run this once as root to create that file, and each time you need to
19change your devices.
20
21
22TODO - Leave it running, and hotplug ALSA / asound audio devices.
23 a2jmidid takes care of hotplugging MIDI devices.
24 Though I think I still need to deal with hotplugged joysticks.
25
26NOTE - Seems both ALSA and JACK are per user.
27
28]]
29
30
31-- CHANGE these to suit.
32local asoundrcPath = '/var/lib/JOAD'
33local asoundrc = 'asoundrc'
34
35
36
37-- This APT stuff was copied from apt-panopticon.
38local APT = {}
39
40APT.readCmd = function(cmd)
41 local result = {}
42 local output = io.popen(cmd)
43 if nil ~= output then
44 for l in output:lines() do
45 table.insert(result, l)
46 end
47 end
48 return result
49end
50
51
52APT.exe = function(c)
53 local exe = {status = 0, result = '', lines = {}, log = true, cmd = c .. ' ', command = c}
54
55 function exe:log()
56 self.log = true
57 return self
58 end
59 function exe:Nice(c)
60 if nil == c then
61 self.cmd = 'ionice -c3 nice -n 19 ' .. self.cmd
62 else
63 self.cmd = self.cmd .. 'ionice -c3 nice -n 19 ' .. c .. ' '
64 end
65 return self
66 end
67 function exe:timeout(c)
68 -- 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.
69 -- --kill-after means "send KILL after TERM fails.
70 if nil == c then
71 self.cmd = 'timeout --kill-after=10.0 --foreground 42.0s ' .. self.cmd
72 else
73 self.cmd = 'timeout --kill-after=10.0 --foreground ' .. c .. ' ' .. self.cmd
74 end
75 return self
76 end
77 function exe:also(c)
78 if nil == c then c = '' else c = ' ' .. c end
79 self.cmd = self.cmd .. ';' .. c .. ' '
80 return self
81 end
82 function exe:And(c)
83 if nil == c then c = '' else c = ' ' .. c end
84 self.cmd = self.cmd .. '&&' .. c .. ' '
85 return self
86 end
87 function exe:Or(c)
88 if nil == c then c = '' end
89 self.cmd = self.cmd .. '|| ' .. c .. ' '
90 return self
91 end
92 function exe:noErr()
93 self.cmd = self.cmd .. '2>/dev/null '
94 return self
95 end
96 function exe:wait(w)
97 self.cmd = self.cmd .. '&& touch ' .. w .. ' '
98 return self
99 end
100 function exe:Do()
101 --[[ "The condition expression of a control structure can return any
102 value. Both false and nil are considered false. All values different
103 from nil and false are considered true (in particular, the number 0
104 and the empty string are also true)."
105 says the docs, I beg to differ.]]
106 if true == self.log then D(" executing - &nbsp; <code>" .. self.cmd .. "</code>") end
107 --[[ Damn os.execute()
108 Lua 5.1 says it returns "a status code, which is system-dependent"
109 Lua 5.2 says it returns true/nil, "exit"/"signal", the status code.
110 I'm getting 7168 or 0. No idea what the fuck that is.
111 local ok, rslt, status = os.execute(s)
112 ]]
113 local f = APT.readCmd(self.cmd, 'r')
114 -- The last line will be the command's returned status, collect everything else in result.
115 self.status = '' -- Otherwise the result starts with 0.
116 self.result = '\n'
117 self.lines = f
118 for i,l in ipairs(f) do
119 self.result = self.result .. l .. "\n"
120 end
121 f = APT.readCmd('echo "$?"', 'r')
122 for i,l in ipairs(f) do
123 self.status = tonumber(l)
124 if (137 == self.status) or (124 == self.status) then
125 print("timeout killed " .. self.status .. ' ' .. self.command)
126 E("timeout killed " .. self.status .. ' ' .. self.command)
127 elseif (0 ~= self.status) then
128 print("status |" .. self.status .. '| ' .. self.command)
129 E("status |" .. self.status .. '| ' .. self.command)
130 end
131 end
132 return self
133 end
134 function exe:fork(host)
135 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
136 self.cmd = '{ ' .. self.cmd .. '; } &'
137 if true == self.log then D(" forking - &nbsp; <code>" .. self.cmd .. "</code>") end
138 os.execute(self.cmd)
139 return self
140 end
141 return exe
142end
143
144
145
146local Cards = {}
147
148print('Scanning for audio devices.')
149local cards = APT.exe('ls -d1 /proc/asound/card[0-9]*'):noErr():Do()
150for i,l in ipairs(cards.lines) do
151 local f, e = io.open(l .. '/id', "r")
152 if nil == f then print("Could not open " .. l .. '/id') else
153 Cards[l] = {path = l, name = f:read("*a"):sub(1, -2), devs = {}, captureDevs = {}, playbackDevs = {}}
154 if "Loopback" ~= Cards[l]['name'] then
155 Cards[l]['capture'] = APT.exe('ls -d1 ' .. l .. '/pcm[0-9]*c*'):noErr():Do()
156 for j,c in ipairs(Cards[l]['capture'].lines) do
157 local n = c:match(".*pcm(%d+).*")
158 Cards[l]['captureDevs'][j] = n
159 Cards[l]['devs'][n] = n
160 print("\tFound capture device: " .. Cards[l]['name'] .. "\tDEVICE: " .. Cards[l]['captureDevs'][j] .. ' ' .. n)
161 end
162 Cards[l]['playback'] = APT.exe('ls -d1 ' .. l .. '/pcm[0-9]*p*'):noErr():Do()
163 for j,p in ipairs(Cards[l]['playback'].lines) do
164 local n = p:match(".*pcm(%d+).*")
165 Cards[l]['playbackDevs'][j] = n
166 Cards[l]['devs'][n] = n
167 print("\tFound playback device: " .. Cards[l]['name'] .. "\tDEVICE: " .. Cards[l]['playbackDevs'][j] .. ' ' .. n)
168 end
169 end
170 end
171end
172
173APT.exe('mkdir -p ' .. asoundrcPath):Do()
174local a, e = io.open(asoundrcPath .. '/' .. asoundrc, "w")
175if nil == a then print("Could not open " .. asoundrcPath .. '/' .. asoundrc) else
176 for i,C in pairs(Cards) do
177 for j,c in pairs(C['devs']) do
178 a:write("pcm." .. C['name'] .. j .. " {\n")
179 a:write(" type hw\n")
180 a:write(" card " .. C['name'] .. "\n")
181 a:write(" device " .. C['devs'][j] .. "\n")
182 a:write("}\n")
183 a:write("ctl." .. C['name'] .. j .. " {\n")
184 a:write(" type hw\n")
185 a:write(" card " .. C['name'] .. "\n")
186 a:write(" device " .. C['devs'][j] .. "\n")
187 a:write("}\n\n")
188 end
189 end
190 a:write([[
191#################################################################################################################################
192
193# The complex way - https://alsa.opensrc.org/Jack_and_Loopback_device_as_Alsa-to-Jack_bridge
194
195# More custom version, but it didn't work for me.
196# hardware 0,0 : used for ALSA playback
197#pcm.loophw00 {
198# type hw
199# card Loopback
200# device 0
201# subdevice 0
202# format S32_LE
203# rate 48000
204#}
205
206# playback PCM device: using loopback subdevice 0,0
207# Don't use a buffer size that is too small. Some apps
208# won't like it and it will sound crappy
209
210#pcm.amix {
211# type dmix
212# ipc_key 219345
213# slave {
214# pcm loophw00
215## period_size 4096
216## periods 2
217# }
218#}
219
220# software volume
221#pcm.asoftvol {
222# type softvol
223# slave.pcm "amix"
224
225# control { name PCM }
226
227# min_dB -51.0
228# max_dB 0.0
229#}
230
231
232# for jack alsa_in: looped-back signal at other ends
233#pcm.cloop {
234# type hw
235# card Loopback
236# device 1
237# subdevice 0
238# format S32_LE
239# rate 48000
240#}
241
242# hardware 0,1 : used for ALSA capture
243#pcm.loophw01 {
244# type hw
245# card Loopback
246# device 0
247# subdevice 1
248# format S32_LE
249# rate 48000
250#}
251
252# for jack alsa_out: looped-back signal at other end
253#pcm.ploop {
254# type hw
255# card Loopback
256# device 1
257# subdevice 1
258# format S32_LE
259# rate 48000
260#}
261
262# duplex device combining our PCM devices defined above
263#pcm.aduplex {
264# type asym
265# playback.pcm "asoftvol"
266# capture.pcm "loophw01"
267#}
268
269# default device
270#pcm.!default {
271# type plug
272# slave.pcm aduplex
273
274# hint {
275# show on
276# description "Duplex Loopback"
277# }
278#}
279
280
281
282# Generic method seems to work better.
283# playback PCM device: using loopback subdevice 0,0
284pcm.amix {
285 type dmix
286 ipc_key 219345
287 slave.pcm "hw:Loopback,0,0"
288}
289
290# capture PCM device: using loopback subdevice 0,1
291pcm.asnoop {
292 type dsnoop
293 ipc_key 219346
294 slave.pcm "hw:Loopback,0,1"
295}
296
297# duplex device combining our PCM devices defined above
298pcm.aduplex {
299 type asym
300 playback.pcm "amix"
301 capture.pcm "asnoop"
302}
303
304# ------------------------------------------------------
305# for jack alsa_in and alsa_out: looped-back signal at other ends
306pcm.ploop {
307 type plug
308 slave.pcm "hw:Loopback,1,1"
309}
310
311pcm.cloop {
312 type dsnoop
313 ipc_key 219348
314 slave.pcm "hw:Loopback,1,0"
315}
316
317# ------------------------------------------------------
318# default device
319
320pcm.!default {
321 type plug
322 slave.pcm "aduplex"
323}
324 ]])
325a:close()
326end