Skip to content
This repository was archived by the owner on Nov 6, 2022. It is now read-only.

Commit 3502cde

Browse files
committed
Merge branch 'repository'
2 parents 2129487 + 71a0aa0 commit 3502cde

File tree

4 files changed

+339
-8
lines changed

4 files changed

+339
-8
lines changed

claw/repo-claw.lua

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ return {
9191
},
9292
["app-kmt"] = {
9393
desc = "Line-terminal for MUDs & such",
94-
v = 0,
94+
v = 1,
9595
deps = {
9696
"neo",
9797
"zzz-license-pd"
@@ -200,6 +200,23 @@ return {
200200
"docs/repoauthors/app-nbcompose"
201201
},
202202
},
203+
["app-tapedeck"] = {
204+
desc = "Computronics Tape Drive interface",
205+
v = 1,
206+
deps = {
207+
"neo",
208+
"zzz-license-pd"
209+
},
210+
dirs = {
211+
"apps",
212+
"docs",
213+
"docs/repoauthors"
214+
},
215+
files = {
216+
"apps/app-tapedeck.lua",
217+
"docs/repoauthors/app-tapedeck"
218+
},
219+
},
203220
["app-launchbar"] = {
204221
desc = "Application launcher bar",
205222
v = 0,

repository/apps/app-kmt.lua

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ while true do
113113
local e = {coroutine.yield()}
114114
if e[1] == "k.timer" then
115115
while true do
116-
local b, e = tcp.read(1)
116+
local b, e = tcp.read(neo.readBufSize)
117117
if not b then
118118
if e then
119119
incoming(":Warning: " .. e)
@@ -123,12 +123,16 @@ while true do
123123
break
124124
elseif b == "" then
125125
break
126-
elseif b ~= "\r" then
127-
if b == "\n" then
128-
incoming("<" .. tcpBuf)
129-
tcpBuf = ""
130-
else
131-
tcpBuf = tcpBuf .. b
126+
else
127+
tcpBuf = tcpBuf .. b:gsub("\r", "")
128+
while true do
129+
local nlp = tcpBuf:find("\n")
130+
if nlp then
131+
incoming("<" .. tcpBuf:sub(1, nlp - 1))
132+
tcpBuf = tcpBuf:sub(nlp + 1)
133+
else
134+
break
135+
end
132136
end
133137
end
134138
end

repository/apps/app-tapedeck.lua

Lines changed: 308 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,308 @@
1+
-- This is released into the public domain.
2+
-- No warranty is provided, implied or otherwise.
3+
4+
-- app-tapedeck.lua : Computronics Tape interface.
5+
-- Added note: Computerized record discs aren't available, so it can't be called vinylscratch.
6+
-- Authors: 20kdc
7+
8+
local tapes = {}
9+
for v in neo.requireAccess("c.tape_drive", "tapedrives").list() do
10+
table.insert(tapes, v)
11+
end
12+
13+
local tapeRate = 4096
14+
15+
local event = require("event")(neo)
16+
local neoux = require("neoux")(event, neo)
17+
18+
-- There's no way to get these, so they get reset
19+
local pcvals = {vol = 100, spd = 100}
20+
local function pcbox(x, y, low, high, id, fun)
21+
return neoux.tcfield(x, y, 5, function (tx)
22+
if tx then
23+
pcvals[id] = math.min(math.max(0, math.floor(tonumber(tx) or 0)), high)
24+
fun(math.max(pcvals[id], low) / 100)
25+
end
26+
return tostring(pcvals[id])
27+
end)
28+
end
29+
30+
local window
31+
local running = true
32+
local focused = true
33+
34+
local updateTick
35+
36+
local downloadCancelled = false
37+
38+
local genPlayer -- used to return to player
39+
40+
local function genDownloading(inst)
41+
local lclLabelText = {"downloading..."}
42+
local lclLabel = neoux.tcrawview(1, 1, lclLabelText)
43+
local thr = {
44+
"/",
45+
"-",
46+
"\\",
47+
"|"
48+
}
49+
local thri = 0
50+
updateTick = function ()
51+
lclLabelText[1] = "downloading... " .. (inst.getPosition() / (1024 * 1024)) .. "MB " .. thr[(thri % #thr) + 1]
52+
thri = thri + 1
53+
lclLabel.update(window)
54+
end
55+
return 40, 1, nil, neoux.tcwindow(40, 1, {
56+
lclLabel
57+
}, function (w)
58+
downloadCancelled = true
59+
end, 0xFFFFFF, 0)
60+
end
61+
62+
local function doINetThing(inet, url, inst)
63+
inet = inet.list()()
64+
assert(inet, "No available card")
65+
inst.stop()
66+
inst.seek(-inst.getSize())
67+
downloadCancelled = false
68+
downloadPercent = 0
69+
window.reset(genDownloading(inst))
70+
local req = assert(inet.request(url))
71+
req.finishConnect()
72+
local tapePos = 0
73+
local tapeSize = inst.getSize()
74+
while (not downloadCancelled) and tapePos < tapeSize do
75+
local n, n2 = req.read(neo.readBufSize)
76+
if not n then
77+
if n2 then
78+
req.close()
79+
error(n2)
80+
end
81+
break
82+
elseif n == "" then
83+
event.sleepTo(os.uptime() + 0.05)
84+
else
85+
inst.write(n)
86+
tapePos = tapePos + #n
87+
end
88+
end
89+
req.close()
90+
inst.seek(-inst.getSize())
91+
end
92+
93+
local function genWeb(inst)
94+
updateTick = nil
95+
local url = ""
96+
local lockout = false
97+
return 40, 3, nil, neoux.tcwindow(40, 3, {
98+
neoux.tcrawview(1, 1, {"URL to write to tape?"}),
99+
neoux.tcfield(1, 2, 40, function (t)
100+
url = t or url
101+
return url
102+
end),
103+
neoux.tcbutton(1, 3, "Download & Write", function (w)
104+
lockout = true
105+
local inet = neo.requestAccess("c.internet")
106+
lockout = false
107+
if inet then
108+
local ok, err = pcall(doINetThing, inet, url, inst)
109+
if not ok then
110+
neoux.startDialog("Couldn't download: " .. tostring(err), "error")
111+
end
112+
end
113+
w.reset(genPlayer(inst))
114+
end)
115+
}, function (w)
116+
w.reset(genPlayer(inst))
117+
end, 0xFFFFFF, 0)
118+
end
119+
120+
-- The actual main UI --
121+
genPlayer = function (inst)
122+
local cachedLabel = inst.getLabel() or ""
123+
local cachedState = inst.getState()
124+
local function pausePlay()
125+
if inst.getState() == "PLAYING" then
126+
inst.stop()
127+
else
128+
inst.play()
129+
end
130+
window.reset(genPlayer(inst))
131+
end
132+
-- Common code for reading/writing tapes.
133+
-- Note that it tries to allow playback to resume later.
134+
local function rwButton(mode)
135+
local fh = neoux.fileDialog(mode)
136+
if not fh then return end
137+
inst.stop()
138+
local sp = inst.getPosition()
139+
local tapeSize = inst.getSize()
140+
inst.seek(-tapeSize)
141+
local tapePos = 0
142+
while tapePos < tapeSize do
143+
if mode then
144+
local data = inst.read(neo.readBufSize)
145+
if not data then break end
146+
tapePos = tapePos + #data
147+
local res, ifo = fh.write(data)
148+
if not res then
149+
neoux.startDialog(tostring(ifo), "issue")
150+
break
151+
end
152+
else
153+
local data = fh.read(neo.readBufSize)
154+
if not data then break end
155+
tapePos = tapePos + #data
156+
inst.write(data)
157+
end
158+
end
159+
inst.seek(-tapeSize)
160+
inst.seek(sp)
161+
fh.close()
162+
end
163+
local elems = {
164+
neoux.tcrawview(1, 1, {
165+
"Label:",
166+
"Contents:"
167+
}),
168+
neoux.tcfield(7, 1, 34, function (tx)
169+
if tx then
170+
inst.setLabel(tx)
171+
cachedLabel = tx
172+
end
173+
return cachedLabel
174+
end),
175+
{
176+
x = 1,
177+
y = 5,
178+
w = 40,
179+
h = 1,
180+
selectable = true,
181+
line = function (w, x, y, lined, bg, fg, selected)
182+
local lx = ""
183+
local pos = inst.getPosition()
184+
local sz = inst.getSize()
185+
if inst.isReady() then
186+
-- Show a bar
187+
local tick = sz / 23
188+
for i = 1, 23 do
189+
local alpos = (tick * i) - (tick / 2)
190+
if pos > alpos then
191+
lx = lx .. "="
192+
else
193+
lx = lx .. "-"
194+
end
195+
end
196+
else
197+
lx = "NO TAPE HERE."
198+
end
199+
local sec = pos / tapeRate
200+
local secz = sz / tapeRate
201+
lx = lx .. string.format(" %03i:%02i / %03i:%02i ",
202+
math.floor(sec / 60), math.floor(sec) % 60,
203+
math.floor(secz / 60), math.floor(secz) % 60)
204+
if selected then bg, fg = fg, bg end
205+
window.span(x, y, lx, bg, fg)
206+
end,
207+
key = function (w, update, a, b, c, kf)
208+
local amount = tapeRate * 10
209+
if kf.shift or kf.rshift then
210+
amount = amount * 24
211+
end
212+
if c then
213+
if a == 32 then
214+
pausePlay()
215+
elseif b == 203 then
216+
inst.seek(-amount)
217+
update()
218+
return true
219+
elseif b == 205 then
220+
inst.seek(amount)
221+
update()
222+
return true
223+
end
224+
end
225+
end
226+
},
227+
neoux.tcrawview(33, 3, {
228+
"% Volume"
229+
}),
230+
neoux.tcrawview(20, 3, {
231+
"% Speed"
232+
}),
233+
pcbox(15, 3, 25, 200, "spd", inst.setSpeed),
234+
pcbox(28, 3, 0, 100, "vol", inst.setVolume),
235+
neoux.tcrawview(1, 4, {
236+
"Seeker: use ◃/▹ (shift goes faster)"
237+
}),
238+
neoux.tcbutton(1, 3, "«", function (w)
239+
inst.seek(-inst.getSize())
240+
end),
241+
neoux.tcbutton(11, 3, "»", function (w)
242+
inst.seek(inst.getSize())
243+
end),
244+
neoux.tcbutton(4, 3, ((inst.getState() == "PLAYING") and "Pause") or "Play", function (w)
245+
pausePlay()
246+
end),
247+
-- R/W buttons
248+
neoux.tcbutton(11, 2, "Read", function (w)
249+
rwButton(true)
250+
end),
251+
neoux.tcbutton(17, 2, "Write", function (w)
252+
rwButton(false)
253+
end),
254+
neoux.tcbutton(24, 2, "Write From Web", function (w)
255+
w.reset(genWeb(inst))
256+
end)
257+
}
258+
updateTick = function ()
259+
local lcl = cachedLabel
260+
cachedLabel = inst.getLabel() or ""
261+
elems[3].update(window)
262+
if inst.getState() ~= cachedState then
263+
window.reset(genPlayer(inst))
264+
elseif lcl ~= cachedLabel then
265+
elems[2].update(window)
266+
end
267+
end
268+
local n = neoux.tcwindow(40, 5, elems, function (w)
269+
updateTick = nil
270+
running = false
271+
w.close()
272+
end, 0xFFFFFF, 0)
273+
return 40, 5, inst.address, function (a, ...)
274+
if a == "focus" then
275+
focused = (...) or true
276+
end
277+
return n(a, ...)
278+
end
279+
end
280+
local function genList()
281+
local elems = {}
282+
for k, v in ipairs(tapes) do
283+
elems[k] = neoux.tcbutton(1, k, v.address:sub(1, 38), function (w)
284+
window.reset(genPlayer(v))
285+
end)
286+
end
287+
tapes = nil
288+
return 40, #elems, nil, neoux.tcwindow(40, #elems, elems, function (w)
289+
running = false
290+
w.close()
291+
end, 0xFFFFFF, 0)
292+
end
293+
294+
295+
window = neoux.create(genList())
296+
297+
-- Timer for time update
298+
local function tick()
299+
if updateTick then
300+
updateTick()
301+
end
302+
event.runAt(os.uptime() + ((focused and 1) or 10), tick)
303+
end
304+
event.runAt(0, tick)
305+
306+
while running do
307+
event.pull()
308+
end
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
repository/apps/app-tapedeck.lua: 20kdc, Public Domain
2+

0 commit comments

Comments
 (0)