commit d146c400cd04867a6e907979911e548dadd97fc0 Author: visionmercer <62051836+visionmercer@users.noreply.github.com> Date: Mon Jun 1 09:16:39 2026 +0200 init diff --git a/cimp.bas b/cimp.bas new file mode 100644 index 0000000..75c0228 --- /dev/null +++ b/cimp.bas @@ -0,0 +1,428 @@ + +declare library "terminkey" + function terminkey% () + sub echooff () + sub echoon () + function termwidth () +end declare + +$console:only + +const KEY_UP = 1001 +const KEY_DOWN = 1002 +const KEY_RIGHT = 1003 +const KEY_LEFT = 1004 + +$if WIN then +Shell "chcp 65001 > nul" +$end if + +redim file(0) as string +if command$ = "" then + print "please specify file to play." + system +end if + +echooff +cursoroff +chdir _startdir$ +dim volume as single +dim repeat as integer +dim shuffle as integer +dim nooutput as integer +dim timevis as integer +dim nyan as integer + +volume = 1 +repeat = 0 +shuffle = 0 +nooutput = 0 +timevis = 1 +nyan = 0 + +for i = 1 to _commandcount + select case command$(i) + case "-v", "--volume" + i = i + 1 + volume = val(command$(i)) / 100 + case "-s", "--shuffle" + shuffle = -1 + case "-r", "--repeat" + if command$(i + 1) = "1" then + repeat = 1 + else + repeat = -1 + end if + case "-n", "--nooutput" + nooutput = -1 + case "-N", "--nyan" + nyan = -1 + case else + if _fileexists(command$(i)) then + if lcase$(right$(command$(i), 4)) = ".m3u" then + ParseM3U command$(i), file() + else + file(ubound(file)) = command$(i) + redim _preserve file(ubound(file) + 1) + end if + end if + end select +next + +redim _preserve file(ubound(file) - 1) + +dim musichandle as long +dim oldhandle as long + +dim keyin as integer +dim playnext as integer + +dim state as string +dim songname as string +dim progress as string +dim progressbar as string + +if shuffle = -1 then shufflearray file() +i = 0 +musichandle = _sndopen(file(i)) +if musichandle = 0 then + print "Error: could not open file "; file(i) + system +end if +_sndvol musichandle, volume +_sndplay musichandle +state = "playing " +songname = beforelast(".", afterlast("/", file(i))) + +while keyin <> 27 + keyin = terminkey + select case keyin + case KEY_UP + volume = volume + (0.01 + (volume / 10)) + if volume > 1 then volume = 1 + _sndvol musichandle, volume + case KEY_DOWN + volume = volume - (0.01 + (volume / 10)) + if volume < 0 then volume = 0 + _sndvol musichandle, volume + case KEY_RIGHT + if _sndgetpos(musichandle) + 5 < _sndlen(musichandle) then + _sndsetpos musichandle, _sndgetpos(musichandle) + 5 + else + playnext = 1 + end if + case KEY_LEFT + if _sndgetpos(musichandle) - 5 > 0 then + _sndsetpos musichandle, _sndgetpos(musichandle) - 5 + else + playnext = -1 + end if + case asc("q") + keyin = 27 + case asc("z") + if _sndgetpos(musichandle) > 2 then + _sndsetpos musichandle, 0 + else + playnext = -1 + end if + case asc("x") + if _sndplaying(musichandle) then + _sndsetpos musichandle, 0 + else + _sndplay musichandle + end if + case asc("c"), asc(" ") + if _sndplaying(musichandle) then + _sndpause musichandle + state = "paused " + else + _sndplay musichandle + state = "playing " + end if + case asc("v") + _sndstop musichandle + state = "stopped " + case asc("b") + playnext = 1 + case asc("t") + timevis = -timevis + case asc("s") + shufflearray file() + case else + end select + + if _sndgetpos(musichandle) = _sndlen(musichandle) then playnext = 1 + if playnext <> 0 then + oldhandle = musichandle + i = i + playnext + if i > ubound(file) then i = 0 + if i < lbound(file) then i = ubound(file) + musichandle = _sndopen(file(i)) + if musichandle <> 0 then + _sndvol musichandle, volume + _sndplay musichandle + _sndstop oldhandle + _sndclose oldhandle + state = "playing " + songname = beforelast(".", afterlast("/", file(i))) + playnext = 0 + else + musichandle=oldhandle + end if + end if + if timevis = 1 then + progress = " -" + timeleft(musichandle) + else + progress = " " + timeelapsed(musichandle) + end if + if nooutput=0 then + if nyan = -1 then + print termcolor(7); state; AnimatedRainbowText(songname); termcolor(7); progress; clearrest + else + print termcolor(7); state; termcolor(3); songname; termcolor(7); progress; clearrest + end if + progressbar = bar(UWidth(state) + UWidth(songname) + UWidth(progress), (_sndgetpos(musichandle) / _sndlen(musichandle)) * 100, 11, 7) + print progressbar; clearrest; cursorback; + end if + _limit 30 + if _exit then goto quit +wend + +quit: +_sndclose musichandle +print clearrest +print clearrest; +print cursorback; +cursoron +echoon +system + +sub shufflearray (stringarray() as string) + randomize timer + for n = ubound(stringarray) to 1 step -1 + j = int(rnd * n) + swap stringarray(n), stringarray(j) + next +end sub + +sub ParseM3U (filename$, array$()) + for i = len(filename$) to 1 step -1 + if mid$(filename$, i, 1) = "/" or mid$(filename$, i, 1) = "\" then + basePath$ = left$(filename$, i) + exit for + end if + next + f = freefile + open filename$ for input as #f + count = 0 + do until eof(f) + line input #f, l$ + l$ = _trim$(l$) + if len(l$) > 0 and left$(l$, 1) <> "#" then + resolvedPath$ = l$ + if not _fileexists(resolvedPath$) then + resolvedPath$ = basePath$ + l$ + end if + if _fileexists(resolvedPath$) then + array$(ubound(array$)) = resolvedPath$ + redim _preserve array$(ubound(array$) + 1) + end if + end if + loop + close #f +end sub + +function timeleft$ (handle&) + dim seconds as integer + seconds = _sndlen(handle&) - _sndgetpos(handle&) + if seconds < 0 then seconds = 0 + timeleft$ = right$("0" + ltrim$(str$(seconds \ 60)), 2) + ":" + right$("0" + ltrim$(str$(seconds mod 60)), 2) +end function + +function timeelapsed$ (handle&) + dim seconds as integer + seconds = _sndgetpos(handle&) + if seconds < 0 then seconds = 0 + timeelapsed$ = right$("0" + ltrim$(str$(seconds \ 60)), 2) + ":" + right$("0" + ltrim$(str$(seconds mod 60)), 2) +end function + +function termcolor$ (colorvalue as _unsigned long) + select case colorvalue + case 0 to 7 + termcolor = chr$(27) + "[0;3" + _trim$(str$(colorvalue)) + "m" + case 8 to 15 + termcolor = chr$(27) + "[1;3" + _trim$(str$(colorvalue - 8)) + "m" + case 16 to 255 + termcolor = chr$(27) + "[38;5;" + _trim$(str$(colorvalue)) + "m" + case is > 255 + termcolor = chr$(27) + "[38;2;" + _trim$(str$(_red32(colorvalue))) + ";" + _trim$(str$(_green32(colorvalue))) + ";" + _trim$(str$(_blue32(colorvalue))) + "m" + end select +end function + + +function cursorback$ () + cursorback = chr$(27) + "[F" +end function + +function clearline$ + clearline = chr$(27) + "[2K" +end function + +function clearrest$ + clearrest = chr$(27) + "[K" +end function + +sub cursoroff () + print chr$(27); "[?25l"; +end sub + +sub cursoron () + print chr$(27); "[?25h"; +end sub + +function bar$ (length as integer, percent as integer, color1 as long, color2 as long) + dim done as string + dim notdone as string + for i = 1 to int((percent / 100) * length) + done = done + "━" + next i + for i = 1 to length - int((percent / 100) * length) + notdone = notdone + "━" + next i + bar$ = termcolor(color1) + done + termcolor(color2) + notdone +end function + +function afterlast$ (delim as string, strng as string) + afterlast = mid$(strng, _instrrev(strng, delim) + 1) +end function + +function beforelast$ (delim as string, strng as string) + beforelast = left$(strng, _instrrev(strng, delim) - 1) +end function + + + +function AnimatedRainbowText$ (text$) + static offset as double + dim result as string + dim L as long, i as long + dim r as integer, g as integer, b as integer + dim hue as double, f as double + dim sector as integer, v as integer, p as integer, q as integer, t as integer + + L = ulen(text$) + if L = 0 then exit function + offset = offset + 5.0 + if offset >= 360 then offset = offset - 360 + + for i = 1 to L + hue = MOD_Double(offset + ((i - 1) / L) * 360, 360) + sector = int(hue / 60) + f = (hue / 60) - sector + v = 255: p = 0: q = 255 * (1 - f): t = 255 * f + select case sector + case 0: r = v: g = t: b = p + case 1: r = q: g = v: b = p + case 2: r = p: g = v: b = t + case 3: r = p: g = q: b = v + case 4: r = t: g = p: b = v + case 5: r = v: g = p: b = q + end select + rgbPart$ = _trim$(str$(r)) + ";" + _trim$(str$(g)) + ";" + _trim$(str$(b)) + result = result + chr$(27) + "[38;2;" + rgbPart$ + "m" + umid$(text$, i, 1) + next i + AnimatedRainbowText$ = result + chr$(27) + "[0m" +end function + +function MOD_Double (value as double, m as double) + MOD_Double = value - (m * int(value / m)) +end function + +function ulen% (txt$) + dim count%, i%, b% + count% = 0 + for i% = 1 to len(txt$) + b% = asc(txt$, i%) + if (b% and &H80) = 0 or (b% and &HC0) = &HC0 then + count% = count% + 1 + end if + next + ulen% = count% +end function + +function umid$ (txt$, startChar%, numChars%) + if startChar% < 1 or numChars% <= 0 or txt$ = "" then exit function + + dim byteIdx%, charCount%, startByte%, endByte% + byteIdx% = 1 + charCount% = 0 + + ' 1. Find the starting byte of the character at startChar% + while byteIdx% <= len(txt$) + b% = asc(txt$, byteIdx%) + if (b% and &H80) = 0 or (b% and &HC0) = &HC0 then + charCount% = charCount% + 1 + if charCount% = startChar% then startByte% = byteIdx% + end if + if startByte% > 0 then exit while + byteIdx% = byteIdx% + 1 + wend + + if startByte% = 0 then exit function + + ' 2. Find the byte where the sequence ends + byteIdx% = startByte% + dim charsFound% + charsFound% = 0 + + ' We look for the start of the "lastChar + 1" to find the boundary + while byteIdx% <= len(txt$) + b% = asc(txt$, byteIdx%) + if (b% and &H80) = 0 or (b% and &HC0) = &HC0 then + charsFound% = charsFound% + 1 + end if + ' If we found the start of the character AFTER our range, stop + if charsFound% > numChars% then exit while + byteIdx% = byteIdx% + 1 + wend + + ' byteIdx now points to the start of the next char, or LEN+1 + umid$ = mid$(txt$, startByte%, byteIdx% - startByte%) +end function + +function UWidth% (txt$) + dim totalWidth%, i%, char$, cp& + totalWidth% = 0 + for i% = 1 to ulen(txt$) + char$ = umid(txt$, i%, 1) + cp& = GetCodePoint&(char$) + + if cp& > &H1100 then + totalWidth% = totalWidth% + 2 + else + totalWidth% = totalWidth% + 1 + end if + next + UWidth% = totalWidth% +end function + +function GetCodePoint& (utf8Char$) + dim lLength as integer + lLength = len(utf8Char$) + dim b1 as _unsigned _byte, b2 as _unsigned _byte + dim b3 as _unsigned _byte, b4 as _unsigned _byte + + select case lLength + case 1 + GetCodePoint& = asc(utf8Char$, 1) + case 2 + b1 = asc(utf8Char$, 1): b2 = asc(utf8Char$, 2) + GetCodePoint& = (b1 and &H1F) * 64 + (b2 and &H3F) + case 3 + b1 = asc(utf8Char$, 1): b2 = asc(utf8Char$, 2): b3 = asc(utf8Char$, 3) + GetCodePoint& = (b1 and &H0F) * 4096 + (b2 and &H3F) * 64 + (b3 and &H3F) + case 4 + b1 = asc(utf8Char$, 1): b2 = asc(utf8Char$, 2): b3 = asc(utf8Char$, 3): b4 = asc(utf8Char$, 4) + GetCodePoint& = (b1 and &H07) * 262144 + (b2 and &H3F) * 4096 + (b3 and &H3F) * 64 + (b4 and &H3F) + end select +end function diff --git a/terminkey.h b/terminkey.h new file mode 100644 index 0000000..d8e7ade --- /dev/null +++ b/terminkey.h @@ -0,0 +1,129 @@ +// #include + +#ifdef _WIN32 + #include + #include +#else + #include + #include + #include + #include +#endif + +// Special key codes (unified across platforms) +#define KEY_ARROW_UP 1001 +#define KEY_ARROW_DOWN 1002 +#define KEY_ARROW_RIGHT 1003 +#define KEY_ARROW_LEFT 1004 + +int terminkey(); +void echooff(); +void echoon(); +int termwidth(); + +#ifdef _WIN32 + +int terminkey() { + if (_kbhit()) { + int ch = _getch(); + // Handle Windows arrow keys + if (ch == 224) { + int next = _getch(); + switch (next) { + case 72: return KEY_ARROW_UP; + case 80: return KEY_ARROW_DOWN; + case 75: return KEY_ARROW_LEFT; + case 77: return KEY_ARROW_RIGHT; + default: return next; + } + } + return ch; + } + return -1; +} + +void echooff() { + HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE); + DWORD mode = 0; + GetConsoleMode(hStdin, &mode); + SetConsoleMode(hStdin, mode & ~ENABLE_ECHO_INPUT); +} + +void echoon() { + HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE); + DWORD mode = 0; + GetConsoleMode(hStdin, &mode); + SetConsoleMode(hStdin, mode | ENABLE_ECHO_INPUT); +} + +int termwidth() { + HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE); + CONSOLE_SCREEN_BUFFER_INFO csbi; + if (GetConsoleScreenBufferInfo(hStdout, &csbi)) { + return csbi.srWindow.Right - csbi.srWindow.Left + 1; + } + return -1; +} + +#else + +int terminkey() { + struct termios oldt, newt; + int ch; + int oldf; + // Save existing terminal settings + tcgetattr(STDIN_FILENO, &oldt); + newt = oldt; + + // Disable buffering and echoing + newt.c_lflag &= ~(ICANON | ECHO); + tcsetattr(STDIN_FILENO, TCSANOW, &newt); + + // Set STDIN to non-blocking + oldf = fcntl(STDIN_FILENO, F_GETFL, 0); + fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK); + ch = getchar(); + + // Handle Unix arrow keys (ESC [ A/B/C/D) + if (ch == 27) { + int next1 = getchar(); + if (next1 == '[') { + int next2 = getchar(); + switch (next2) { + case 'A': ch = KEY_ARROW_UP; break; + case 'B': ch = KEY_ARROW_DOWN; break; + case 'C': ch = KEY_ARROW_RIGHT; break; + case 'D': ch = KEY_ARROW_LEFT; break; + } + } + } + + // Restore terminal settings + tcsetattr(STDIN_FILENO, TCSANOW, &oldt); + fcntl(STDIN_FILENO, F_SETFL, oldf); + return ch; +} + +void echooff() { + struct termios tty; + tcgetattr(STDIN_FILENO, &tty); + tty.c_lflag &= ~ECHO; + tcsetattr(STDIN_FILENO, TCSANOW, &tty); +} + +void echoon() { + struct termios tty; + tcgetattr(STDIN_FILENO, &tty); + tty.c_lflag |= ECHO; + tcsetattr(STDIN_FILENO, TCSANOW, &tty); +} + +int termwidth() { + struct winsize w; + if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) == 0) { + return w.ws_col; + } + return -1; +} + +#endif