Compare commits

...
Author SHA1 Message Date
visionmercer
1d83475666 oi 2026-10-02 11:26:00 +02:00
visionmercer
499fcff6dd remove excessive use of space. 2026-10-02 11:22:56 +02:00
visionmercer
4d5522f1bf Remove useless code 2026-10-01 13:15:43 +02:00
visionmercer
eb50085052 Use whole width if needed. 2026-09-18 11:55:46 +02:00
visionmercer
670a19aae6 Repeat off in ipc. 2026-09-17 12:50:45 +02:00
visionmercer
321b0a3424 configurable
added the ability to use a config file.
2026-09-15 13:16:56 +02:00
visionmercer
662907254a Update readme 2026-09-10 13:59:06 +02:00
2 changed files with 260 additions and 188 deletions

407
cimp.bas
View file

@ -4,7 +4,7 @@ declare library"terminkey"
sub echoon()
function termwidth()
function ipc_init&()
function ipc_check_message%(byval buf as _offset, byval max_len as long)
function ipc_check_message%(byval buf as _offset,byval max_len as long)
sub ipc_send_message(buf as string)
sub ipc_cleanup()
end declare
@ -25,89 +25,93 @@ $end if
redim file(0) as string
chdir _startdir$
if command$=""then
print"please specify file to play."
goto quit
print"please specify file to play."
goto quit
end if
dim ipc_status as long
ipc_status = ipc_init
ipc_status=ipc_init
if ipc_status = 0 then
if ipc_status=0 then
' --- CLIENT MODE ---
dim cmd_msg as string
Select Case command$(1)
Case "--soundbank"
cmd_msg = "SOUNDBANK:" + _cwd$ + slash + command$(2)
Case "--next"
cmd_msg = "NEXT"
select case command$(1)
case "--soundbank"
cmd_msg="SOUNDBANK:"+_cwd$ +slash+command$(2)
case "--next"
cmd_msg="NEXT"
Case "--prev"
cmd_msg = "PREV"
case "--prev"
cmd_msg="PREV"
Case "-v", "--volume"
cmd_msg = "VOL:" + command$(2)
case "-v","--volume"
cmd_msg="VOL:"+command$(2)
case "--pause"
cmd_msg = "PAUSE"
cmd_msg="PAUSE"
case "--stop"
cmd_msg = "STOP"
cmd_msg="STOP"
case "--play"
cmd_msg = "PLAY"
cmd_msg="PLAY"
case "--quit"
cmd_msg = "QUIT"
cmd_msg="QUIT"
case "--shuffle"
cmd_msg = "SHUFFLE"
cmd_msg="SHUFFLE"
case "--repeat"
cmd_msg = "REPEAT"
cmd_msg="REPEAT"
case "--repeat-1"
cmd_msg = "REPEAT1"
cmd_msg="REPEAT1"
case "--repeat-off"
cmd_msg="REPEATOFF"
case "--nyan"
cmd_msg = "NYAN"
Case "--add"
For i = 2 To _commandcount
cmd_msg = "ADD:" + _cwd$ + slash + command$(i)
cmd_msg="NYAN"
case "--nyan-off"
cmd_msg="NYANOFF"
case "--add"
for i=2 to _commandcount
cmd_msg="ADD:"+_cwd$ +slash+command$(i)
ipc_send_message cmd_msg
Next i
System
next i
system
Case "--playlist"
cmd_msg = "GET_PLAYLIST"
case "--playlist"
cmd_msg="GET_PLAYLIST"
Case Else
case else
' Default behavior: Resolve target file/playlist and replace active queue
cmd_msg = "PLAY:" + _cwd$ + slash + command$(1)
cmd_msg="PLAY:"+_cwd$ +slash+command$(1)
ipc_send_message cmd_msg
If _commandcount > 1 Then
For i = 2 To _commandcount
cmd_msg = "ADD:" + _cwd$ + slash + command$(i)
if _commandcount>1 then
for i=2 to _commandcount
cmd_msg="ADD:"+_cwd$ +slash+command$(i)
ipc_send_message cmd_msg
Next i
System
End If
End Select
next i
system
end if
end select
' Send instruction to the main player instance
ipc_send_message cmd_msg
' --- Two-way Client feedback for --playlist ---
if cmd_msg = "GET_PLAYLIST" then
if cmd_msg="GET_PLAYLIST" then
ipc_cleanup
_delay 0.1
dim client_listen as long
client_listen = ipc_init
if client_listen = 1 then
client_listen=ipc_init
if client_listen=1 then
dim reply_buf as string
reply_buf = space$(4096) + chr$(0)
reply_buf=space$(4096)+chr$(0)
dim start_wait as double
start_wait = timer
start_wait=timer
do while timer - start_wait < 2
do while timer-start_wait<2
dim reply_len as long
reply_len = ipc_check_message(_offset(reply_buf), 4096)
if reply_len > 0 then
print left$(reply_buf, reply_len)
reply_len=ipc_check_message(_offset(reply_buf),4096)
if reply_len>0 then
print left$(reply_buf,reply_len)
exit do
end if
_limit 30
@ -117,7 +121,7 @@ if ipc_status = 0 then
end if
system ' Exit client instance completely
elseif ipc_status = -1 then
elseif ipc_status=-1 then
print "Error initializing Inter-Process Communication."
goto quit
end if
@ -133,6 +137,8 @@ dim shuffle as integer
dim nooutput as integer
dim timevis as integer
dim nyan as integer
dim server as integer
dim marqueeoffset as integer
dim i as integer
@ -167,6 +173,40 @@ timevis=1
nyan=0
marqueeoffset=0
dim config as string
config=GetConfig("cimp.conf")
if _fileexists(config) then
dim li as string
dim fh as integer
fh=freefile
open config for input as fh
while not eof(fh)
line input #fh,li
if left$(li,1)="#" then _continue
select case _trim$(left$(li,instr(li,"=")-1))
case "volume"
volume=val(_trim$(mid$(li,instr(li,"=")+1)))/100
case "shuffle"
if _trim$(mid$(li,instr(li,"=")+1))="true" then shuffle=-1 else shuffle=0
case "repeat"
if _trim$(mid$(li,instr(li,"=")+1))="true" then repeat=-1 else repeat=0
if _trim$(mid$(li,instr(li,"=")+1))="1" then repeat=1
case "server"
if _trim$(mid$(li,instr(li,"=")+1))="true" then server=-1 else server=0
case "nyan"
if _trim$(mid$(li,instr(li,"=")+1))="true" then nyan=-1 else nyan=0
case "nooutput"
if _trim$(mid$(li,instr(li,"=")+1))="true" then nooutput=-1 else nooutput=0
case ""
case else
print "Config not understood:"
print li
end select
wend
close fh
end if
for i=1 to _commandcount
select case command$(i)
case "-v","--volume"
@ -176,31 +216,31 @@ for i=1 to _commandcount
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 "-b","--soundbank"
if _commandcount>i and _fileexists(command$(i+1)) then
loadsoundbank command$(i+1)
else
print "error loading soundbank"
system
end if
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
repeat=1
else
repeat=-1
end if
case "-n","--nooutput"
nooutput=-1
case "-N","--nyan"
nyan=-1
case "-b","--soundbank"
if _commandcount>i and _fileexists(command$(i+1)) then
loadsoundbank command$(i+1)
else
print "error loading soundbank"
system
end if
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)
@ -209,7 +249,7 @@ if shuffle=-1 then shufflearray file()
i=0
musichandle=_sndopen(file(i))
if musichandle=0 then
print"Error: could not open file "; file(i)
print"Error: could not open file ";file(i)
goto quit
end if
_sndvol musichandle,volume
@ -219,93 +259,97 @@ songname=beforelast(".",afterlast("/",file(i)))
while keyin<>27
keyin=terminkey
' ---Poll Client Messages---
' ---Poll Client Messages---
dim incoming_buf as string
incoming_buf = space$(512) + chr$(0)
incoming_buf=space$(512)+chr$(0)
dim msg_len as long
msg_len = ipc_check_message(_offset(incoming_buf), 512)
msg_len=ipc_check_message(_offset(incoming_buf),512)
if msg_len > 0 then
if msg_len>0 then
dim client_cmd as string
client_cmd = left$(incoming_buf, msg_len)
client_cmd=left$(incoming_buf,msg_len)
if client_cmd = "NEXT" then
playnext = 1
elseif client_cmd = "PLAY" then
if client_cmd="NEXT" then
playnext=1
elseif client_cmd="PLAY" then
keyin=asc("x")
elseif client_cmd = "PAUSE" then
elseif client_cmd="PAUSE" then
keyin=asc("c")
elseif client_cmd = "STOP" then
elseif client_cmd="STOP" then
keyin=asc("v")
elseif client_cmd = "QUIT" then
elseif client_cmd="QUIT" then
keyin=27
elseif client_cmd = "REPEAT" then
elseif client_cmd="REPEAT" then
repeat=-1
elseif client_cmd = "REPEAT1" then
elseif client_cmd="REPEAT1" then
repeat=1
elseif client_cmd = "SHUFFLE" then
elseif client_cmd="REPEATOFF" then
repeat=0
elseif client_cmd="SHUFFLE" then
keyin=asc("s")
elseif client_cmd = "NYAN" then
nyan = not nyan
elseif left$(client_cmd, 10) = "SOUNDBANK:" then
if client_cmd="default" then loadsoundbank "" else loadsoundbank mid$(client_cmd,11)
elseif client_cmd="NYAN" then
nyan=not nyan
elseif client_cmd="NYANOFF" then
nyan=0
elseif left$(client_cmd,10)="SOUNDBANK:" then
if client_cmd="default" then loadsoundbank "" else loadsoundbank mid$(client_cmd,11)
if _SNDPLAYING(musichandle) then
if _sndplaying(musichandle) then
' a hack to make qb64pe load the midi file that is already loaded.
' qb64 can't open the same file again with a new sound bank for some reason
' so it has to be closed, freed and given a short delay before reloading
' which gives a short break in the playing of music, very annoying.
' this should be reverted if qb64pe ever gets the ability to reload the same
' file more than once.
' a hack to make qb64pe load the midi file that is already loaded.
' qb64 can't open the same file again with a new sound bank for some reason
' so it has to be closed, freed and given a short delay before reloading
' which gives a short break in the playing of music, very annoying.
' this should be reverted if qb64pe ever gets the ability to reload the same
' file more than once.
tmppos=_sndgetpos(musichandle)
_sndstop musichandle
_sndclose musichandle
_delay .1
musichandle=_sndopen(file(i))
_sndvol musichandle,volume
_sndsetpos musichandle,tmppos
_sndplay musichandle
end if
elseif left$(client_cmd, 4) = "VOL:" then
volume = val(mid$(client_cmd, 5)) / 100
if volume > 1 then volume = 1
if volume < 0 then volume = 0
_sndvol musichandle, volume
elseif left$(client_cmd, 4) = "ADD:" then
tmppos=_sndgetpos(musichandle)
_sndstop musichandle
_sndclose musichandle
_delay .1
musichandle=_sndopen(file(i))
_sndvol musichandle,volume
_sndsetpos musichandle,tmppos
_sndplay musichandle
end if
elseif left$(client_cmd,4)="VOL:" then
volume=val(mid$(client_cmd,5))/100
if volume>1 then volume=1
if volume<0 then volume=0
_sndvol musichandle,volume
elseif left$(client_cmd,4)="ADD:" then
dim new_file as string
new_file = _trim$(mid$(client_cmd, 5))
new_file=_trim$(mid$(client_cmd,5))
if _fileexists(new_file) then
if lcase$(right$(new_file, 4)) = ".m3u" then
parsem3u new_file, file()
if lcase$(right$(new_file,4))=".m3u" then
parsem3u new_file,file()
else
redim _preserve file(ubound(file) + 1) as string
file(ubound(file)) = new_file
redim _preserve file(ubound(file)+1) as string
file(ubound(file))=new_file
end if
end if
elseif left$(client_cmd, 5) = "PLAY:" then
elseif left$(client_cmd,5)="PLAY:" then
dim replace_file as string
replace_file = _trim$(mid$(client_cmd, 6))
replace_file=_trim$(mid$(client_cmd,6))
if _fileexists(replace_file) then
redim file(0) as string
if lcase$(right$(replace_file, 4)) = ".m3u" then
parsem3u replace_file, file()
if lcase$(right$(replace_file,4))=".m3u" then
parsem3u replace_file,file()
else
file(0) = replace_file
file(0)=replace_file
end if
i = -1
playnext = 1
i=-1
playnext=1
end if
elseif client_cmd = "GET_PLAYLIST" then
elseif client_cmd="GET_PLAYLIST" then
dim p_idx as long
dim playlist_payload as string
playlist_payload = "=== Current Playlist ===" + chr$(10)
for p_idx = lbound(file) to ubound(file)
if p_idx = i then
playlist_payload = playlist_payload + "-> " + file(p_idx) + chr$(10)
playlist_payload="=== Current Playlist ==="+chr$(10)
for p_idx=lbound(file) to ubound(file)
if p_idx=i then
playlist_payload=playlist_payload+"-> "+file(p_idx)+chr$(10)
else
playlist_payload = playlist_payload + " " + file(p_idx) + chr$(10)
playlist_payload=playlist_payload+" "+file(p_idx)+chr$(10)
end if
next p_idx
@ -314,7 +358,7 @@ while keyin<>27
ipc_send_message playlist_payload
_delay 0.1
dim reinit as long
reinit = ipc_init
reinit=ipc_init
end if
end if
' --- End Poll Client Messages ---
@ -416,7 +460,7 @@ while keyin<>27
if nooutput=0 then
tw=termwidth
fixedwidth=uwidth(state)+uwidth(progress)
maxtitlewidth=tw-fixedwidth-2
maxtitlewidth=tw-fixedwidth
currentsongwidth=uwidth(songname)
if currentsongwidth>maxtitlewidth and maxtitlewidth>4 then
@ -454,20 +498,20 @@ while keyin<>27
' Print the text line
if nyan=-1 then
print termcolor(7); state; animatedrainbowtext(visibletitle); termcolor(7); progress; clearrest
print termcolor(7);state;animatedrainbowtext(visibletitle);termcolor(7);progress;clearrest
else
print termcolor(7); state; termcolor(3); visibletitle; termcolor(7); progress; clearrest
print termcolor(7);state;termcolor(3);visibletitle;termcolor(7);progress;clearrest
end if
' Generate and print progress bar matching the layout width
progressbar=bar(uwidth(state)+uwidth(visibletitle)+uwidth(progress),(_sndgetpos(musichandle)/_sndlen(musichandle))*100,11,7)
print progressbar; clearrest; cursorback;
print progressbar;clearrest;cursorback;
end if
_limit 30
if _exit then goto quit
wend
wend
quit:
_sndclose musichandle
@ -494,42 +538,42 @@ sub parsem3u (filename$,array$())
dim basepath$,l$,resolvedpath$
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
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)
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)
timeelapsed$=right$("0"+ltrim$(str$(seconds\60)),2)+":"+right$("0"+ltrim$(str$(seconds mod 60)),2)
end function
function termcolor$ (colorvalue as _unsigned long)
@ -625,12 +669,9 @@ 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
if (b% and &h80)=0 or (b% and &hc0)=&hc0 then count%=count%+1
next
ulen%=count%
end function
@ -708,5 +749,37 @@ function getcodepoint& (utf8char$)
end function
sub loadsoundbank (filename as string)
_midisoundbank filename
_midisoundbank filename
end sub
function GetConfig$ (FileName as string)
select case left$(_os$,instr(_os$,"]"))
case "[WINDOWS]"
dim appdata as string
appdata=environ$("APPDATA")
if appdata="" then appdata=environ$("USERPROFILE")+"\AppData\Roaming"
if right$(appdata,1)<>"\" then appdata=appdata+"\"
GetConfig=appdata+FileName
case "[MACOSX]"
dim homemac as string
homemac=environ$("HOME")
if homemac="" then homemac="/tmp"
if right$(homemac,1)="/" then homemac=left$(homemac,len(homemac)-1)
GetConfig=homemac+"/Library/Application Support/"+FileName
case else ' Linux and other Unix-like systems
dim xdg as string,baseDir as string,homelinux as string
xdg=environ$("XDG_CONFIG_HOME")
if xdg<>"" then
baseDir=xdg
else
homelinux=environ$("HOME")
if homelinux="" then homelinux="/tmp"
baseDir=homelinux+"/.config"
end if
if right$(baseDir,1)="/" then baseDir=left$(baseDir,len(baseDir)-1)
GetConfig=baseDir+"/"+FileName
end select
end function

View file

@ -129,9 +129,8 @@ When interacting directly with the player interface terminal, use these keys:
## Supported Audio Formats
All formats supported by QB64/QB64PE are supported by cimp, as QB64 handles the
decoding. The following formats are supported by the most recent versions of
both compilers:
All formats supported by QB64PE are supported by cimp, as it handles the
decoding. The following formats are supported by the most recent version:
Audio files:
`mod`, `xm`, `s3m`, `it`, `mid`, `mp3`, `ogg`, and `flac`
@ -143,7 +142,7 @@ Sound banks:
| File | Description |
| ------------- | --------------------------------------------------------------------------------------- |
| `cimp.bas` | Main player — QB64-PE source handling client/server states and UI |
| `cimp.bas` | Main player - QB64 source handling client/server states and UI |
| `terminkey.h` | C library for cross-platform raw keyboard input, IPC pipes/sockets, and terminal sizing |
## Notes