more zfm stuffs

This commit is contained in:
minjaesong
2023-01-12 19:42:12 +09:00
parent bf4a337f0a
commit da5833935f
8 changed files with 322 additions and 57 deletions

View File

@@ -759,7 +759,7 @@ shell.execute = function(line) {
errorlevel = 1
}
finally {
debugprintln("[shell.execute] exec app " + searchFile.fullPath + "exit with no exception; errorlevel = " + errorlevel)
debugprintln("[shell.execute] exec app " + searchFile.fullPath + " exit with no exception; errorlevel = " + errorlevel)
// sometimes no-error program may return nothing as the errorlevel; force set to 0 then.
if (!gotError && (errorlevel == undefined || (typeof errorlevel.trim == "function" && errorlevel.trim().length == 0) || isNaN(errorlevel)))

View File

@@ -3,6 +3,7 @@ if (exec_args[1] == undefined) {
return 1
}
const interactive = exec_args[2] && exec_args[2].toLowerCase() == "/i"
let infile = files.open(_G.shell.resolvePathInput(exec_args[1]).full)
// read input file
@@ -49,4 +50,37 @@ graphics.setGraphicsMode(4)
graphics.clearText(); graphics.clearPixels(0); graphics.clearPixels2(0)
decodefun(ipfbuf, -1048577, -1310721, width, height, hasAlpha)
sys.free(ipfbuf)*/
sys.free(ipfbuf)*/
let wait = interactive
if (interactive) {
con.clear(); con.curs_set(0); con.move(1,1)
println("Push and hold Backspace to exit")
}
let t1 = sys.nanoTime()
let akku = 0
let notifHideTimer = 0
const NOTIF_SHOWUPTIME = 3000000000
while (wait) {
sys.poke(-40, 1)
if (sys.peek(-41) == 67) {
wait = false
con.curs_set(1)
}
sys.sleep(50)
let t2 = sys.nanoTime()
akku += (t2 - t1) / 1000000000.0
notifHideTimer += (t2 - t1)
if (notifHideTimer > NOTIF_SHOWUPTIME) {
con.clear()
}
t1 = t2
}

View File

@@ -1,5 +1,5 @@
// usage: playmov moviefile.mov [/i]
const interactive = exec_args[2].toLowerCase() == "/i"
const interactive = exec_args[2] && exec_args[2].toLowerCase() == "/i"
const WIDTH = 560
const HEIGHT = 448
const FBUF_SIZE = WIDTH * HEIGHT
@@ -87,7 +87,7 @@ if (interactive) {
println("Push and hold Backspace to exit")
}
let notifHideTimer = 0
const NOTIF_SHOWUPTIME = 2000000000
const NOTIF_SHOWUPTIME = 3000000000
let [cy, cx] = con.getyx()
let t1 = sys.nanoTime()
renderLoop:
@@ -237,7 +237,7 @@ while (!stopPlay && seqread.getReadCount() < FILE_LENGTH) {
if (interactive) {
notifHideTimer += (t2 - t1)
if (notifHideTimer > NOTIF_SHOWUPTIME) {
if (notifHideTimer > (NOTIF_SHOWUPTIME + frameTime)) {
con.clear()
}
}

View File

@@ -0,0 +1,162 @@
// usage: playpcm audiofile.pcm [/i]
let filename = _G.shell.resolvePathInput(exec_args[1]).full
function printdbg(s) { if (0) serial.println(s) }
const interactive = exec_args[2] && exec_args[2].toLowerCase() == "/i"
const pcm = require("pcm")
const FILE_SIZE = files.open(filename).size
function printComments() {
for (const [key, value] of Object.entries(comments)) {
printdbg(`${key}: ${value}`)
}
}
function GCD(a, b) {
a = Math.abs(a)
b = Math.abs(b)
if (b > a) {var temp = a; a = b; b = temp}
while (true) {
if (b == 0) return a
a %= b
if (a == 0) return b
b %= a
}
}
function LCM(a, b) {
return (!a || !b) ? 0 : Math.abs((a * b) / GCD(a, b))
}
//println("Reading...")
//serial.println("!!! READING")
const seqread = require("seqread")
seqread.prepare(filename)
let BLOCK_SIZE = 4096
let INFILE_BLOCK_SIZE = BLOCK_SIZE
const QUEUE_MAX = 4 // according to the spec
let nChannels = 2
let samplingRate = pcm.HW_SAMPLING_RATE;
let blockSize = 2;
let bitsPerSample = 8;
let byterate = 2*samplingRate;
let comments = {};
let readPtr = undefined
let decodePtr = undefined
function bytesToSec(i) {
return i / byterate
}
function secToReadable(n) {
let mins = ''+((n/60)|0)
let secs = ''+(n % 60)
return `${mins.padStart(2,'0')}:${secs.padStart(2,'0')}`
}
let stopPlay = false
con.curs_set(0)
if (interactive) {
con.clear(); con.move(1,1)
println("Push and hold Backspace to exit")
}
let [cy, cx] = con.getyx()
let [__, CONSOLE_WIDTH] = con.getmaxyx()
let paintWidth = CONSOLE_WIDTH - 16
// read chunks loop
readPtr = sys.malloc(BLOCK_SIZE * bitsPerSample / 8)
decodePtr = sys.malloc(BLOCK_SIZE * pcm.HW_SAMPLING_RATE / samplingRate)
audio.resetParams(0)
audio.purgeQueue(0)
audio.setPcmMode(0)
audio.setMasterVolume(0, 255)
let readLength = 1
function printPlayBar(startOffset) {
if (interactive) {
let currently = seqread.getReadCount() - startOffset
let total = FILE_SIZE - startOffset - 8
let currentlySec = Math.round(bytesToSec(currently))
let totalSec = Math.round(bytesToSec(total))
con.move(cy, 1)
print(' '.repeat(15))
con.move(cy, 1)
print(`${secToReadable(currentlySec)} / ${secToReadable(totalSec)}`)
con.move(cy, 15)
print(' ')
let progressbar = '\x84205u'.repeat(paintWidth + 1)
print(progressbar)
con.mvaddch(cy, 16 + Math.round(paintWidth * (currently / total)), 0xDB)
}
}
while (!stopPlay && seqread.getReadCount() < FILE_SIZE && readLength > 0) {
if (interactive) {
sys.poke(-40, 1)
if (sys.peek(-41) == 67) {
stopPlay = true
}
}
let queueSize = audio.getPosition(0)
if (queueSize <= 1) {
printPlayBar()
// upload four samples for lag-safely
for (let repeat = QUEUE_MAX - queueSize; repeat > 0; repeat--) {
let remainingBytes = FILE_SIZE - seqread.getReadCount()
readLength = (remainingBytes < INFILE_BLOCK_SIZE) ? remainingBytes : INFILE_BLOCK_SIZE
if (readLength <= 0) {
printdbg(`readLength = ${readLength}`)
break
}
printdbg(`offset: ${seqread.getReadCount()}/${FILE_SIZE}; readLength: ${readLength}`)
seqread.readBytes(readLength, readPtr)
audio.putPcmDataByPtr(readPtr, readLength, 0)
audio.setSampleUploadLength(0, readLength)
audio.startSampleUpload(0)
if (repeat > 1) sys.sleep(10)
printPlayBar()
}
audio.play(0)
}
let remainingBytes = FILE_SIZE - seqread.getReadCount()
printdbg(`readLength = ${readLength}; remainingBytes2 = ${remainingBytes}; seqread.getReadCount() = ${seqread.getReadCount()};`)
sys.sleep(10)
}
audio.stop(0)
if (readPtr !== undefined) sys.free(readPtr)
if (decodePtr !== undefined) sys.free(decodePtr)

View File

@@ -2,7 +2,7 @@
let filename = _G.shell.resolvePathInput(exec_args[1]).full
function printdbg(s) { if (0) serial.println(s) }
const interactive = exec_args[2].toLowerCase() == "/i"
const interactive = exec_args[2] && exec_args[2].toLowerCase() == "/i"
const seqread = require("seqread")
const pcm = require("pcm")
@@ -104,6 +104,29 @@ if (interactive) {
}
let [cy, cx] = con.getyx()
let [__, CONSOLE_WIDTH] = con.getmaxyx()
let paintWidth = CONSOLE_WIDTH - 16
function printPlayBar(startOffset) {
if (interactive) {
let currently = seqread.getReadCount() - startOffset
let total = FILE_SIZE - startOffset - 8
let currentlySec = Math.round(bytesToSec(currently))
let totalSec = Math.round(bytesToSec(total))
con.move(cy, 1)
print(' '.repeat(15))
con.move(cy, 1)
print(`${secToReadable(currentlySec)} / ${secToReadable(totalSec)}`)
con.move(cy, 15)
print(' ')
let progressbar = '\x84205u'.repeat(paintWidth + 1)
print(progressbar)
con.mvaddch(cy, 16 + Math.round(paintWidth * (currently / total)), 0xDB)
}
}
// read chunks loop
while (!stopPlay && seqread.getReadCount() < FILE_SIZE - 8) {
let chunkName = seqread.readFourCC()
@@ -195,29 +218,8 @@ while (!stopPlay && seqread.getReadCount() < FILE_SIZE - 8) {
let queueSize = audio.getPosition(0)
if (queueSize <= 1) {
if (interactive) {
let currently = seqread.getReadCount() - startOffset
let total = FILE_SIZE - startOffset - 8
let currentlySec = Math.round(bytesToSec(currently))
let totalSec = Math.round(bytesToSec(total))
con.move(cy, 1)
print(' '.repeat(40))
con.move(cy, 1)
print(`${secToReadable(currentlySec)} / ${secToReadable(totalSec)}`)
con.move(cy, 15)
print(' ')
let paintWidth = CONSOLE_WIDTH - 16
let progressbar = '\x84205u'.repeat(paintWidth + 1)
print(progressbar)
con.mvaddch(cy, 16 + Math.round(paintWidth * (currently / total)), 0xDB)
}
printPlayBar(startOffset)
// upload four samples for lag-safely
for (let repeat = QUEUE_MAX - queueSize; repeat > 0; repeat--) {
@@ -242,6 +244,8 @@ while (!stopPlay && seqread.getReadCount() < FILE_SIZE - 8) {
if (repeat > 1) sys.sleep(10)
printPlayBar(startOffset)
}
audio.play(0)

View File

@@ -24,7 +24,7 @@ function s16Tou8(i) {
// return s8Tou8((i >> 8) & 255)
// apply dithering
let ufval = (i / 65536.0) + 0.5
let ival = randomRound(ufval * 256.0)
let ival = randomRound(ufval * 255.0)
return ival|0
}
function u16Tos16(i) { return (i > 32767) ? i - 65536 : i }

View File

@@ -1,46 +1,108 @@
const win = require("wintex")
const [HEIGHt, WIDTH] = con.getmaxyx()
println("let's install!")
/* procedure:
CANCELLED_BY_USER :=
println("Installation of TVDOS was cancelled by the user.")
exit with errorlevel 1
Untick all sidebar
title: Abort Installation
message: Installation of TVDOS was cancelled by the user.
with button: Quit
on button Quit: exit with errorlevel 1
NO_SUITABLE_TARGET :=
Untick all sidebar
title: Unable to Install
message: Your system appears to not have a suitable disk for TVDOS installation. Please shut off the power, insert/plug the disk then restart the computer and the installer.
with button: Quit
on button Quit: exit with errorlevel 127
Sidebar and Chapter Title :=
[] Welcome - License Agreement
[] Customisation - User Interface
[] Disk - Installation Target
[] Summary - Installation Settings
[] Installation - Perform Installation
var USER_INTERFACE; // "zfm" or "cmd"
0. Probe all suitable installation candidates
0.1 If there is none, do NO_SUITABLE_TARGET
else, proceed to next step
1. show the list of installable drives. Read-only drives are considered not installable
1.1 if there is at least one installable drives, show the following message:
select drive to install [B,C,D]:
1.2 else, show the following message:
No suitable drives were detected for installing TVDOS. The setup program will exit. (exit with errorlevel 2)
1. Chapter Welcome
show wall of text: <COPYING>
with button: Abort, [], Next
on Abort: do CANCELLED_BY_USER
2. check if the drive has boot sector. if there is, show message:
This drive appears to be bootable, which means there might be other operation system on this drive.
Proceed anyway? [Y/N]:
2.1. if read().trim().toLowercase() is not "y", do CANCELLED_BY_USER
3. show the following message:
In order to install TVDOS to the drive ${destDrive}, the drive must be wiped clean first.
THIS PROCESS WILL IRREVERSIBLY DESTROY ALL THE DATA IN THE DRIVE ${destDrive}!
Type "yes, I consent" to proceed, or type any other text to cancel the installation process:
3.1. if read().trim().toLowercase() is not "yes, i consent" or "yes i consent", do CANCELLED_BY_USER
2. Chapter Customisation
message: Select the default user interface your new system will have. You can change the configuration any time after the installation.
button1:
title: Z File Manager (emph with same goldenrod colour as the focused window frame)
desc: Text-based Graphical Interface for navigating the system using arrow keys
button2:
title: Command-line Interface (emph with same goldenrod colour as the focused window frame)
desc: Traditional DOS experience. Black screen, blinking cursor
with button: Abort, Back Next.
on Abort: do CANCELLED_BY_USER
on Next with button1: set USER_INTERFACE to "zfm"
on Next with button2: set USER_INTERFACE to "cmd"
4. show the following message:
Enter the new name for the drive that TVDOS will be installed:
5. show the following message:
The destination disk will be wiped now. Do not turn off the power...
3. Chapter Disk
message: Choose the disk to install TVDOS.
Selected disk will be cleared only on the actual Installation step.
show buttons on grid arrangement. use template:
title: <drive letter>: // A: B: C: etc
desc:
if clean: This disk is clear
Total <disk size> bytes
if has bootsector: This disk has bootsector
Used <used size> bytes/Total <disk size> bytes
if has files: This disk has files on it
Used <used size> bytes/Total <disk size> bytes
with button: Abort, Back, Next
on Abort: do CANCELLED_BY_USER
on Next with non-clean disk selected: show popup
heading: Warning
title: Selected disk will be wiped clean and any files on it will be lost permanently. Proceed with installation?
with button: Cancel, Proceed
on Cancel: go back to disk selection
on Proceed: go to next step
6. formatDrive(destDrive, newName, driveNum)
7. show following message:
TVDOS will be installed into the drive ${destDrive}...
4. Chapter Summary
message: This is the overview of the installation. Read carefully before clicking Next.
show wall of text:
Booting
- on Drive <drive letter>:
8. copyFiles(destDrive)
Environment
- start system with <program> (program := if USER_INTERFACE is zfm, "Z File Manager"; is cmd, "Command Line Interface")
- Size of packages to install: <filesize> kB
9. show following message
TVDOS is successfully installed. You may continue using the Live Boot environment.
To boot from the newly-installed TVDOS, turn off the computer, remove the installation medium, then start the
computer again. (exit with errorlevel 0)
with button: Abort, Back, Next
on Abort: do CANCELLED_BY_USER
5. Chapter Installation
5.1 Disk Clear
message: Disk is being cleared, do not turn off the power
formatDrive(destDrive, "TVDOS", driveNum)
5.2 Copy Files
message: Installing TVDOS...
copyFiles(destDrive)
6. Still on Chapter Installtion but change title: Installation Was Successful
message: TVDOS is successfully installed. You may continue using the Live Boot environment.
To boot from the new disk, turn off the computer, remove the installation medium, then restart the computer.
with button: [], [], OK
on OK: con.clear(); exit with errorlevel 0
*/

View File

@@ -36,6 +36,9 @@ const EXEC_FUNS = {
"wav": (f) => _G.shell.execute(`playwav ${f} /i`),
"adpcm": (f) => _G.shell.execute(`playwav ${f} /i`),
"mov": (f) => _G.shell.execute(`playmov ${f} /i`),
"pcm": (f) => _G.shell.execute(`playpcm ${f} /i`),
"ipf1": (f) => _G.shell.execute(`decodeipf ${f} /i`),
"ipf2": (f) => _G.shell.execute(`decodeipf ${f} /i`),
"bas": (f) => _G.shell.execute(`basic ${f}`)
}