Compare commits
No commits in common. "main" and "playlist" have entirely different histories.
|
@ -39,32 +39,6 @@ jobs:
|
||||||
overwrite: true
|
overwrite: true
|
||||||
include-hidden-files: true
|
include-hidden-files: true
|
||||||
if-no-files-found: error
|
if-no-files-found: error
|
||||||
build-deb:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: get-source-code
|
|
||||||
steps:
|
|
||||||
- name: Download and cache system dependencies
|
|
||||||
uses: https://complecwaft.com/catmeow/cache-apt-pkgs-action@latest
|
|
||||||
with:
|
|
||||||
packages: debhelper-compat devscripts cmake git python3 libprotobuf-dev protobuf-compiler libsoundtouch-dev libsdl2-dev libsdl2-image-dev qt6-base-dev liburiparser-dev libexpat1-dev libsdbus-c++-dev libsdbus-c++-bin build-essential zstd wget git-buildpackage libfmt-dev libogg-dev libvorbis-dev libmpg123-dev libportal-dev libjsoncpp-dev libfluidsynth-dev
|
|
||||||
version: 1.0
|
|
||||||
- name: Download repository code
|
|
||||||
uses: actions/download-artifact@v3
|
|
||||||
with:
|
|
||||||
name: source_archive
|
|
||||||
path: .
|
|
||||||
- name: Extract repository code
|
|
||||||
run: mkdir -p looper/subprojects/vgmstream/dependencies/{vorbis,ogg} && tar -xf source.tar.zst -C looper
|
|
||||||
- name: Build package
|
|
||||||
run: cd looper && gbp buildpackage --git-ignore-new
|
|
||||||
- name: Upload package artifacts
|
|
||||||
uses: actions/upload-artifact@v3
|
|
||||||
with:
|
|
||||||
name: debian-packages
|
|
||||||
path: ./looper*.deb
|
|
||||||
- name: Push package to repository
|
|
||||||
if: ${{vars.user != null && secrets.token != null}}
|
|
||||||
run: for i in looper*.deb; do curl --user ${{vars.user}}:${{secrets.token}} --upload-file "$i" https://complecwaft.com/api/packages/${{vars.user}}/debian/pool/bookworm/main/upload; done
|
|
||||||
build-appimage:
|
build-appimage:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: get-source-code
|
needs: get-source-code
|
||||||
|
|
8
.gitignore
vendored
|
@ -1,5 +1,4 @@
|
||||||
assets/*.h
|
assets/*.h
|
||||||
assets/*.hpp
|
|
||||||
build*
|
build*
|
||||||
!build-env
|
!build-env
|
||||||
.vscode/settings.json
|
.vscode/settings.json
|
||||||
|
@ -26,10 +25,3 @@ local.properties
|
||||||
hs_err_*.log
|
hs_err_*.log
|
||||||
replay_pid*.log
|
replay_pid*.log
|
||||||
assets/btcc
|
assets/btcc
|
||||||
.debhelper
|
|
||||||
/debian/looper
|
|
||||||
obj-*/
|
|
||||||
debian/files
|
|
||||||
debian/*.log
|
|
||||||
debian/debhelper-build-stamp
|
|
||||||
debian/*.substvars
|
|
||||||
|
|
|
@ -1,21 +0,0 @@
|
||||||
--- b/build-aux/config.guess 2009-03-06 16:08:51.041943040 -0800
|
|
||||||
+++ a/build-aux/config.guess 2024-12-08 11:12:59.774111232 -0800
|
|
||||||
@@ -121,7 +121,7 @@
|
|
||||||
fi ;
|
|
||||||
done ;
|
|
||||||
if test x"$CC_FOR_BUILD" = x ; then
|
|
||||||
- CC_FOR_BUILD=no_compiler_found ;
|
|
||||||
+ CC_FOR_BUILD=no_compiler_found ;
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
,,*) CC_FOR_BUILD=$CC ;;
|
|
||||||
@@ -1353,6 +1353,9 @@
|
|
||||||
i*86:AROS:*:*)
|
|
||||||
echo ${UNAME_MACHINE}-pc-aros
|
|
||||||
exit ;;
|
|
||||||
+ *:Haiku:*:*)
|
|
||||||
+ echo ${UNAME_MACHINE}-pc-haiku
|
|
||||||
+ exit ;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
#echo '(No uname command or uname output not recognized.)' 1>&2
|
|
|
@ -17,14 +17,14 @@ set(SDL_MIXER_X_SHARED OFF CACHE BOOL "")
|
||||||
set(DOWNLOAD_AUDIO_CODECS_DEPENDENCY OFF CACHE BOOL "")
|
set(DOWNLOAD_AUDIO_CODECS_DEPENDENCY OFF CACHE BOOL "")
|
||||||
set(AUDIO_CODECS_BUILD_LOCAL_SDL2 OFF CACHE BOOL "" FORCE)
|
set(AUDIO_CODECS_BUILD_LOCAL_SDL2 OFF CACHE BOOL "" FORCE)
|
||||||
set(MIXERX_LGPL ON CACHE BOOL "" FORCE)
|
set(MIXERX_LGPL ON CACHE BOOL "" FORCE)
|
||||||
set(USE_MIDI OFF CACHE BOOL "" FORCE)
|
set(USE_MIDI ON CACHE BOOL "" FORCE)
|
||||||
set(USE_MIDI_NATIVE_ALT OFF CACHE BOOL "" FORCE)
|
set(USE_MIDI_NATIVE_ALT OFF CACHE BOOL "" FORCE)
|
||||||
set(USE_MIDI_NATIVE OFF CACHE BOOL "" FORCE)
|
set(USE_MIDI_NATIVE OFF CACHE BOOL "" FORCE)
|
||||||
set(USE_MIDI_TIMIDITY OFF CACHE BOOL "" FORCE)
|
set(USE_MIDI_TIMIDITY OFF CACHE BOOL "" FORCE)
|
||||||
set(USE_MIDI_FLUIDLITE OFF CACHE BOOL "" FORCE)
|
set(USE_MIDI_FLUIDLITE OFF CACHE BOOL "" FORCE)
|
||||||
set(USE_MIDI_OPNMIDI OFF CACHE BOOL "" FORCE)
|
set(USE_MIDI_OPNMIDI OFF CACHE BOOL "" FORCE)
|
||||||
set(USE_MIDI_ADLMIDI OFF CACHE BOOL "" FORCE)
|
set(USE_MIDI_ADLMIDI OFF CACHE BOOL "" FORCE)
|
||||||
set(USE_MIDI_FLUIDSYNTH OFF CACHE BOOL "" FORCE)
|
set(USE_MIDI_FLUIDSYNTH ON CACHE BOOL "" FORCE)
|
||||||
set(CMAKE_C_STANDARD 99)
|
set(CMAKE_C_STANDARD 99)
|
||||||
set(CMAKE_C_STANDARD_REQUIRED ON)
|
set(CMAKE_C_STANDARD_REQUIRED ON)
|
||||||
set(BUILD_FB2K OFF CACHE BOOL "" FORCE)
|
set(BUILD_FB2K OFF CACHE BOOL "" FORCE)
|
||||||
|
@ -43,10 +43,6 @@ if (UNIX AND NOT APPLE AND NOT ANDROID AND NOT HAIKU)
|
||||||
option(ENABLE_DBUS "Enables DBus support" ON)
|
option(ENABLE_DBUS "Enables DBus support" ON)
|
||||||
endif()
|
endif()
|
||||||
option(BUILD_LIBFMT "Builds libfmt" OFF)
|
option(BUILD_LIBFMT "Builds libfmt" OFF)
|
||||||
if(NOT MSVC)
|
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC")
|
|
||||||
set(CMAKE_C_FLAGS "${CMAKE_CXX_FLAGS} -fPIC")
|
|
||||||
endif()
|
|
||||||
if(HAIKU)
|
if(HAIKU)
|
||||||
set(USE_CELT OFF CACHE BOOL "" FORCE)
|
set(USE_CELT OFF CACHE BOOL "" FORCE)
|
||||||
set(USE_SPEEX OFF CACHE BOOL "" FORCE)
|
set(USE_SPEEX OFF CACHE BOOL "" FORCE)
|
||||||
|
@ -315,8 +311,8 @@ prefix_all(LIBRARY_SOURCES
|
||||||
base85.h
|
base85.h
|
||||||
)
|
)
|
||||||
run_protoc(OUTDIR ${CMAKE_BINARY_DIR}/google/protobuf SOURCE google/protobuf/any.proto OUTVAR _src)
|
run_protoc(OUTDIR ${CMAKE_BINARY_DIR}/google/protobuf SOURCE google/protobuf/any.proto OUTVAR _src)
|
||||||
add_library(liblooper SHARED ${LIBRARY_SOURCES})
|
add_library(liblooper STATIC ${LIBRARY_SOURCES})
|
||||||
set_target_properties(liblooper PROPERTIES PREFIX "")
|
|
||||||
if(FOR_WASMER)
|
if(FOR_WASMER)
|
||||||
target_compile_definitions(liblooper PUBLIC FOR_WASMER)
|
target_compile_definitions(liblooper PUBLIC FOR_WASMER)
|
||||||
endif()
|
endif()
|
||||||
|
@ -347,7 +343,6 @@ if(BUILD_JSONCPP)
|
||||||
set(JSONCPP_TARGET jsoncpp_static)
|
set(JSONCPP_TARGET jsoncpp_static)
|
||||||
endif()
|
endif()
|
||||||
if(BUILD_SOUNDTOUCH)
|
if(BUILD_SOUNDTOUCH)
|
||||||
message("Building SoundTouch.")
|
|
||||||
set(SOUNDSTRETCH OFF CACHE BOOL "" FORCE)
|
set(SOUNDSTRETCH OFF CACHE BOOL "" FORCE)
|
||||||
set(INTEGER_SAMPLES OFF CACHE BOOL "")
|
set(INTEGER_SAMPLES OFF CACHE BOOL "")
|
||||||
add_subdirectory(subprojects/soundtouch)
|
add_subdirectory(subprojects/soundtouch)
|
||||||
|
@ -367,12 +362,12 @@ if (DEFINED ANDROID_NDK)
|
||||||
target_link_libraries(liblooper PUBLIC oboe)
|
target_link_libraries(liblooper PUBLIC oboe)
|
||||||
endif()
|
endif()
|
||||||
pkg_check_modules(libxspf IMPORTED_TARGET libxspf)
|
pkg_check_modules(libxspf IMPORTED_TARGET libxspf)
|
||||||
include(ExternalProject)
|
|
||||||
if (NOT libxspf_FOUND)
|
if (NOT libxspf_FOUND)
|
||||||
|
include(ExternalProject)
|
||||||
set(XSPF ${CMAKE_BINARY_DIR}/libxspf-prefix/src/libxspf-build/.libs/${CMAKE_STATIC_LIBRARY_PREFIX}xspf${CMAKE_STATIC_LIBRARY_SUFFIX})
|
set(XSPF ${CMAKE_BINARY_DIR}/libxspf-prefix/src/libxspf-build/.libs/${CMAKE_STATIC_LIBRARY_PREFIX}xspf${CMAKE_STATIC_LIBRARY_SUFFIX})
|
||||||
ExternalProject_Add(libxspf
|
ExternalProject_Add(libxspf
|
||||||
URL https://ftp.osuosl.org/pub/xiph/releases/xspf/libxspf-1.2.0.tar.lzma
|
URL https://ftp.osuosl.org/pub/xiph/releases/xspf/libxspf-1.2.0.tar.lzma
|
||||||
PATCH_COMMAND cd <SOURCE_DIR> && patch -Np1 -i ${CMAKE_SOURCE_DIR}/01-xspf-no-examples.patch && patch -Np1 -i ${CMAKE_SOURCE_DIR}/02-xspf-haiku.patch
|
PATCH_COMMAND cd <SOURCE_DIR> && patch -Np1 -i ${CMAKE_SOURCE_DIR}/xspf-no-examples.patch
|
||||||
CONFIGURE_COMMAND <SOURCE_DIR>/configure --disable-test --enable-static --disable-shared
|
CONFIGURE_COMMAND <SOURCE_DIR>/configure --disable-test --enable-static --disable-shared
|
||||||
BUILD_COMMAND make
|
BUILD_COMMAND make
|
||||||
INSTALL_COMMAND make install DESTDIR=<BINARY_DIR>
|
INSTALL_COMMAND make install DESTDIR=<BINARY_DIR>
|
||||||
|
@ -418,34 +413,28 @@ else()
|
||||||
target_link_libraries(SDL2_image::SDL2_image INTERFACE ${sdl2_image_LIBRARIES})
|
target_link_libraries(SDL2_image::SDL2_image INTERFACE ${sdl2_image_LIBRARIES})
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
if (WINDOWS)
|
|
||||||
set(ENABLE_DBUS OFF CACHE BOOL "" FORCE)
|
|
||||||
endif()
|
|
||||||
if (ENABLE_DBUS)
|
if (ENABLE_DBUS)
|
||||||
find_package(sdbus-c++ 2.0)
|
|
||||||
if(${sdbus-c++_FOUND})
|
|
||||||
set(OLD_SDBUS OFF)
|
|
||||||
else()
|
|
||||||
find_package(sdbus-c++)
|
find_package(sdbus-c++)
|
||||||
if (${sdbus-c++_FOUND})
|
if(NOT ${sdbus-c++_FOUND})
|
||||||
set(OLD_SDBUS ON)
|
|
||||||
else()
|
|
||||||
set(OLD_SDBUS ON)
|
|
||||||
set(ENABLE_DBUS OFF)
|
set(ENABLE_DBUS OFF)
|
||||||
message("Warning: Dbus support not found - Not enabling DBus. This program requires version 2.0 or later.")
|
message("Warning: Dbus support not found - Not enabling DBus")
|
||||||
endif()
|
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
set(SDL2_TARGET SDL2::SDL2)
|
set(SDL2_TARGET SDL2::SDL2)
|
||||||
if (TARGET SDL2-static)
|
if (TARGET SDL2-static)
|
||||||
set(SDL2_TARGET SDL2-static)
|
set(SDL2_TARGET SDL2-static)
|
||||||
endif()
|
endif()
|
||||||
target_link_libraries(liblooper PUBLIC ${SDL2_TARGET} ${SDL_MIXER_X_TARGET} ${SOUNDTOUCH_TARGET} libvgmstream_shared ${JSONCPP_TARGET})
|
target_link_libraries(liblooper PUBLIC ${SDL2_TARGET} ${SDL_MIXER_X_TARGET} ${SOUNDTOUCH_TARGET} libvgmstream ${JSONCPP_TARGET})
|
||||||
endif()
|
endif()
|
||||||
if(BUILD_PROTOBUF)
|
if(BUILD_PROTOBUF)
|
||||||
add_subdirectory(subprojects/protobuf)
|
add_subdirectory(subprojects/protobuf)
|
||||||
else()
|
else()
|
||||||
|
if (CMAKE_SYSTEM_NAME STREQUAL "Haiku")
|
||||||
find_package(Protobuf REQUIRED)
|
find_package(Protobuf REQUIRED)
|
||||||
|
else()
|
||||||
|
find_package(protobuf REQUIRED)
|
||||||
|
find_package(absl CONFIG REQUIRED)
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (${ENABLE_DBUS})
|
if (${ENABLE_DBUS})
|
||||||
|
@ -455,8 +444,7 @@ endif()
|
||||||
macro(add_ui_backend)
|
macro(add_ui_backend)
|
||||||
set(ARGS ${ARGV})
|
set(ARGS ${ARGV})
|
||||||
list(POP_FRONT ARGS target)
|
list(POP_FRONT ARGS target)
|
||||||
add_library(${target} SHARED ${ARGS})
|
add_library(${target} STATIC ${ARGS})
|
||||||
set_target_properties(${target} PROPERTIES LIBRARY_OUTPUT_NAME looper_frontend_${target})
|
|
||||||
message("Enabling UI backend '" ${target} "'...")
|
message("Enabling UI backend '" ${target} "'...")
|
||||||
list(APPEND UI_BACKENDS ${target})
|
list(APPEND UI_BACKENDS ${target})
|
||||||
set(UI_BACKENDS ${UI_BACKENDS} PARENT_SCOPE)
|
set(UI_BACKENDS ${UI_BACKENDS} PARENT_SCOPE)
|
||||||
|
@ -491,8 +479,7 @@ endmacro()
|
||||||
macro(add_playback_backend)
|
macro(add_playback_backend)
|
||||||
set(ARGS ${ARGV})
|
set(ARGS ${ARGV})
|
||||||
list(POP_FRONT ARGS target)
|
list(POP_FRONT ARGS target)
|
||||||
add_library(${target} SHARED ${ARGS})
|
add_library(${target} STATIC ${ARGS})
|
||||||
set_target_properties(${target} PROPERTIES LIBRARY_OUTPUT_NAME looper_playback_backend_${target})
|
|
||||||
message("Enabling playback backend '" ${target} "'...")
|
message("Enabling playback backend '" ${target} "'...")
|
||||||
list(APPEND PLAYBACK_BACKENDS ${target})
|
list(APPEND PLAYBACK_BACKENDS ${target})
|
||||||
set(PLAYBACK_BACKENDS ${PLAYBACK_BACKENDS} PARENT_SCOPE)
|
set(PLAYBACK_BACKENDS ${PLAYBACK_BACKENDS} PARENT_SCOPE)
|
||||||
|
@ -528,8 +515,6 @@ endif()
|
||||||
playback_backend_subdir(NAME "VGMSTREAM" READABLE_NAME "VgmStream" SUBDIR backends/playback/vgmstream)
|
playback_backend_subdir(NAME "VGMSTREAM" READABLE_NAME "VgmStream" SUBDIR backends/playback/vgmstream)
|
||||||
playback_backend_subdir(NAME "SDL_MIXER_X" READABLE_NAME "SDL Mixer X" SUBDIR backends/playback/sdl_mixer_x)
|
playback_backend_subdir(NAME "SDL_MIXER_X" READABLE_NAME "SDL Mixer X" SUBDIR backends/playback/sdl_mixer_x)
|
||||||
playback_backend_subdir(NAME "ZSM" READABLE_NAME "ZSM" SUBDIR backends/playback/zsm)
|
playback_backend_subdir(NAME "ZSM" READABLE_NAME "ZSM" SUBDIR backends/playback/zsm)
|
||||||
playback_backend_subdir(NAME "FLUIDSYNTH" READABLE_NAME "Fluidsynth" SUBDIR backends/playback/fluidsynth)
|
|
||||||
playback_backend_subdir(NAME "GME" READABLE_NAME "Game Music Emu" SUBDIR backends/playback/gme)
|
|
||||||
execute_process(COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/gen_ui_backend_inc.py ${CMAKE_CURRENT_BINARY_DIR} --ui ${ENABLED_UIS} --playback ${ENABLED_PLAYBACK_BACKENDS})
|
execute_process(COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/gen_ui_backend_inc.py ${CMAKE_CURRENT_BINARY_DIR} --ui ${ENABLED_UIS} --playback ${ENABLED_PLAYBACK_BACKENDS})
|
||||||
prefix_all(SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/ main.cpp daemon_backend.cpp daemon_backend.hpp proxy_backend.cpp proxy_backend.hpp)
|
prefix_all(SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/ main.cpp daemon_backend.cpp daemon_backend.hpp proxy_backend.cpp proxy_backend.hpp)
|
||||||
list(APPEND SOURCES ${CMAKE_CURRENT_BINARY_DIR}/backend_glue.cpp)
|
list(APPEND SOURCES ${CMAKE_CURRENT_BINARY_DIR}/backend_glue.cpp)
|
||||||
|
@ -576,15 +561,12 @@ if(DEFINED EMSCRIPTEN)
|
||||||
copy_to_bindir(assets/ForkAwesome/css/fork-awesome.min.css.map fork-awesome.min.css.map)
|
copy_to_bindir(assets/ForkAwesome/css/fork-awesome.min.css.map fork-awesome.min.css.map)
|
||||||
endif()
|
endif()
|
||||||
target_link_libraries(${TARGET_NAME} PUBLIC liblooper ${UI_BACKENDS} ${PLAYBACK_BACKENDS})
|
target_link_libraries(${TARGET_NAME} PUBLIC liblooper ${UI_BACKENDS} ${PLAYBACK_BACKENDS})
|
||||||
install(TARGETS ${TARGET_NAME} liblooper ${EXTRA_LIBS} ${UI_BACKENDS} ${PLAYBACK_BACKENDS})
|
install(TARGETS ${TARGET_NAME} ${EXTRA_LIBS})
|
||||||
if (UNIX AND NOT APPLE)
|
|
||||||
install(FILES assets/zsm-mime.xml DESTINATION ${CMAKE_INSTALL_DATADIR}/mime/audio RENAME x-zsound.xml)
|
|
||||||
endif()
|
|
||||||
if (${BUILD_SDL2})
|
if (${BUILD_SDL2})
|
||||||
install(EXPORT SDL2-static SDL2main)
|
install(EXPORT SDL2-static SDL2main)
|
||||||
endif()
|
endif()
|
||||||
if (NOT DEFINED EMSCRIPTEN)
|
if (NOT DEFINED EMSCRIPTEN)
|
||||||
install(FILES assets/icon.svg DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/scalable/apps/ RENAME looper.svg)
|
install(FILES assets/icon.svg DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/scalable/apps/)
|
||||||
install(FILES assets/com.complecwaft.Looper.desktop DESTINATION ${CMAKE_INSTALL_DATADIR}/applications)
|
install(FILES assets/com.complecwaft.Looper.desktop DESTINATION ${CMAKE_INSTALL_DATADIR}/applications)
|
||||||
install(FILES assets/com.complecwaft.Looper.metainfo.xml DESTINATION ${CMAKE_INSTALL_DATADIR}/metainfo)
|
install(FILES assets/com.complecwaft.Looper.metainfo.xml DESTINATION ${CMAKE_INSTALL_DATADIR}/metainfo)
|
||||||
install(DIRECTORY assets/translations/ TYPE LOCALE PATTERN "*" EXCLUDE PATTERN "looper.pot")
|
install(DIRECTORY assets/translations/ TYPE LOCALE PATTERN "*" EXCLUDE PATTERN "looper.pot")
|
||||||
|
@ -614,7 +596,3 @@ if(TESTS)
|
||||||
target_link_libraries(liblooper PUBLIC gtest_main)
|
target_link_libraries(liblooper PUBLIC gtest_main)
|
||||||
target_compile_definitions(liblooper PUBLIC TESTS)
|
target_compile_definitions(liblooper PUBLIC TESTS)
|
||||||
endif()
|
endif()
|
||||||
set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON)
|
|
||||||
set(CPACK_DEBIAN_PACKAGE_GENERATE_SHLIBS ON)
|
|
||||||
set(CPACK_DEBIAN_PACKAGE_MAINTAINER "Catmeow72")
|
|
||||||
include(CPack)
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"version": 6,
|
"version": 9,
|
||||||
"cmakeMinimumRequired": {
|
"cmakeMinimumRequired": {
|
||||||
"major": 3,
|
"major": 3,
|
||||||
"minor": 23,
|
"minor": 23,
|
||||||
|
|
BIN
assets/catoc.png
Before Width: | Height: | Size: 64 KiB |
493
assets/catoc.svg
|
@ -1,493 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
||||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
|
||||||
|
|
||||||
<svg
|
|
||||||
width="535"
|
|
||||||
height="1000"
|
|
||||||
viewBox="0 0 141.55207 264.58331"
|
|
||||||
version="1.1"
|
|
||||||
id="svg1"
|
|
||||||
inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
|
|
||||||
sodipodi:docname="catoc.svg"
|
|
||||||
inkscape:export-filename="catoc.png"
|
|
||||||
inkscape:export-xdpi="24.576"
|
|
||||||
inkscape:export-ydpi="24.576"
|
|
||||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
|
||||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
|
||||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
xmlns:svg="http://www.w3.org/2000/svg">
|
|
||||||
<sodipodi:namedview
|
|
||||||
id="namedview1"
|
|
||||||
pagecolor="#ffffff"
|
|
||||||
bordercolor="#000000"
|
|
||||||
borderopacity="0.25"
|
|
||||||
inkscape:showpageshadow="2"
|
|
||||||
inkscape:pageopacity="0.0"
|
|
||||||
inkscape:pagecheckerboard="0"
|
|
||||||
inkscape:deskcolor="#d1d1d1"
|
|
||||||
inkscape:document-units="mm"
|
|
||||||
inkscape:zoom="0.64"
|
|
||||||
inkscape:cx="-82.03125"
|
|
||||||
inkscape:cy="670.3125"
|
|
||||||
inkscape:window-width="1280"
|
|
||||||
inkscape:window-height="963"
|
|
||||||
inkscape:window-x="0"
|
|
||||||
inkscape:window-y="61"
|
|
||||||
inkscape:window-maximized="1"
|
|
||||||
inkscape:current-layer="layer1"
|
|
||||||
showguides="false"
|
|
||||||
showgrid="false" />
|
|
||||||
<defs
|
|
||||||
id="defs1">
|
|
||||||
<linearGradient
|
|
||||||
id="linearGradient2"
|
|
||||||
inkscape:collect="always">
|
|
||||||
<stop
|
|
||||||
style="stop-color:#3155a7;stop-opacity:1;"
|
|
||||||
offset="0"
|
|
||||||
id="stop1" />
|
|
||||||
<stop
|
|
||||||
style="stop-color:#3155a7;stop-opacity:1;"
|
|
||||||
offset="0.15000001"
|
|
||||||
id="stop4" />
|
|
||||||
<stop
|
|
||||||
style="stop-color:#6a00d8;stop-opacity:1;"
|
|
||||||
offset="0.15000001"
|
|
||||||
id="stop3" />
|
|
||||||
<stop
|
|
||||||
style="stop-color:#6a00d8;stop-opacity:1;"
|
|
||||||
offset="0.30000001"
|
|
||||||
id="stop5" />
|
|
||||||
<stop
|
|
||||||
style="stop-color:#3155a7;stop-opacity:1;"
|
|
||||||
offset="0.30000001"
|
|
||||||
id="stop6" />
|
|
||||||
<stop
|
|
||||||
style="stop-color:#3155a7;stop-opacity:1;"
|
|
||||||
offset="0.44710121"
|
|
||||||
id="stop7" />
|
|
||||||
<stop
|
|
||||||
style="stop-color:#6a00d8;stop-opacity:1;"
|
|
||||||
offset="0.44710121"
|
|
||||||
id="stop8" />
|
|
||||||
<stop
|
|
||||||
style="stop-color:#6a00d8;stop-opacity:1;"
|
|
||||||
offset="0.59767956"
|
|
||||||
id="stop9" />
|
|
||||||
<stop
|
|
||||||
style="stop-color:#3155a7;stop-opacity:1;"
|
|
||||||
offset="0.59847426"
|
|
||||||
id="stop10" />
|
|
||||||
<stop
|
|
||||||
style="stop-color:#3155a7;stop-opacity:1;"
|
|
||||||
offset="0.74785447"
|
|
||||||
id="stop11" />
|
|
||||||
<stop
|
|
||||||
style="stop-color:#6a00d8;stop-opacity:1;"
|
|
||||||
offset="0.75"
|
|
||||||
id="stop13" />
|
|
||||||
<stop
|
|
||||||
style="stop-color:#6a00d8;stop-opacity:1;"
|
|
||||||
offset="0.89999998"
|
|
||||||
id="stop12" />
|
|
||||||
<stop
|
|
||||||
style="stop-color:#3155a7;stop-opacity:1;"
|
|
||||||
offset="0.89999998"
|
|
||||||
id="stop14" />
|
|
||||||
<stop
|
|
||||||
style="stop-color:#3155a7;stop-opacity:1;"
|
|
||||||
offset="1"
|
|
||||||
id="stop2" />
|
|
||||||
</linearGradient>
|
|
||||||
<linearGradient
|
|
||||||
inkscape:collect="always"
|
|
||||||
xlink:href="#linearGradient2"
|
|
||||||
id="linearGradient59"
|
|
||||||
x1="9.3510761"
|
|
||||||
y1="100.67726"
|
|
||||||
x2="110.34445"
|
|
||||||
y2="100.67726"
|
|
||||||
gradientUnits="userSpaceOnUse" />
|
|
||||||
<linearGradient
|
|
||||||
inkscape:collect="always"
|
|
||||||
xlink:href="#linearGradient2"
|
|
||||||
id="linearGradient60"
|
|
||||||
x1="9.5552998"
|
|
||||||
y1="97.639015"
|
|
||||||
x2="103.40803"
|
|
||||||
y2="97.639015"
|
|
||||||
gradientUnits="userSpaceOnUse" />
|
|
||||||
<linearGradient
|
|
||||||
inkscape:collect="always"
|
|
||||||
xlink:href="#linearGradient2"
|
|
||||||
id="linearGradient61"
|
|
||||||
x1="9.3773193"
|
|
||||||
y1="104.65613"
|
|
||||||
x2="104.10086"
|
|
||||||
y2="104.65613"
|
|
||||||
gradientUnits="userSpaceOnUse" />
|
|
||||||
<filter
|
|
||||||
inkscape:label="Opacity"
|
|
||||||
style="color-interpolation-filters:sRGB;"
|
|
||||||
id="filter23"
|
|
||||||
x="-0.0014374264"
|
|
||||||
y="-0.007162038"
|
|
||||||
width="1.0028749"
|
|
||||||
height="1.0143241">
|
|
||||||
<feColorMatrix
|
|
||||||
values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 5 -1 "
|
|
||||||
result="colormatrix"
|
|
||||||
id="feColorMatrix23" />
|
|
||||||
<feComposite
|
|
||||||
in2="colormatrix"
|
|
||||||
operator="arithmetic"
|
|
||||||
k2="0.5"
|
|
||||||
result="composite"
|
|
||||||
id="feComposite23" />
|
|
||||||
</filter>
|
|
||||||
</defs>
|
|
||||||
<g
|
|
||||||
inkscape:label="Head"
|
|
||||||
inkscape:groupmode="layer"
|
|
||||||
id="layer1">
|
|
||||||
<g
|
|
||||||
id="g50"
|
|
||||||
inkscape:label="Tail">
|
|
||||||
<path
|
|
||||||
style="fill:#7f5e26;fill-opacity:1;stroke:#000000;stroke-width:2.117;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:normal"
|
|
||||||
d="m 81.31513,201.57342 c 0,0 44.65674,2.06431 52.75519,-16.5361 8.09842,-18.60041 6.16431,-44.43869 6.16431,-44.43869 0,0 2.16066,-12.67379 -6.04901,-12.76544 -8.20968,-0.0917 -6.02588,14.46574 -6.02588,14.46574 0.024,0.82478 2.30658,45.23958 -20.11661,46.5612 -21.45737,1.26469 -26.07784,4.79133 -26.44439,-1.84445 z"
|
|
||||||
id="path38"
|
|
||||||
sodipodi:nodetypes="cscscscc"
|
|
||||||
inkscape:label="Tail BG" />
|
|
||||||
<path
|
|
||||||
d="m 140.20217,141.17324 c 0,0 2.16066,-12.6738 -6.049,-12.76545 -8.20967,-0.0916 -5.90345,13.21277 -5.90345,13.21277"
|
|
||||||
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:2.117;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:normal"
|
|
||||||
id="path1"
|
|
||||||
sodipodi:nodetypes="csc"
|
|
||||||
inkscape:label="Tail Tip" />
|
|
||||||
</g>
|
|
||||||
<path
|
|
||||||
id="path37-6"
|
|
||||||
style="fill:#7f5e26;fill-opacity:1;stroke:none;stroke-width:2.117;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:normal"
|
|
||||||
inkscape:label="BG"
|
|
||||||
d="M 55.3035,8.4955596 C 25.344765,8.4954496 1.0583871,32.715097 1.0585001,62.591508 c 0.05254,17.299173 8.398299,33.529924 22.4539769,43.668282 -11.643,3.58532 -16.6885119,10.11067 -18.6377609,25.95713 l -0.086159,41.94243 c 0,0 0.1588792,8.39256 7.4463319,7.75774 7.556655,-0.65827 6.525522,-9.32683 6.525522,-9.32683 l 2.617341,-44.10625 c 0.361695,14.81035 0.285403,55.63255 1.778478,73.45536 2.489066,7.93619 4.366747,14.09362 12.481949,15.10093 v 38.14935 c 0,0 2.26e-4,8.33511 8.358064,8.33511 8.357847,0 8.357347,-8.33511 8.357347,-8.33511 v -36.81917 c 1.50095,0.0507 3.002,0.0815 4.50548,0.0927 v 36.72655 c 0,0 -4.9e-4,8.33511 8.35735,8.33511 8.35783,0 8.35806,-8.33511 8.35806,-8.33511 v -37.49538 c 8.40465,-0.8609 11.03872,-10.43343 12.78036,-16.78447 1.88113,-23.6903 -1.01595,-50.65735 0.72463,-72.60112 l 4.34539,43.55489 c 0,0 0.553951,7.50293 7.272843,6.69329 6.896977,-0.8311 6.426267,-5.46934 6.426267,-5.46934 l 1.94888,-42.84854 C 106.26406,113.49311 103.10594,110.76612 87.08948,106.26414 101.1483,96.125962 109.49617,79.893145 109.5485,62.591548 109.54862,32.715137 85.26223,8.4954896 55.3035,8.4955996 Z"
|
|
||||||
sodipodi:nodetypes="cccccscccccsccccscccccscccccc" />
|
|
||||||
<g
|
|
||||||
id="g33"
|
|
||||||
inkscape:label="Eyes"
|
|
||||||
transform="matrix(1.3929758,0,0,1.3891483,-19.917224,-15.351834)"
|
|
||||||
style="stroke-width:0.718876">
|
|
||||||
<g
|
|
||||||
id="g22"
|
|
||||||
transform="matrix(1.5232552,0,0,1.5232552,-35.323913,-24.272608)"
|
|
||||||
style="stroke-width:0.471934"
|
|
||||||
inkscape:label="Right">
|
|
||||||
<circle
|
|
||||||
style="fill:#8e37e8;fill-opacity:1;stroke:#000000;stroke-width:0.471934;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:normal"
|
|
||||||
id="path8-3"
|
|
||||||
cy="49.415627"
|
|
||||||
cx="63.892059"
|
|
||||||
r="3.6106884"
|
|
||||||
inkscape:label="BG" />
|
|
||||||
<ellipse
|
|
||||||
style="fill:#0a0213;fill-opacity:1;stroke:none;stroke-width:0.471934;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:normal"
|
|
||||||
id="path21-2"
|
|
||||||
cx="63.892059"
|
|
||||||
cy="49.415627"
|
|
||||||
rx="1.5"
|
|
||||||
ry="2.3700783"
|
|
||||||
inkscape:label="Pupil" />
|
|
||||||
</g>
|
|
||||||
<g
|
|
||||||
id="g21"
|
|
||||||
transform="matrix(1.5232552,0,0,1.5232552,-21.191835,-24.069739)"
|
|
||||||
style="stroke-width:0.471934"
|
|
||||||
inkscape:label="Left">
|
|
||||||
<circle
|
|
||||||
style="fill:#8e37e8;fill-opacity:1;stroke:#000000;stroke-width:0.471934;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:normal"
|
|
||||||
id="path8"
|
|
||||||
cy="49.282444"
|
|
||||||
cx="44.110687"
|
|
||||||
r="3.6106884"
|
|
||||||
inkscape:label="BG" />
|
|
||||||
<ellipse
|
|
||||||
style="fill:#0a0213;fill-opacity:1;stroke:none;stroke-width:0.471934;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:normal"
|
|
||||||
id="path21"
|
|
||||||
cx="44.133587"
|
|
||||||
cy="49.14122"
|
|
||||||
rx="1.5"
|
|
||||||
ry="2.3700783"
|
|
||||||
inkscape:label="Pupil" />
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
<g
|
|
||||||
id="g29"
|
|
||||||
inkscape:label="Mouth"
|
|
||||||
transform="matrix(1.8992416,0,0,1.9433789,-46.72397,-43.132852)"
|
|
||||||
style="stroke-width:0.520513">
|
|
||||||
<path
|
|
||||||
id="path7"
|
|
||||||
style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.520513;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:normal"
|
|
||||||
inkscape:label="Mouth"
|
|
||||||
d="m 44.91884,65.772675 c 0,0 0.315319,2.172806 4.400627,2.172806 4.274019,0 4.608539,-2.121784 4.608539,-2.121784 0,0 0.465709,2.146332 4.192716,2.146332 4.017862,0 4.400628,-2.147625 4.400628,-2.147625"
|
|
||||||
sodipodi:nodetypes="cscsc" />
|
|
||||||
<g
|
|
||||||
id="g28"
|
|
||||||
inkscape:label="Right Whiskers"
|
|
||||||
style="stroke-width:0.520513">
|
|
||||||
<path
|
|
||||||
style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.520513;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:normal"
|
|
||||||
d="M 40.952837,63.163701 32.127438,60.798942"
|
|
||||||
id="path27" />
|
|
||||||
<path
|
|
||||||
style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.520513;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:normal"
|
|
||||||
d="M 41.153873,64.908123 H 30.687658"
|
|
||||||
id="path25" />
|
|
||||||
<path
|
|
||||||
style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.520513;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:normal"
|
|
||||||
d="m 41.038936,66.695674 -8.423664,2.257115"
|
|
||||||
id="path26" />
|
|
||||||
</g>
|
|
||||||
<g
|
|
||||||
id="g27"
|
|
||||||
inkscape:label="Left Whiskers"
|
|
||||||
style="stroke-width:0.520513">
|
|
||||||
<path
|
|
||||||
style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.520513;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:normal"
|
|
||||||
d="M 66.286649,64.975847 H 76.752864"
|
|
||||||
id="path25-9" />
|
|
||||||
<path
|
|
||||||
style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.520513;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:normal"
|
|
||||||
d="m 66.401586,66.763398 8.423664,2.257115"
|
|
||||||
id="path26-3" />
|
|
||||||
<path
|
|
||||||
style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.520513;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:normal"
|
|
||||||
d="m 66.487685,63.231425 8.825399,-2.364759"
|
|
||||||
id="path27-1" />
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
<g
|
|
||||||
id="g36"
|
|
||||||
inkscape:label="Nose"
|
|
||||||
transform="matrix(1.3929758,0,0,1.3891483,-0.41556395,-0.413298)"
|
|
||||||
style="stroke-width:0.718876">
|
|
||||||
<path
|
|
||||||
style="fill:#660d0d;fill-opacity:1;stroke:#000000;stroke-width:0.718876;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:normal"
|
|
||||||
d="M 40.325309,60.936139 35,55 h 10 z"
|
|
||||||
id="path34"
|
|
||||||
sodipodi:nodetypes="cccc"
|
|
||||||
inkscape:label="BG" />
|
|
||||||
<g
|
|
||||||
id="g37"
|
|
||||||
inkscape:label="Nose Holes"
|
|
||||||
style="stroke-width:0.718876">
|
|
||||||
<circle
|
|
||||||
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.718876;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:normal"
|
|
||||||
id="path35"
|
|
||||||
cx="38.5"
|
|
||||||
cy="56.499996"
|
|
||||||
r="0.5" />
|
|
||||||
<circle
|
|
||||||
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.718876;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:normal"
|
|
||||||
id="path35-6"
|
|
||||||
cx="41.5"
|
|
||||||
cy="56.5"
|
|
||||||
r="0.5"
|
|
||||||
inkscape:label="path35-6" />
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
<g
|
|
||||||
id="g49"
|
|
||||||
inkscape:label="Paw Pads"
|
|
||||||
transform="matrix(1,0,0,0.82665321,0,29.198221)"
|
|
||||||
style="stroke-width:1.09986">
|
|
||||||
<g
|
|
||||||
id="g39"
|
|
||||||
transform="matrix(1.3929758,0,0,1.3891483,-70.497406,-13.791684)"
|
|
||||||
style="stroke-width:0.790665">
|
|
||||||
<path
|
|
||||||
id="path39"
|
|
||||||
style="fill:#b862d3;fill-opacity:1;stroke:#000000;stroke-width:0.197666;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
|
|
||||||
d="m 56.884125,138.58073 c 0,0.69984 -0.26898,1.11549 -0.600782,1.11549 -0.331801,0 -0.600781,-0.42038 -0.600781,-1.11549 0,-0.67707 0.268978,-1.1155 0.600781,-1.1155 0.331804,0 0.600782,0.41882 0.600782,1.1155 z"
|
|
||||||
sodipodi:nodetypes="sssss" />
|
|
||||||
<path
|
|
||||||
id="path39-2"
|
|
||||||
style="fill:#b862d3;fill-opacity:1;stroke:#000000;stroke-width:0.197666;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
|
|
||||||
d="m 59.997876,139.85128 c 0,0.69984 -0.26898,1.11549 -0.600782,1.11549 -0.331801,0 -0.600781,-0.42038 -0.600781,-1.11549 0,-0.67707 0.268978,-1.1155 0.600781,-1.1155 0.331804,0 0.600782,0.41882 0.600782,1.1155 z"
|
|
||||||
sodipodi:nodetypes="sssss" />
|
|
||||||
<path
|
|
||||||
id="path39-2-8"
|
|
||||||
style="fill:#b862d3;fill-opacity:1;stroke:#000000;stroke-width:0.197666;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
|
|
||||||
d="m 58.325884,139.93293 c 0,0.69984 -0.26898,1.11549 -0.600782,1.11549 -0.331801,0 -0.600781,-0.42038 -0.600781,-1.11549 0,-0.67707 0.268978,-1.1155 0.600781,-1.1155 0.331804,0 0.600782,0.41882 0.600782,1.1155 z"
|
|
||||||
sodipodi:nodetypes="sssss" />
|
|
||||||
<path
|
|
||||||
id="path39-4"
|
|
||||||
style="fill:#b862d3;fill-opacity:1;stroke:#000000;stroke-width:0.197666;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
|
|
||||||
d="m 61.592165,138.07349 c 0,0.69984 -0.26898,1.11549 -0.600782,1.11549 -0.331801,0 -0.600781,-0.42038 -0.600781,-1.11549 0,-0.67707 0.268978,-1.1155 0.600781,-1.1155 0.331804,0 0.600782,0.41882 0.600782,1.1155 z"
|
|
||||||
sodipodi:nodetypes="sssss" />
|
|
||||||
<path
|
|
||||||
id="path39-7"
|
|
||||||
style="fill:#b862d3;fill-opacity:1;stroke:#000000;stroke-width:0.197666;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
|
|
||||||
d="m 60.961403,135.10548 c 0,0.79141 -0.304435,1.41111 -0.752213,1.51736 -0.493691,0.11707 -0.626988,0.36745 -0.847147,0.64265 -0.182081,0.22762 -0.07256,1.15351 -0.887792,1.15351 -0.827635,0 -0.65112,-0.91251 -0.931846,-1.16492 -0.281516,-0.25307 -0.574749,-0.51043 -0.929047,-0.56656 -0.504565,-0.0799 -0.692101,-0.70847 -0.692101,-1.49454 0,-1.53131 1.138003,-1.81964 2.62222,-1.82979 1.372821,-0.01 2.417926,0.16663 2.417926,1.74229 z"
|
|
||||||
sodipodi:nodetypes="sssssssss" />
|
|
||||||
</g>
|
|
||||||
<g
|
|
||||||
id="g39-4"
|
|
||||||
transform="matrix(1.3929758,0,0,1.3891483,17.273715,-16.822661)"
|
|
||||||
style="stroke-width:0.790665">
|
|
||||||
<path
|
|
||||||
id="path39-9"
|
|
||||||
style="fill:#b862d3;fill-opacity:1;stroke:#000000;stroke-width:0.197666;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
|
|
||||||
d="m 56.884125,138.58073 c 0,0.69984 -0.26898,1.11549 -0.600782,1.11549 -0.331801,0 -0.600781,-0.42038 -0.600781,-1.11549 0,-0.67707 0.268978,-1.1155 0.600781,-1.1155 0.331804,0 0.600782,0.41882 0.600782,1.1155 z"
|
|
||||||
sodipodi:nodetypes="sssss" />
|
|
||||||
<path
|
|
||||||
id="path39-2-2"
|
|
||||||
style="fill:#b862d3;fill-opacity:1;stroke:#000000;stroke-width:0.197666;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
|
|
||||||
d="m 59.997876,139.85128 c 0,0.69984 -0.26898,1.11549 -0.600782,1.11549 -0.331801,0 -0.600781,-0.42038 -0.600781,-1.11549 0,-0.67707 0.268978,-1.1155 0.600781,-1.1155 0.331804,0 0.600782,0.41882 0.600782,1.1155 z"
|
|
||||||
sodipodi:nodetypes="sssss" />
|
|
||||||
<path
|
|
||||||
id="path39-2-8-0"
|
|
||||||
style="fill:#b862d3;fill-opacity:1;stroke:#000000;stroke-width:0.197666;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
|
|
||||||
d="m 58.325884,139.93293 c 0,0.69984 -0.26898,1.11549 -0.600782,1.11549 -0.331801,0 -0.600781,-0.42038 -0.600781,-1.11549 0,-0.67707 0.268978,-1.1155 0.600781,-1.1155 0.331804,0 0.600782,0.41882 0.600782,1.1155 z"
|
|
||||||
sodipodi:nodetypes="sssss" />
|
|
||||||
<path
|
|
||||||
id="path39-4-6"
|
|
||||||
style="fill:#b862d3;fill-opacity:1;stroke:#000000;stroke-width:0.197666;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
|
|
||||||
d="m 61.592165,138.07349 c 0,0.69984 -0.26898,1.11549 -0.600782,1.11549 -0.331801,0 -0.600781,-0.42038 -0.600781,-1.11549 0,-0.67707 0.268978,-1.1155 0.600781,-1.1155 0.331804,0 0.600782,0.41882 0.600782,1.1155 z"
|
|
||||||
sodipodi:nodetypes="sssss" />
|
|
||||||
<path
|
|
||||||
id="path39-7-8"
|
|
||||||
style="fill:#b862d3;fill-opacity:1;stroke:#000000;stroke-width:0.197666;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
|
|
||||||
d="m 60.961403,135.10548 c 0,0.79141 -0.304435,1.41111 -0.752213,1.51736 -0.493691,0.11707 -0.626988,0.36745 -0.847147,0.64265 -0.182081,0.22762 -0.07256,1.15351 -0.887792,1.15351 -0.827635,0 -0.65112,-0.91251 -0.931846,-1.16492 -0.281516,-0.25307 -0.574749,-0.51043 -0.929047,-0.56656 -0.504565,-0.0799 -0.692101,-0.70847 -0.692101,-1.49454 0,-1.53131 1.138003,-1.81964 2.62222,-1.82979 1.372821,-0.01 2.417926,0.16663 2.417926,1.74229 z"
|
|
||||||
sodipodi:nodetypes="sssssssss" />
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
<g
|
|
||||||
id="g48"
|
|
||||||
inkscape:label="Claw Sheaths">
|
|
||||||
<g
|
|
||||||
id="g47">
|
|
||||||
<path
|
|
||||||
style="fill:#b862d3;fill-opacity:1;stroke:#000000;stroke-width:0.25;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:0.608953;paint-order:normal"
|
|
||||||
d="m 39.460601,261.60263 v -8.94561"
|
|
||||||
id="path42" />
|
|
||||||
<path
|
|
||||||
style="fill:#b862d3;fill-opacity:1;stroke:#000000;stroke-width:0.25;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:0.608953;paint-order:normal"
|
|
||||||
d="m 43.986037,262.7061 v -8.94562"
|
|
||||||
id="path42-6" />
|
|
||||||
<path
|
|
||||||
style="fill:#b862d3;fill-opacity:1;stroke:#000000;stroke-width:0.25;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:0.608953;paint-order:normal"
|
|
||||||
d="m 48.408425,261.60326 v -8.94562"
|
|
||||||
id="path42-0" />
|
|
||||||
</g>
|
|
||||||
<g
|
|
||||||
id="g46">
|
|
||||||
<path
|
|
||||||
style="fill:#b862d3;fill-opacity:1;stroke:#000000;stroke-width:0.25;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:0.608953;paint-order:normal"
|
|
||||||
d="m 61.13422,262.35416 v -8.94562"
|
|
||||||
id="path42-1" />
|
|
||||||
<path
|
|
||||||
style="fill:#b862d3;fill-opacity:1;stroke:#000000;stroke-width:0.25;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:0.608953;paint-order:normal"
|
|
||||||
d="m 65.65967,263.45726 v -8.94562"
|
|
||||||
id="path42-6-7" />
|
|
||||||
<path
|
|
||||||
style="fill:#b862d3;fill-opacity:1;stroke:#000000;stroke-width:0.25;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:0.608953;paint-order:normal"
|
|
||||||
d="m 70.08205,262.35441 v -8.94562"
|
|
||||||
id="path42-0-2" />
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
<path
|
|
||||||
id="path37-6-6"
|
|
||||||
style="fill:#7240c6;fill-opacity:1;stroke:none;stroke-width:2.117;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:normal"
|
|
||||||
inkscape:label="Shirt"
|
|
||||||
d="M 23.641128,106.48962 C 11.998135,110.07494 6.9522611,116.60036 5.0030151,132.44679 l -0.55499,36.96847 14.6228339,0.16009 2.435214,-40.86143 c 0.3617,14.81033 0.285657,55.63245 1.778732,73.45526 2.489067,7.93616 4.366826,14.09364 12.482025,15.10094 12.126669,1.82005 25.25376,0.78509 37.9363,0.65402 8.21893,-0.84186 10.89922,-9.98211 12.64327,-16.32634 2.06804,-13.8909 -0.88582,-51.02841 0.86165,-73.05898 l 3.98361,39.92461 15.20373,-1.52832 0.80622,-36.46596 C 106.98142,112.64201 97.75062,108.88688 86.4099,106.3796 67.32316,105.7358 52.88194,103.37042 23.641128,106.48962 Z"
|
|
||||||
sodipodi:nodetypes="ccccccccccccccc" />
|
|
||||||
<path
|
|
||||||
id="path37-6-8"
|
|
||||||
style="fill:#3155a7;fill-opacity:1;stroke:none;stroke-width:2.117;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:normal"
|
|
||||||
inkscape:label="Pants"
|
|
||||||
d="m 23.04314,200.177 c 0.04037,0.54899 0.07011,1.25017 0.113013,1.76233 2.489065,7.93619 4.366836,14.09367 12.48203,15.10097 v 35.41071 H 52.3536 v -34.08052 c 1.50094,0.0507 3.00199,0.0815 4.50547,0.0926 v 33.98787 h 16.71541 v -34.75674 c 8.40465,-0.8609 11.03914,-10.4333 12.78076,-16.78435 0.0191,-0.24057 0.0222,-0.49167 0.0403,-0.73292 z" />
|
|
||||||
<path
|
|
||||||
style="fill:#3155a7;fill-opacity:1;stroke:#000000;stroke-width:1.5;stroke-linecap:butt;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
|
|
||||||
d="M 23.173635,200.20717 H 86.646638"
|
|
||||||
id="path14"
|
|
||||||
inkscape:label="Pants Shirt Separator" />
|
|
||||||
<g
|
|
||||||
id="g45"
|
|
||||||
inkscape:label="Shirt Bands">
|
|
||||||
<path
|
|
||||||
id="path37-6-9"
|
|
||||||
style="fill:#4487fd;fill-opacity:1;stroke:none;stroke-width:2.117;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:normal"
|
|
||||||
inkscape:label="path37-6"
|
|
||||||
d="m 4.7188891,151.38605 -0.168443,11.22377 H 19.343881 l 0.668734,-11.22377 z m 17.0969249,0 c 0.04085,3.69823 0.07986,7.30165 0.135327,11.22377 H 86.74251 c -0.0826,-3.78094 -0.1474,-7.51941 -0.19219,-11.22377 z m 67.672176,0 1.12007,11.22377 h 15.74867 l 0.24834,-11.22377 z" />
|
|
||||||
<path
|
|
||||||
id="path37-6-9-5"
|
|
||||||
style="fill:#4487fd;fill-opacity:1;stroke:none;stroke-width:2.117;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:normal"
|
|
||||||
inkscape:label="path37-6"
|
|
||||||
d="m 5.1925441,131.09782 c -0.06285,0.45053 -0.132653,0.88233 -0.190038,1.34886 l -0.148288,9.8742 H 20.552494 l 0.668731,-11.22306 z m 16.3475699,0 c 0.06093,3.09208 0.113598,6.80043 0.162684,11.22306 H 86.54385 c 0.039,-3.83184 0.12941,-7.6015 0.35128,-11.22306 z m 65.922966,0 1.11935,11.22306 h 18.22276 l 0.24835,-11.22306 z" />
|
|
||||||
</g>
|
|
||||||
<path
|
|
||||||
id="path37-6-67"
|
|
||||||
style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:2.117;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:normal"
|
|
||||||
inkscape:label="Outline"
|
|
||||||
d="M 55.30367,8.4954506 C 25.34493,8.4953406 1.0585521,32.714988 1.0586651,62.591399 1.1112051,79.890572 9.4569641,96.121322 23.512642,106.25968 11.869641,109.845 6.8241301,116.37035 4.8748811,132.21681 l -0.14504,40.16752 c 0,0 -0.860414,10.08289 6.4270389,9.44807 7.556655,-0.65827 7.27456,-9.45652 7.27456,-9.45652 l 2.946477,-43.89198 c 0.361695,14.81035 0.285403,55.63256 1.778478,73.45536 2.489067,7.93619 4.366748,14.09363 12.481951,15.10093 v 38.14935 c 0,0 2.22e-4,8.33511 8.358063,8.33511 8.357851,0 8.357341,-8.33511 8.357341,-8.33511 v -36.81917 c 1.50095,0.0507 3.002,0.0815 4.50548,0.0927 v 36.72655 c 0,0 -4.9e-4,8.33511 8.35735,8.33511 8.35783,0 8.35805,-8.33511 8.35805,-8.33511 v -37.49538 c 8.40467,-0.8609 11.03874,-10.43343 12.78038,-16.78447 1.88113,-23.6903 -1.01596,-50.65735 0.72463,-72.60112 l 5.148385,41.90888 c 0,0 0.0058,9.28455 6.74456,8.66148 6.594675,-0.60975 6.254675,-7.77439 6.254675,-7.77439 l 1.84575,-40.86567 C 106.26423,113.493 103.1061,110.76602 87.08964,106.26403 101.14845,96.125852 109.49634,79.893036 109.54867,62.591439 109.54878,32.715028 85.26239,8.4953806 55.30367,8.4954906 Z"
|
|
||||||
sodipodi:nodetypes="cccccscccccsccccscccccscccccc" />
|
|
||||||
<g
|
|
||||||
id="g34"
|
|
||||||
inkscape:label="Ears"
|
|
||||||
transform="matrix(1.3929758,0,0,1.3891483,-15.90372,-14.367408)"
|
|
||||||
style="stroke-width:0.718876">
|
|
||||||
<g
|
|
||||||
id="g31"
|
|
||||||
inkscape:label="Right"
|
|
||||||
style="stroke-width:0.718876">
|
|
||||||
<path
|
|
||||||
style="fill:#7f5e26;fill-opacity:1;stroke:#000000;stroke-width:1.52187;stroke-linecap:butt;stroke-linejoin:round;stroke-dasharray:none"
|
|
||||||
d="M 60.974461,29.862762 71.752186,11.103415 77.322667,31.99494"
|
|
||||||
id="path3"
|
|
||||||
sodipodi:nodetypes="ccc"
|
|
||||||
inkscape:label="Outer" />
|
|
||||||
<path
|
|
||||||
style="fill:#d05b5b;fill-opacity:1;stroke:#000000;stroke-width:1.52187;stroke-dasharray:none"
|
|
||||||
d="m 66.028789,30.129287 3.664363,-6.491093 2.107466,8.0439"
|
|
||||||
id="path5"
|
|
||||||
inkscape:label="Inner" />
|
|
||||||
</g>
|
|
||||||
<g
|
|
||||||
id="g32"
|
|
||||||
inkscape:label="Left"
|
|
||||||
style="stroke-width:0.718876">
|
|
||||||
<path
|
|
||||||
style="fill:#7f5e26;fill-opacity:1;stroke:#000000;stroke-width:1.52187;stroke-linecap:butt;stroke-linejoin:round;stroke-dasharray:none"
|
|
||||||
d="M 24.914191,32.689715 30.664597,11.228906 40.939569,29.025678"
|
|
||||||
id="path6"
|
|
||||||
sodipodi:nodetypes="ccc"
|
|
||||||
inkscape:label="Outer" />
|
|
||||||
<path
|
|
||||||
style="fill:#d05b5b;fill-opacity:1;stroke:#000000;stroke-width:1.52187;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;paint-order:normal"
|
|
||||||
d="m 30.1894,31.368573 2.014095,-7.516708 3.38236,5.858416"
|
|
||||||
id="path4"
|
|
||||||
inkscape:label="Inner" />
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
<g
|
|
||||||
id="g14"
|
|
||||||
inkscape:label="Scarf"
|
|
||||||
style="stroke-width:1;stroke-dasharray:none">
|
|
||||||
<path
|
|
||||||
style="fill:url(#linearGradient60);fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:normal"
|
|
||||||
d="m 11.637857,96.798891 c 0,0 80.076142,-7.520607 87.375922,-4.190299 7.299781,3.330308 3.026241,8.003668 3.026241,8.003668 l -92.3597245,2.90803 z"
|
|
||||||
id="path51" />
|
|
||||||
<path
|
|
||||||
style="fill:url(#linearGradient61);fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:normal"
|
|
||||||
d="m 14.525243,99.534235 c 0,0 25.459413,-1.07202 41.280118,-1.04653 15.820705,0.02548 43.931474,-1.122979 43.931474,-1.122979 0,0 4.381055,3.496594 4.235455,8.063244 -0.1456,4.56665 -7.330932,4.96115 -7.330932,4.96115 L 12.2758,111.94754 c 0,0 -2.8460075,-0.55174 -2.7720644,-7.18035 0.073943,-6.628619 5.0215074,-5.232955 5.0215074,-5.232955 z"
|
|
||||||
id="path50"
|
|
||||||
sodipodi:nodetypes="cscsccsc" />
|
|
||||||
<path
|
|
||||||
id="path52"
|
|
||||||
style="fill:url(#linearGradient59);fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:normal"
|
|
||||||
d="m 112.54197,95.644808 -2.66186,1.55236 -0.001,0.01757 c -4.77517,-3.439318 -98.929315,0.344308 -99.731896,2.056722 0,0 -0.5685094,0.673104 -0.659391,2.913 -0.089194,2.19831 0.3622518,2.78019 0.3622518,2.78019 1.4417732,1.48841 92.6509052,-0.0855 99.7939052,-2.85254 l 2.8696,1.57303 z" />
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 27 KiB |
|
@ -6,7 +6,7 @@ Comment=An audio player that can properly loop audio files
|
||||||
GenericName=Looping audio player
|
GenericName=Looping audio player
|
||||||
Exec=looper -n %f
|
Exec=looper -n %f
|
||||||
Icon=looper
|
Icon=looper
|
||||||
StartupWMClass=looper
|
StartupWMClass=looper;com.complecwaft.Looper;com.complecwaft.Looper.GTK
|
||||||
MimeType=audio/x-wav;audio/ogg;audio/x-vorbis+ogg;audio/x-opus+ogg;audio/mpeg;audio/flac;audio/xm;audio/x-mod;audio/x-zsound;
|
MimeType=audio/x-wav;audio/ogg;audio/x-vorbis+ogg;audio/x-opus+ogg;audio/mpeg;audio/flac;audio/xm;audio/x-mod;audio/x-zsound;
|
||||||
Categories=Audio;AudioVideo;
|
Categories=Audio;AudioVideo;
|
||||||
Terminal=false
|
Terminal=false
|
||||||
|
|
232
assets/dbus_stub_adaptor.hpp
Normal file
|
@ -0,0 +1,232 @@
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT!
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __sdbuscpp__dbus_stub_adaptor_hpp__adaptor__H__
|
||||||
|
#define __sdbuscpp__dbus_stub_adaptor_hpp__adaptor__H__
|
||||||
|
|
||||||
|
#include <sdbus-c++/sdbus-c++.h>
|
||||||
|
#include <string>
|
||||||
|
#include <tuple>
|
||||||
|
|
||||||
|
namespace org {
|
||||||
|
namespace freedesktop {
|
||||||
|
|
||||||
|
class Application_adaptor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static constexpr const char* INTERFACE_NAME = "org.freedesktop.Application";
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Application_adaptor(sdbus::IObject& object)
|
||||||
|
: object_(&object)
|
||||||
|
{
|
||||||
|
object_->registerMethod("Activate").onInterface(INTERFACE_NAME).withInputParamNames("platform_data").implementedAs([this](const std::map<std::string, sdbus::Variant>& platform_data){ return this->Activate(platform_data); });
|
||||||
|
object_->registerMethod("Open").onInterface(INTERFACE_NAME).withInputParamNames("uris", "platform_data").implementedAs([this](const std::vector<std::string>& uris, const std::map<std::string, sdbus::Variant>& platform_data){ return this->Open(uris, platform_data); });
|
||||||
|
object_->registerMethod("ActivateAction").onInterface(INTERFACE_NAME).withInputParamNames("action_name", "parameter", "platform_data").implementedAs([this](const std::string& action_name, const std::vector<sdbus::Variant>& parameter, const std::map<std::string, sdbus::Variant>& platform_data){ return this->ActivateAction(action_name, parameter, platform_data); });
|
||||||
|
}
|
||||||
|
|
||||||
|
Application_adaptor(const Application_adaptor&) = delete;
|
||||||
|
Application_adaptor& operator=(const Application_adaptor&) = delete;
|
||||||
|
Application_adaptor(Application_adaptor&&) = default;
|
||||||
|
Application_adaptor& operator=(Application_adaptor&&) = default;
|
||||||
|
|
||||||
|
~Application_adaptor() = default;
|
||||||
|
|
||||||
|
private:
|
||||||
|
virtual void Activate(const std::map<std::string, sdbus::Variant>& platform_data) = 0;
|
||||||
|
virtual void Open(const std::vector<std::string>& uris, const std::map<std::string, sdbus::Variant>& platform_data) = 0;
|
||||||
|
virtual void ActivateAction(const std::string& action_name, const std::vector<sdbus::Variant>& parameter, const std::map<std::string, sdbus::Variant>& platform_data) = 0;
|
||||||
|
|
||||||
|
private:
|
||||||
|
sdbus::IObject* object_;
|
||||||
|
};
|
||||||
|
|
||||||
|
}} // namespaces
|
||||||
|
|
||||||
|
namespace com {
|
||||||
|
namespace complecwaft {
|
||||||
|
|
||||||
|
class looper_adaptor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static constexpr const char* INTERFACE_NAME = "com.complecwaft.looper";
|
||||||
|
|
||||||
|
protected:
|
||||||
|
looper_adaptor(sdbus::IObject& object)
|
||||||
|
: object_(&object)
|
||||||
|
{
|
||||||
|
object_->registerMethod("CreateHandle").onInterface(INTERFACE_NAME).withOutputParamNames("new_handle").implementedAs([this](){ return this->CreateHandle(); });
|
||||||
|
object_->registerMethod("ClearHandle").onInterface(INTERFACE_NAME).withInputParamNames("handle").implementedAs([this](const std::string& handle){ return this->ClearHandle(handle); });
|
||||||
|
object_->registerMethod("Start").onInterface(INTERFACE_NAME).withInputParamNames("path", "isUri").implementedAs([this](const std::string& path, const bool& isUri){ return this->Start(path, isUri); });
|
||||||
|
object_->registerMethod("StartWithStreamIndex").onInterface(INTERFACE_NAME).withInputParamNames("path", "isUri", "streamIndex").implementedAs([this](const std::string& path, const bool& isUri, const uint32_t& streamIndex){ return this->StartWithStreamIndex(path, isUri, streamIndex); });
|
||||||
|
object_->registerMethod("Load").onInterface(INTERFACE_NAME).withInputParamNames("path", "isUri").implementedAs([this](const std::string& path, const bool& isUri){ return this->Load(path, isUri); });
|
||||||
|
object_->registerMethod("Quit").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->Quit(); });
|
||||||
|
object_->registerMethod("Stop").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->Stop(); });
|
||||||
|
object_->registerMethod("TogglePause").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->TogglePause(); });
|
||||||
|
object_->registerMethod("GetStreams").onInterface(INTERFACE_NAME).withOutputParamNames("streams").implementedAs([this](){ return this->GetStreams(); });
|
||||||
|
object_->registerMethod("PlayStream").onInterface(INTERFACE_NAME).withInputParamNames("idx").implementedAs([this](const uint32_t& idx){ return this->PlayStream(idx); });
|
||||||
|
object_->registerSignal("PlaybackEngineStarted").onInterface(INTERFACE_NAME);
|
||||||
|
object_->registerSignal("SpeedChanged").onInterface(INTERFACE_NAME).withParameters<double>("new_speed");
|
||||||
|
object_->registerSignal("TempoChanged").onInterface(INTERFACE_NAME).withParameters<double>("new_tempo");
|
||||||
|
object_->registerSignal("PitchChanged").onInterface(INTERFACE_NAME).withParameters<double>("new_pitch");
|
||||||
|
object_->registerSignal("PauseChanged").onInterface(INTERFACE_NAME).withParameters<bool>("now_paused");
|
||||||
|
object_->registerSignal("Stopped").onInterface(INTERFACE_NAME);
|
||||||
|
object_->registerSignal("ErrorOccurred").onInterface(INTERFACE_NAME).withParameters<std::string, std::string>("error_desc", "error_type");
|
||||||
|
object_->registerSignal("Seeked").onInterface(INTERFACE_NAME).withParameters<double>("to_position");
|
||||||
|
object_->registerSignal("FileChanged").onInterface(INTERFACE_NAME).withParameters<std::string, std::string>("path", "title");
|
||||||
|
object_->registerProperty("FilePath").onInterface(INTERFACE_NAME).withGetter([this](){ return this->FilePath(); });
|
||||||
|
object_->registerProperty("FileTitle").onInterface(INTERFACE_NAME).withGetter([this](){ return this->FileTitle(); });
|
||||||
|
object_->registerProperty("Position").onInterface(INTERFACE_NAME).withGetter([this](){ return this->Position(); }).withSetter([this](const double& value){ this->Position(value); });
|
||||||
|
object_->registerProperty("Length").onInterface(INTERFACE_NAME).withGetter([this](){ return this->Length(); });
|
||||||
|
object_->registerProperty("Speed").onInterface(INTERFACE_NAME).withGetter([this](){ return this->Speed(); }).withSetter([this](const double& value){ this->Speed(value); });
|
||||||
|
object_->registerProperty("Tempo").onInterface(INTERFACE_NAME).withGetter([this](){ return this->Tempo(); }).withSetter([this](const double& value){ this->Tempo(value); });
|
||||||
|
object_->registerProperty("Pitch").onInterface(INTERFACE_NAME).withGetter([this](){ return this->Pitch(); }).withSetter([this](const double& value){ this->Pitch(value); });
|
||||||
|
object_->registerProperty("Volume").onInterface(INTERFACE_NAME).withGetter([this](){ return this->Volume(); }).withSetter([this](const double& value){ this->Volume(value); });
|
||||||
|
object_->registerProperty("Paused").onInterface(INTERFACE_NAME).withGetter([this](){ return this->Paused(); }).withSetter([this](const bool& value){ this->Paused(value); });
|
||||||
|
object_->registerProperty("IsStopped").onInterface(INTERFACE_NAME).withGetter([this](){ return this->IsStopped(); });
|
||||||
|
object_->registerProperty("IsDaemon").onInterface(INTERFACE_NAME).withGetter([this](){ return this->IsDaemon(); });
|
||||||
|
object_->registerProperty("StreamIdx").onInterface(INTERFACE_NAME).withGetter([this](){ return this->StreamIdx(); });
|
||||||
|
}
|
||||||
|
|
||||||
|
looper_adaptor(const looper_adaptor&) = delete;
|
||||||
|
looper_adaptor& operator=(const looper_adaptor&) = delete;
|
||||||
|
looper_adaptor(looper_adaptor&&) = default;
|
||||||
|
looper_adaptor& operator=(looper_adaptor&&) = default;
|
||||||
|
|
||||||
|
~looper_adaptor() = default;
|
||||||
|
|
||||||
|
public:
|
||||||
|
void emitPlaybackEngineStarted()
|
||||||
|
{
|
||||||
|
object_->emitSignal("PlaybackEngineStarted").onInterface(INTERFACE_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
void emitSpeedChanged(const double& new_speed)
|
||||||
|
{
|
||||||
|
object_->emitSignal("SpeedChanged").onInterface(INTERFACE_NAME).withArguments(new_speed);
|
||||||
|
}
|
||||||
|
|
||||||
|
void emitTempoChanged(const double& new_tempo)
|
||||||
|
{
|
||||||
|
object_->emitSignal("TempoChanged").onInterface(INTERFACE_NAME).withArguments(new_tempo);
|
||||||
|
}
|
||||||
|
|
||||||
|
void emitPitchChanged(const double& new_pitch)
|
||||||
|
{
|
||||||
|
object_->emitSignal("PitchChanged").onInterface(INTERFACE_NAME).withArguments(new_pitch);
|
||||||
|
}
|
||||||
|
|
||||||
|
void emitPauseChanged(const bool& now_paused)
|
||||||
|
{
|
||||||
|
object_->emitSignal("PauseChanged").onInterface(INTERFACE_NAME).withArguments(now_paused);
|
||||||
|
}
|
||||||
|
|
||||||
|
void emitStopped()
|
||||||
|
{
|
||||||
|
object_->emitSignal("Stopped").onInterface(INTERFACE_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
void emitErrorOccurred(const std::string& error_desc, const std::string& error_type)
|
||||||
|
{
|
||||||
|
object_->emitSignal("ErrorOccurred").onInterface(INTERFACE_NAME).withArguments(error_desc, error_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
void emitSeeked(const double& to_position)
|
||||||
|
{
|
||||||
|
object_->emitSignal("Seeked").onInterface(INTERFACE_NAME).withArguments(to_position);
|
||||||
|
}
|
||||||
|
|
||||||
|
void emitFileChanged(const std::string& path, const std::string& title)
|
||||||
|
{
|
||||||
|
object_->emitSignal("FileChanged").onInterface(INTERFACE_NAME).withArguments(path, title);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
virtual std::string CreateHandle() = 0;
|
||||||
|
virtual void ClearHandle(const std::string& handle) = 0;
|
||||||
|
virtual void Start(const std::string& path, const bool& isUri) = 0;
|
||||||
|
virtual void StartWithStreamIndex(const std::string& path, const bool& isUri, const uint32_t& streamIndex) = 0;
|
||||||
|
virtual void Load(const std::string& path, const bool& isUri) = 0;
|
||||||
|
virtual void Quit() = 0;
|
||||||
|
virtual void Stop() = 0;
|
||||||
|
virtual void TogglePause() = 0;
|
||||||
|
virtual std::vector<sdbus::Struct<double, std::string, int32_t>> GetStreams() = 0;
|
||||||
|
virtual void PlayStream(const uint32_t& idx) = 0;
|
||||||
|
|
||||||
|
private:
|
||||||
|
virtual std::string FilePath() = 0;
|
||||||
|
virtual std::string FileTitle() = 0;
|
||||||
|
virtual double Position() = 0;
|
||||||
|
virtual void Position(const double& value) = 0;
|
||||||
|
virtual double Length() = 0;
|
||||||
|
virtual double Speed() = 0;
|
||||||
|
virtual void Speed(const double& value) = 0;
|
||||||
|
virtual double Tempo() = 0;
|
||||||
|
virtual void Tempo(const double& value) = 0;
|
||||||
|
virtual double Pitch() = 0;
|
||||||
|
virtual void Pitch(const double& value) = 0;
|
||||||
|
virtual double Volume() = 0;
|
||||||
|
virtual void Volume(const double& value) = 0;
|
||||||
|
virtual bool Paused() = 0;
|
||||||
|
virtual void Paused(const bool& value) = 0;
|
||||||
|
virtual bool IsStopped() = 0;
|
||||||
|
virtual bool IsDaemon() = 0;
|
||||||
|
virtual uint32_t StreamIdx() = 0;
|
||||||
|
|
||||||
|
private:
|
||||||
|
sdbus::IObject* object_;
|
||||||
|
};
|
||||||
|
|
||||||
|
}} // namespaces
|
||||||
|
|
||||||
|
namespace com {
|
||||||
|
namespace complecwaft {
|
||||||
|
namespace looper {
|
||||||
|
|
||||||
|
class Errors_adaptor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static constexpr const char* INTERFACE_NAME = "com.complecwaft.looper.Errors";
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Errors_adaptor(sdbus::IObject& object)
|
||||||
|
: object_(&object)
|
||||||
|
{
|
||||||
|
object_->registerMethod("PopFront").onInterface(INTERFACE_NAME).withInputParamNames("handle").withOutputParamNames("error").implementedAs([this](const std::string& handle){ return this->PopFront(handle); });
|
||||||
|
object_->registerMethod("PopBack").onInterface(INTERFACE_NAME).withInputParamNames("handle").withOutputParamNames("error").implementedAs([this](const std::string& handle){ return this->PopBack(handle); });
|
||||||
|
object_->registerMethod("PeekFront").onInterface(INTERFACE_NAME).withInputParamNames("handle").withOutputParamNames("error").implementedAs([this](const std::string& handle){ return this->PeekFront(handle); });
|
||||||
|
object_->registerMethod("PeekBack").onInterface(INTERFACE_NAME).withInputParamNames("handle").withOutputParamNames("error").implementedAs([this](const std::string& handle){ return this->PeekBack(handle); });
|
||||||
|
object_->registerMethod("GetCount").onInterface(INTERFACE_NAME).withInputParamNames("handle").withOutputParamNames("count").implementedAs([this](const std::string& handle){ return this->GetCount(handle); });
|
||||||
|
object_->registerMethod("IsEmpty").onInterface(INTERFACE_NAME).withInputParamNames("handle").withOutputParamNames("empty").implementedAs([this](const std::string& handle){ return this->IsEmpty(handle); });
|
||||||
|
object_->registerMethod("Clear").onInterface(INTERFACE_NAME).withInputParamNames("handle").implementedAs([this](const std::string& handle){ return this->Clear(handle); });
|
||||||
|
object_->registerMethod("PeekAll").onInterface(INTERFACE_NAME).withInputParamNames("handle").withOutputParamNames("errors").implementedAs([this](const std::string& handle){ return this->PeekAll(handle); });
|
||||||
|
object_->registerMethod("GetAllAndClear").onInterface(INTERFACE_NAME).withInputParamNames("handle").withOutputParamNames("errors").implementedAs([this](const std::string& handle){ return this->GetAllAndClear(handle); });
|
||||||
|
}
|
||||||
|
|
||||||
|
Errors_adaptor(const Errors_adaptor&) = delete;
|
||||||
|
Errors_adaptor& operator=(const Errors_adaptor&) = delete;
|
||||||
|
Errors_adaptor(Errors_adaptor&&) = default;
|
||||||
|
Errors_adaptor& operator=(Errors_adaptor&&) = default;
|
||||||
|
|
||||||
|
~Errors_adaptor() = default;
|
||||||
|
|
||||||
|
private:
|
||||||
|
virtual std::string PopFront(const std::string& handle) = 0;
|
||||||
|
virtual std::string PopBack(const std::string& handle) = 0;
|
||||||
|
virtual std::string PeekFront(const std::string& handle) = 0;
|
||||||
|
virtual std::string PeekBack(const std::string& handle) = 0;
|
||||||
|
virtual uint32_t GetCount(const std::string& handle) = 0;
|
||||||
|
virtual bool IsEmpty(const std::string& handle) = 0;
|
||||||
|
virtual void Clear(const std::string& handle) = 0;
|
||||||
|
virtual std::vector<std::string> PeekAll(const std::string& handle) = 0;
|
||||||
|
virtual std::vector<std::string> GetAllAndClear(const std::string& handle) = 0;
|
||||||
|
|
||||||
|
private:
|
||||||
|
sdbus::IObject* object_;
|
||||||
|
};
|
||||||
|
|
||||||
|
}}} // namespaces
|
||||||
|
|
||||||
|
#endif
|
338
assets/dbus_stub_proxy.hpp
Normal file
|
@ -0,0 +1,338 @@
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT!
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __sdbuscpp__dbus_stub_proxy_hpp__proxy__H__
|
||||||
|
#define __sdbuscpp__dbus_stub_proxy_hpp__proxy__H__
|
||||||
|
|
||||||
|
#include <sdbus-c++/sdbus-c++.h>
|
||||||
|
#include <string>
|
||||||
|
#include <tuple>
|
||||||
|
|
||||||
|
namespace org {
|
||||||
|
namespace freedesktop {
|
||||||
|
|
||||||
|
class Application_proxy
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static constexpr const char* INTERFACE_NAME = "org.freedesktop.Application";
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Application_proxy(sdbus::IProxy& proxy)
|
||||||
|
: proxy_(&proxy)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Application_proxy(const Application_proxy&) = delete;
|
||||||
|
Application_proxy& operator=(const Application_proxy&) = delete;
|
||||||
|
Application_proxy(Application_proxy&&) = default;
|
||||||
|
Application_proxy& operator=(Application_proxy&&) = default;
|
||||||
|
|
||||||
|
~Application_proxy() = default;
|
||||||
|
|
||||||
|
public:
|
||||||
|
void Activate(const std::map<std::string, sdbus::Variant>& platform_data)
|
||||||
|
{
|
||||||
|
proxy_->callMethod("Activate").onInterface(INTERFACE_NAME).withArguments(platform_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Open(const std::vector<std::string>& uris, const std::map<std::string, sdbus::Variant>& platform_data)
|
||||||
|
{
|
||||||
|
proxy_->callMethod("Open").onInterface(INTERFACE_NAME).withArguments(uris, platform_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActivateAction(const std::string& action_name, const std::vector<sdbus::Variant>& parameter, const std::map<std::string, sdbus::Variant>& platform_data)
|
||||||
|
{
|
||||||
|
proxy_->callMethod("ActivateAction").onInterface(INTERFACE_NAME).withArguments(action_name, parameter, platform_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
sdbus::IProxy* proxy_;
|
||||||
|
};
|
||||||
|
|
||||||
|
}} // namespaces
|
||||||
|
|
||||||
|
namespace com {
|
||||||
|
namespace complecwaft {
|
||||||
|
|
||||||
|
class looper_proxy
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static constexpr const char* INTERFACE_NAME = "com.complecwaft.looper";
|
||||||
|
|
||||||
|
protected:
|
||||||
|
looper_proxy(sdbus::IProxy& proxy)
|
||||||
|
: proxy_(&proxy)
|
||||||
|
{
|
||||||
|
proxy_->uponSignal("PlaybackEngineStarted").onInterface(INTERFACE_NAME).call([this](){ this->onPlaybackEngineStarted(); });
|
||||||
|
proxy_->uponSignal("SpeedChanged").onInterface(INTERFACE_NAME).call([this](const double& new_speed){ this->onSpeedChanged(new_speed); });
|
||||||
|
proxy_->uponSignal("TempoChanged").onInterface(INTERFACE_NAME).call([this](const double& new_tempo){ this->onTempoChanged(new_tempo); });
|
||||||
|
proxy_->uponSignal("PitchChanged").onInterface(INTERFACE_NAME).call([this](const double& new_pitch){ this->onPitchChanged(new_pitch); });
|
||||||
|
proxy_->uponSignal("PauseChanged").onInterface(INTERFACE_NAME).call([this](const bool& now_paused){ this->onPauseChanged(now_paused); });
|
||||||
|
proxy_->uponSignal("Stopped").onInterface(INTERFACE_NAME).call([this](){ this->onStopped(); });
|
||||||
|
proxy_->uponSignal("ErrorOccurred").onInterface(INTERFACE_NAME).call([this](const std::string& error_desc, const std::string& error_type){ this->onErrorOccurred(error_desc, error_type); });
|
||||||
|
proxy_->uponSignal("Seeked").onInterface(INTERFACE_NAME).call([this](const double& to_position){ this->onSeeked(to_position); });
|
||||||
|
proxy_->uponSignal("FileChanged").onInterface(INTERFACE_NAME).call([this](const std::string& path, const std::string& title){ this->onFileChanged(path, title); });
|
||||||
|
}
|
||||||
|
|
||||||
|
looper_proxy(const looper_proxy&) = delete;
|
||||||
|
looper_proxy& operator=(const looper_proxy&) = delete;
|
||||||
|
looper_proxy(looper_proxy&&) = default;
|
||||||
|
looper_proxy& operator=(looper_proxy&&) = default;
|
||||||
|
|
||||||
|
~looper_proxy() = default;
|
||||||
|
|
||||||
|
virtual void onPlaybackEngineStarted() = 0;
|
||||||
|
virtual void onSpeedChanged(const double& new_speed) = 0;
|
||||||
|
virtual void onTempoChanged(const double& new_tempo) = 0;
|
||||||
|
virtual void onPitchChanged(const double& new_pitch) = 0;
|
||||||
|
virtual void onPauseChanged(const bool& now_paused) = 0;
|
||||||
|
virtual void onStopped() = 0;
|
||||||
|
virtual void onErrorOccurred(const std::string& error_desc, const std::string& error_type) = 0;
|
||||||
|
virtual void onSeeked(const double& to_position) = 0;
|
||||||
|
virtual void onFileChanged(const std::string& path, const std::string& title) = 0;
|
||||||
|
|
||||||
|
public:
|
||||||
|
std::string CreateHandle()
|
||||||
|
{
|
||||||
|
std::string result;
|
||||||
|
proxy_->callMethod("CreateHandle").onInterface(INTERFACE_NAME).storeResultsTo(result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClearHandle(const std::string& handle)
|
||||||
|
{
|
||||||
|
proxy_->callMethod("ClearHandle").onInterface(INTERFACE_NAME).withArguments(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Start(const std::string& path, const bool& isUri)
|
||||||
|
{
|
||||||
|
proxy_->callMethod("Start").onInterface(INTERFACE_NAME).withArguments(path, isUri);
|
||||||
|
}
|
||||||
|
|
||||||
|
void StartWithStreamIndex(const std::string& path, const bool& isUri, const uint32_t& streamIndex)
|
||||||
|
{
|
||||||
|
proxy_->callMethod("StartWithStreamIndex").onInterface(INTERFACE_NAME).withArguments(path, isUri, streamIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Load(const std::string& path, const bool& isUri)
|
||||||
|
{
|
||||||
|
proxy_->callMethod("Load").onInterface(INTERFACE_NAME).withArguments(path, isUri);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Quit()
|
||||||
|
{
|
||||||
|
proxy_->callMethod("Quit").onInterface(INTERFACE_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Stop()
|
||||||
|
{
|
||||||
|
proxy_->callMethod("Stop").onInterface(INTERFACE_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TogglePause()
|
||||||
|
{
|
||||||
|
proxy_->callMethod("TogglePause").onInterface(INTERFACE_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<sdbus::Struct<double, std::string, int32_t>> GetStreams()
|
||||||
|
{
|
||||||
|
std::vector<sdbus::Struct<double, std::string, int32_t>> result;
|
||||||
|
proxy_->callMethod("GetStreams").onInterface(INTERFACE_NAME).storeResultsTo(result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlayStream(const uint32_t& idx)
|
||||||
|
{
|
||||||
|
proxy_->callMethod("PlayStream").onInterface(INTERFACE_NAME).withArguments(idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
std::string FilePath()
|
||||||
|
{
|
||||||
|
return proxy_->getProperty("FilePath").onInterface(INTERFACE_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string FileTitle()
|
||||||
|
{
|
||||||
|
return proxy_->getProperty("FileTitle").onInterface(INTERFACE_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
double Position()
|
||||||
|
{
|
||||||
|
return proxy_->getProperty("Position").onInterface(INTERFACE_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Position(const double& value)
|
||||||
|
{
|
||||||
|
proxy_->setProperty("Position").onInterface(INTERFACE_NAME).toValue(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
double Length()
|
||||||
|
{
|
||||||
|
return proxy_->getProperty("Length").onInterface(INTERFACE_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
double Speed()
|
||||||
|
{
|
||||||
|
return proxy_->getProperty("Speed").onInterface(INTERFACE_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Speed(const double& value)
|
||||||
|
{
|
||||||
|
proxy_->setProperty("Speed").onInterface(INTERFACE_NAME).toValue(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
double Tempo()
|
||||||
|
{
|
||||||
|
return proxy_->getProperty("Tempo").onInterface(INTERFACE_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Tempo(const double& value)
|
||||||
|
{
|
||||||
|
proxy_->setProperty("Tempo").onInterface(INTERFACE_NAME).toValue(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
double Pitch()
|
||||||
|
{
|
||||||
|
return proxy_->getProperty("Pitch").onInterface(INTERFACE_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Pitch(const double& value)
|
||||||
|
{
|
||||||
|
proxy_->setProperty("Pitch").onInterface(INTERFACE_NAME).toValue(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
double Volume()
|
||||||
|
{
|
||||||
|
return proxy_->getProperty("Volume").onInterface(INTERFACE_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Volume(const double& value)
|
||||||
|
{
|
||||||
|
proxy_->setProperty("Volume").onInterface(INTERFACE_NAME).toValue(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Paused()
|
||||||
|
{
|
||||||
|
return proxy_->getProperty("Paused").onInterface(INTERFACE_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Paused(const bool& value)
|
||||||
|
{
|
||||||
|
proxy_->setProperty("Paused").onInterface(INTERFACE_NAME).toValue(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsStopped()
|
||||||
|
{
|
||||||
|
return proxy_->getProperty("IsStopped").onInterface(INTERFACE_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsDaemon()
|
||||||
|
{
|
||||||
|
return proxy_->getProperty("IsDaemon").onInterface(INTERFACE_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t StreamIdx()
|
||||||
|
{
|
||||||
|
return proxy_->getProperty("StreamIdx").onInterface(INTERFACE_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
sdbus::IProxy* proxy_;
|
||||||
|
};
|
||||||
|
|
||||||
|
}} // namespaces
|
||||||
|
|
||||||
|
namespace com {
|
||||||
|
namespace complecwaft {
|
||||||
|
namespace looper {
|
||||||
|
|
||||||
|
class Errors_proxy
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static constexpr const char* INTERFACE_NAME = "com.complecwaft.looper.Errors";
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Errors_proxy(sdbus::IProxy& proxy)
|
||||||
|
: proxy_(&proxy)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Errors_proxy(const Errors_proxy&) = delete;
|
||||||
|
Errors_proxy& operator=(const Errors_proxy&) = delete;
|
||||||
|
Errors_proxy(Errors_proxy&&) = default;
|
||||||
|
Errors_proxy& operator=(Errors_proxy&&) = default;
|
||||||
|
|
||||||
|
~Errors_proxy() = default;
|
||||||
|
|
||||||
|
public:
|
||||||
|
std::string PopFront(const std::string& handle)
|
||||||
|
{
|
||||||
|
std::string result;
|
||||||
|
proxy_->callMethod("PopFront").onInterface(INTERFACE_NAME).withArguments(handle).storeResultsTo(result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string PopBack(const std::string& handle)
|
||||||
|
{
|
||||||
|
std::string result;
|
||||||
|
proxy_->callMethod("PopBack").onInterface(INTERFACE_NAME).withArguments(handle).storeResultsTo(result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string PeekFront(const std::string& handle)
|
||||||
|
{
|
||||||
|
std::string result;
|
||||||
|
proxy_->callMethod("PeekFront").onInterface(INTERFACE_NAME).withArguments(handle).storeResultsTo(result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string PeekBack(const std::string& handle)
|
||||||
|
{
|
||||||
|
std::string result;
|
||||||
|
proxy_->callMethod("PeekBack").onInterface(INTERFACE_NAME).withArguments(handle).storeResultsTo(result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t GetCount(const std::string& handle)
|
||||||
|
{
|
||||||
|
uint32_t result;
|
||||||
|
proxy_->callMethod("GetCount").onInterface(INTERFACE_NAME).withArguments(handle).storeResultsTo(result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsEmpty(const std::string& handle)
|
||||||
|
{
|
||||||
|
bool result;
|
||||||
|
proxy_->callMethod("IsEmpty").onInterface(INTERFACE_NAME).withArguments(handle).storeResultsTo(result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Clear(const std::string& handle)
|
||||||
|
{
|
||||||
|
proxy_->callMethod("Clear").onInterface(INTERFACE_NAME).withArguments(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> PeekAll(const std::string& handle)
|
||||||
|
{
|
||||||
|
std::vector<std::string> result;
|
||||||
|
proxy_->callMethod("PeekAll").onInterface(INTERFACE_NAME).withArguments(handle).storeResultsTo(result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> GetAllAndClear(const std::string& handle)
|
||||||
|
{
|
||||||
|
std::vector<std::string> result;
|
||||||
|
proxy_->callMethod("GetAllAndClear").onInterface(INTERFACE_NAME).withArguments(handle).storeResultsTo(result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
sdbus::IProxy* proxy_;
|
||||||
|
};
|
||||||
|
|
||||||
|
}}} // namespaces
|
||||||
|
|
||||||
|
#endif
|
Before Width: | Height: | Size: 8.7 KiB |
1049
assets/icon-old.svg
Before Width: | Height: | Size: 36 KiB |
BIN
assets/icon.png
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 8.7 KiB |
1083
assets/icon.svg
Before Width: | Height: | Size: 5 KiB After Width: | Height: | Size: 36 KiB |
214
assets/mpris_stub_adaptor.hpp
Normal file
|
@ -0,0 +1,214 @@
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT!
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __sdbuscpp__mpris_stub_adaptor_hpp__adaptor__H__
|
||||||
|
#define __sdbuscpp__mpris_stub_adaptor_hpp__adaptor__H__
|
||||||
|
|
||||||
|
#include <sdbus-c++/sdbus-c++.h>
|
||||||
|
#include <string>
|
||||||
|
#include <tuple>
|
||||||
|
|
||||||
|
namespace org {
|
||||||
|
namespace mpris {
|
||||||
|
|
||||||
|
class MediaPlayer2_adaptor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static constexpr const char* INTERFACE_NAME = "org.mpris.MediaPlayer2";
|
||||||
|
|
||||||
|
protected:
|
||||||
|
MediaPlayer2_adaptor(sdbus::IObject& object)
|
||||||
|
: object_(&object)
|
||||||
|
{
|
||||||
|
object_->registerMethod("Raise").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->Raise(); });
|
||||||
|
object_->registerMethod("Quit").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->Quit(); });
|
||||||
|
object_->registerProperty("CanRaise").onInterface(INTERFACE_NAME).withGetter([this](){ return this->CanRaise(); });
|
||||||
|
object_->registerProperty("CanQuit").onInterface(INTERFACE_NAME).withGetter([this](){ return this->CanQuit(); });
|
||||||
|
object_->registerProperty("HasTrackList").onInterface(INTERFACE_NAME).withGetter([this](){ return this->HasTrackList(); });
|
||||||
|
object_->registerProperty("Identity").onInterface(INTERFACE_NAME).withGetter([this](){ return this->Identity(); });
|
||||||
|
object_->registerProperty("SupportedUriSchemes").onInterface(INTERFACE_NAME).withGetter([this](){ return this->SupportedUriSchemes(); });
|
||||||
|
object_->registerProperty("SupportedMimeTypes").onInterface(INTERFACE_NAME).withGetter([this](){ return this->SupportedMimeTypes(); });
|
||||||
|
}
|
||||||
|
|
||||||
|
MediaPlayer2_adaptor(const MediaPlayer2_adaptor&) = delete;
|
||||||
|
MediaPlayer2_adaptor& operator=(const MediaPlayer2_adaptor&) = delete;
|
||||||
|
MediaPlayer2_adaptor(MediaPlayer2_adaptor&&) = default;
|
||||||
|
MediaPlayer2_adaptor& operator=(MediaPlayer2_adaptor&&) = default;
|
||||||
|
|
||||||
|
~MediaPlayer2_adaptor() = default;
|
||||||
|
|
||||||
|
private:
|
||||||
|
virtual void Raise() = 0;
|
||||||
|
virtual void Quit() = 0;
|
||||||
|
|
||||||
|
private:
|
||||||
|
virtual bool CanRaise() = 0;
|
||||||
|
virtual bool CanQuit() = 0;
|
||||||
|
virtual bool HasTrackList() = 0;
|
||||||
|
virtual std::string Identity() = 0;
|
||||||
|
virtual std::vector<std::string> SupportedUriSchemes() = 0;
|
||||||
|
virtual std::vector<std::string> SupportedMimeTypes() = 0;
|
||||||
|
|
||||||
|
private:
|
||||||
|
sdbus::IObject* object_;
|
||||||
|
};
|
||||||
|
|
||||||
|
}} // namespaces
|
||||||
|
|
||||||
|
namespace org {
|
||||||
|
namespace mpris {
|
||||||
|
namespace MediaPlayer2 {
|
||||||
|
|
||||||
|
class Player_adaptor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static constexpr const char* INTERFACE_NAME = "org.mpris.MediaPlayer2.Player";
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Player_adaptor(sdbus::IObject& object)
|
||||||
|
: object_(&object)
|
||||||
|
{
|
||||||
|
object_->registerMethod("Next").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->Next(); });
|
||||||
|
object_->registerMethod("Previous").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->Previous(); });
|
||||||
|
object_->registerMethod("Pause").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->Pause(); });
|
||||||
|
object_->registerMethod("PlayPause").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->PlayPause(); });
|
||||||
|
object_->registerMethod("Stop").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->Stop(); });
|
||||||
|
object_->registerMethod("Play").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->Play(); });
|
||||||
|
object_->registerMethod("Seek").onInterface(INTERFACE_NAME).withInputParamNames("Offset").implementedAs([this](const int64_t& Offset){ return this->Seek(Offset); });
|
||||||
|
object_->registerMethod("SetPosition").onInterface(INTERFACE_NAME).withInputParamNames("TrackId", "Position").implementedAs([this](const sdbus::ObjectPath& TrackId, const int64_t& Position){ return this->SetPosition(TrackId, Position); });
|
||||||
|
object_->registerMethod("OpenUri").onInterface(INTERFACE_NAME).withInputParamNames("Uri").implementedAs([this](const std::string& Uri){ return this->OpenUri(Uri); });
|
||||||
|
object_->registerSignal("Seeked").onInterface(INTERFACE_NAME).withParameters<int64_t>("Position");
|
||||||
|
object_->registerProperty("PlaybackStatus").onInterface(INTERFACE_NAME).withGetter([this](){ return this->PlaybackStatus(); });
|
||||||
|
object_->registerProperty("Rate").onInterface(INTERFACE_NAME).withGetter([this](){ return this->Rate(); }).withSetter([this](const double& value){ this->Rate(value); });
|
||||||
|
object_->registerProperty("Metadata").onInterface(INTERFACE_NAME).withGetter([this](){ return this->Metadata(); });
|
||||||
|
object_->registerProperty("Volume").onInterface(INTERFACE_NAME).withGetter([this](){ return this->Volume(); }).withSetter([this](const double& value){ this->Volume(value); });
|
||||||
|
object_->registerProperty("Position").onInterface(INTERFACE_NAME).withGetter([this](){ return this->Position(); });
|
||||||
|
object_->registerProperty("MinimumRate").onInterface(INTERFACE_NAME).withGetter([this](){ return this->MinimumRate(); });
|
||||||
|
object_->registerProperty("MaximumRate").onInterface(INTERFACE_NAME).withGetter([this](){ return this->MaximumRate(); });
|
||||||
|
object_->registerProperty("CanGoNext").onInterface(INTERFACE_NAME).withGetter([this](){ return this->CanGoNext(); });
|
||||||
|
object_->registerProperty("CanGoPrevious").onInterface(INTERFACE_NAME).withGetter([this](){ return this->CanGoPrevious(); });
|
||||||
|
object_->registerProperty("CanPlay").onInterface(INTERFACE_NAME).withGetter([this](){ return this->CanPlay(); });
|
||||||
|
object_->registerProperty("CanPause").onInterface(INTERFACE_NAME).withGetter([this](){ return this->CanPause(); });
|
||||||
|
object_->registerProperty("CanSeek").onInterface(INTERFACE_NAME).withGetter([this](){ return this->CanSeek(); });
|
||||||
|
object_->registerProperty("CanControl").onInterface(INTERFACE_NAME).withGetter([this](){ return this->CanControl(); });
|
||||||
|
}
|
||||||
|
|
||||||
|
Player_adaptor(const Player_adaptor&) = delete;
|
||||||
|
Player_adaptor& operator=(const Player_adaptor&) = delete;
|
||||||
|
Player_adaptor(Player_adaptor&&) = default;
|
||||||
|
Player_adaptor& operator=(Player_adaptor&&) = default;
|
||||||
|
|
||||||
|
~Player_adaptor() = default;
|
||||||
|
|
||||||
|
public:
|
||||||
|
void emitSeeked(const int64_t& Position)
|
||||||
|
{
|
||||||
|
object_->emitSignal("Seeked").onInterface(INTERFACE_NAME).withArguments(Position);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
virtual void Next() = 0;
|
||||||
|
virtual void Previous() = 0;
|
||||||
|
virtual void Pause() = 0;
|
||||||
|
virtual void PlayPause() = 0;
|
||||||
|
virtual void Stop() = 0;
|
||||||
|
virtual void Play() = 0;
|
||||||
|
virtual void Seek(const int64_t& Offset) = 0;
|
||||||
|
virtual void SetPosition(const sdbus::ObjectPath& TrackId, const int64_t& Position) = 0;
|
||||||
|
virtual void OpenUri(const std::string& Uri) = 0;
|
||||||
|
|
||||||
|
private:
|
||||||
|
virtual std::string PlaybackStatus() = 0;
|
||||||
|
virtual double Rate() = 0;
|
||||||
|
virtual void Rate(const double& value) = 0;
|
||||||
|
virtual std::map<std::string, sdbus::Variant> Metadata() = 0;
|
||||||
|
virtual double Volume() = 0;
|
||||||
|
virtual void Volume(const double& value) = 0;
|
||||||
|
virtual int64_t Position() = 0;
|
||||||
|
virtual double MinimumRate() = 0;
|
||||||
|
virtual double MaximumRate() = 0;
|
||||||
|
virtual bool CanGoNext() = 0;
|
||||||
|
virtual bool CanGoPrevious() = 0;
|
||||||
|
virtual bool CanPlay() = 0;
|
||||||
|
virtual bool CanPause() = 0;
|
||||||
|
virtual bool CanSeek() = 0;
|
||||||
|
virtual bool CanControl() = 0;
|
||||||
|
|
||||||
|
private:
|
||||||
|
sdbus::IObject* object_;
|
||||||
|
};
|
||||||
|
|
||||||
|
}}} // namespaces
|
||||||
|
|
||||||
|
namespace org {
|
||||||
|
namespace mpris {
|
||||||
|
namespace MediaPlayer2 {
|
||||||
|
|
||||||
|
class TrackList_adaptor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static constexpr const char* INTERFACE_NAME = "org.mpris.MediaPlayer2.TrackList";
|
||||||
|
|
||||||
|
protected:
|
||||||
|
TrackList_adaptor(sdbus::IObject& object)
|
||||||
|
: object_(&object)
|
||||||
|
{
|
||||||
|
object_->registerMethod("GetTracksMetadata").onInterface(INTERFACE_NAME).withInputParamNames("TrackIds").withOutputParamNames("Metadata").implementedAs([this](const std::vector<sdbus::ObjectPath>& TrackIds){ return this->GetTracksMetadata(TrackIds); });
|
||||||
|
object_->registerMethod("AddTrack").onInterface(INTERFACE_NAME).withInputParamNames("Uri", "AfterTrack", "SetAsCurrent").implementedAs([this](const std::string& Uri, const sdbus::ObjectPath& AfterTrack, const bool& SetAsCurrent){ return this->AddTrack(Uri, AfterTrack, SetAsCurrent); });
|
||||||
|
object_->registerMethod("RemoveTrack").onInterface(INTERFACE_NAME).withInputParamNames("TrackId").implementedAs([this](const sdbus::ObjectPath& TrackId){ return this->RemoveTrack(TrackId); });
|
||||||
|
object_->registerMethod("GoTo").onInterface(INTERFACE_NAME).withInputParamNames("TrackId").implementedAs([this](const sdbus::ObjectPath& TrackId){ return this->GoTo(TrackId); });
|
||||||
|
object_->registerSignal("TrackListReplaced").onInterface(INTERFACE_NAME).withParameters<std::vector<sdbus::ObjectPath>, sdbus::ObjectPath>("Tracks", "CurrentTrack");
|
||||||
|
object_->registerSignal("TrackAdded").onInterface(INTERFACE_NAME).withParameters<std::map<std::string, sdbus::Variant>, sdbus::ObjectPath>("Metadata", "AfterTrack");
|
||||||
|
object_->registerSignal("TrackRemoved").onInterface(INTERFACE_NAME).withParameters<sdbus::ObjectPath>("TrackId");
|
||||||
|
object_->registerSignal("TrackMetadataChanged").onInterface(INTERFACE_NAME).withParameters<sdbus::ObjectPath, std::map<std::string, sdbus::Variant>>("TrackId", "Metadata");
|
||||||
|
object_->registerProperty("Tracks").onInterface(INTERFACE_NAME).withGetter([this](){ return this->Tracks(); });
|
||||||
|
object_->registerProperty("CanEditTracks").onInterface(INTERFACE_NAME).withGetter([this](){ return this->CanEditTracks(); });
|
||||||
|
}
|
||||||
|
|
||||||
|
TrackList_adaptor(const TrackList_adaptor&) = delete;
|
||||||
|
TrackList_adaptor& operator=(const TrackList_adaptor&) = delete;
|
||||||
|
TrackList_adaptor(TrackList_adaptor&&) = default;
|
||||||
|
TrackList_adaptor& operator=(TrackList_adaptor&&) = default;
|
||||||
|
|
||||||
|
~TrackList_adaptor() = default;
|
||||||
|
|
||||||
|
public:
|
||||||
|
void emitTrackListReplaced(const std::vector<sdbus::ObjectPath>& Tracks, const sdbus::ObjectPath& CurrentTrack)
|
||||||
|
{
|
||||||
|
object_->emitSignal("TrackListReplaced").onInterface(INTERFACE_NAME).withArguments(Tracks, CurrentTrack);
|
||||||
|
}
|
||||||
|
|
||||||
|
void emitTrackAdded(const std::map<std::string, sdbus::Variant>& Metadata, const sdbus::ObjectPath& AfterTrack)
|
||||||
|
{
|
||||||
|
object_->emitSignal("TrackAdded").onInterface(INTERFACE_NAME).withArguments(Metadata, AfterTrack);
|
||||||
|
}
|
||||||
|
|
||||||
|
void emitTrackRemoved(const sdbus::ObjectPath& TrackId)
|
||||||
|
{
|
||||||
|
object_->emitSignal("TrackRemoved").onInterface(INTERFACE_NAME).withArguments(TrackId);
|
||||||
|
}
|
||||||
|
|
||||||
|
void emitTrackMetadataChanged(const sdbus::ObjectPath& TrackId, const std::map<std::string, sdbus::Variant>& Metadata)
|
||||||
|
{
|
||||||
|
object_->emitSignal("TrackMetadataChanged").onInterface(INTERFACE_NAME).withArguments(TrackId, Metadata);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
virtual std::vector<std::map<std::string, sdbus::Variant>> GetTracksMetadata(const std::vector<sdbus::ObjectPath>& TrackIds) = 0;
|
||||||
|
virtual void AddTrack(const std::string& Uri, const sdbus::ObjectPath& AfterTrack, const bool& SetAsCurrent) = 0;
|
||||||
|
virtual void RemoveTrack(const sdbus::ObjectPath& TrackId) = 0;
|
||||||
|
virtual void GoTo(const sdbus::ObjectPath& TrackId) = 0;
|
||||||
|
|
||||||
|
private:
|
||||||
|
virtual std::vector<sdbus::ObjectPath> Tracks() = 0;
|
||||||
|
virtual bool CanEditTracks() = 0;
|
||||||
|
|
||||||
|
private:
|
||||||
|
sdbus::IObject* object_;
|
||||||
|
};
|
||||||
|
|
||||||
|
}}} // namespaces
|
||||||
|
|
||||||
|
#endif
|
306
assets/mpris_stub_proxy.hpp
Normal file
|
@ -0,0 +1,306 @@
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT!
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __sdbuscpp__mpris_stub_proxy_hpp__proxy__H__
|
||||||
|
#define __sdbuscpp__mpris_stub_proxy_hpp__proxy__H__
|
||||||
|
|
||||||
|
#include <sdbus-c++/sdbus-c++.h>
|
||||||
|
#include <string>
|
||||||
|
#include <tuple>
|
||||||
|
|
||||||
|
namespace org {
|
||||||
|
namespace mpris {
|
||||||
|
|
||||||
|
class MediaPlayer2_proxy
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static constexpr const char* INTERFACE_NAME = "org.mpris.MediaPlayer2";
|
||||||
|
|
||||||
|
protected:
|
||||||
|
MediaPlayer2_proxy(sdbus::IProxy& proxy)
|
||||||
|
: proxy_(&proxy)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
MediaPlayer2_proxy(const MediaPlayer2_proxy&) = delete;
|
||||||
|
MediaPlayer2_proxy& operator=(const MediaPlayer2_proxy&) = delete;
|
||||||
|
MediaPlayer2_proxy(MediaPlayer2_proxy&&) = default;
|
||||||
|
MediaPlayer2_proxy& operator=(MediaPlayer2_proxy&&) = default;
|
||||||
|
|
||||||
|
~MediaPlayer2_proxy() = default;
|
||||||
|
|
||||||
|
public:
|
||||||
|
void Raise()
|
||||||
|
{
|
||||||
|
proxy_->callMethod("Raise").onInterface(INTERFACE_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Quit()
|
||||||
|
{
|
||||||
|
proxy_->callMethod("Quit").onInterface(INTERFACE_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool CanRaise()
|
||||||
|
{
|
||||||
|
return proxy_->getProperty("CanRaise").onInterface(INTERFACE_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CanQuit()
|
||||||
|
{
|
||||||
|
return proxy_->getProperty("CanQuit").onInterface(INTERFACE_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HasTrackList()
|
||||||
|
{
|
||||||
|
return proxy_->getProperty("HasTrackList").onInterface(INTERFACE_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Identity()
|
||||||
|
{
|
||||||
|
return proxy_->getProperty("Identity").onInterface(INTERFACE_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> SupportedUriSchemes()
|
||||||
|
{
|
||||||
|
return proxy_->getProperty("SupportedUriSchemes").onInterface(INTERFACE_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> SupportedMimeTypes()
|
||||||
|
{
|
||||||
|
return proxy_->getProperty("SupportedMimeTypes").onInterface(INTERFACE_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
sdbus::IProxy* proxy_;
|
||||||
|
};
|
||||||
|
|
||||||
|
}} // namespaces
|
||||||
|
|
||||||
|
namespace org {
|
||||||
|
namespace mpris {
|
||||||
|
namespace MediaPlayer2 {
|
||||||
|
|
||||||
|
class Player_proxy
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static constexpr const char* INTERFACE_NAME = "org.mpris.MediaPlayer2.Player";
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Player_proxy(sdbus::IProxy& proxy)
|
||||||
|
: proxy_(&proxy)
|
||||||
|
{
|
||||||
|
proxy_->uponSignal("Seeked").onInterface(INTERFACE_NAME).call([this](const int64_t& Position){ this->onSeeked(Position); });
|
||||||
|
}
|
||||||
|
|
||||||
|
Player_proxy(const Player_proxy&) = delete;
|
||||||
|
Player_proxy& operator=(const Player_proxy&) = delete;
|
||||||
|
Player_proxy(Player_proxy&&) = default;
|
||||||
|
Player_proxy& operator=(Player_proxy&&) = default;
|
||||||
|
|
||||||
|
~Player_proxy() = default;
|
||||||
|
|
||||||
|
virtual void onSeeked(const int64_t& Position) = 0;
|
||||||
|
|
||||||
|
public:
|
||||||
|
void Next()
|
||||||
|
{
|
||||||
|
proxy_->callMethod("Next").onInterface(INTERFACE_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Previous()
|
||||||
|
{
|
||||||
|
proxy_->callMethod("Previous").onInterface(INTERFACE_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Pause()
|
||||||
|
{
|
||||||
|
proxy_->callMethod("Pause").onInterface(INTERFACE_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlayPause()
|
||||||
|
{
|
||||||
|
proxy_->callMethod("PlayPause").onInterface(INTERFACE_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Stop()
|
||||||
|
{
|
||||||
|
proxy_->callMethod("Stop").onInterface(INTERFACE_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Play()
|
||||||
|
{
|
||||||
|
proxy_->callMethod("Play").onInterface(INTERFACE_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Seek(const int64_t& Offset)
|
||||||
|
{
|
||||||
|
proxy_->callMethod("Seek").onInterface(INTERFACE_NAME).withArguments(Offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetPosition(const sdbus::ObjectPath& TrackId, const int64_t& Position)
|
||||||
|
{
|
||||||
|
proxy_->callMethod("SetPosition").onInterface(INTERFACE_NAME).withArguments(TrackId, Position);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenUri(const std::string& Uri)
|
||||||
|
{
|
||||||
|
proxy_->callMethod("OpenUri").onInterface(INTERFACE_NAME).withArguments(Uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
std::string PlaybackStatus()
|
||||||
|
{
|
||||||
|
return proxy_->getProperty("PlaybackStatus").onInterface(INTERFACE_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
double Rate()
|
||||||
|
{
|
||||||
|
return proxy_->getProperty("Rate").onInterface(INTERFACE_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Rate(const double& value)
|
||||||
|
{
|
||||||
|
proxy_->setProperty("Rate").onInterface(INTERFACE_NAME).toValue(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::map<std::string, sdbus::Variant> Metadata()
|
||||||
|
{
|
||||||
|
return proxy_->getProperty("Metadata").onInterface(INTERFACE_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
double Volume()
|
||||||
|
{
|
||||||
|
return proxy_->getProperty("Volume").onInterface(INTERFACE_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Volume(const double& value)
|
||||||
|
{
|
||||||
|
proxy_->setProperty("Volume").onInterface(INTERFACE_NAME).toValue(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t Position()
|
||||||
|
{
|
||||||
|
return proxy_->getProperty("Position").onInterface(INTERFACE_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
double MinimumRate()
|
||||||
|
{
|
||||||
|
return proxy_->getProperty("MinimumRate").onInterface(INTERFACE_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
double MaximumRate()
|
||||||
|
{
|
||||||
|
return proxy_->getProperty("MaximumRate").onInterface(INTERFACE_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CanGoNext()
|
||||||
|
{
|
||||||
|
return proxy_->getProperty("CanGoNext").onInterface(INTERFACE_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CanGoPrevious()
|
||||||
|
{
|
||||||
|
return proxy_->getProperty("CanGoPrevious").onInterface(INTERFACE_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CanPlay()
|
||||||
|
{
|
||||||
|
return proxy_->getProperty("CanPlay").onInterface(INTERFACE_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CanPause()
|
||||||
|
{
|
||||||
|
return proxy_->getProperty("CanPause").onInterface(INTERFACE_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CanSeek()
|
||||||
|
{
|
||||||
|
return proxy_->getProperty("CanSeek").onInterface(INTERFACE_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CanControl()
|
||||||
|
{
|
||||||
|
return proxy_->getProperty("CanControl").onInterface(INTERFACE_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
sdbus::IProxy* proxy_;
|
||||||
|
};
|
||||||
|
|
||||||
|
}}} // namespaces
|
||||||
|
|
||||||
|
namespace org {
|
||||||
|
namespace mpris {
|
||||||
|
namespace MediaPlayer2 {
|
||||||
|
|
||||||
|
class TrackList_proxy
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static constexpr const char* INTERFACE_NAME = "org.mpris.MediaPlayer2.TrackList";
|
||||||
|
|
||||||
|
protected:
|
||||||
|
TrackList_proxy(sdbus::IProxy& proxy)
|
||||||
|
: proxy_(&proxy)
|
||||||
|
{
|
||||||
|
proxy_->uponSignal("TrackListReplaced").onInterface(INTERFACE_NAME).call([this](const std::vector<sdbus::ObjectPath>& Tracks, const sdbus::ObjectPath& CurrentTrack){ this->onTrackListReplaced(Tracks, CurrentTrack); });
|
||||||
|
proxy_->uponSignal("TrackAdded").onInterface(INTERFACE_NAME).call([this](const std::map<std::string, sdbus::Variant>& Metadata, const sdbus::ObjectPath& AfterTrack){ this->onTrackAdded(Metadata, AfterTrack); });
|
||||||
|
proxy_->uponSignal("TrackRemoved").onInterface(INTERFACE_NAME).call([this](const sdbus::ObjectPath& TrackId){ this->onTrackRemoved(TrackId); });
|
||||||
|
proxy_->uponSignal("TrackMetadataChanged").onInterface(INTERFACE_NAME).call([this](const sdbus::ObjectPath& TrackId, const std::map<std::string, sdbus::Variant>& Metadata){ this->onTrackMetadataChanged(TrackId, Metadata); });
|
||||||
|
}
|
||||||
|
|
||||||
|
TrackList_proxy(const TrackList_proxy&) = delete;
|
||||||
|
TrackList_proxy& operator=(const TrackList_proxy&) = delete;
|
||||||
|
TrackList_proxy(TrackList_proxy&&) = default;
|
||||||
|
TrackList_proxy& operator=(TrackList_proxy&&) = default;
|
||||||
|
|
||||||
|
~TrackList_proxy() = default;
|
||||||
|
|
||||||
|
virtual void onTrackListReplaced(const std::vector<sdbus::ObjectPath>& Tracks, const sdbus::ObjectPath& CurrentTrack) = 0;
|
||||||
|
virtual void onTrackAdded(const std::map<std::string, sdbus::Variant>& Metadata, const sdbus::ObjectPath& AfterTrack) = 0;
|
||||||
|
virtual void onTrackRemoved(const sdbus::ObjectPath& TrackId) = 0;
|
||||||
|
virtual void onTrackMetadataChanged(const sdbus::ObjectPath& TrackId, const std::map<std::string, sdbus::Variant>& Metadata) = 0;
|
||||||
|
|
||||||
|
public:
|
||||||
|
std::vector<std::map<std::string, sdbus::Variant>> GetTracksMetadata(const std::vector<sdbus::ObjectPath>& TrackIds)
|
||||||
|
{
|
||||||
|
std::vector<std::map<std::string, sdbus::Variant>> result;
|
||||||
|
proxy_->callMethod("GetTracksMetadata").onInterface(INTERFACE_NAME).withArguments(TrackIds).storeResultsTo(result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddTrack(const std::string& Uri, const sdbus::ObjectPath& AfterTrack, const bool& SetAsCurrent)
|
||||||
|
{
|
||||||
|
proxy_->callMethod("AddTrack").onInterface(INTERFACE_NAME).withArguments(Uri, AfterTrack, SetAsCurrent);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RemoveTrack(const sdbus::ObjectPath& TrackId)
|
||||||
|
{
|
||||||
|
proxy_->callMethod("RemoveTrack").onInterface(INTERFACE_NAME).withArguments(TrackId);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GoTo(const sdbus::ObjectPath& TrackId)
|
||||||
|
{
|
||||||
|
proxy_->callMethod("GoTo").onInterface(INTERFACE_NAME).withArguments(TrackId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
std::vector<sdbus::ObjectPath> Tracks()
|
||||||
|
{
|
||||||
|
return proxy_->getProperty("Tracks").onInterface(INTERFACE_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CanEditTracks()
|
||||||
|
{
|
||||||
|
return proxy_->getProperty("CanEditTracks").onInterface(INTERFACE_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
sdbus::IProxy* proxy_;
|
||||||
|
};
|
||||||
|
|
||||||
|
}}} // namespaces
|
||||||
|
|
||||||
|
#endif
|
|
@ -44,7 +44,7 @@ def add_font(input: str, output: str|None = None):
|
||||||
def add_graphic(input: str):
|
def add_graphic(input: str):
|
||||||
GRAPHIC=path.basename(input).removesuffix(".png").lower().replace('-', '_')
|
GRAPHIC=path.basename(input).removesuffix(".png").lower().replace('-', '_')
|
||||||
print("Adding graphic '%s' from file '%s'" % (GRAPHIC, input))
|
print("Adding graphic '%s' from file '%s'" % (GRAPHIC, input))
|
||||||
add_basic(input, GRAPHIC)
|
add_base85(input, GRAPHIC)
|
||||||
def add_license(input: str, output: str):
|
def add_license(input: str, output: str):
|
||||||
LICENSE = output + "_license"
|
LICENSE = output + "_license"
|
||||||
print("Adding license '%s' (C identifier: '%s') from file '%s'" % (output, LICENSE, input))
|
print("Adding license '%s' (C identifier: '%s') from file '%s'" % (output, LICENSE, input))
|
||||||
|
@ -72,7 +72,6 @@ for i in glob("Noto_Sans_JP/*.ttf"):
|
||||||
add_font(i)
|
add_font(i)
|
||||||
add_font("ForkAwesome/fonts/forkawesome-webfont.ttf", "forkawesome")
|
add_font("ForkAwesome/fonts/forkawesome-webfont.ttf", "forkawesome")
|
||||||
add_graphic("icon.png")
|
add_graphic("icon.png")
|
||||||
add_graphic("catoc.png")
|
|
||||||
add_license("Noto_Sans/OFL.txt", "notosans")
|
add_license("Noto_Sans/OFL.txt", "notosans")
|
||||||
add_license("Noto_Sans_JP/OFL.txt", "notosansjp")
|
add_license("Noto_Sans_JP/OFL.txt", "notosansjp")
|
||||||
add_license("../LICENSE.MIT", "looper_mit")
|
add_license("../LICENSE.MIT", "looper_mit")
|
||||||
|
|
|
@ -3,7 +3,5 @@ set(BACKEND_FLUIDSYNTH_INC ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DI
|
||||||
add_playback_backend(fluidsynth_backend ${BACKEND_FLUIDSYNTH_SRC})
|
add_playback_backend(fluidsynth_backend ${BACKEND_FLUIDSYNTH_SRC})
|
||||||
target_include_directories(fluidsynth_backend PRIVATE ${BACKEND_FLUIDSYNTH_INC})
|
target_include_directories(fluidsynth_backend PRIVATE ${BACKEND_FLUIDSYNTH_INC})
|
||||||
find_package(OpenMP)
|
find_package(OpenMP)
|
||||||
find_package(PkgConfig)
|
find_package(FluidSynth)
|
||||||
pkg_check_modules(fluidsynth fluidsynth IMPORTED_TARGET)
|
target_link_libraries(fluidsynth_backend PUBLIC OpenMP::OpenMP_CXX FluidSynth::libfluidsynth)
|
||||||
|
|
||||||
target_link_libraries(fluidsynth_backend PUBLIC OpenMP::OpenMP_CXX PkgConfig::fluidsynth)
|
|
||||||
|
|
|
@ -8,23 +8,6 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <file_backend.hpp>
|
#include <file_backend.hpp>
|
||||||
#include <util.hpp>
|
#include <util.hpp>
|
||||||
#include <filesystem>
|
|
||||||
#include <limits.h>
|
|
||||||
#include <log.hpp>
|
|
||||||
namespace fs = std::filesystem;
|
|
||||||
using Looper::Log::LogStream;
|
|
||||||
static void log_fn(int level, const char *msg, void *data) {
|
|
||||||
LogStream *stream;
|
|
||||||
switch (level) {
|
|
||||||
case FLUID_ERR:
|
|
||||||
case FLUID_PANIC: stream = &ERROR; break;
|
|
||||||
case FLUID_WARN: stream = &WARNING; break;
|
|
||||||
default:
|
|
||||||
case FLUID_INFO: stream = &INFO; break;
|
|
||||||
case FLUID_DBG: stream = &DEBUG; break;
|
|
||||||
}
|
|
||||||
stream->writeln(msg);
|
|
||||||
}
|
|
||||||
void FluidSynthBackend::fluidsynth_get_property_list_wrapper(void *udata, const char *name, int type) {
|
void FluidSynthBackend::fluidsynth_get_property_list_wrapper(void *udata, const char *name, int type) {
|
||||||
((FluidSynthBackend*)udata)->fluidsynth_get_property_list(name, type);
|
((FluidSynthBackend*)udata)->fluidsynth_get_property_list(name, type);
|
||||||
}
|
}
|
||||||
|
@ -33,238 +16,53 @@ void FluidSynthBackend::fluidsynth_get_property_list(const char *name, int type)
|
||||||
property.set_path(fmt::format("fluidsynth/{0}", name));
|
property.set_path(fmt::format("fluidsynth/{0}", name));
|
||||||
property.set_name(name);
|
property.set_name(name);
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case FLUID_NO_TYPE:
|
|
||||||
case FLUID_NUM_TYPE: {
|
case FLUID_NUM_TYPE: {
|
||||||
property.set_type(PropertyType::Double);
|
property.set_type(PropertyType::Double);
|
||||||
double min, max;
|
|
||||||
if (fluid_settings_getnum_range(settings, name, &min, &max) == FLUID_OK) {
|
|
||||||
auto *range = property.mutable_hint()->mutable_range();
|
|
||||||
range->set_min(min);
|
|
||||||
range->set_max(max);
|
|
||||||
}
|
|
||||||
} break;
|
} break;
|
||||||
case FLUID_INT_TYPE: {
|
case FLUID_INT_TYPE: {
|
||||||
property.set_type(PropertyType::Int);
|
property.set_type(PropertyType::Int);
|
||||||
int min, max;
|
|
||||||
if (fluid_settings_getint_range(settings, name, &min, &max) == FLUID_OK) {
|
|
||||||
auto *range = property.mutable_hint()->mutable_range();
|
|
||||||
range->set_min(min);
|
|
||||||
range->set_max(max);
|
|
||||||
}
|
|
||||||
} break;
|
} break;
|
||||||
case FLUID_STR_TYPE: {
|
case FLUID_STR_TYPE: {
|
||||||
property.set_type(PropertyType::String);
|
property.set_type(PropertyType::String);
|
||||||
} break;
|
} break;
|
||||||
default: {
|
|
||||||
throw std::exception();
|
|
||||||
} break;
|
|
||||||
}
|
}
|
||||||
property.set_id(PropertyId::BackendSpecific);
|
property.set_id(PropertyId::BackendSpecific);
|
||||||
fluidsynth_properties.push_back(property);
|
fluidsynth_properties.push_back(property);
|
||||||
}
|
}
|
||||||
static bool log_fn_registered = false;
|
|
||||||
std::vector<Property> FluidSynthBackend::get_property_list() {
|
std::vector<Property> FluidSynthBackend::get_property_list() {
|
||||||
return fluidsynth_properties;
|
return fluidsynth_properties;
|
||||||
}
|
}
|
||||||
void FluidSynthBackend::load(const char *filename) {
|
void FluidSynthBackend::load(const char *filename) {
|
||||||
memset(&spec, 0, sizeof(spec));
|
memset(&spec, 0, sizeof(spec));
|
||||||
if (!log_fn_registered) {
|
|
||||||
fluid_set_log_function(FLUID_PANIC, &log_fn, nullptr);
|
|
||||||
fluid_set_log_function(FLUID_ERR, &log_fn, nullptr);
|
|
||||||
fluid_set_log_function(FLUID_WARN, &log_fn, nullptr);
|
|
||||||
fluid_set_log_function(FLUID_INFO, &log_fn, nullptr);
|
|
||||||
fluid_set_log_function(FLUID_DBG, &log_fn, nullptr);
|
|
||||||
log_fn_registered = true;
|
|
||||||
}
|
|
||||||
current_file = filename;
|
current_file = filename;
|
||||||
spec.format = AUDIO_F32SYS;
|
spec.format = AUDIO_F32SYS;
|
||||||
spec.samples = 100;
|
spec.samples = 100;
|
||||||
spec.channels = 2;
|
spec.channels = 2;
|
||||||
spec.freq = 96000;
|
spec.freq = 48000;
|
||||||
spec.size = 100 * 2 * sizeof(int16_t);
|
spec.size = 100 * 2 * sizeof(int16_t);
|
||||||
File *file = open_file(filename);
|
file = open_file(filename);
|
||||||
settings = new_fluid_settings();
|
this->settings = new_fluid_settings();
|
||||||
fluid_settings_setnum(settings, "synth.sample-rate", 96000.0);
|
|
||||||
fluid_settings_setnum(settings, "synth.gain", 0.5);
|
|
||||||
fluid_settings_foreach(settings, (void*)this, &fluidsynth_get_property_list_wrapper);
|
fluid_settings_foreach(settings, (void*)this, &fluidsynth_get_property_list_wrapper);
|
||||||
synth = new_fluid_synth(settings);
|
|
||||||
player = new_fluid_player(synth);
|
|
||||||
fs::path fpath(filename);
|
|
||||||
fpath = fpath.parent_path() / fpath.stem();
|
|
||||||
|
|
||||||
std::string fpath_str = fpath.string();
|
|
||||||
std::vector<std::string> try_paths = std::vector<std::string>({
|
|
||||||
fpath_str + ".sf2", fpath_str + ".dls"
|
|
||||||
});
|
|
||||||
bool found = false;
|
|
||||||
for (auto &path : try_paths) {
|
|
||||||
const char *path_c = path.c_str();
|
|
||||||
if (fluid_is_soundfont(path_c)) {
|
|
||||||
fluid_synth_sfload(synth, path_c, 1);
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!found) {
|
|
||||||
WARNING.writeln("Could not find a valid companion file to use as a sound font. Make sure the extension is all-lowercase, if you're on a case sensitive filesystem (Such as on Linux).");
|
|
||||||
throw std::exception();
|
|
||||||
}
|
|
||||||
file_data = malloc(file->get_len());
|
|
||||||
file_len = file->read(file_data, 1, file->get_len());
|
|
||||||
delete file;
|
|
||||||
file_data = realloc(file_data, file_len);
|
|
||||||
fluid_player_add_mem(player, file_data, file_len);
|
|
||||||
fluid_player_set_loop(player, -1);
|
|
||||||
fluid_player_play(player);
|
|
||||||
size_t prev_pos = 0;
|
|
||||||
size_t cur_pos = 0;
|
|
||||||
size_t samples = 0;
|
|
||||||
sample_positions.push_back({0, 0});
|
|
||||||
float fakebuf;
|
|
||||||
fluid_player_seek(player, 0);
|
|
||||||
while (prev_pos <= cur_pos) {
|
|
||||||
size_t samples_to_add = std::floor((96000.0 * 60.0) / fluid_player_get_bpm(player));
|
|
||||||
fluid_synth_write_float(synth, samples_to_add, &fakebuf, 0, 0, &fakebuf, 0, 0);
|
|
||||||
samples += samples_to_add;
|
|
||||||
prev_pos = cur_pos;
|
|
||||||
while (prev_pos == cur_pos) {
|
|
||||||
cur_pos = fluid_player_get_current_tick(player);
|
|
||||||
if (prev_pos == cur_pos) {
|
|
||||||
fluid_synth_write_float(synth, 1, &fakebuf, 0, 0, &fakebuf, 0, 0);
|
|
||||||
samples++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sample_positions.push_back({samples, cur_pos});
|
|
||||||
}
|
|
||||||
this->length = samples;
|
|
||||||
}
|
}
|
||||||
extern SDL_AudioSpec obtained;
|
extern SDL_AudioSpec obtained;
|
||||||
void FluidSynthBackend::switch_stream(int idx) {
|
void FluidSynthBackend::switch_stream(int idx) {
|
||||||
fluid_player_seek(player, 0);
|
|
||||||
open = true;
|
|
||||||
}
|
}
|
||||||
void FluidSynthBackend::cleanup() {
|
void FluidSynthBackend::cleanup() {
|
||||||
delete_fluid_player(player);
|
delete file;
|
||||||
player = nullptr;
|
file = nullptr;
|
||||||
delete_fluid_synth(synth);
|
|
||||||
synth = nullptr;
|
|
||||||
delete_fluid_settings(settings);
|
|
||||||
settings = nullptr;
|
|
||||||
file_len = 0;
|
|
||||||
free(file_data);
|
|
||||||
file_data = nullptr;
|
|
||||||
open = false;
|
|
||||||
}
|
}
|
||||||
size_t FluidSynthBackend::render(void *buf, size_t maxlen) {
|
size_t FluidSynthBackend::render(void *buf, size_t maxlen) {
|
||||||
size_t sample_type_len = sizeof(float);
|
size_t sample_type_len = 2;
|
||||||
maxlen /= sample_type_len * 2;
|
maxlen /= sample_type_len;
|
||||||
position += maxlen;
|
maxlen *= sample_type_len;
|
||||||
maxlen *= sample_type_len * 2;
|
return copied;
|
||||||
if (fluid_synth_write_float(synth, maxlen / 2 / sample_type_len, buf, 0, 2, buf, 1, 2) == FLUID_FAILED) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (position >= length) {
|
|
||||||
int tick = fluid_player_get_current_tick(player);
|
|
||||||
int prev_sample = 0;
|
|
||||||
int cur_sample = 0;
|
|
||||||
for (auto &pair : sample_positions) {
|
|
||||||
prev_sample = cur_sample;
|
|
||||||
cur_sample = pair.first;
|
|
||||||
if (pair.second > tick) {
|
|
||||||
position = ((double)prev_sample) / 96000.0;
|
|
||||||
break;
|
|
||||||
} else if (pair.second == tick) {
|
|
||||||
position = ((double)cur_sample) / 96000.0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
void FluidSynthBackend::seek(double position) {
|
||||||
|
|
||||||
return maxlen;
|
|
||||||
}
|
}
|
||||||
bool FluidSynthBackend::is_fluidsynth_setting(std::string path) {
|
double FluidSynthBackend::get_position() {
|
||||||
const char *prefix = "fluidsynth/";
|
|
||||||
if (path.length() < strlen(prefix)) return false;
|
|
||||||
return path.substr(0, strlen(prefix)) == std::string(prefix);
|
|
||||||
}
|
|
||||||
void FluidSynthBackend::seek_samples(uint64_t position) {
|
|
||||||
size_t tick = 0;
|
|
||||||
size_t sample = position;
|
|
||||||
size_t prev_sample = 0;
|
|
||||||
size_t next_sample = 0;
|
|
||||||
for (auto &pair : sample_positions) {
|
|
||||||
prev_sample = next_sample;
|
|
||||||
next_sample = pair.first;
|
|
||||||
if (next_sample > sample) {
|
|
||||||
tick = pair.second - 1;
|
|
||||||
this->position = prev_sample;
|
|
||||||
break;
|
|
||||||
} else if (next_sample == sample) {
|
|
||||||
tick = pair.second;
|
|
||||||
this->position = next_sample;
|
|
||||||
prev_sample = next_sample;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fluid_player_seek(player, tick);
|
|
||||||
float fakebuf;
|
|
||||||
if (sample > prev_sample) fluid_synth_write_float(synth, sample - prev_sample, &fakebuf, 0, 0, &fakebuf, 0, 0);
|
|
||||||
this->position = position;
|
|
||||||
}
|
|
||||||
uint64_t FluidSynthBackend::get_position_samples() {
|
|
||||||
return position;
|
return position;
|
||||||
}
|
}
|
||||||
int FluidSynthBackend::get_stream_idx() {
|
int FluidSynthBackend::get_stream_idx() {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
void FluidSynthBackend::set_fluidsynth_property_str(std::string path, std::string val) {
|
|
||||||
fluid_settings_setstr(settings, path.c_str(), val.c_str());
|
|
||||||
}
|
|
||||||
void FluidSynthBackend::set_fluidsynth_property_num(std::string path, double val) {
|
|
||||||
fluid_settings_setnum(settings, path.c_str(), val);
|
|
||||||
}
|
|
||||||
void FluidSynthBackend::set_fluidsynth_property_int(std::string path, int val) {
|
|
||||||
fluid_settings_setint(settings, path.c_str(), val);
|
|
||||||
}
|
|
||||||
std::optional<std::string> FluidSynthBackend::get_fluidsynth_property_str(std::string path) {
|
|
||||||
char *tmp;
|
|
||||||
if (fluid_settings_dupstr(settings, path.c_str(), &tmp) == FLUID_OK) {
|
|
||||||
std::string output = tmp;
|
|
||||||
free((void*)tmp);
|
|
||||||
return output;
|
|
||||||
} else {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
std::optional<double> FluidSynthBackend::get_fluidsynth_property_num(std::string path) {
|
|
||||||
double output = NAN;
|
|
||||||
if (fluid_settings_getnum(settings, path.c_str(), &output) == FLUID_OK) return output;
|
|
||||||
else return {};
|
|
||||||
}
|
|
||||||
std::optional<int> FluidSynthBackend::get_fluidsynth_property_int(std::string path) {
|
|
||||||
int output = 0;
|
|
||||||
if (fluid_settings_getint(settings, path.c_str(), &output) == FLUID_OK) return output;
|
|
||||||
else return {};
|
|
||||||
}
|
|
||||||
void FluidSynthBackend::reset_fluidsynth_property(std::string path) {
|
|
||||||
switch (fluid_settings_get_type(settings, path.c_str())) {
|
|
||||||
case FLUID_INT_TYPE: {
|
|
||||||
int output;
|
|
||||||
if (fluid_settings_getint_default(settings, path.c_str(), &output) == FLUID_OK) {
|
|
||||||
fluid_settings_setint(settings, path.c_str(), output);
|
|
||||||
}
|
|
||||||
} break;
|
|
||||||
case FLUID_STR_TYPE: {
|
|
||||||
char *val;
|
|
||||||
if (fluid_settings_getstr_default(settings, path.c_str(), &val) == FLUID_OK) {
|
|
||||||
fluid_settings_setstr(settings, path.c_str(), val);
|
|
||||||
}
|
|
||||||
} break;
|
|
||||||
case FLUID_NUM_TYPE: {
|
|
||||||
double val;
|
|
||||||
if (fluid_settings_getnum_default(settings, path.c_str(), &val) == FLUID_OK) {
|
|
||||||
fluid_settings_setnum(settings, path.c_str(), val);
|
|
||||||
}
|
|
||||||
} break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -12,114 +12,19 @@
|
||||||
#include <SDL.h>
|
#include <SDL.h>
|
||||||
#include "file_backend.hpp"
|
#include "file_backend.hpp"
|
||||||
#include <fluidsynth.h>
|
#include <fluidsynth.h>
|
||||||
#include <vector>
|
|
||||||
class FluidSynthBackend : public PlaybackBackend {
|
class FluidSynthBackend : public PlaybackBackend {
|
||||||
void *file_data;
|
File *file;
|
||||||
size_t file_len;
|
|
||||||
static void fluidsynth_get_property_list_wrapper(void *udata, const char *name, int type);
|
static void fluidsynth_get_property_list_wrapper(void *udata, const char *name, int type);
|
||||||
std::vector<Property> fluidsynth_properties;
|
std::vector<Property> fluidsynth_properties;
|
||||||
fluid_settings_t *settings;
|
fluid_settings_t *settings;
|
||||||
fluid_synth_t *synth;
|
|
||||||
fluid_player_t *player;
|
|
||||||
std::vector<std::pair<size_t, size_t>> sample_positions;
|
|
||||||
void fluidsynth_get_property_list(const char *name, int type);
|
void fluidsynth_get_property_list(const char *name, int type);
|
||||||
public:
|
public:
|
||||||
void set_fluidsynth_property_str(std::string path, std::string val);
|
void set_fluidsynth_property_str(std::string path, std::string val);
|
||||||
void set_fluidsynth_property_num(std::string path, double val);
|
void set_fluidsynth_property_num(std::string path, double val);
|
||||||
void set_fluidsynth_property_int(std::string path, int val);
|
void set_fluidsynth_property_int(std::string path, int val);
|
||||||
std::optional<std::string> get_fluidsynth_property_str(std::string path);
|
std::string get_fluidsynth_property_str(std::string path);
|
||||||
std::optional<double> get_fluidsynth_property_num(std::string path);
|
double get_fluidsynth_property_num(std::string path);
|
||||||
std::optional<int> get_fluidsynth_property_int(std::string path);
|
int get_fluidsynth_property_int(std::string path);
|
||||||
void reset_fluidsynth_property(std::string path);
|
|
||||||
bool is_fluidsynth_setting(std::string path);
|
|
||||||
inline std::optional<std::string> get_property_string(google::protobuf::Any value) {
|
|
||||||
try {
|
|
||||||
StringProperty * property = resolve_any<StringProperty>(value);
|
|
||||||
std::string output = property->value();
|
|
||||||
delete property;
|
|
||||||
return output;
|
|
||||||
} catch (std::exception e) {
|
|
||||||
}
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
inline std::optional<double> get_property_double(google::protobuf::Any value) {
|
|
||||||
try {
|
|
||||||
DoubleProperty *property = resolve_any<DoubleProperty>(value);
|
|
||||||
double output = property->value();
|
|
||||||
delete property;
|
|
||||||
return output;
|
|
||||||
} catch (std::exception e) {
|
|
||||||
}
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
inline std::optional<int> get_property_int(google::protobuf::Any value) {
|
|
||||||
try {
|
|
||||||
IntProperty *property = resolve_any<IntProperty>(value);
|
|
||||||
int output = property->value();
|
|
||||||
delete property;
|
|
||||||
return output;
|
|
||||||
} catch (std::exception e) {
|
|
||||||
}
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
inline bool set(std::string path, google::protobuf::Any value) override {
|
|
||||||
if (!is_fluidsynth_setting(path)) {
|
|
||||||
return PlaybackBackend::set(path, value);
|
|
||||||
}
|
|
||||||
std::string fluidsynth_path = path.substr(strlen("fluidsynth/"));
|
|
||||||
auto maybe_num = get_property_double(value);
|
|
||||||
if (maybe_num.has_value()) {
|
|
||||||
set_fluidsynth_property_num(fluidsynth_path, maybe_num.value());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
auto maybe_int = get_property_int(value);
|
|
||||||
if (maybe_int.has_value()) {
|
|
||||||
set_fluidsynth_property_int(fluidsynth_path, maybe_int.value());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
auto maybe_string = get_property_string(value);
|
|
||||||
if (maybe_string.has_value()) {
|
|
||||||
set_fluidsynth_property_str(fluidsynth_path, maybe_string.value());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
inline std::optional<google::protobuf::Any> get(std::string path) override {
|
|
||||||
if (!is_fluidsynth_setting(path)) return PlaybackBackend::get(path);
|
|
||||||
std::string fluidsynth_path = path.substr(strlen("fluidsynth/"));
|
|
||||||
google::protobuf::Any output;
|
|
||||||
switch (fluid_settings_get_type(settings, fluidsynth_path.c_str())) {
|
|
||||||
case FLUID_INT_TYPE: {
|
|
||||||
IntProperty prop;
|
|
||||||
auto val = get_fluidsynth_property_int(fluidsynth_path);
|
|
||||||
if (!val.has_value()) return {};
|
|
||||||
prop.set_value(val.value());
|
|
||||||
output.PackFrom(prop);
|
|
||||||
} break;
|
|
||||||
case FLUID_STR_TYPE: {
|
|
||||||
StringProperty prop;
|
|
||||||
auto val = get_fluidsynth_property_str(fluidsynth_path);
|
|
||||||
if (!val.has_value()) return {};
|
|
||||||
prop.set_value(val.value());
|
|
||||||
output.PackFrom(prop);
|
|
||||||
} break;
|
|
||||||
case FLUID_NUM_TYPE: {
|
|
||||||
DoubleProperty prop;
|
|
||||||
auto val = get_fluidsynth_property_num(fluidsynth_path);
|
|
||||||
if (!val.has_value()) return {};
|
|
||||||
prop.set_value(val.value());
|
|
||||||
output.PackFrom(prop);
|
|
||||||
} break;
|
|
||||||
default: return {};
|
|
||||||
}
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
inline std::optional<google::protobuf::Any> reset(std::string path) override {
|
|
||||||
if (!is_fluidsynth_setting(path)) return PlaybackBackend::reset(path);
|
|
||||||
std::string fluidsynth_path = path.substr(strlen("fluidsynth/"));
|
|
||||||
reset_fluidsynth_property(fluidsynth_path);
|
|
||||||
return get(path);
|
|
||||||
}
|
|
||||||
inline std::string get_id() override {
|
inline std::string get_id() override {
|
||||||
return "fluidsynth";
|
return "fluidsynth";
|
||||||
}
|
}
|
||||||
|
@ -127,12 +32,15 @@ class FluidSynthBackend : public PlaybackBackend {
|
||||||
return "MIDI player";
|
return "MIDI player";
|
||||||
}
|
}
|
||||||
std::vector<Property> get_property_list() override;
|
std::vector<Property> get_property_list() override;
|
||||||
void seek_samples(uint64_t position) override;
|
void seek(double position) override;
|
||||||
void load(const char *filename) override;
|
void load(const char *filename) override;
|
||||||
void switch_stream(int idx) override;
|
void switch_stream(int idx) override;
|
||||||
void cleanup() override;
|
void cleanup() override;
|
||||||
int get_stream_idx() override;
|
int get_stream_idx() override;
|
||||||
size_t render(void *buf, size_t maxlen) override;
|
size_t render(void *buf, size_t maxlen) override;
|
||||||
uint64_t get_position_samples() override;
|
double get_position() override;
|
||||||
|
inline double get_length() override {
|
||||||
|
return length;
|
||||||
|
}
|
||||||
inline ~FluidSynthBackend() override { }
|
inline ~FluidSynthBackend() override { }
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
set(BACKEND_GME_SRC ${CMAKE_CURRENT_SOURCE_DIR}/gme_backend.cpp)
|
|
||||||
set(BACKEND_GME_INC ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR})
|
|
||||||
pkg_check_modules(libgme IMPORTED_TARGET libgme)
|
|
||||||
add_playback_backend(gme_backend ${BACKEND_GME_SRC})
|
|
||||||
target_include_directories(gme_backend PRIVATE ${BACKEND_GME_INC})
|
|
||||||
find_package(OpenMP)
|
|
||||||
target_link_libraries(gme_backend PUBLIC PkgConfig::libgme OpenMP::OpenMP_CXX)
|
|
|
@ -1,4 +0,0 @@
|
||||||
{
|
|
||||||
"class_name": "GmeBackend",
|
|
||||||
"include_path": "gme_backend.hpp"
|
|
||||||
}
|
|
|
@ -1,39 +0,0 @@
|
||||||
# Install script for directory: /boot/home/Desktop/looper/backends/playback/zsm
|
|
||||||
|
|
||||||
# Set the install prefix
|
|
||||||
if(NOT DEFINED CMAKE_INSTALL_PREFIX)
|
|
||||||
set(CMAKE_INSTALL_PREFIX "/boot/system")
|
|
||||||
endif()
|
|
||||||
string(REGEX REPLACE "/$" "" CMAKE_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}")
|
|
||||||
|
|
||||||
# Set the install configuration name.
|
|
||||||
if(NOT DEFINED CMAKE_INSTALL_CONFIG_NAME)
|
|
||||||
if(BUILD_TYPE)
|
|
||||||
string(REGEX REPLACE "^[^A-Za-z0-9_]+" ""
|
|
||||||
CMAKE_INSTALL_CONFIG_NAME "${BUILD_TYPE}")
|
|
||||||
else()
|
|
||||||
set(CMAKE_INSTALL_CONFIG_NAME "RelWithDebInfo")
|
|
||||||
endif()
|
|
||||||
message(STATUS "Install configuration: \"${CMAKE_INSTALL_CONFIG_NAME}\"")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Set the component getting installed.
|
|
||||||
if(NOT CMAKE_INSTALL_COMPONENT)
|
|
||||||
if(COMPONENT)
|
|
||||||
message(STATUS "Install component: \"${COMPONENT}\"")
|
|
||||||
set(CMAKE_INSTALL_COMPONENT "${COMPONENT}")
|
|
||||||
else()
|
|
||||||
set(CMAKE_INSTALL_COMPONENT)
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Is this installation the result of a crosscompile?
|
|
||||||
if(NOT DEFINED CMAKE_CROSSCOMPILING)
|
|
||||||
set(CMAKE_CROSSCOMPILING "FALSE")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Set path to fallback-tool for dependency-resolution.
|
|
||||||
if(NOT DEFINED CMAKE_OBJDUMP)
|
|
||||||
set(CMAKE_OBJDUMP "/system/bin/objdump")
|
|
||||||
endif()
|
|
||||||
|
|
|
@ -1,123 +0,0 @@
|
||||||
#include "gme_backend.hpp"
|
|
||||||
#include <algorithm>
|
|
||||||
#include <ipc/common.pb.h>
|
|
||||||
#include <exception>
|
|
||||||
#include <filesystem>
|
|
||||||
#include "file_backend.hpp"
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <file_backend.hpp>
|
|
||||||
#include <util.hpp>
|
|
||||||
#include <license.hpp>
|
|
||||||
#include <assets/assets.h>
|
|
||||||
#include <limits.h>
|
|
||||||
#include <gme/gme.h>
|
|
||||||
void GmeBackend::load(const char *filename) {
|
|
||||||
memset(&spec, 0, sizeof(spec));
|
|
||||||
current_file = filename;
|
|
||||||
spec.format = AUDIO_S16SYS;
|
|
||||||
spec.samples = 100;
|
|
||||||
spec.channels = 2;
|
|
||||||
spec.freq = 48000;
|
|
||||||
spec.size = 100 * 2 * sizeof(int16_t);
|
|
||||||
gme_open_file(filename, &gme_backend, spec.freq);
|
|
||||||
if (gme_backend == NULL) {
|
|
||||||
throw std::exception();
|
|
||||||
}
|
|
||||||
int track_count = gme_track_count(gme_backend);
|
|
||||||
streams.clear();
|
|
||||||
for (int i = 0; i < track_count; i++) {
|
|
||||||
gme_info_t *info;
|
|
||||||
gme_track_info(gme_backend, &info, i);
|
|
||||||
PlaybackStream stream;
|
|
||||||
if (info->song[0] == '\0') {
|
|
||||||
stream.name = fmt::format("Song {}", i);
|
|
||||||
} else {
|
|
||||||
stream.name = info->song;
|
|
||||||
}
|
|
||||||
|
|
||||||
stream.length = ((double)info->length) / 1000.0;
|
|
||||||
if (stream.length < 0.0) stream.length = 0.0;
|
|
||||||
stream.id = i;
|
|
||||||
streams.push_back(stream);
|
|
||||||
gme_free_info(info);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
extern SDL_AudioSpec obtained;
|
|
||||||
void GmeBackend::switch_stream(int idx) {
|
|
||||||
if (gme_backend == NULL) {
|
|
||||||
throw std::exception();
|
|
||||||
}
|
|
||||||
if (idx > streams.size()) {
|
|
||||||
throw std::exception();
|
|
||||||
}
|
|
||||||
gme_start_track(gme_backend, idx);
|
|
||||||
gme_info_t *info;
|
|
||||||
gme_track_info(gme_backend, &info, idx);
|
|
||||||
if (info->length < 0) {
|
|
||||||
info->length = 0;
|
|
||||||
}
|
|
||||||
uint64_t tmp = info->length;
|
|
||||||
tmp *= spec.freq;
|
|
||||||
tmp /= 1000;
|
|
||||||
this->length = tmp;
|
|
||||||
this->loop_len = info->loop_length;
|
|
||||||
this->loop_start = info->intro_length;
|
|
||||||
if (info->song[0] == '\0') {
|
|
||||||
this->current_title = {};
|
|
||||||
} else {
|
|
||||||
this->current_title = info->song;
|
|
||||||
}
|
|
||||||
gme_free_info(info);
|
|
||||||
gme_ignore_silence(gme_backend, true);
|
|
||||||
open = true;
|
|
||||||
}
|
|
||||||
void GmeBackend::cleanup() {
|
|
||||||
gme_delete(gme_backend);
|
|
||||||
gme_backend = NULL;
|
|
||||||
streams.clear();
|
|
||||||
}
|
|
||||||
size_t GmeBackend::render(void *buf, size_t maxlen) {
|
|
||||||
if (gme_backend == NULL) return 0;
|
|
||||||
const char *err;
|
|
||||||
size_t sample_type_len = 4;
|
|
||||||
maxlen /= sample_type_len;
|
|
||||||
if (err = gme_play(gme_backend, maxlen * 2, (short*)buf)) {
|
|
||||||
ERROR.writefln("Failed to play audio: %s", err);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
int pos_samples = gme_tell_samples(gme_backend);
|
|
||||||
int loop_end = loop_len + loop_start;
|
|
||||||
uint64_t loop_end_samples = loop_end;
|
|
||||||
loop_end_samples *= spec.freq;
|
|
||||||
loop_end_samples /= 1000;
|
|
||||||
uint64_t loop_start_samples = loop_start;
|
|
||||||
loop_start_samples *= spec.freq;
|
|
||||||
loop_start_samples /= 1000;
|
|
||||||
if (pos_samples >= loop_end_samples || gme_track_ended(gme_backend)) {
|
|
||||||
gme_seek_samples(gme_backend, loop_start_samples + (pos_samples - loop_end_samples));
|
|
||||||
}
|
|
||||||
maxlen *= sample_type_len;
|
|
||||||
return maxlen;
|
|
||||||
}
|
|
||||||
uint64_t GmeBackend::get_min_samples() {
|
|
||||||
return spec.size;
|
|
||||||
}
|
|
||||||
std::optional<uint64_t> GmeBackend::get_max_samples() {
|
|
||||||
return get_min_samples();
|
|
||||||
}
|
|
||||||
void GmeBackend::seek_samples(uint64_t position) {
|
|
||||||
gme_seek_samples(gme_backend, position);
|
|
||||||
}
|
|
||||||
uint64_t GmeBackend::get_position_samples() {
|
|
||||||
return gme_tell_samples(gme_backend);
|
|
||||||
}
|
|
||||||
int GmeBackend::get_stream_idx() {
|
|
||||||
return streamidx;
|
|
||||||
}
|
|
||||||
void GmeBackend::add_licenses() {
|
|
||||||
auto &license_data = get_license_data();
|
|
||||||
auto gme = LicenseData("gme", "lgpl-2.1");
|
|
||||||
LOAD_LICENSE(gme, lgpl_2_1);
|
|
||||||
license_data.insert(gme);
|
|
||||||
}
|
|
|
@ -1,44 +0,0 @@
|
||||||
#pragma once
|
|
||||||
#include "playback_backend.hpp"
|
|
||||||
#include <omp.h>
|
|
||||||
#include <cstdint>
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <streambuf>
|
|
||||||
#include <vector>
|
|
||||||
#include <util.hpp>
|
|
||||||
#include <SDL.h>
|
|
||||||
#include <gme/gme.h>
|
|
||||||
#include "file_backend.hpp"
|
|
||||||
class GmeBackend : public PlaybackBackend {
|
|
||||||
File *file;
|
|
||||||
Fifo<int16_t> audio_buf;
|
|
||||||
Music_Emu *gme_backend;
|
|
||||||
int streamidx;
|
|
||||||
int loop_len, loop_start;
|
|
||||||
std::map<std::string, int> voices;
|
|
||||||
public:
|
|
||||||
uint64_t get_min_samples() override;
|
|
||||||
std::optional<uint64_t> get_max_samples() override;
|
|
||||||
inline std::string get_id() override {
|
|
||||||
return "gme";
|
|
||||||
}
|
|
||||||
inline std::string get_name() override {
|
|
||||||
return "Game Music Emu";
|
|
||||||
}
|
|
||||||
void add_licenses() override;
|
|
||||||
//std::vector<Property> get_property_list() override;
|
|
||||||
void seek_samples(uint64_t position) override;
|
|
||||||
void load(const char *filename) override;
|
|
||||||
void switch_stream(int idx) override;
|
|
||||||
void cleanup() override;
|
|
||||||
int get_stream_idx() override;
|
|
||||||
size_t render(void *buf, size_t maxlen) override;
|
|
||||||
uint64_t get_position_samples() override;
|
|
||||||
inline uint64_t get_length_samples() override {
|
|
||||||
return length;
|
|
||||||
}
|
|
||||||
inline ~GmeBackend() override { }
|
|
||||||
};
|
|
|
@ -1,10 +0,0 @@
|
||||||
#define BOOL_PROPERTY(name, default_value) _PROPERTY(name, bool, default_value)
|
|
||||||
#define DOUBLE_PROPERTY(name, default_value) _PROPERTY(name, double, default_value)
|
|
||||||
BOOL_PROPERTY(pcm_enable, true)
|
|
||||||
BOOL_PROPERTY(psg_enable, true)
|
|
||||||
BOOL_PROPERTY(fm_enable, true)
|
|
||||||
DOUBLE_PROPERTY(pcm_volume, 1.0)
|
|
||||||
DOUBLE_PROPERTY(psg_volume, 1.0)
|
|
||||||
DOUBLE_PROPERTY(fm_volume, 1.0)
|
|
||||||
#undef BOOL_PROPERTY
|
|
||||||
#undef DOUBLE_PROPERTY
|
|
|
@ -62,7 +62,10 @@ void SDLMixerXBackend::load(const char *filename) {
|
||||||
current_file = std::string(filename);
|
current_file = std::string(filename);
|
||||||
const char *title_tag = Mix_GetMusicTitleTag(output);
|
const char *title_tag = Mix_GetMusicTitleTag(output);
|
||||||
// Check for an empty string, which indicates there's no title tag.
|
// Check for an empty string, which indicates there's no title tag.
|
||||||
if (title_tag[0] != '\0') {
|
if (title_tag[0] == '\0') {
|
||||||
|
std::filesystem::path path(current_file);
|
||||||
|
current_title = path.stem().string();
|
||||||
|
} else {
|
||||||
current_title = std::string(title_tag);
|
current_title = std::string(title_tag);
|
||||||
}
|
}
|
||||||
this->music = output;
|
this->music = output;
|
||||||
|
@ -70,9 +73,9 @@ void SDLMixerXBackend::load(const char *filename) {
|
||||||
PlaybackStream stream;
|
PlaybackStream stream;
|
||||||
stream.id = 0;
|
stream.id = 0;
|
||||||
stream.length = Mix_MusicDuration(output);
|
stream.length = Mix_MusicDuration(output);
|
||||||
open = true;
|
stream.name = current_title;
|
||||||
stream.name = get_title().value();
|
|
||||||
streams.push_back(stream);
|
streams.push_back(stream);
|
||||||
|
open = true;
|
||||||
initial = true;
|
initial = true;
|
||||||
}
|
}
|
||||||
void SDLMixerXBackend::switch_stream(int idx) {
|
void SDLMixerXBackend::switch_stream(int idx) {
|
||||||
|
@ -110,7 +113,7 @@ size_t SDLMixerXBackend::render(void *buf, size_t maxlen) {
|
||||||
}
|
}
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
double SDLMixerXBackend::get_position_time() {
|
double SDLMixerXBackend::get_position() {
|
||||||
if (music == nullptr || file == nullptr) {
|
if (music == nullptr || file == nullptr) {
|
||||||
open = false;
|
open = false;
|
||||||
return 0.0;
|
return 0.0;
|
||||||
|
|
|
@ -7,7 +7,6 @@ class SDLMixerXBackend : public PlaybackBackend {
|
||||||
Mix_CommonMixer_t mixer;
|
Mix_CommonMixer_t mixer;
|
||||||
File *file;
|
File *file;
|
||||||
bool initial = false;
|
bool initial = false;
|
||||||
double length;
|
|
||||||
public:
|
public:
|
||||||
inline std::string get_id() override {
|
inline std::string get_id() override {
|
||||||
return "sdl_mixer_x";
|
return "sdl_mixer_x";
|
||||||
|
@ -16,20 +15,8 @@ class SDLMixerXBackend : public PlaybackBackend {
|
||||||
return "SDL Mixer X";
|
return "SDL Mixer X";
|
||||||
}
|
}
|
||||||
std::optional<uint64_t> get_max_samples() override;
|
std::optional<uint64_t> get_max_samples() override;
|
||||||
inline double get_length() override {
|
|
||||||
return length;
|
|
||||||
}
|
|
||||||
inline uint64_t get_length_samples() override {
|
|
||||||
return time_to_samples(get_length());
|
|
||||||
}
|
|
||||||
void seek(double position) override;
|
void seek(double position) override;
|
||||||
inline void seek_samples(uint64_t position) override {
|
double get_position() override;
|
||||||
seek(samples_to_time(position));
|
|
||||||
}
|
|
||||||
double get_position_time() override;
|
|
||||||
inline uint64_t get_position_samples() override {
|
|
||||||
return time_to_samples(get_position_time());
|
|
||||||
}
|
|
||||||
void load(const char *filename) override;
|
void load(const char *filename) override;
|
||||||
void switch_stream(int idx) override;
|
void switch_stream(int idx) override;
|
||||||
void cleanup() override;
|
void cleanup() override;
|
||||||
|
|
|
@ -115,23 +115,23 @@ size_t VgmStreamBackend::render(void *buf, size_t maxlen) {
|
||||||
size_t new_samples = render_vgmstream((sample_t*)(buf), (int)maxlen, vf);
|
size_t new_samples = render_vgmstream((sample_t*)(buf), (int)maxlen, vf);
|
||||||
if (maxlen > new_samples) {
|
if (maxlen > new_samples) {
|
||||||
reset_vgmstream(vf);
|
reset_vgmstream(vf);
|
||||||
position = 0;
|
position = 0.0;
|
||||||
} else {
|
} else {
|
||||||
position += new_samples;
|
position += (double)new_samples / (double)vf->sample_rate;
|
||||||
}
|
}
|
||||||
return new_samples * sizeof(sample_t);
|
return new_samples * sizeof(sample_t);
|
||||||
}
|
}
|
||||||
void VgmStreamBackend::seek_samples(uint64_t position) {
|
void VgmStreamBackend::seek(double position) {
|
||||||
|
|
||||||
if (vf == nullptr || sf == nullptr || file == nullptr) {
|
if (vf == nullptr || sf == nullptr || file == nullptr) {
|
||||||
open = false;
|
open = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto pos32 = (int32_t)(position);
|
auto pos32 = (int32_t)(position * vf->sample_rate);
|
||||||
seek_vgmstream(vf, pos32);
|
seek_vgmstream(vf, pos32);
|
||||||
this->position = position;
|
this->position = position;
|
||||||
}
|
}
|
||||||
uint64_t VgmStreamBackend::get_position_samples() {
|
double VgmStreamBackend::get_position() {
|
||||||
return position;
|
return position;
|
||||||
}
|
}
|
||||||
int VgmStreamBackend::get_stream_idx() {
|
int VgmStreamBackend::get_stream_idx() {
|
||||||
|
|
|
@ -17,13 +17,13 @@ class VgmStreamBackend : public PlaybackBackend {
|
||||||
inline std::string get_name() override {
|
inline std::string get_name() override {
|
||||||
return "VGMStream";
|
return "VGMStream";
|
||||||
}
|
}
|
||||||
void seek_samples(uint64_t position) override;
|
void seek(double position) override;
|
||||||
void load(const char *filename) override;
|
void load(const char *filename) override;
|
||||||
void switch_stream(int idx) override;
|
void switch_stream(int idx) override;
|
||||||
void cleanup() override;
|
void cleanup() override;
|
||||||
int get_stream_idx() override;
|
int get_stream_idx() override;
|
||||||
size_t render(void *buf, size_t maxlen) override;
|
size_t render(void *buf, size_t maxlen) override;
|
||||||
uint64_t get_position_samples() override;
|
double get_position() override;
|
||||||
void add_licenses() override;
|
void add_licenses() override;
|
||||||
inline ~VgmStreamBackend() override { }
|
inline ~VgmStreamBackend() override { }
|
||||||
};
|
};
|
||||||
|
|
|
@ -106,31 +106,31 @@ void ZsmBackend::load(const char *filename) {
|
||||||
}
|
}
|
||||||
file->seek(music_data_start, SeekType::SET);
|
file->seek(music_data_start, SeekType::SET);
|
||||||
this->loop_point = std::max(this->loop_point, (uint32_t)music_data_start);
|
this->loop_point = std::max(this->loop_point, (uint32_t)music_data_start);
|
||||||
uint64_t prev_time = 0;
|
double prev_time = 0.0;
|
||||||
uint64_t time = 0;
|
double time = 0.0;
|
||||||
double tmpDelayTicks = 0.0;
|
double tmpDelayTicks = 0.0;
|
||||||
loop_pos = UINT64_MAX;
|
loop_pos = -1.0;
|
||||||
uint32_t prev_pos = music_data_start;
|
uint32_t prev_pos = music_data_start;
|
||||||
while (true) {
|
while (true) {
|
||||||
tmpDelayTicks -= get_delay_per_frame();
|
tmpDelayTicks -= get_delay_per_frame();
|
||||||
if (tmpDelayTicks < 0.0) {
|
if (tmpDelayTicks < 0.0) {
|
||||||
ZsmCommand cmd = get_command();
|
ZsmCommand cmd = get_command();
|
||||||
size_t cur_pos = file->get_pos();
|
size_t cur_pos = file->get_pos();
|
||||||
if (cur_pos >= this->loop_point && this->loop_pos == UINT64_MAX) {
|
if (cur_pos >= this->loop_point && this->loop_pos < 0) {
|
||||||
loop_pos = time;
|
loop_pos = time;
|
||||||
this->loop_point = cur_pos;
|
this->loop_point = cur_pos;
|
||||||
}
|
}
|
||||||
if (cmd.id == ZsmEOF) {
|
if (cmd.id == ZsmEOF) {
|
||||||
break;
|
break;
|
||||||
} else if (cmd.id == Delay) {
|
} else if (cmd.id == Delay) {
|
||||||
time += (((double)cmd.delay) / ((double)(tick_rate))) * PSG_FREQ;
|
time += ((double)cmd.delay) / ((double)(tick_rate));
|
||||||
tmpDelayTicks += cmd.delay;
|
tmpDelayTicks += cmd.delay;
|
||||||
}
|
}
|
||||||
prev_pos = file->get_pos();
|
prev_pos = file->get_pos();
|
||||||
prev_time = time;
|
prev_time = time;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (this->loop_pos == UINT64_MAX) {
|
if (this->loop_pos < 0.0) {
|
||||||
this->loop_pos = 0.0;
|
this->loop_pos = 0.0;
|
||||||
this->loop_point = music_data_start;
|
this->loop_point = music_data_start;
|
||||||
}
|
}
|
||||||
|
@ -157,7 +157,6 @@ void ZsmBackend::load(const char *filename) {
|
||||||
property_defaults[#name] = value; \
|
property_defaults[#name] = value; \
|
||||||
}
|
}
|
||||||
#include "properties.inc"
|
#include "properties.inc"
|
||||||
PlaybackStream stream;
|
|
||||||
}
|
}
|
||||||
extern SDL_AudioSpec obtained;
|
extern SDL_AudioSpec obtained;
|
||||||
void ZsmBackend::switch_stream(int idx) {
|
void ZsmBackend::switch_stream(int idx) {
|
||||||
|
@ -173,7 +172,6 @@ void ZsmBackend::switch_stream(int idx) {
|
||||||
this->cpuClocks = 0.0;
|
this->cpuClocks = 0.0;
|
||||||
this->delayTicks = 0.0;
|
this->delayTicks = 0.0;
|
||||||
this->ticks = 0.0;
|
this->ticks = 0.0;
|
||||||
open = true;
|
|
||||||
}
|
}
|
||||||
void ZsmBackend::cleanup() {
|
void ZsmBackend::cleanup() {
|
||||||
delete file;
|
delete file;
|
||||||
|
@ -225,7 +223,7 @@ void ZsmBackend::tick(bool step) {
|
||||||
} break;
|
} break;
|
||||||
case Delay: {
|
case Delay: {
|
||||||
delayTicks += cmd.delay;
|
delayTicks += cmd.delay;
|
||||||
position += (((double)cmd.delay) / ((double)(tick_rate))) * spec.freq;
|
position += ((double)cmd.delay) / ((double)(tick_rate));
|
||||||
} break;
|
} break;
|
||||||
case ExtCmd: {
|
case ExtCmd: {
|
||||||
//cmd.extcmd.channel
|
//cmd.extcmd.channel
|
||||||
|
@ -386,14 +384,16 @@ ZsmCommand::~ZsmCommand() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void ZsmBackend::seek_internal(uint64_t position, bool loop) {;
|
void ZsmBackend::seek_internal(double position, bool loop) {
|
||||||
|
this->position = std::floor(this->position * PSG_FREQ) / PSG_FREQ;
|
||||||
|
position = std::floor(position * PSG_FREQ) / PSG_FREQ;
|
||||||
if (this->position > position) {
|
if (this->position > position) {
|
||||||
switch_stream(0);
|
switch_stream(0);
|
||||||
file->seek(music_data_start, SeekType::SET);
|
file->seek(music_data_start, SeekType::SET);
|
||||||
this->cpuClocks = 0.0;
|
this->cpuClocks = 0.0;
|
||||||
this->delayTicks = 0;
|
this->delayTicks = 0;
|
||||||
this->ticks = 0.0;
|
this->ticks = 0.0;
|
||||||
this->position = 0;
|
this->position = 0.0;
|
||||||
} else if (this->position == position) {
|
} else if (this->position == position) {
|
||||||
audio_buf.clear();
|
audio_buf.clear();
|
||||||
return;
|
return;
|
||||||
|
@ -408,7 +408,7 @@ void ZsmBackend::seek_internal(uint64_t position, bool loop) {;
|
||||||
this->cpuClocks = 0.0;
|
this->cpuClocks = 0.0;
|
||||||
this->delayTicks = 0;
|
this->delayTicks = 0;
|
||||||
this->ticks = 0.0;
|
this->ticks = 0.0;
|
||||||
this->position = 0;
|
this->position = 0.0;
|
||||||
audio_buf.clear();
|
audio_buf.clear();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -419,18 +419,15 @@ void ZsmBackend::seek_internal(uint64_t position, bool loop) {;
|
||||||
}
|
}
|
||||||
this->position = position;
|
this->position = position;
|
||||||
}
|
}
|
||||||
void ZsmBackend::seek_samples(uint64_t position) {
|
void ZsmBackend::seek(double position) {
|
||||||
seek_internal(position, false);
|
seek_internal(position, false);
|
||||||
}
|
}
|
||||||
uint64_t ZsmBackend::get_position_samples() {
|
double ZsmBackend::get_position() {
|
||||||
return position;
|
return position;
|
||||||
}
|
}
|
||||||
int ZsmBackend::get_stream_idx() {
|
int ZsmBackend::get_stream_idx() {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
uint64_t ZsmBackend::get_loop_start_samples() {
|
|
||||||
return loop_start;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ZsmBackend::audio_step(size_t samples) {
|
void ZsmBackend::audio_step(size_t samples) {
|
||||||
if (samples == 0) return;
|
if (samples == 0) return;
|
||||||
|
|
|
@ -108,7 +108,7 @@ class ZsmBackend : public PlaybackBackend {
|
||||||
return audio_buf.pop((int16_t*)buf, len);
|
return audio_buf.pop((int16_t*)buf, len);
|
||||||
}
|
}
|
||||||
uint32_t loop_point;
|
uint32_t loop_point;
|
||||||
uint64_t loop_pos = 0;
|
double loop_pos = 0.0;
|
||||||
uint32_t pcm_offset;
|
uint32_t pcm_offset;
|
||||||
uint8_t fm_mask;
|
uint8_t fm_mask;
|
||||||
uint16_t psg_channel_mask;
|
uint16_t psg_channel_mask;
|
||||||
|
@ -123,7 +123,7 @@ class ZsmBackend : public PlaybackBackend {
|
||||||
return 1.0;
|
return 1.0;
|
||||||
}
|
}
|
||||||
void tick(bool step = true);\
|
void tick(bool step = true);\
|
||||||
void seek_internal(uint64_t position, bool loop = true);
|
void seek_internal(double position, bool loop = true);
|
||||||
ZsmCommand get_command();
|
ZsmCommand get_command();
|
||||||
public:
|
public:
|
||||||
uint64_t get_min_samples() override;
|
uint64_t get_min_samples() override;
|
||||||
|
@ -136,16 +136,15 @@ class ZsmBackend : public PlaybackBackend {
|
||||||
}
|
}
|
||||||
void add_licenses() override;
|
void add_licenses() override;
|
||||||
std::vector<Property> get_property_list() override;
|
std::vector<Property> get_property_list() override;
|
||||||
void seek_samples(uint64_t position) override;
|
void seek(double position) override;
|
||||||
void load(const char *filename) override;
|
void load(const char *filename) override;
|
||||||
void switch_stream(int idx) override;
|
void switch_stream(int idx) override;
|
||||||
void cleanup() override;
|
void cleanup() override;
|
||||||
int get_stream_idx() override;
|
int get_stream_idx() override;
|
||||||
size_t render(void *buf, size_t maxlen) override;
|
size_t render(void *buf, size_t maxlen) override;
|
||||||
uint64_t get_position_samples() override;
|
double get_position() override;
|
||||||
inline uint64_t get_length_samples() override {
|
inline double get_length() override {
|
||||||
return length;
|
return length;
|
||||||
}
|
}
|
||||||
uint64_t get_loop_start_samples() override;
|
|
||||||
inline ~ZsmBackend() override { }
|
inline ~ZsmBackend() override { }
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
set(BACKEND_HAIKU_SRC_BASE main.cpp main_window.cpp prefs.cpp slider.cpp slider.h main.h main_window.h aboutwindow.h aboutwindow.cpp prefs.h image_view.cpp image_view.h)
|
set(BACKEND_HAIKU_SRC_BASE main.cpp main_window.cpp prefs.cpp slider.cpp slider.h main.h main_window.h aboutwindow.h aboutwindow.cpp prefs.h)
|
||||||
set(BACKEND_HAIKU_SRC )
|
set(BACKEND_HAIKU_SRC )
|
||||||
foreach(SRC IN ITEMS ${BACKEND_HAIKU_SRC_BASE})
|
foreach(SRC IN ITEMS ${BACKEND_HAIKU_SRC_BASE})
|
||||||
set(BACKEND_HAIKU_SRC ${BACKEND_HAIKU_SRC} ${CMAKE_CURRENT_SOURCE_DIR}/${SRC})
|
set(BACKEND_HAIKU_SRC ${BACKEND_HAIKU_SRC} ${CMAKE_CURRENT_SOURCE_DIR}/${SRC})
|
||||||
|
|
|
@ -1,96 +0,0 @@
|
||||||
#include "image_view.h"
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
|
|
||||||
LImageView::LImageView(const char *name, BBitmap *bitmap, BAlignment align) : BView(name, B_SUPPORTS_LAYOUT|B_FRAME_EVENTS|B_WILL_DRAW)
|
|
||||||
{
|
|
||||||
SetBitmap(bitmap);
|
|
||||||
SetAlignment(align);
|
|
||||||
}
|
|
||||||
void LImageView::SetBitmap(BBitmap *bitmap) {
|
|
||||||
this->bitmap = bitmap;
|
|
||||||
Invalidate();
|
|
||||||
}
|
|
||||||
void LImageView::SetAlignment(BAlignment align) {
|
|
||||||
this->align = align;
|
|
||||||
Invalidate();
|
|
||||||
}
|
|
||||||
BBitmap *LImageView::Bitmap() {
|
|
||||||
return bitmap;
|
|
||||||
}
|
|
||||||
BAlignment LImageView::Alignment() {
|
|
||||||
return align;
|
|
||||||
}
|
|
||||||
|
|
||||||
void LImageView::FrameResized(float newW, float newH) {
|
|
||||||
Invalidate();
|
|
||||||
}
|
|
||||||
void LImageView::Draw(BRect updateRect) {
|
|
||||||
AdoptSystemColors();
|
|
||||||
SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY);
|
|
||||||
SetDrawingMode(B_OP_ALPHA);
|
|
||||||
FillRect(img_bounds, B_SOLID_LOW);
|
|
||||||
if (bitmap == NULL) return; // Handle null image.
|
|
||||||
int x = 0, y = 0;
|
|
||||||
int mw, mh;
|
|
||||||
int bw, bh;
|
|
||||||
bw = bitmap->Bounds().Width();
|
|
||||||
bh = bitmap->Bounds().Height();
|
|
||||||
int iw = bw, ih = bh;
|
|
||||||
mw = Bounds().Width();
|
|
||||||
mh = Bounds().Height();
|
|
||||||
float wr = ((float)mw) / ((float)bw);
|
|
||||||
float hr = ((float)mh) / ((float)bh);
|
|
||||||
if (wr < hr) {
|
|
||||||
iw *= wr;
|
|
||||||
ih *= wr;
|
|
||||||
} else {
|
|
||||||
iw *= hr;
|
|
||||||
ih *= hr;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
switch (align.Horizontal()) {
|
|
||||||
case B_ALIGN_LEFT: {
|
|
||||||
x = 0;
|
|
||||||
} break;
|
|
||||||
case B_ALIGN_HORIZONTAL_CENTER: {
|
|
||||||
x = (mw - iw) / 2;
|
|
||||||
} break;
|
|
||||||
case B_ALIGN_RIGHT: {
|
|
||||||
x = mw - iw;
|
|
||||||
} break;
|
|
||||||
}
|
|
||||||
switch (align.Vertical()) {
|
|
||||||
case B_ALIGN_TOP: {
|
|
||||||
y = 0;
|
|
||||||
} break;
|
|
||||||
case B_ALIGN_VERTICAL_CENTER: {
|
|
||||||
y = (mh - ih) / 2;
|
|
||||||
} break;
|
|
||||||
case B_ALIGN_BOTTOM: {
|
|
||||||
y = mh - ih;
|
|
||||||
} break;
|
|
||||||
}
|
|
||||||
BRect bitmap_rect(0, 0, bw, bh);
|
|
||||||
BRect draw_rect(x, y, iw + x, ih + y);
|
|
||||||
int left = updateRect.left;
|
|
||||||
int right = updateRect.right;
|
|
||||||
int top = updateRect.top;
|
|
||||||
int bottom = updateRect.bottom;
|
|
||||||
int x2 = x + bw;
|
|
||||||
int y2 = y + bh;
|
|
||||||
FillRect(draw_rect, B_SOLID_LOW);
|
|
||||||
DrawBitmap(bitmap, bitmap_rect, draw_rect);
|
|
||||||
img_bounds = draw_rect;
|
|
||||||
}
|
|
||||||
|
|
||||||
void LImageView::GetPreferredSize(float *w, float *h) {
|
|
||||||
if (!bitmap) {
|
|
||||||
*w = 0;
|
|
||||||
*h = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
*w = bitmap->Bounds().Width();
|
|
||||||
*h = bitmap->Bounds().Height();
|
|
||||||
}
|
|
|
@ -1,21 +0,0 @@
|
||||||
#pragma once
|
|
||||||
#include <View.h>
|
|
||||||
#include <Bitmap.h>
|
|
||||||
#include <Alignment.h>
|
|
||||||
#include <Rect.h>
|
|
||||||
|
|
||||||
class LImageView : public BView {
|
|
||||||
BBitmap *bitmap;
|
|
||||||
BAlignment align;
|
|
||||||
BRect img_bounds;
|
|
||||||
public:
|
|
||||||
void GetPreferredSize(float *w, float *h) override;
|
|
||||||
void SetBitmap(BBitmap *bitmap);
|
|
||||||
BBitmap *Bitmap();
|
|
||||||
void SetAlignment(BAlignment align);
|
|
||||||
BAlignment Alignment();
|
|
||||||
void Draw(BRect updateRect) override;
|
|
||||||
void FrameResized(float newW, float newH) override;
|
|
||||||
|
|
||||||
LImageView(const char *name, BBitmap *bitmap, BAlignment align);
|
|
||||||
};
|
|
|
@ -17,10 +17,7 @@
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <fmt/core.h>
|
#include <fmt/core.h>
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
#include <LayoutItem.h>
|
|
||||||
#include <TranslationUtils.h>
|
|
||||||
#include <SDL.h>
|
#include <SDL.h>
|
||||||
#include <cats.hpp>
|
|
||||||
#include "icons.h"
|
#include "icons.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "aboutwindow.h"
|
#include "aboutwindow.h"
|
||||||
|
@ -63,7 +60,6 @@ void HaikuLooperWindow::UpdateViewFlags(BLayout *layout) {
|
||||||
}
|
}
|
||||||
UpdateViewFlags(owner);
|
UpdateViewFlags(owner);
|
||||||
}
|
}
|
||||||
|
|
||||||
HaikuLooperWindow::HaikuLooperWindow(Playback *playback) : BWindow(BRect(100, 100, 500, 100), "Looper", B_TITLED_WINDOW, 0) {
|
HaikuLooperWindow::HaikuLooperWindow(Playback *playback) : BWindow(BRect(100, 100, 500, 100), "Looper", B_TITLED_WINDOW, 0) {
|
||||||
pause_bitmap = load_icon(ICON_PAUSE);
|
pause_bitmap = load_icon(ICON_PAUSE);
|
||||||
resume_bitmap = load_icon(ICON_PLAY);
|
resume_bitmap = load_icon(ICON_PLAY);
|
||||||
|
@ -97,7 +93,7 @@ HaikuLooperWindow::HaikuLooperWindow(Playback *playback) : BWindow(BRect(100, 10
|
||||||
menu_bar->AddItem(file_menu);
|
menu_bar->AddItem(file_menu);
|
||||||
menu_bar->AddItem(help_menu);
|
menu_bar->AddItem(help_menu);
|
||||||
layout->AddView(menu_bar);
|
layout->AddView(menu_bar);
|
||||||
spacer = new LImageView("spacer", NULL, BAlignment(B_ALIGN_RIGHT, B_ALIGN_BOTTOM));
|
BView *spacer = new BView("spacer", B_SUPPORTS_LAYOUT|B_FRAME_EVENTS);
|
||||||
spacer->SetExplicitPreferredSize(BSize(0, 0));
|
spacer->SetExplicitPreferredSize(BSize(0, 0));
|
||||||
spacer->SetExplicitMinSize(BSize(0, 0));
|
spacer->SetExplicitMinSize(BSize(0, 0));
|
||||||
layout->AddView(spacer);
|
layout->AddView(spacer);
|
||||||
|
@ -111,22 +107,10 @@ HaikuLooperWindow::HaikuLooperWindow(Playback *playback) : BWindow(BRect(100, 10
|
||||||
restart_btn = new BButton(NULL, new BMessage(CMD_RESTART));
|
restart_btn = new BButton(NULL, new BMessage(CMD_RESTART));
|
||||||
restart_btn->SetTarget(this);
|
restart_btn->SetTarget(this);
|
||||||
top_row->AddChild(restart_btn);
|
top_row->AddChild(restart_btn);
|
||||||
BView *slider_parent = new BView("main:slider_parent", B_SUPPORTS_LAYOUT);
|
|
||||||
BGroupLayout *slider_parent_layout = new BGroupLayout(B_HORIZONTAL, 0);
|
|
||||||
slider_parent_layout->SetInsets(0);
|
|
||||||
slider_parent->SetLayout(slider_parent_layout);
|
|
||||||
slider = new BSlider("seek_slider", "Seek", make_slider_msg(CMD_SEEK, false), 0, INT32_MAX, B_HORIZONTAL);
|
slider = new BSlider("seek_slider", "Seek", make_slider_msg(CMD_SEEK, false), 0, INT32_MAX, B_HORIZONTAL);
|
||||||
slider->SetModificationMessage(make_slider_msg(CMD_SEEK, true));
|
slider->SetModificationMessage(make_slider_msg(CMD_SEEK, true));
|
||||||
slider->SetTarget(this);
|
slider->SetTarget(this);
|
||||||
auto *slider_item = slider_parent_layout->AddView(slider);
|
top_row->AddChild(slider);
|
||||||
slider_item->SetExplicitAlignment(BAlignment(B_ALIGN_USE_FULL_WIDTH, B_ALIGN_USE_FULL_HEIGHT));
|
|
||||||
position_label = new BStringView("main:position_label", "Stopped");
|
|
||||||
auto *pos_label_item = slider_parent_layout->AddView(position_label);
|
|
||||||
pos_label_item->SetExplicitAlignment(BAlignment(B_ALIGN_USE_FULL_WIDTH, B_ALIGN_VERTICAL_CENTER));
|
|
||||||
position_label->Show();
|
|
||||||
auto *slider_parent_item = top_row->GroupLayout()->AddView(slider_parent);
|
|
||||||
slider_parent_item->SetExplicitAlignment(BAlignment(B_ALIGN_USE_FULL_WIDTH, B_ALIGN_USE_FULL_HEIGHT));
|
|
||||||
slider->Hide();
|
|
||||||
stop_btn = new BButton(NULL, new BMessage(CMD_STOP));
|
stop_btn = new BButton(NULL, new BMessage(CMD_STOP));
|
||||||
stop_btn->SetTarget(this);
|
stop_btn->SetTarget(this);
|
||||||
top_row->AddChild(stop_btn);
|
top_row->AddChild(stop_btn);
|
||||||
|
@ -164,32 +148,6 @@ HaikuLooperWindow::HaikuLooperWindow(Playback *playback) : BWindow(BRect(100, 10
|
||||||
MessageReceived(msg);
|
MessageReceived(msg);
|
||||||
delete msg;
|
delete msg;
|
||||||
}
|
}
|
||||||
void HaikuLooperWindow::UpdateCat(BBitmap *cat) {
|
|
||||||
LockLooper();
|
|
||||||
if (cat != NULL) {
|
|
||||||
auto bounds = cat->Bounds();
|
|
||||||
auto w = bounds.Width(), h = bounds.Height();
|
|
||||||
auto sb = spacer->Bounds();
|
|
||||||
auto sw = sb.Width(), sh = sb.Height();
|
|
||||||
BRect src(0, 0, w, h);
|
|
||||||
if (w > sw || h > sh) {
|
|
||||||
float aspect = w / h;
|
|
||||||
if (w > sw) {
|
|
||||||
w = sw;
|
|
||||||
h = sw / aspect;
|
|
||||||
}
|
|
||||||
if (h > sh) {
|
|
||||||
h = sh;
|
|
||||||
w = sh * aspect;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
BRect dst(sw - w, sh - h, w, h);
|
|
||||||
spacer->SetBitmap(cat);
|
|
||||||
} else {
|
|
||||||
spacer->SetBitmap(NULL);
|
|
||||||
}
|
|
||||||
UnlockLooper();
|
|
||||||
}
|
|
||||||
HaikuLooperWindow::~HaikuLooperWindow() {
|
HaikuLooperWindow::~HaikuLooperWindow() {
|
||||||
delete ref_handler;
|
delete ref_handler;
|
||||||
delete pause_bitmap;
|
delete pause_bitmap;
|
||||||
|
@ -274,13 +232,6 @@ void HaikuLooperWindow::MessageReceived(BMessage *msg) {
|
||||||
case CMD_PREFS: {
|
case CMD_PREFS: {
|
||||||
prefs_subwindow->Show();
|
prefs_subwindow->Show();
|
||||||
} break;
|
} break;
|
||||||
case CMD_SET_CAT: {
|
|
||||||
BBitmap *cat = NULL;
|
|
||||||
if (msg->FindPointer("cat", (void**)&cat) != B_OK) {
|
|
||||||
cat = NULL;
|
|
||||||
}
|
|
||||||
UpdateCat(cat);
|
|
||||||
}
|
|
||||||
case CMD_UPDATE_LABEL_SETTING: {
|
case CMD_UPDATE_LABEL_SETTING: {
|
||||||
volume_slider->MessageReceived(msg);
|
volume_slider->MessageReceived(msg);
|
||||||
speed_slider->MessageReceived(msg);
|
speed_slider->MessageReceived(msg);
|
||||||
|
@ -338,22 +289,13 @@ void HaikuLooperWindow::Pulse() {
|
||||||
auto component_count = TimeToComponentCount(len);
|
auto component_count = TimeToComponentCount(len);
|
||||||
bool enable_ui = !playback->IsStopped();
|
bool enable_ui = !playback->IsStopped();
|
||||||
if (enable_ui) {
|
if (enable_ui) {
|
||||||
if (len <= 0.0) {
|
|
||||||
position_label->SetText(fmt::format("Position: {} units", (int)pos).c_str());
|
|
||||||
slider->Hide();
|
|
||||||
position_label->Show();
|
|
||||||
} else {
|
|
||||||
slider->SetLabel(fmt::format("Position: {}", TimeToString(pos, component_count)).c_str());
|
slider->SetLabel(fmt::format("Position: {}", TimeToString(pos, component_count)).c_str());
|
||||||
slider->SetLimitLabels(TimeToString(0, component_count).c_str(), TimeToString(len, component_count).c_str());
|
slider->SetLimitLabels(TimeToString(0, component_count).c_str(), TimeToString(len, component_count).c_str());
|
||||||
position_label->Hide();
|
|
||||||
slider->Show();
|
|
||||||
}
|
|
||||||
if (show_icons) pause_resume_btn->SetIcon(playback->IsPaused() ? resume_bitmap : pause_bitmap);
|
if (show_icons) pause_resume_btn->SetIcon(playback->IsPaused() ? resume_bitmap : pause_bitmap);
|
||||||
if (show_labels) pause_resume_btn->SetLabel(playback->IsPaused() ? "Resume" : "Pause");
|
if (show_labels) pause_resume_btn->SetLabel(playback->IsPaused() ? "Resume" : "Pause");
|
||||||
} else {
|
} else {
|
||||||
position_label->SetText("Stopped.");
|
slider->SetLabel("Position");
|
||||||
slider->Hide();
|
slider->SetLimitLabels("N/A", "N/A");
|
||||||
position_label->Show();
|
|
||||||
if (show_icons) pause_resume_btn->SetIcon(pause_bitmap);
|
if (show_icons) pause_resume_btn->SetIcon(pause_bitmap);
|
||||||
if (show_labels) pause_resume_btn->SetLabel("Pause");
|
if (show_labels) pause_resume_btn->SetLabel("Pause");
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
#include <Application.h>
|
#include <Application.h>
|
||||||
#include <GroupLayout.h>
|
#include <GroupLayout.h>
|
||||||
#include <Slider.h>
|
#include <Slider.h>
|
||||||
#include <StringView.h>
|
|
||||||
#include <playback.h>
|
#include <playback.h>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <FilePanel.h>
|
#include <FilePanel.h>
|
||||||
|
@ -14,7 +13,6 @@
|
||||||
#include "aboutwindow.h"
|
#include "aboutwindow.h"
|
||||||
#include "slider.h"
|
#include "slider.h"
|
||||||
#include "prefs.h"
|
#include "prefs.h"
|
||||||
#include "image_view.h"
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <util.hpp>
|
#include <util.hpp>
|
||||||
#define CMD_UPDATE_LABEL_SETTING 0x1000
|
#define CMD_UPDATE_LABEL_SETTING 0x1000
|
||||||
|
@ -44,7 +42,6 @@ class Subwindow {
|
||||||
class HaikuLooperRefHandler;
|
class HaikuLooperRefHandler;
|
||||||
class HaikuLooperWindow : public BWindow {
|
class HaikuLooperWindow : public BWindow {
|
||||||
BSlider *slider;
|
BSlider *slider;
|
||||||
BStringView *position_label;
|
|
||||||
BBitmap *pause_bitmap;
|
BBitmap *pause_bitmap;
|
||||||
BBitmap *resume_bitmap;
|
BBitmap *resume_bitmap;
|
||||||
BBitmap *refresh_bitmap;
|
BBitmap *refresh_bitmap;
|
||||||
|
@ -60,8 +57,6 @@ class HaikuLooperWindow : public BWindow {
|
||||||
BButton *restart_btn;
|
BButton *restart_btn;
|
||||||
BButton *stop_btn;
|
BButton *stop_btn;
|
||||||
BButton *pause_resume_btn;
|
BButton *pause_resume_btn;
|
||||||
LImageView *spacer;
|
|
||||||
void UpdateCat(BBitmap *cat);
|
|
||||||
bool volume_clicked = false;
|
bool volume_clicked = false;
|
||||||
bool speed_clicked = false;
|
bool speed_clicked = false;
|
||||||
bool pitch_clicked = false;
|
bool pitch_clicked = false;
|
||||||
|
|
|
@ -7,50 +7,16 @@
|
||||||
#include <Box.h>
|
#include <Box.h>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include "main_window.h"
|
#include "main_window.h"
|
||||||
#include <cats.hpp>
|
|
||||||
#include <TranslationUtils.h>
|
|
||||||
#include "image_view.h"
|
|
||||||
using namespace Looper::Options;
|
using namespace Looper::Options;
|
||||||
#define CMD_UPDATE_LABEL_SETTING 0x1000
|
#define CMD_UPDATE_LABEL_SETTING 0x1000
|
||||||
#define CMD_FRONTEND 0x1001
|
#define CMD_FRONTEND 0x1001
|
||||||
#define CMD_SET_SETTING 0x1002
|
#define CMD_SET_SETTING 0x1002
|
||||||
#define CMD_REVERT 0x1003
|
#define CMD_REVERT 0x1003
|
||||||
#define CMD_APPLY 0x1004
|
#define CMD_APPLY 0x1004
|
||||||
#define CMD_SET_SETTING_CHECKBOX 0x1005
|
|
||||||
bool show_icons, show_labels;
|
bool show_icons, show_labels;
|
||||||
void HaikuPrefsWindow::AddCat(std::string name, BBitmap *bitmap) {
|
|
||||||
if (bitmap == NULL) return;
|
|
||||||
if (cats.contains(name)) {
|
|
||||||
delete cats[name];
|
|
||||||
}
|
|
||||||
cats[name] = bitmap;
|
|
||||||
}
|
|
||||||
BBitmap *HaikuPrefsWindow::LoadCat(const char *path) {
|
|
||||||
return BTranslationUtils::GetBitmap(path);
|
|
||||||
}
|
|
||||||
BBitmap *HaikuPrefsWindow::LoadCat(const void *ptr, size_t len, const char *name) {
|
|
||||||
BMemoryIO *io = new BMemoryIO(ptr, len);
|
|
||||||
BBitmap *output = BTranslationUtils::GetBitmap(io);
|
|
||||||
delete io;
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
HaikuPrefsWindow::HaikuPrefsWindow(BLooper *next_handler) : BWindow(BRect(100, 100, 0, 0), "Preferences", B_TITLED_WINDOW, B_AUTO_UPDATE_SIZE_LIMITS) {
|
HaikuPrefsWindow::HaikuPrefsWindow(BLooper *next_handler) : BWindow(BRect(100, 100, 0, 0), "Preferences", B_TITLED_WINDOW, B_AUTO_UPDATE_SIZE_LIMITS) {
|
||||||
this->next_handler = next_handler;
|
this->next_handler = next_handler;
|
||||||
|
|
||||||
for (auto &cat : get_cat_data()) {
|
|
||||||
switch (cat.get_type()) {
|
|
||||||
case CatDataType::Memory: {
|
|
||||||
MemoryCat mem_cat = cat.get_memory_cat();
|
|
||||||
|
|
||||||
AddCat(cat.get_name(), LoadCat(mem_cat.get_ptr(), mem_cat.get_len(), cat.get_path().c_str()));
|
|
||||||
} break;
|
|
||||||
case CatDataType::File: {
|
|
||||||
fs::path cat_path = cat.get_path();
|
|
||||||
AddCat(cat.get_name(), LoadCat(cat_path.c_str()));
|
|
||||||
} break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
auto *root_layout = new BGroupLayout(B_VERTICAL);
|
auto *root_layout = new BGroupLayout(B_VERTICAL);
|
||||||
SetLayout(root_layout);
|
SetLayout(root_layout);
|
||||||
root_layout->SetSpacing(0.0);
|
root_layout->SetSpacing(0.0);
|
||||||
|
@ -74,7 +40,6 @@ HaikuPrefsWindow::HaikuPrefsWindow(BLooper *next_handler) : BWindow(BRect(100, 1
|
||||||
BBox *box = new BBox("prefs:label_settings_box");
|
BBox *box = new BBox("prefs:label_settings_box");
|
||||||
box->SetLabel("Labels and Icons");
|
box->SetLabel("Labels and Icons");
|
||||||
auto *label_settings_group = new BGroupView(B_VERTICAL);
|
auto *label_settings_group = new BGroupView(B_VERTICAL);
|
||||||
box->AddChild(label_settings_group);
|
|
||||||
BGroupLayout *label_settings_layout = label_settings_group->GroupLayout();
|
BGroupLayout *label_settings_layout = label_settings_group->GroupLayout();
|
||||||
BMessage *labels_only_msg = new BMessage(CMD_SET_SETTING);
|
BMessage *labels_only_msg = new BMessage(CMD_SET_SETTING);
|
||||||
labels_only_msg->AddString("pref_path", "ui.haiku.label_setting");
|
labels_only_msg->AddString("pref_path", "ui.haiku.label_setting");
|
||||||
|
@ -91,49 +56,8 @@ HaikuPrefsWindow::HaikuPrefsWindow(BLooper *next_handler) : BWindow(BRect(100, 1
|
||||||
label_settings_layout->AddView(labels_only);
|
label_settings_layout->AddView(labels_only);
|
||||||
label_settings_layout->AddView(icons_only);
|
label_settings_layout->AddView(icons_only);
|
||||||
label_settings_layout->AddView(both_labels_icons);
|
label_settings_layout->AddView(both_labels_icons);
|
||||||
BMessage *cat_enable_msg = new BMessage(CMD_SET_SETTING_CHECKBOX);
|
box->AddChild(label_settings_group);
|
||||||
cat_enable_msg->AddString("pref_path", "ui.enable_cat");
|
|
||||||
cat_enable = new BCheckBox("Enable Cat", cat_enable_msg);
|
|
||||||
BGroupView *cat_enable_view = new BGroupView(B_HORIZONTAL);
|
|
||||||
cat_enable_view->AddChild(cat_enable);
|
|
||||||
BBox *cat_box = new BBox("prefs:cat_options");
|
|
||||||
cat_box->SetLabel("Cat Options");
|
|
||||||
BGroupView *cat_group = new BGroupView(B_VERTICAL);
|
|
||||||
BGroupLayout *cat_layout = cat_group->GroupLayout();
|
|
||||||
for (auto &kv : cats) {
|
|
||||||
BMessage *msg = new BMessage(CMD_SET_SETTING);
|
|
||||||
msg->AddString("pref_path", "ui.cat");
|
|
||||||
msg->AddString("pref_value", kv.first.c_str());
|
|
||||||
BGroupView *cat_row = new BGroupView(B_HORIZONTAL);
|
|
||||||
BRadioButton *cat_radio = new BRadioButton(kv.first.c_str(), msg);
|
|
||||||
cat_btns[kv.first] = cat_radio;
|
|
||||||
BBitmap *cat_bmp = kv.second;
|
|
||||||
BRect src = cat_bmp->Bounds();
|
|
||||||
float w = src.Width(), h = src.Height();
|
|
||||||
float rw = cat_radio->Bounds().Width(), rh = cat_radio->Bounds().Height();
|
|
||||||
if (w > rw || h > rh) {
|
|
||||||
float aspect = w / h;
|
|
||||||
if (h > rh) {
|
|
||||||
h = rh;
|
|
||||||
w = h * aspect;
|
|
||||||
}
|
|
||||||
if (w > rw) {
|
|
||||||
w = rw;
|
|
||||||
h = h / aspect;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
BRect dst(rw - w, (rh - h) / 2, rw, rh);
|
|
||||||
LImageView *img_view = new LImageView("prefs:cat:preview", cat_bmp, BAlignment(B_ALIGN_RIGHT, B_ALIGN_BOTTOM));
|
|
||||||
img_view->SetExplicitMinSize(BSize(16, 16));
|
|
||||||
img_view->SetExplicitPreferredSize(BSize(16, 16));
|
|
||||||
cat_row->AddChild(cat_radio);
|
|
||||||
cat_row->AddChild(img_view);
|
|
||||||
cat_layout->AddView(cat_row);
|
|
||||||
}
|
|
||||||
root_layout->AddView(box, 3.0);
|
root_layout->AddView(box, 3.0);
|
||||||
cat_box->AddChild(cat_group);
|
|
||||||
root_layout->AddView(cat_enable_view, 1.0);
|
|
||||||
root_layout->AddView(cat_box, 3.0);
|
|
||||||
BGroupView *btn_view = new BGroupView(B_HORIZONTAL);
|
BGroupView *btn_view = new BGroupView(B_HORIZONTAL);
|
||||||
BGroupLayout *btn_box = btn_view->GroupLayout();
|
BGroupLayout *btn_box = btn_view->GroupLayout();
|
||||||
revert_btn = new BButton("prefs:revert", "Revert", new BMessage(CMD_REVERT));
|
revert_btn = new BButton("prefs:revert", "Revert", new BMessage(CMD_REVERT));
|
||||||
|
@ -178,17 +102,10 @@ void HaikuPrefsWindow::MessageReceived(BMessage *msg) {
|
||||||
else restart_warning->Hide();
|
else restart_warning->Hide();
|
||||||
set_option<std::string>("ui.haiku.label_setting", new_label_setting);
|
set_option<std::string>("ui.haiku.label_setting", new_label_setting);
|
||||||
update_label_setting();
|
update_label_setting();
|
||||||
set_option<std::string>("ui.cat", cat_id);
|
|
||||||
set_option<bool>("ui.enable_cat", enable_cat);
|
|
||||||
next_handler->PostMessage(CMD_UPDATE_LABEL_SETTING);
|
next_handler->PostMessage(CMD_UPDATE_LABEL_SETTING);
|
||||||
BMessage *cat_msg = new BMessage(CMD_SET_CAT);
|
|
||||||
if (enable_cat) cat_msg->AddPointer("cat", cats[cat_id]);
|
|
||||||
next_handler->PostMessage(cat_msg);
|
|
||||||
save_options();
|
|
||||||
} break;
|
} break;
|
||||||
case CMD_REVERT: {
|
case CMD_REVERT: {
|
||||||
set_options_changed(false);
|
set_options_changed(false);
|
||||||
load_options();
|
|
||||||
new_label_setting = get_option<std::string>("ui.haiku.label_setting", "icons");
|
new_label_setting = get_option<std::string>("ui.haiku.label_setting", "icons");
|
||||||
new_frontend = get_option<std::string>("ui.frontend", "haiku");
|
new_frontend = get_option<std::string>("ui.frontend", "haiku");
|
||||||
if (new_frontend != "haiku") restart_warning->Show();
|
if (new_frontend != "haiku") restart_warning->Show();
|
||||||
|
@ -200,16 +117,8 @@ void HaikuPrefsWindow::MessageReceived(BMessage *msg) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (cat_btns.contains(cat_id)) cat_btns[cat_id]->SetValue(B_CONTROL_OFF);
|
|
||||||
cat_id = get_option<std::string>("ui.cat", cats.empty() ? "" : cats.begin()->first);
|
|
||||||
if (cat_btns.contains(cat_id)) cat_btns[cat_id]->SetValue(B_CONTROL_ON);
|
|
||||||
enable_cat = get_option<bool>("ui.enable_cat", false);
|
|
||||||
cat_enable->SetValue(enable_cat ? B_CONTROL_ON : B_CONTROL_OFF);
|
|
||||||
update_label_setting();
|
update_label_setting();
|
||||||
next_handler->PostMessage(CMD_UPDATE_LABEL_SETTING);
|
next_handler->PostMessage(CMD_UPDATE_LABEL_SETTING);
|
||||||
BMessage *cat_msg = new BMessage(CMD_SET_CAT);
|
|
||||||
if (enable_cat) cat_msg->AddPointer("cat", cats[cat_id]);
|
|
||||||
next_handler->PostMessage(cat_msg);
|
|
||||||
} break;
|
} break;
|
||||||
case CMD_FRONTEND: {
|
case CMD_FRONTEND: {
|
||||||
auto option = msg->GetInt32("be:value", cur_option);
|
auto option = msg->GetInt32("be:value", cur_option);
|
||||||
|
@ -227,23 +136,6 @@ void HaikuPrefsWindow::MessageReceived(BMessage *msg) {
|
||||||
if (std::string(setting) == "ui.haiku.label_setting") {
|
if (std::string(setting) == "ui.haiku.label_setting") {
|
||||||
new_label_setting = setting_value;
|
new_label_setting = setting_value;
|
||||||
set_options_changed(true);
|
set_options_changed(true);
|
||||||
} else if (std::string(setting) == "ui.cat") {
|
|
||||||
if (cat_btns.contains(cat_id)) cat_btns[cat_id]->SetValue(B_CONTROL_OFF);
|
|
||||||
cat_id = setting_value;
|
|
||||||
if (cat_btns.contains(cat_id)) cat_btns[cat_id]->SetValue(B_CONTROL_ON);
|
|
||||||
set_options_changed(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} break;
|
|
||||||
case CMD_SET_SETTING_CHECKBOX: {
|
|
||||||
const char *setting;
|
|
||||||
if (msg->FindString("pref_path", &setting) == B_OK) {
|
|
||||||
int32 setting_value_int32;
|
|
||||||
if (msg->FindInt32("be:value", &setting_value_int32) == B_OK) {
|
|
||||||
if (std::string(setting) == "ui.enable_cat") {
|
|
||||||
enable_cat = setting_value_int32 == B_CONTROL_ON;
|
|
||||||
set_options_changed(true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,17 +13,8 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <map>
|
#include <map>
|
||||||
#define CMD_SET_CAT 0x1010
|
|
||||||
class HaikuPrefsWindow : public BWindow {
|
class HaikuPrefsWindow : public BWindow {
|
||||||
std::vector<std::string> backend_ids;
|
std::vector<std::string> backend_ids;
|
||||||
std::string cat_id;
|
|
||||||
bool enable_cat;
|
|
||||||
std::map<std::string, BBitmap*> cats;
|
|
||||||
std::map<std::string, BRadioButton*> cat_btns;
|
|
||||||
BCheckBox *cat_enable;
|
|
||||||
void AddCat(std::string name, BBitmap* img);
|
|
||||||
BBitmap *LoadCat(const char *path);
|
|
||||||
BBitmap *LoadCat(const void *ptr, size_t len, const char *name);
|
|
||||||
int32 cur_option = 0;
|
int32 cur_option = 0;
|
||||||
BLooper *next_handler;
|
BLooper *next_handler;
|
||||||
BStringView *restart_warning;
|
BStringView *restart_warning;
|
||||||
|
|
|
@ -17,8 +17,6 @@
|
||||||
#include <log.hpp>
|
#include <log.hpp>
|
||||||
#include <options.hpp>
|
#include <options.hpp>
|
||||||
#include <web_functions.hpp>
|
#include <web_functions.hpp>
|
||||||
#include <fmt/core.h>
|
|
||||||
#include <fmt/format.h>
|
|
||||||
using std::vector;
|
using std::vector;
|
||||||
using namespace Looper::Options;
|
using namespace Looper::Options;
|
||||||
void RendererBackend::on_resize() {
|
void RendererBackend::on_resize() {
|
||||||
|
@ -153,23 +151,13 @@ void RendererBackend::LoopFunction() {
|
||||||
ImGui::NewFrame();
|
ImGui::NewFrame();
|
||||||
// Run the GUI
|
// Run the GUI
|
||||||
GuiFunction();
|
GuiFunction();
|
||||||
if (!main_menu_bar_used) {
|
|
||||||
BeginMainMenuBar();
|
|
||||||
EndMainMenuBar();
|
|
||||||
}
|
|
||||||
// Rendering
|
// Rendering
|
||||||
ImGui::Render();
|
ImGui::Render();
|
||||||
SDL_SetRenderDrawColor(rend, (Uint8)(clear_color.x * clear_color.w * 255), (Uint8)(clear_color.y * clear_color.w * 255), (Uint8)(clear_color.z * clear_color.w * 255), (Uint8)(clear_color.w * 255));
|
SDL_SetRenderDrawColor(rend, (Uint8)(clear_color.x * clear_color.w * 255), (Uint8)(clear_color.y * clear_color.w * 255), (Uint8)(clear_color.z * clear_color.w * 255), (Uint8)(clear_color.w * 255));
|
||||||
SDL_RenderClear(rend);
|
SDL_RenderClear(rend);
|
||||||
// Tell ImGui to render.
|
// Tell ImGui to render.
|
||||||
ImGui_ImplSDLRenderer2_RenderDrawData(ImGui::GetDrawData(), rend);
|
ImGui_ImplSDLRenderer2_RenderDrawData(ImGui::GetDrawData(), rend);
|
||||||
SDL_Rect rect;
|
|
||||||
SDL_GetWindowSize(window, &rect.w, &rect.h);
|
|
||||||
rect.x = 0;
|
|
||||||
rect.y = 0;
|
|
||||||
ImVec4 color = ImGui::GetStyle().Colors[ImGuiCol_Border];
|
|
||||||
SDL_SetRenderDrawColor(rend, color.x * 255, color.y * 255, color.z * 255, color.w * 255);
|
|
||||||
SDL_RenderDrawRect(rend, &rect);
|
|
||||||
|
|
||||||
// Swap the buffers, and do VSync if enabled.
|
// Swap the buffers, and do VSync if enabled.
|
||||||
SDL_RenderPresent(rend);
|
SDL_RenderPresent(rend);
|
||||||
|
@ -224,8 +212,7 @@ RendererBackend::~RendererBackend() {
|
||||||
renderer_backend = nullptr;
|
renderer_backend = nullptr;
|
||||||
}
|
}
|
||||||
void RendererBackend::SetWindowTitle(const char *title) {
|
void RendererBackend::SetWindowTitle(const char *title) {
|
||||||
this->title_text = title;
|
SDL_SetWindowTitle(window, title);
|
||||||
update_real_title();
|
|
||||||
}
|
}
|
||||||
void RendererBackend::GuiFunction() {
|
void RendererBackend::GuiFunction() {
|
||||||
// Do nothing by default.
|
// Do nothing by default.
|
||||||
|
@ -304,10 +291,6 @@ static EM_BOOL resize_callback(int event_type, const EmscriptenUiEvent *event, v
|
||||||
return EM_FALSE;
|
return EM_FALSE;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
static SDL_HitTestResult hit_test(SDL_Window *window, const SDL_Point *area, void *data) {
|
|
||||||
return ((RendererBackend*)data)->HitTest(window, area);
|
|
||||||
}
|
|
||||||
|
|
||||||
void RendererBackend::BackendInit() {
|
void RendererBackend::BackendInit() {
|
||||||
setup_locale("neko_player");
|
setup_locale("neko_player");
|
||||||
DEBUG.writefln("Loaded locale '%s' from '%s'...", CURRENT_LANGUAGE, LOCALE_DIR);
|
DEBUG.writefln("Loaded locale '%s' from '%s'...", CURRENT_LANGUAGE, LOCALE_DIR);
|
||||||
|
@ -336,7 +319,7 @@ void RendererBackend::BackendInit() {
|
||||||
#ifdef SDL_HINT_IME_SHOW_UI
|
#ifdef SDL_HINT_IME_SHOW_UI
|
||||||
SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1");
|
SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1");
|
||||||
#endif
|
#endif
|
||||||
SDL_WindowFlags window_flags = (SDL_WindowFlags)(SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_HIDDEN | SDL_WINDOW_BORDERLESS);
|
SDL_WindowFlags window_flags = (SDL_WindowFlags)(SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_HIDDEN);
|
||||||
SDL_CreateWindowAndRenderer(window_width, window_height, window_flags, &window, &rend);
|
SDL_CreateWindowAndRenderer(window_width, window_height, window_flags, &window, &rend);
|
||||||
|
|
||||||
#ifndef __ANDROID__
|
#ifndef __ANDROID__
|
||||||
|
@ -346,8 +329,8 @@ void RendererBackend::BackendInit() {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
SDL_EventState(SDL_DROPFILE, SDL_ENABLE);
|
SDL_EventState(SDL_DROPFILE, SDL_ENABLE);
|
||||||
SDL_Surface* icon = IMG_Load_RW(SDL_RWFromConstMem(icon_data, icon_size), 1);
|
const vector<unsigned char> icon_data = DecodeBase85(icon_compressed_data_base85);
|
||||||
icon_texture = SDL_CreateTextureFromSurface(rend, icon);
|
SDL_Surface* icon = IMG_Load_RW(SDL_RWFromConstMem(icon_data.data(), icon_data.size()), 1);
|
||||||
SDL_SetWindowIcon(window, icon);
|
SDL_SetWindowIcon(window, icon);
|
||||||
|
|
||||||
// Setup Dear ImGui context
|
// Setup Dear ImGui context
|
||||||
|
@ -407,127 +390,10 @@ void RendererBackend::BackendInit() {
|
||||||
SDL_RenderSetVSync(rend, vsync ? 1 : 0);
|
SDL_RenderSetVSync(rend, vsync ? 1 : 0);
|
||||||
#endif
|
#endif
|
||||||
theme->Apply(accent_color, (float)scale);
|
theme->Apply(accent_color, (float)scale);
|
||||||
SDL_SetWindowHitTest(window, &hit_test, this);
|
|
||||||
Init();
|
Init();
|
||||||
SDL_ShowWindow(window);
|
SDL_ShowWindow(window);
|
||||||
started = true;
|
started = true;
|
||||||
}
|
}
|
||||||
bool RendererBackend::BeginMainMenuBar() {
|
|
||||||
main_menu_bar_used = true;
|
|
||||||
if (ImGui::BeginMainMenuBar()) {
|
|
||||||
ImVec2 winsize = ImGui::GetWindowSize();
|
|
||||||
float texsize = winsize.y;
|
|
||||||
ImGui::SetCursorPosX(0);
|
|
||||||
ImGui::SetCursorPosY(0);
|
|
||||||
ImGui::Image((ImTextureID)(icon_texture), ImVec2(texsize, texsize));
|
|
||||||
ImGui::TextUnformatted(title_text.c_str());
|
|
||||||
menubar_start = ImGui::GetCursorPosX();
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bool RendererBackend::is_fullscreen() {
|
|
||||||
return SDL_GetWindowFlags(window) & (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_FULLSCREEN_DESKTOP);
|
|
||||||
}
|
|
||||||
bool RendererBackend::is_maximized() {
|
|
||||||
return SDL_GetWindowFlags(window) & SDL_WINDOW_MAXIMIZED;
|
|
||||||
}
|
|
||||||
SDL_HitTestResult RendererBackend::HitTest(SDL_Window *window, const SDL_Point *area) {
|
|
||||||
int w, h;
|
|
||||||
bool rtop, rbottom, rleft, rright;
|
|
||||||
SDL_GetWindowSize(window, &w, &h);
|
|
||||||
rtop = area->y <= 4;
|
|
||||||
rleft = area->x <= 4;
|
|
||||||
rright = area->x >= w-5;
|
|
||||||
rbottom = area->y >= h-5;
|
|
||||||
if (is_fullscreen()) return SDL_HITTEST_NORMAL;
|
|
||||||
if (!is_maximized()) {
|
|
||||||
if (rtop) {
|
|
||||||
if (rright) {
|
|
||||||
return SDL_HITTEST_RESIZE_TOPRIGHT;
|
|
||||||
} else if (rleft) {
|
|
||||||
return SDL_HITTEST_RESIZE_TOPLEFT;
|
|
||||||
} else {
|
|
||||||
return SDL_HITTEST_RESIZE_TOP;
|
|
||||||
}
|
|
||||||
} else if (rbottom) {
|
|
||||||
if (rright) {
|
|
||||||
return SDL_HITTEST_RESIZE_BOTTOMRIGHT;
|
|
||||||
} else if (rleft) {
|
|
||||||
return SDL_HITTEST_RESIZE_BOTTOMLEFT;
|
|
||||||
} else {
|
|
||||||
return SDL_HITTEST_RESIZE_BOTTOM;
|
|
||||||
}
|
|
||||||
} else if (rleft) {
|
|
||||||
return SDL_HITTEST_RESIZE_LEFT;
|
|
||||||
} else if (rright) {
|
|
||||||
return SDL_HITTEST_RESIZE_RIGHT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (area->y < (16 * this->scale) && (area->x < menubar_start || (area->x > menubar_end && area->x < title_btn_start))) {
|
|
||||||
return SDL_HITTEST_DRAGGABLE;
|
|
||||||
} else {
|
|
||||||
return SDL_HITTEST_NORMAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
void RendererBackend::SetSubtitle(const char *subtitle) {
|
|
||||||
this->subtitle = subtitle;
|
|
||||||
update_real_title();
|
|
||||||
}
|
|
||||||
void RendererBackend::update_real_title() {
|
|
||||||
if (subtitle == "") {
|
|
||||||
SDL_SetWindowTitle(window, title_text.c_str());
|
|
||||||
} else {
|
|
||||||
SDL_SetWindowTitle(window, fmt::format("{} - {}", subtitle, title_text).c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void RendererBackend::EndMainMenuBar() {
|
|
||||||
#ifndef __EMSCRIPTEN__
|
|
||||||
menubar_end = ImGui::GetCursorPosX();
|
|
||||||
ImVec2 size = ImGui::GetWindowSize();
|
|
||||||
if (subtitle != "") {
|
|
||||||
ImVec4 text_color = Theme::GetColor(LooperCol_Subtitle);
|
|
||||||
ImGui::PushStyleColor(ImGuiCol_Text, text_color);
|
|
||||||
ImGui::TextUnformatted(subtitle.c_str());
|
|
||||||
ImGui::PopStyleColor();
|
|
||||||
}
|
|
||||||
float btnw = size.y;
|
|
||||||
int btn_count = 3;
|
|
||||||
ImVec2 btn_size(btnw, btnw);
|
|
||||||
ImGui::SetCursorPosY(0);
|
|
||||||
static const size_t titlebar_btn_count = 3;
|
|
||||||
const char *titlebar_icons[titlebar_btn_count] = {
|
|
||||||
ICON_FK_WINDOW_MINIMIZE,
|
|
||||||
is_maximized() ? ICON_FK_WINDOW_RESTORE : ICON_FK_WINDOW_MAXIMIZE,
|
|
||||||
ICON_FK_WINDOW_CLOSE
|
|
||||||
};
|
|
||||||
float tmp = size.x;
|
|
||||||
float padding = ImGui::GetStyle().FramePadding.x;
|
|
||||||
float spacing = ImGui::GetStyle().ItemSpacing.x;
|
|
||||||
for (size_t i = 0; i < titlebar_btn_count; i++) {
|
|
||||||
tmp -= padding * 2.0f;
|
|
||||||
// No need to use the correct index, as long as this is hit only once.
|
|
||||||
if (i == 0) tmp -= spacing / 2.0f;
|
|
||||||
else tmp -= spacing;
|
|
||||||
tmp -= ImGui::CalcTextSize(titlebar_icons[i]).x;
|
|
||||||
}
|
|
||||||
title_btn_start = std::ceil(tmp);
|
|
||||||
ImGui::SetCursorPosX(title_btn_start);
|
|
||||||
if (ImGui::MenuItem(titlebar_icons[0])) {
|
|
||||||
SDL_MinimizeWindow(window);
|
|
||||||
}
|
|
||||||
if (ImGui::MenuItem(titlebar_icons[1])) {
|
|
||||||
if (is_maximized()) SDL_RestoreWindow(window);
|
|
||||||
else SDL_MaximizeWindow(window);
|
|
||||||
}
|
|
||||||
if (ImGui::MenuItem(titlebar_icons[2])) {
|
|
||||||
done = true;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
ImGui::EndMainMenuBar();
|
|
||||||
}
|
|
||||||
int RendererBackend::Run() {
|
int RendererBackend::Run() {
|
||||||
framerate = 60;
|
framerate = 60;
|
||||||
started = false;
|
started = false;
|
||||||
|
@ -537,8 +403,7 @@ int RendererBackend::Run() {
|
||||||
#else
|
#else
|
||||||
try {
|
try {
|
||||||
BackendInit();
|
BackendInit();
|
||||||
} catch (std::exception &e) {
|
} catch (std::exception) {
|
||||||
ERROR.writefln("Error occurred during initialization: %s", e.what());
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
started = true;
|
started = true;
|
||||||
|
|
|
@ -25,19 +25,7 @@ class RendererBackend {
|
||||||
bool resize_needed = true;
|
bool resize_needed = true;
|
||||||
void on_resize();
|
void on_resize();
|
||||||
bool update_scale = false;
|
bool update_scale = false;
|
||||||
SDL_Texture *icon_texture;
|
|
||||||
bool main_menu_bar_used = false;
|
|
||||||
int menubar_start;
|
|
||||||
int menubar_end;
|
|
||||||
int title_btn_start;
|
|
||||||
std::string subtitle;
|
|
||||||
std::string title_text;
|
|
||||||
void update_real_title();
|
|
||||||
public:
|
public:
|
||||||
bool is_fullscreen();
|
|
||||||
bool is_maximized();
|
|
||||||
int window_border_radius = 8;
|
|
||||||
SDL_HitTestResult HitTest(SDL_Window *window, const SDL_Point *area);
|
|
||||||
std::optional<bool> touchScreenModeOverride;
|
std::optional<bool> touchScreenModeOverride;
|
||||||
std::optional<double> scaleOverride;
|
std::optional<double> scaleOverride;
|
||||||
bool isTouchScreenMode();
|
bool isTouchScreenMode();
|
||||||
|
@ -58,10 +46,6 @@ class RendererBackend {
|
||||||
const char *prefPath;
|
const char *prefPath;
|
||||||
ImVec4 accent_color = ImVec4(0.75, 1.0, 1.0, 1.0);
|
ImVec4 accent_color = ImVec4(0.75, 1.0, 1.0, 1.0);
|
||||||
int Run();
|
int Run();
|
||||||
void SetSubtitle(const char *subtitle);
|
|
||||||
inline void ClearSubtitle() {
|
|
||||||
SetSubtitle("");
|
|
||||||
}
|
|
||||||
void SetWindowTitle(const char *title);
|
void SetWindowTitle(const char *title);
|
||||||
virtual void Init();
|
virtual void Init();
|
||||||
virtual void GuiFunction();
|
virtual void GuiFunction();
|
||||||
|
@ -73,8 +57,6 @@ class RendererBackend {
|
||||||
void AddFonts();
|
void AddFonts();
|
||||||
void SetWindowSize(int w, int h);
|
void SetWindowSize(int w, int h);
|
||||||
void GetWindowsize(int *w, int *h);
|
void GetWindowsize(int *w, int *h);
|
||||||
bool BeginMainMenuBar();
|
|
||||||
void EndMainMenuBar();
|
|
||||||
RendererBackend();
|
RendererBackend();
|
||||||
virtual ~RendererBackend();
|
virtual ~RendererBackend();
|
||||||
friend void main_loop();
|
friend void main_loop();
|
||||||
|
|
|
@ -7,9 +7,7 @@
|
||||||
#include "imgui/imgui.h"
|
#include "imgui/imgui.h"
|
||||||
#include "ui_backend.hpp"
|
#include "ui_backend.hpp"
|
||||||
#include "thirdparty/CLI11.hpp"
|
#include "thirdparty/CLI11.hpp"
|
||||||
#include "imgui/misc/cpp/imgui_stdlib.h"
|
|
||||||
#include <web_functions.hpp>
|
#include <web_functions.hpp>
|
||||||
#include <cats.hpp>
|
|
||||||
using namespace Looper::Options;
|
using namespace Looper::Options;
|
||||||
void MainLoop::Init() {
|
void MainLoop::Init() {
|
||||||
#ifdef PORTALS
|
#ifdef PORTALS
|
||||||
|
@ -29,25 +27,6 @@ void MainLoop::Init() {
|
||||||
theme_editor = false;
|
theme_editor = false;
|
||||||
stopped = true;
|
stopped = true;
|
||||||
about_window = false;
|
about_window = false;
|
||||||
for (auto &cat : get_cat_data()) {
|
|
||||||
switch (cat.get_type()) {
|
|
||||||
case CatDataType::Memory: {
|
|
||||||
auto mem_cat = cat.get_memory_cat();
|
|
||||||
AddCat(cat.get_name(), LoadCatFromMemory(mem_cat.get_ptr(), mem_cat.get_len(), cat.get_path().c_str()));
|
|
||||||
} break;
|
|
||||||
case CatDataType::File: {
|
|
||||||
fs::path cat_path = cat.get_path();
|
|
||||||
try {
|
|
||||||
AddCat(cat.get_name(), LoadCat(cat_path.string()));
|
|
||||||
} catch (std::exception &e) {
|
|
||||||
WARNING.writefln("Failed to load cat %s at path %s: %s", cat_path.c_str(), cat.get_name().c_str(), e.what());
|
|
||||||
}
|
|
||||||
} break;
|
|
||||||
default: {
|
|
||||||
WARNING.writefln("Invalid cat type with numerical value: %d", cat.get_type());
|
|
||||||
} break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
string lang;
|
string lang;
|
||||||
{
|
{
|
||||||
Json::Value config;
|
Json::Value config;
|
||||||
|
@ -123,11 +102,6 @@ void MainLoop::Init() {
|
||||||
accent_color.w = (float)get_option<double>("ui.imgui.accent_color.a", accent_color.w);
|
accent_color.w = (float)get_option<double>("ui.imgui.accent_color.a", accent_color.w);
|
||||||
debug_mode = get_option<bool>("ui.imgui.debug_mode", false);
|
debug_mode = get_option<bool>("ui.imgui.debug_mode", false);
|
||||||
}
|
}
|
||||||
{
|
|
||||||
enable_cat = get_option<bool>("ui.enable_cat", false);
|
|
||||||
cat_setting = get_option<std::string>("ui.cat", cats.empty() ? "" : cats.begin()->first);
|
|
||||||
if (cats.contains(cat_setting)) cat = cats[cat_setting];
|
|
||||||
}
|
|
||||||
Theme::updateAvailableThemes();
|
Theme::updateAvailableThemes();
|
||||||
if (Theme::availableThemes.empty()) {
|
if (Theme::availableThemes.empty()) {
|
||||||
path lightPath = Theme::themeDir / "light.toml";
|
path lightPath = Theme::themeDir / "light.toml";
|
||||||
|
@ -154,57 +128,18 @@ void MainLoop::Init() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
theme->Apply(accent_color, (float)scale);
|
theme->Apply(accent_color, (float)scale);
|
||||||
SetWindowTitle("Looper");
|
|
||||||
FileLoaded();
|
FileLoaded();
|
||||||
}
|
}
|
||||||
void MainLoop::Drop(std::string file) {
|
void MainLoop::Drop(std::string file) {
|
||||||
LoadFile(file);
|
LoadFile(file);
|
||||||
}
|
}
|
||||||
SDL_Texture *MainLoop::LoadCat(File *file) {
|
|
||||||
size_t pos = file->get_pos();
|
|
||||||
file->seek(0, SeekType::SET);
|
|
||||||
std::string fname = file->name;
|
|
||||||
|
|
||||||
SDL_RWops *rwops = get_sdl_file(file);
|
|
||||||
const char *ext = std::filesystem::path(fname).extension().c_str();
|
|
||||||
DEBUG.writefln("Extension: %s\n", ext);
|
|
||||||
if (ext[0] == '.') ext = ext + 1;
|
|
||||||
SDL_Texture *tex = IMG_LoadTextureTyped_RW(rend, rwops, 0, ext);
|
|
||||||
delete rwops;
|
|
||||||
if (!tex) throw CustomException(fmt::format("Failed to load cat {}: {}", fname, IMG_GetError()));
|
|
||||||
file->seek(pos, SeekType::SET);
|
|
||||||
return tex;
|
|
||||||
}
|
|
||||||
SDL_Texture *MainLoop::LoadCat(std::string path) {
|
|
||||||
|
|
||||||
std::string fname = path;
|
|
||||||
|
|
||||||
SDL_RWops *rwops = SDL_RWFromFile(path.c_str(), "rb");
|
|
||||||
SDL_Texture *tex = IMG_LoadTexture_RW(rend, rwops, 1);
|
|
||||||
if (!tex) throw CustomException(fmt::format("Failed to load cat {}: {}", fname, IMG_GetError()));
|
|
||||||
return tex;
|
|
||||||
}
|
|
||||||
SDL_Texture *MainLoop::LoadCatFromMemory(const void *ptr, size_t len, const char *name) {
|
|
||||||
std::string fname = name;
|
|
||||||
|
|
||||||
SDL_RWops *rwops = SDL_RWFromConstMem(ptr, len);
|
|
||||||
SDL_Texture *tex = IMG_LoadTexture_RW(rend, rwops, 1);
|
|
||||||
if (!tex) throw CustomException(fmt::format("Failed to load cat {}: {}", fname, IMG_GetError()));
|
|
||||||
return tex;
|
|
||||||
}
|
|
||||||
void MainLoop::AddCat(std::string name, SDL_Texture *tex) {
|
|
||||||
if (cats.contains(name)) {
|
|
||||||
SDL_DestroyTexture(cats[name]);
|
|
||||||
}
|
|
||||||
cats[name] = tex;
|
|
||||||
}
|
|
||||||
void MainLoop::FileLoaded() {
|
void MainLoop::FileLoaded() {
|
||||||
auto file_maybe = playback->get_current_title();
|
auto file_maybe = playback->get_current_title();
|
||||||
if (file_maybe.has_value()) {
|
if (file_maybe.has_value()) {
|
||||||
auto name = file_maybe.value();
|
auto name = file_maybe.value();
|
||||||
SetSubtitle(name.c_str());
|
SetWindowTitle((name + std::string(" - Looper")).c_str());
|
||||||
} else {
|
} else {
|
||||||
ClearSubtitle();
|
SetWindowTitle("Looper");
|
||||||
}
|
}
|
||||||
streams = playback->get_streams();
|
streams = playback->get_streams();
|
||||||
properties = playback->get_property_list();
|
properties = playback->get_property_list();
|
||||||
|
@ -226,7 +161,7 @@ void MainLoop::GuiFunction() {
|
||||||
// 1. Show the big demo window (Most of the sample code is in ImGui::ShowDemoWindow()! You can browse its code to learn more about Dear ImGui!).
|
// 1. Show the big demo window (Most of the sample code is in ImGui::ShowDemoWindow()! You can browse its code to learn more about Dear ImGui!).
|
||||||
if (show_demo_window)
|
if (show_demo_window)
|
||||||
ImGui::ShowDemoWindow(&show_demo_window);
|
ImGui::ShowDemoWindow(&show_demo_window);
|
||||||
if (BeginMainMenuBar()) {
|
if (ImGui::BeginMainMenuBar()) {
|
||||||
if (ImGui::BeginMenu(_TRI_CTX(ICON_FK_FILE, "Main menu", "File"))) {
|
if (ImGui::BeginMenu(_TRI_CTX(ICON_FK_FILE, "Main menu", "File"))) {
|
||||||
if (ImGui::MenuItem(_TRI_CTX(ICON_FK_FOLDER_OPEN, "Main menu | File", "Open"))) {
|
if (ImGui::MenuItem(_TRI_CTX(ICON_FK_FOLDER_OPEN, "Main menu | File", "Open"))) {
|
||||||
// Set translatable strings here so that they are in the correct language even when it changes at runtime.
|
// Set translatable strings here so that they are in the correct language even when it changes at runtime.
|
||||||
|
@ -275,22 +210,11 @@ void MainLoop::GuiFunction() {
|
||||||
}
|
}
|
||||||
ImGui::EndMenu();
|
ImGui::EndMenu();
|
||||||
}
|
}
|
||||||
EndMainMenuBar();
|
ImGui::EndMainMenuBar();
|
||||||
}
|
}
|
||||||
ImGui::SetNextWindowDockID(dockid);
|
ImGui::SetNextWindowDockID(dockid);
|
||||||
ImGui::Begin(_TRI_CTX(ICON_FK_PLAY, "Main window title", "Player"), nullptr, 0);
|
ImGui::Begin(_TRI_CTX(ICON_FK_PLAY, "Main window title", "Player"), nullptr, 0);
|
||||||
{
|
{
|
||||||
ImGui::SetCursorPosY(0);
|
|
||||||
float y_pos = ImGui::GetWindowHeight() - ImGui::GetFrameHeightWithSpacing() - ImGui::GetFrameHeight() - ImGui::GetStyle().WindowPadding.y;
|
|
||||||
if (enable_cat && cat) {
|
|
||||||
int cw, ch;
|
|
||||||
SDL_QueryTexture(cat, NULL, NULL, &cw, &ch);
|
|
||||||
float aspect = ((float)cw) / ((float)ch);
|
|
||||||
float x_size = y_pos * aspect;
|
|
||||||
float x_pos = ImGui::GetWindowWidth() - ImGui::GetStyle().WindowPadding.x - x_size;
|
|
||||||
ImGui::SetCursorPosX(x_pos);
|
|
||||||
ImGui::Image((ImTextureID)cat, ImVec2(x_size, y_pos));
|
|
||||||
}
|
|
||||||
float centerSpace = ImGui::GetWindowHeight() - ImGui::GetFrameHeightWithSpacing() - ImGui::GetFrameHeight() - ImGui::GetStyle().WindowPadding.y;
|
float centerSpace = ImGui::GetWindowHeight() - ImGui::GetFrameHeightWithSpacing() - ImGui::GetFrameHeight() - ImGui::GetStyle().WindowPadding.y;
|
||||||
if (streams.size() > 0) {
|
if (streams.size() > 0) {
|
||||||
static string filter = "";
|
static string filter = "";
|
||||||
|
@ -330,7 +254,7 @@ void MainLoop::GuiFunction() {
|
||||||
}
|
}
|
||||||
ImGui::EndChildFrame();
|
ImGui::EndChildFrame();
|
||||||
}
|
}
|
||||||
ImGui::SetCursorPosY(y_pos);
|
ImGui::SetCursorPosY(ImGui::GetWindowHeight() - ImGui::GetFrameHeightWithSpacing() - ImGui::GetFrameHeight() - ImGui::GetStyle().WindowPadding.y);
|
||||||
if (ImGui::Button(playback->IsPaused() ? ICON_FK_PLAY "##Pause" : ICON_FK_PAUSE "##Pause")) {
|
if (ImGui::Button(playback->IsPaused() ? ICON_FK_PLAY "##Pause" : ICON_FK_PAUSE "##Pause")) {
|
||||||
playback->Pause();
|
playback->Pause();
|
||||||
}
|
}
|
||||||
|
@ -388,58 +312,6 @@ void MainLoop::GuiFunction() {
|
||||||
ImGui::PushID(property.path().c_str());
|
ImGui::PushID(property.path().c_str());
|
||||||
bool valid = false;
|
bool valid = false;
|
||||||
switch (property.type()) {
|
switch (property.type()) {
|
||||||
case PropertyType::String: {
|
|
||||||
std::string value = "";
|
|
||||||
if (string_properties.contains(property.path())) {
|
|
||||||
value = string_properties[property.path()];
|
|
||||||
} else {
|
|
||||||
auto value_to_resolve = playback->get_property(property.path());
|
|
||||||
if (value_to_resolve.has_value()) {
|
|
||||||
value = resolve_value<std::string>(value_to_resolve.value());
|
|
||||||
}
|
|
||||||
string_properties[property.path()] = value;
|
|
||||||
}
|
|
||||||
ImGui::InputText(property.path().c_str(), &value);
|
|
||||||
string_properties[property.path()] = value;
|
|
||||||
valid = true;
|
|
||||||
} break;
|
|
||||||
case PropertyType::Int: {
|
|
||||||
std::optional<double> min;
|
|
||||||
std::optional<double> max;
|
|
||||||
int value = 0;
|
|
||||||
if (int_properties.contains(property.path())) {
|
|
||||||
value = int_properties[property.path()];
|
|
||||||
} else {
|
|
||||||
auto value_to_resolve = playback->get_property(property.path());
|
|
||||||
if (value_to_resolve.has_value()) {
|
|
||||||
value = resolve_value<int>(value_to_resolve.value());
|
|
||||||
}
|
|
||||||
int_properties[property.path()] = value;
|
|
||||||
}
|
|
||||||
if (property.has_hint() && property.hint().has_range()) {
|
|
||||||
auto range = property.hint().range();
|
|
||||||
if (range.has_min() && range.has_max()) {
|
|
||||||
if (ImGui::SliderInt(property.path().c_str(), &value, (int)range.min(), (int)range.max())) {
|
|
||||||
int_properties[property.path()] = value;
|
|
||||||
}
|
|
||||||
valid = true;
|
|
||||||
} else {
|
|
||||||
if (range.has_min()) min = range.min();
|
|
||||||
if (range.has_max()) max = range.max();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!valid) {
|
|
||||||
ImGui::InputInt(property.path().c_str(), &value);
|
|
||||||
if (min.has_value() && value < min) {
|
|
||||||
value = min.value();
|
|
||||||
}
|
|
||||||
if (max.has_value() && value > max) {
|
|
||||||
value = max.value();
|
|
||||||
}
|
|
||||||
int_properties[property.path()] = value;
|
|
||||||
valid = true;
|
|
||||||
}
|
|
||||||
} break;
|
|
||||||
case PropertyType::Double: {
|
case PropertyType::Double: {
|
||||||
std::optional<double> min;
|
std::optional<double> min;
|
||||||
std::optional<double> max;
|
std::optional<double> max;
|
||||||
|
@ -499,20 +371,6 @@ void MainLoop::GuiFunction() {
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
if (ImGui::Button("Set")) {
|
if (ImGui::Button("Set")) {
|
||||||
switch (property.type()) {
|
switch (property.type()) {
|
||||||
case PropertyType::String: {
|
|
||||||
StringProperty property_s;
|
|
||||||
property_s.set_value(string_properties[property.path()]);
|
|
||||||
google::protobuf::Any value;
|
|
||||||
value.PackFrom(property_s);
|
|
||||||
playback->set_property(property.path(), value);
|
|
||||||
} break;
|
|
||||||
case PropertyType::Int: {
|
|
||||||
IntProperty property_i;
|
|
||||||
property_i.set_value(int_properties[property.path()]);
|
|
||||||
google::protobuf::Any value;
|
|
||||||
value.PackFrom(property_i);
|
|
||||||
playback->set_property(property.path(), value);
|
|
||||||
} break;
|
|
||||||
case PropertyType::Double: {
|
case PropertyType::Double: {
|
||||||
DoubleProperty property_d;
|
DoubleProperty property_d;
|
||||||
property_d.set_value(double_properties[property.path()]);
|
property_d.set_value(double_properties[property.path()]);
|
||||||
|
@ -592,54 +450,6 @@ void MainLoop::GuiFunction() {
|
||||||
set_option<std::string>("ui.imgui.lang", lang);
|
set_option<std::string>("ui.imgui.lang", lang);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static SDL_Texture *disp_cat = nullptr;
|
|
||||||
if (ImGui::Checkbox(_TR_CTX("Preference | cat enable checkbox", "Enable cat"), &enable_cat)) {
|
|
||||||
disp_cat = nullptr;
|
|
||||||
set_option<bool>("ui.enable_cat", enable_cat);
|
|
||||||
}
|
|
||||||
if (enable_cat) {
|
|
||||||
|
|
||||||
ImVec2 TableSize = ImVec2(0, 0);
|
|
||||||
if (ImGui::BeginTable("##Cats", 2, ImGuiTableFlags_SizingFixedFit|ImGuiTableFlags_NoSavedSettings|ImGuiTableFlags_ScrollY, TableSize)) {
|
|
||||||
ImGui::TableSetupColumn("Cat Name", ImGuiTableColumnFlags_WidthStretch);
|
|
||||||
ImGui::TableSetupColumn("Preview", 0);
|
|
||||||
for (auto &kv : cats) {
|
|
||||||
ImGui::TableNextRow();
|
|
||||||
ImGui::TableSetColumnIndex(0);
|
|
||||||
if (ImGui::Selectable(kv.first.c_str(), kv.first == cat_setting, 0)) {
|
|
||||||
cat_setting = kv.first;
|
|
||||||
cat = cats[cat_setting];
|
|
||||||
set_option<std::string>("ui.cat", cat_setting);
|
|
||||||
}
|
|
||||||
ImGui::TableSetColumnIndex(1);
|
|
||||||
int cw, ch;
|
|
||||||
SDL_QueryTexture(kv.second, NULL, NULL, &cw, &ch);
|
|
||||||
float aspect = ((float)cw) / ((float)ch);
|
|
||||||
bool portrait = ch > cw;
|
|
||||||
ImVec2 size = ImVec2(16.0f * aspect, 16.0f);
|
|
||||||
if (ImGui::ImageButton(fmt::format("disp_cat_{}", kv.first).c_str(), (ImTextureID)kv.second, size)) {
|
|
||||||
if (disp_cat == kv.second) {
|
|
||||||
disp_cat = nullptr;
|
|
||||||
} else {
|
|
||||||
disp_cat = kv.second;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ImGui::EndTable();
|
|
||||||
}
|
|
||||||
bool show_cat_preview = disp_cat != nullptr;
|
|
||||||
if (show_cat_preview && ImGui::Begin("Cat Preview", &show_cat_preview, ImGuiWindowFlags_NoSavedSettings|ImGuiWindowFlags_AlwaysAutoResize)) {
|
|
||||||
int cw, ch;
|
|
||||||
SDL_QueryTexture(disp_cat, NULL, NULL, &cw, &ch);
|
|
||||||
ImGui::Image((ImTextureID)disp_cat, ImVec2(cw, ch));
|
|
||||||
ImGui::End();
|
|
||||||
}
|
|
||||||
// Handle window close.
|
|
||||||
if (!show_cat_preview) {
|
|
||||||
disp_cat = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (override_lang) {
|
if (override_lang) {
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
ImGui::SetNextItemWidth(ImGui::GetWindowWidth() - ImGui::GetCursorPosX() - (ImGui::GetFontSize()) - ((ImGui::GetStyle().ItemSpacing.x + (ImGui::GetStyle().FramePadding.x * 2.0f))) - (ImGui::GetStyle().WindowPadding.x));
|
ImGui::SetNextItemWidth(ImGui::GetWindowWidth() - ImGui::GetCursorPosX() - (ImGui::GetFontSize()) - ((ImGui::GetStyle().ItemSpacing.x + (ImGui::GetStyle().FramePadding.x * 2.0f))) - (ImGui::GetStyle().WindowPadding.x));
|
||||||
|
@ -752,8 +562,6 @@ void MainLoop::GuiFunction() {
|
||||||
ImGui::SetCursorPosX((ImGui::GetWindowWidth() - ImGui::GetFont()->CalcTextSizeA(ImGui::GetFontSize(), FLT_MAX, 0.0f, VER_STRING.c_str()).x) / 2.0f);
|
ImGui::SetCursorPosX((ImGui::GetWindowWidth() - ImGui::GetFont()->CalcTextSizeA(ImGui::GetFontSize(), FLT_MAX, 0.0f, VER_STRING.c_str()).x) / 2.0f);
|
||||||
ImGui::TextUnformatted(VER_STRING.c_str());
|
ImGui::TextUnformatted(VER_STRING.c_str());
|
||||||
ImGui::NewLine();
|
ImGui::NewLine();
|
||||||
ImGui::Text("SDL video driver: %s", SDL_GetCurrentVideoDriver());
|
|
||||||
ImGui::NewLine();
|
|
||||||
auto &license_data = get_license_data();
|
auto &license_data = get_license_data();
|
||||||
// Left
|
// Left
|
||||||
static LicenseData selected = *license_data.begin();
|
static LicenseData selected = *license_data.begin();
|
||||||
|
@ -814,18 +622,13 @@ void MainLoop::LoadFile(std::string file) {
|
||||||
playback->Start(file);
|
playback->Start(file);
|
||||||
}
|
}
|
||||||
void MainLoop::Deinit() {
|
void MainLoop::Deinit() {
|
||||||
for (auto kv : cats) {
|
|
||||||
SDL_DestroyTexture(kv.second);
|
|
||||||
}
|
|
||||||
cats.clear();
|
|
||||||
{
|
{
|
||||||
path themePath(theme->file_path);
|
path themePath(theme->file_path);
|
||||||
themePath = themePath.stem();
|
themePath = themePath.stem();
|
||||||
if (!themePath.empty()) {
|
if (!themePath.empty()) {
|
||||||
set_option<std::string>("ui.imgui.theme", themePath.string());
|
set_option<std::string>("ui.imgui.theme", themePath.string());
|
||||||
}
|
}
|
||||||
set_option<bool>("ui.enable_cat", enable_cat);
|
|
||||||
set_option<std::string>("ui.cat", cat_setting);
|
|
||||||
set_option<double>("ui.imgui.accent_color.h", accent_color.x);
|
set_option<double>("ui.imgui.accent_color.h", accent_color.x);
|
||||||
set_option<double>("ui.imgui.accent_color.s", accent_color.y);
|
set_option<double>("ui.imgui.accent_color.s", accent_color.y);
|
||||||
set_option<double>("ui.imgui.accent_color.v", accent_color.z);
|
set_option<double>("ui.imgui.accent_color.v", accent_color.z);
|
||||||
|
@ -861,10 +664,6 @@ void ImGuiUIBackend::QuitHandler() {
|
||||||
// Main code
|
// Main code
|
||||||
int ImGuiUIBackend::run(std::vector<std::string> realArgs, int argc, char** argv)
|
int ImGuiUIBackend::run(std::vector<std::string> realArgs, int argc, char** argv)
|
||||||
{
|
{
|
||||||
SDL_setenv("SDL_VIDEO_X11_WMCLASS", "looper", 1);
|
|
||||||
if (SDL_getenv("WAYLAND_DISPLAY")) {
|
|
||||||
SDL_setenv("SDL_VIDEODRIVER", "wayland", 0);
|
|
||||||
}
|
|
||||||
int possible_error = UIBackend::run(realArgs, argc, argv);
|
int possible_error = UIBackend::run(realArgs, argc, argv);
|
||||||
if (possible_error != 0) {
|
if (possible_error != 0) {
|
||||||
return possible_error;
|
return possible_error;
|
||||||
|
|
|
@ -36,7 +36,6 @@
|
||||||
using namespace std::filesystem;
|
using namespace std::filesystem;
|
||||||
using std::string;
|
using std::string;
|
||||||
#define IMGUI_FRONTEND
|
#define IMGUI_FRONTEND
|
||||||
|
|
||||||
class MainLoop : public RendererBackend {
|
class MainLoop : public RendererBackend {
|
||||||
bool show_demo_window = false;
|
bool show_demo_window = false;
|
||||||
FileBrowser fileDialog = FileBrowser(false);
|
FileBrowser fileDialog = FileBrowser(false);
|
||||||
|
@ -50,24 +49,14 @@ class MainLoop : public RendererBackend {
|
||||||
bool property_editor = false;
|
bool property_editor = false;
|
||||||
bool restart_needed = false;
|
bool restart_needed = false;
|
||||||
bool stopped = true;
|
bool stopped = true;
|
||||||
bool enable_cat = false;
|
|
||||||
std::string cat_setting = "__default__";
|
|
||||||
std::vector<UIBackend*> backends;
|
std::vector<UIBackend*> backends;
|
||||||
UIBackend *cur_backend;
|
UIBackend *cur_backend;
|
||||||
friend class ImGuiUIBackend;
|
friend class ImGuiUIBackend;
|
||||||
std::atomic_bool exit_flag;
|
std::atomic_bool exit_flag;
|
||||||
std::map<std::string, bool> boolean_properties;
|
std::map<std::string, bool> boolean_properties;
|
||||||
std::map<std::string, double> double_properties;
|
std::map<std::string, double> double_properties;
|
||||||
std::map<std::string, int> int_properties;
|
|
||||||
std::map<std::string, std::string> string_properties;
|
|
||||||
std::vector<Property> properties;
|
std::vector<Property> properties;
|
||||||
std::vector<PlaybackStream> streams;
|
std::vector<PlaybackStream> streams;
|
||||||
std::map<std::string, SDL_Texture*> cats;
|
|
||||||
SDL_Texture *cat = nullptr;
|
|
||||||
SDL_Texture *LoadCatFromMemory(const void *ptr, size_t len, const char *name);
|
|
||||||
SDL_Texture *LoadCat(File *file);
|
|
||||||
SDL_Texture *LoadCat(std::string path);
|
|
||||||
void AddCat(std::string name, SDL_Texture *tex);
|
|
||||||
public:
|
public:
|
||||||
Playback *playback;
|
Playback *playback;
|
||||||
vector<std::string> args;
|
vector<std::string> args;
|
||||||
|
|
|
@ -20,7 +20,6 @@ const char* Theme::prefPath = NULL;
|
||||||
path Theme::themeDir = path();
|
path Theme::themeDir = path();
|
||||||
std::set<path> Theme::availableThemes = std::set<path>();
|
std::set<path> Theme::availableThemes = std::set<path>();
|
||||||
std::map<path, ThemeStrings> Theme::themeStrings = std::map<path, ThemeStrings>();
|
std::map<path, ThemeStrings> Theme::themeStrings = std::map<path, ThemeStrings>();
|
||||||
Theme *Theme::cur_theme = nullptr;
|
|
||||||
|
|
||||||
ImVec4 change_accent_color(ImVec4 in, float hue) {
|
ImVec4 change_accent_color(ImVec4 in, float hue) {
|
||||||
if (in.x == in.y && in.y == in.z) {
|
if (in.x == in.y && in.y == in.z) {
|
||||||
|
@ -186,11 +185,9 @@ bool Theme::ShowEditor(bool* open, Theme* &theme, ImGuiID dockid, int window_wid
|
||||||
|
|
||||||
ImGui::BeginChild("##colors", ImVec2(0, 0), true, ImGuiWindowFlags_AlwaysVerticalScrollbar | ImGuiWindowFlags_AlwaysHorizontalScrollbar | ImGuiWindowFlags_NavFlattened);
|
ImGui::BeginChild("##colors", ImVec2(0, 0), true, ImGuiWindowFlags_AlwaysVerticalScrollbar | ImGuiWindowFlags_AlwaysHorizontalScrollbar | ImGuiWindowFlags_NavFlattened);
|
||||||
ImGui::PushItemWidth(-160);
|
ImGui::PushItemWidth(-160);
|
||||||
for (int i = 0; i < (int)ImGuiCol_COUNT + (int)LooperCol_COUNT; i++)
|
for (int i = 0; i < ImGuiCol_COUNT; i++)
|
||||||
{
|
{
|
||||||
const char* name;
|
const char* name = ImGui::GetStyleColorName(i);
|
||||||
if (i < ImGuiCol_COUNT) name = ImGui::GetStyleColorName(i);
|
|
||||||
else name = theme->GetStyleColorName(i-ImGuiCol_COUNT);
|
|
||||||
if (!filter.PassFilter(name))
|
if (!filter.PassFilter(name))
|
||||||
continue;
|
continue;
|
||||||
ImGui::PushID(i);
|
ImGui::PushID(i);
|
||||||
|
@ -200,7 +197,7 @@ bool Theme::ShowEditor(bool* open, Theme* &theme, ImGuiID dockid, int window_wid
|
||||||
ImGui::Checkbox(_TR_CTX("Theme Editor | Colors | (Any color) | recoloring checkbox | Saturation", "S: "), &colorizer.Saturation); ImGui::SameLine();
|
ImGui::Checkbox(_TR_CTX("Theme Editor | Colors | (Any color) | recoloring checkbox | Saturation", "S: "), &colorizer.Saturation); ImGui::SameLine();
|
||||||
ImGui::Checkbox(_TR_CTX("Theme Editor | Colors | (Any color) | recoloring checkbox | Value", "V: "), &colorizer.Value); ImGui::SameLine();
|
ImGui::Checkbox(_TR_CTX("Theme Editor | Colors | (Any color) | recoloring checkbox | Value", "V: "), &colorizer.Value); ImGui::SameLine();
|
||||||
ImGui::Checkbox(_TR_CTX("Theme Editor | Colors | (Any color) | recoloring checkbox | Alpha (opacity)", "A: "), &colorizer.Alpha); ImGui::SameLine();
|
ImGui::Checkbox(_TR_CTX("Theme Editor | Colors | (Any color) | recoloring checkbox | Alpha (opacity)", "A: "), &colorizer.Alpha); ImGui::SameLine();
|
||||||
ImGui::ColorEdit4("##color", (float*)&(i < ImGuiCol_COUNT ? style.Colors[i] : theme->Colors[i-ImGuiCol_COUNT]), ImGuiColorEditFlags_AlphaBar | alpha_flags | ImGuiColorEditFlags_DisplayHSV);
|
ImGui::ColorEdit4("##color", (float*)&style.Colors[i], ImGuiColorEditFlags_AlphaBar | alpha_flags | ImGuiColorEditFlags_DisplayHSV);
|
||||||
ImGui::SameLine(0.0f, style.ItemInnerSpacing.x);
|
ImGui::SameLine(0.0f, style.ItemInnerSpacing.x);
|
||||||
ImGui::TextUnformatted(name);
|
ImGui::TextUnformatted(name);
|
||||||
ImGui::PopID();
|
ImGui::PopID();
|
||||||
|
@ -376,7 +373,6 @@ void Theme::Apply(ImVec4 accent, float scale) {
|
||||||
actual_style.WindowMinSize.y = MAX(actual_style.WindowMinSize.y, 1.0);
|
actual_style.WindowMinSize.y = MAX(actual_style.WindowMinSize.y, 1.0);
|
||||||
actual_style.CurveTessellationTol = MAX(actual_style.CurveTessellationTol, 0.1);
|
actual_style.CurveTessellationTol = MAX(actual_style.CurveTessellationTol, 0.1);
|
||||||
actual_style.CircleTessellationMaxError = MAX(actual_style.CircleTessellationMaxError, 0.1);
|
actual_style.CircleTessellationMaxError = MAX(actual_style.CircleTessellationMaxError, 0.1);
|
||||||
cur_theme = this;
|
|
||||||
}
|
}
|
||||||
void Theme::Save(string path) {
|
void Theme::Save(string path) {
|
||||||
INFO.writefln("Saving theme to %s...", path.c_str());
|
INFO.writefln("Saving theme to %s...", path.c_str());
|
||||||
|
@ -444,18 +440,11 @@ void Theme::Save(string path) {
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
toml::table colors;
|
toml::table colors;
|
||||||
for (int i = 0; i < (int)ImGuiCol_COUNT + (int)LooperCol_COUNT; i++)
|
for (int i = 0; i < ImGuiCol_COUNT; i++)
|
||||||
{
|
{
|
||||||
const char *name;
|
const char* name = ImGui::GetStyleColorName(i);
|
||||||
ImVec4 color;
|
ImVec4 color = style.Colors[i];
|
||||||
toml::table colorValue;
|
toml::table colorValue;
|
||||||
if (i >= ImGuiCol_COUNT) {
|
|
||||||
name = GetStyleColorName(i - ImGuiCol_COUNT);
|
|
||||||
color = this->Colors[i - ImGuiCol_COUNT];
|
|
||||||
} else {
|
|
||||||
name = ImGui::GetStyleColorName(i);
|
|
||||||
color = style.Colors[i];
|
|
||||||
}
|
|
||||||
colorValue.insert("r", color.x);
|
colorValue.insert("r", color.x);
|
||||||
colorValue.insert("g", color.y);
|
colorValue.insert("g", color.y);
|
||||||
colorValue.insert("b", color.z);
|
colorValue.insert("b", color.z);
|
||||||
|
@ -476,20 +465,6 @@ void Theme::Save(string path) {
|
||||||
}
|
}
|
||||||
updateAvailableThemes();
|
updateAvailableThemes();
|
||||||
}
|
}
|
||||||
ImVec4 Theme::GetColor(int color) {
|
|
||||||
if (cur_theme == nullptr) {
|
|
||||||
return ImVec4(255, 0, 255, 0);
|
|
||||||
} else {
|
|
||||||
return cur_theme->Colors[color];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const char *Theme::GetStyleColorName(int color) {
|
|
||||||
switch (color) {
|
|
||||||
case LooperCol_Subtitle: return "Subtitle";
|
|
||||||
}
|
|
||||||
ERROR.writefln("Invalid looper-specific color ID: %d\n", color);
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
void Theme::Save(path path) {
|
void Theme::Save(path path) {
|
||||||
Save((string)path.string());
|
Save((string)path.string());
|
||||||
}
|
}
|
||||||
|
@ -560,16 +535,9 @@ Theme::Theme(bool dark) : Theme() {
|
||||||
ImGui::StyleColorsLight(&style);
|
ImGui::StyleColorsLight(&style);
|
||||||
style.FrameBorderSize = 1;
|
style.FrameBorderSize = 1;
|
||||||
}
|
}
|
||||||
this->Colors[LooperCol_Subtitle] = style.Colors[ImGuiCol_Text];
|
for (int i = 0; i < ImGuiCol_COUNT; i++)
|
||||||
this->Colors[LooperCol_Subtitle].w *= 0.5;
|
|
||||||
for (int i = 0; i < (int)ImGuiCol_COUNT + (int)LooperCol_COUNT; i++)
|
|
||||||
{
|
{
|
||||||
ImVec4 color;
|
ImVec4 color = style.Colors[i];
|
||||||
if (i < ImGuiCol_COUNT) {
|
|
||||||
color = style.Colors[i];
|
|
||||||
} else {
|
|
||||||
color = this->Colors[i-ImGuiCol_COUNT];
|
|
||||||
}
|
|
||||||
auto colorizer = AccentColorizer();
|
auto colorizer = AccentColorizer();
|
||||||
if (color.x != color.y || color.y != color.z) {
|
if (color.x != color.y || color.y != color.z) {
|
||||||
colorizer.Hue = true;
|
colorizer.Hue = true;
|
||||||
|
@ -794,27 +762,14 @@ Theme::Theme(string path) : Theme() {
|
||||||
}
|
}
|
||||||
if (config.contains("colors")) {
|
if (config.contains("colors")) {
|
||||||
toml::table colors = *config["colors"].as_table();
|
toml::table colors = *config["colors"].as_table();
|
||||||
for (int i = 0; i < (int)ImGuiCol_COUNT + (int)LooperCol_COUNT; i++)
|
for (int i = 0; i < ImGuiCol_COUNT; i++)
|
||||||
{
|
{
|
||||||
const char* name;
|
const char* name = ImGui::GetStyleColorName(i);
|
||||||
if (i < ImGuiCol_COUNT) name = ImGui::GetStyleColorName(i);
|
|
||||||
else name = GetStyleColorName(i-ImGuiCol_COUNT);
|
|
||||||
if (colors.contains(name)) {
|
if (colors.contains(name)) {
|
||||||
toml::table colorValue = *colors[name].as_table();
|
toml::table colorValue = *colors[name].as_table();
|
||||||
ImVec4 color = ImVec4((float)**colorValue["r"].as_floating_point(), (float)**colorValue["g"].as_floating_point(), (float)**colorValue["b"].as_floating_point(), (float)**colorValue["a"].as_floating_point());
|
ImVec4 color = ImVec4((float)**colorValue["r"].as_floating_point(), (float)**colorValue["g"].as_floating_point(), (float)**colorValue["b"].as_floating_point(), (float)**colorValue["a"].as_floating_point());
|
||||||
AccentColorizers[i] = AccentColorizer(*colorValue["accent"].as_table());
|
AccentColorizers[i] = AccentColorizer(*colorValue["accent"].as_table());
|
||||||
if (i < ImGuiCol_COUNT) style.Colors[i] = color;
|
style.Colors[i] = color;
|
||||||
else this->Colors[i-ImGuiCol_COUNT] = color;
|
|
||||||
} else {
|
|
||||||
WARNING.writefln("Missing color upon load: %s\nThis may have a sensible default, but be sure to check the theme colors!", name);
|
|
||||||
if (i >= ImGuiCol_COUNT) {
|
|
||||||
switch (i-ImGuiCol_COUNT) {
|
|
||||||
case LooperCol_Subtitle: {
|
|
||||||
this->Colors[LooperCol_Subtitle] = style.Colors[ImGuiCol_Text];
|
|
||||||
this->Colors[LooperCol_Subtitle].w *= 0.5;
|
|
||||||
} break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,12 +17,6 @@ struct ThemeStrings {
|
||||||
ThemeStrings();
|
ThemeStrings();
|
||||||
ThemeStrings(toml::table config);
|
ThemeStrings(toml::table config);
|
||||||
};
|
};
|
||||||
enum LooperCol {
|
|
||||||
LooperCol_Subtitle,
|
|
||||||
// LooperCol_Title,
|
|
||||||
// LooperCol_WindowBorder,
|
|
||||||
LooperCol_COUNT
|
|
||||||
};
|
|
||||||
|
|
||||||
struct AccentColorizer {
|
struct AccentColorizer {
|
||||||
/// @brief Whether or not to change the hue.
|
/// @brief Whether or not to change the hue.
|
||||||
|
@ -57,11 +51,7 @@ class Theme {
|
||||||
static const char* prefPath;
|
static const char* prefPath;
|
||||||
static const int MinSchemaVersion = 0;
|
static const int MinSchemaVersion = 0;
|
||||||
static const int MaxSchemaVersion = 1;
|
static const int MaxSchemaVersion = 1;
|
||||||
static Theme *cur_theme;
|
|
||||||
ImVec4 Colors[LooperCol_COUNT];
|
|
||||||
string file_path;
|
string file_path;
|
||||||
static ImVec4 GetColor(int color);
|
|
||||||
const char *GetStyleColorName(int color);
|
|
||||||
std::map<string, ThemeStrings> strings;
|
std::map<string, ThemeStrings> strings;
|
||||||
std::map<int, AccentColorizer> AccentColorizers;
|
std::map<int, AccentColorizer> AccentColorizers;
|
||||||
ThemeStrings GetStrings();
|
ThemeStrings GetStrings();
|
||||||
|
|
|
@ -4,8 +4,8 @@ foreach(SRC IN ITEMS ${BACKEND_QT_SRC_BASE})
|
||||||
set(BACKEND_QT_SRC ${BACKEND_QT_SRC} ${CMAKE_CURRENT_SOURCE_DIR}/${SRC})
|
set(BACKEND_QT_SRC ${BACKEND_QT_SRC} ${CMAKE_CURRENT_SOURCE_DIR}/${SRC})
|
||||||
endforeach()
|
endforeach()
|
||||||
set(BACKEND_QT_INC ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR})
|
set(BACKEND_QT_INC ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
|
set(CMAKE_AUTOMOC ON)
|
||||||
add_ui_backend(qt_ui ${BACKEND_QT_SRC})
|
add_ui_backend(qt_ui ${BACKEND_QT_SRC})
|
||||||
set_target_properties(qt_ui PROPERTIES AUTOMOC ON)
|
|
||||||
find_package(Qt6 COMPONENTS Core Gui Widgets)
|
find_package(Qt6 COMPONENTS Core Gui Widgets)
|
||||||
target_link_libraries(qt_ui PRIVATE Qt6::Core Qt6::Gui Qt6::Widgets SDL2::SDL2 fmt::fmt liblooper)
|
target_link_libraries(qt_ui PRIVATE Qt6::Core Qt6::Gui Qt6::Widgets SDL2::SDL2 fmt::fmt liblooper)
|
||||||
target_include_directories(qt_ui PRIVATE ../../..)
|
target_include_directories(qt_ui PRIVATE ../../..)
|
||||||
|
|
|
@ -5,7 +5,7 @@ void LooperWindow::Pulse() {
|
||||||
auto len = playback->GetLength();
|
auto len = playback->GetLength();
|
||||||
auto pos = playback->GetPosition();
|
auto pos = playback->GetPosition();
|
||||||
this->slider->SetLimits(0.0, len);
|
this->slider->SetLimits(0.0, len);
|
||||||
if (!this->slider->IsPressed()) this->slider->SetValueNoSignal(pos);
|
if (!this->slider->IsPressed()) this->slider->SetValue(pos);
|
||||||
auto component_count = TimeToComponentCount(len);
|
auto component_count = TimeToComponentCount(len);
|
||||||
bool enable_ui = !playback->IsStopped();
|
bool enable_ui = !playback->IsStopped();
|
||||||
if (enable_ui) {
|
if (enable_ui) {
|
||||||
|
@ -24,10 +24,10 @@ void LooperWindow::Pulse() {
|
||||||
auto pitch = playback->GetPitch();
|
auto pitch = playback->GetPitch();
|
||||||
auto speed = playback->GetSpeed();
|
auto speed = playback->GetSpeed();
|
||||||
auto tempo = playback->GetTempo();
|
auto tempo = playback->GetTempo();
|
||||||
if (!volume_slider->IsPressed()) volume_slider->SetValueNoSignal(volume);
|
if (!volume_slider->IsPressed()) volume_slider->SetValue(volume);
|
||||||
if (!pitch_slider->IsPressed()) pitch_slider->SetValueNoSignal(pitch);
|
if (!pitch_slider->IsPressed()) pitch_slider->SetValue(pitch);
|
||||||
if (!speed_slider->IsPressed()) speed_slider->SetValueNoSignal(speed);
|
if (!speed_slider->IsPressed()) speed_slider->SetValue(speed);
|
||||||
if (!tempo_slider->IsPressed()) tempo_slider->SetValueNoSignal(tempo);
|
if (!tempo_slider->IsPressed()) tempo_slider->SetValue(tempo);
|
||||||
volume_slider->SetLabel(fmt::format("Volume: {}%", (int)volume).c_str());
|
volume_slider->SetLabel(fmt::format("Volume: {}%", (int)volume).c_str());
|
||||||
pitch_slider->SetLabel(fmt::format("Pitch {:.02f}x", pitch).c_str());
|
pitch_slider->SetLabel(fmt::format("Pitch {:.02f}x", pitch).c_str());
|
||||||
speed_slider->SetLabel(fmt::format("Speed: {:.02f}x", speed).c_str());
|
speed_slider->SetLabel(fmt::format("Speed: {:.02f}x", speed).c_str());
|
||||||
|
@ -40,9 +40,6 @@ void LooperWindow::Pulse() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void LooperWindow::resizeEvent(QResizeEvent *event) {
|
|
||||||
if (cat_pixmap != NULL) update_cat(*cat_pixmap);
|
|
||||||
}
|
|
||||||
LooperWindow::LooperWindow(Playback *playback) : QMainWindow() {
|
LooperWindow::LooperWindow(Playback *playback) : QMainWindow() {
|
||||||
labels_visible = false;
|
labels_visible = false;
|
||||||
icons_visible = true;
|
icons_visible = true;
|
||||||
|
@ -83,15 +80,10 @@ LooperWindow::LooperWindow(Playback *playback) : QMainWindow() {
|
||||||
help_menu->addAction(about_item);
|
help_menu->addAction(about_item);
|
||||||
bar->addMenu(file_menu);
|
bar->addMenu(file_menu);
|
||||||
bar->addMenu(help_menu);
|
bar->addMenu(help_menu);
|
||||||
cat_disp = new QLabel();
|
root_layout->addWidget(bar);
|
||||||
cat_disp->setAlignment(Qt::Alignment::enum_type::AlignRight);
|
QSpacerItem *spacer = new QSpacerItem(0, 0, QSizePolicy::Minimum, QSizePolicy::MinimumExpanding);
|
||||||
cat_disp->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
|
root_layout->addSpacerItem(spacer);
|
||||||
root_layout->addWidget(cat_disp);
|
QBoxLayout *top_row = new QBoxLayout(QBoxLayout::LeftToRight, this);
|
||||||
QWidget *controls_widget = new QWidget(this);
|
|
||||||
QBoxLayout *controls_layout = new QBoxLayout(QBoxLayout::TopToBottom, controls_widget);
|
|
||||||
controls_widget->setLayout(controls_layout);
|
|
||||||
controls_widget->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
|
|
||||||
QBoxLayout *top_row = new QBoxLayout(QBoxLayout::LeftToRight, controls_widget);
|
|
||||||
pause_resume_btn = new QPushButton("Pause", this);
|
pause_resume_btn = new QPushButton("Pause", this);
|
||||||
QObject::connect(pause_resume_btn, &QPushButton::pressed, [=,this]() {
|
QObject::connect(pause_resume_btn, &QPushButton::pressed, [=,this]() {
|
||||||
playback->Pause();
|
playback->Pause();
|
||||||
|
@ -121,9 +113,8 @@ LooperWindow::LooperWindow(Playback *playback) : QMainWindow() {
|
||||||
});
|
});
|
||||||
top_row->addWidget(volume_slider);
|
top_row->addWidget(volume_slider);
|
||||||
QWidget *top_row_widget = new QWidget(this);
|
QWidget *top_row_widget = new QWidget(this);
|
||||||
top_row_widget->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Minimum);
|
|
||||||
top_row_widget->setLayout(top_row);
|
top_row_widget->setLayout(top_row);
|
||||||
controls_layout->addWidget(top_row_widget);
|
root_layout->addWidget(top_row_widget);
|
||||||
QBoxLayout *bottom_row = new QBoxLayout(QBoxLayout::LeftToRight, this);
|
QBoxLayout *bottom_row = new QBoxLayout(QBoxLayout::LeftToRight, this);
|
||||||
speed_slider = new LooperSlider("speed", "Speed", 0.25, 4.0, 0.01, true);
|
speed_slider = new LooperSlider("speed", "Speed", 0.25, 4.0, 0.01, true);
|
||||||
pitch_slider = new LooperSlider("pitch", "Pitch", 0.25, 4.0, 0.01, true);
|
pitch_slider = new LooperSlider("pitch", "Pitch", 0.25, 4.0, 0.01, true);
|
||||||
|
@ -144,10 +135,8 @@ LooperWindow::LooperWindow(Playback *playback) : QMainWindow() {
|
||||||
bottom_row->addWidget(pitch_slider);
|
bottom_row->addWidget(pitch_slider);
|
||||||
bottom_row->addWidget(tempo_slider);
|
bottom_row->addWidget(tempo_slider);
|
||||||
QWidget *bottom_row_widget = new QWidget(this);
|
QWidget *bottom_row_widget = new QWidget(this);
|
||||||
bottom_row_widget->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Minimum);
|
|
||||||
bottom_row_widget->setLayout(bottom_row);
|
bottom_row_widget->setLayout(bottom_row);
|
||||||
controls_layout->addWidget(bottom_row_widget);
|
root_layout->addWidget(bottom_row_widget);
|
||||||
root_layout->addWidget(controls_widget);
|
|
||||||
QTimer *timer = new QTimer(this);
|
QTimer *timer = new QTimer(this);
|
||||||
QObject::connect(timer, &QTimer::timeout, [=,this]() {
|
QObject::connect(timer, &QTimer::timeout, [=,this]() {
|
||||||
Pulse();
|
Pulse();
|
||||||
|
@ -157,9 +146,6 @@ LooperWindow::LooperWindow(Playback *playback) : QMainWindow() {
|
||||||
timer->setInterval(1);
|
timer->setInterval(1);
|
||||||
timer->start();
|
timer->start();
|
||||||
QObject::connect(prefs_window, &PrefsWindow::settings_changed, this, &LooperWindow::update_label_setting);
|
QObject::connect(prefs_window, &PrefsWindow::settings_changed, this, &LooperWindow::update_label_setting);
|
||||||
QObject::connect(prefs_window, &PrefsWindow::cat_set, this, &LooperWindow::update_cat);
|
|
||||||
QObject::connect(prefs_window, &PrefsWindow::cat_unset, this, &LooperWindow::clear_cat);
|
|
||||||
prefs_window->send_cat_signal();
|
|
||||||
//setLayout(layout);
|
//setLayout(layout);
|
||||||
}
|
}
|
||||||
void LooperWindow::update_label_setting(bool labels_visible, bool icons_visible) {
|
void LooperWindow::update_label_setting(bool labels_visible, bool icons_visible) {
|
||||||
|
@ -187,12 +173,3 @@ void LooperWindow::update_label_setting(bool labels_visible, bool icons_visible)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LooperWindow::clear_cat() {
|
|
||||||
cat_pixmap = NULL;
|
|
||||||
cat_disp->clear();
|
|
||||||
}
|
|
||||||
void LooperWindow::update_cat(QPixmap &img) {
|
|
||||||
cat_pixmap = &img;
|
|
||||||
cat_disp->setPixmap(img.scaled(cat_disp->width(), cat_disp->height(), Qt::KeepAspectRatio));
|
|
||||||
}
|
|
||||||
|
|
|
@ -23,7 +23,6 @@ class LooperWindow : public QMainWindow {
|
||||||
LooperSlider *speed_slider;
|
LooperSlider *speed_slider;
|
||||||
LooperSlider *tempo_slider;
|
LooperSlider *tempo_slider;
|
||||||
LooperSlider *pitch_slider;
|
LooperSlider *pitch_slider;
|
||||||
QPixmap *cat_pixmap = NULL;
|
|
||||||
std::thread *update_thread = nullptr;
|
std::thread *update_thread = nullptr;
|
||||||
bool done = false;
|
bool done = false;
|
||||||
void Pulse();
|
void Pulse();
|
||||||
|
@ -42,12 +41,7 @@ class LooperWindow : public QMainWindow {
|
||||||
QAction *about_item;
|
QAction *about_item;
|
||||||
QFileDialog *file_dialog;
|
QFileDialog *file_dialog;
|
||||||
QBoxLayout *root_layout;
|
QBoxLayout *root_layout;
|
||||||
QLabel *cat_disp;
|
|
||||||
void update_label_setting(bool labels_visible, bool icons_visible);
|
void update_label_setting(bool labels_visible, bool icons_visible);
|
||||||
void update_cat(QPixmap &img);
|
|
||||||
void clear_cat();
|
|
||||||
protected:
|
|
||||||
void resizeEvent(QResizeEvent *event) override;
|
|
||||||
public:
|
public:
|
||||||
AboutWindow *about_window;
|
AboutWindow *about_window;
|
||||||
PrefsWindow *prefs_window;
|
PrefsWindow *prefs_window;
|
||||||
|
|
|
@ -1,34 +1,10 @@
|
||||||
#include "preferences.h"
|
#include "preferences.h"
|
||||||
#include <QMenu>
|
#include <QMenu>
|
||||||
#include <QBoxLayout>
|
#include <QBoxLayout>
|
||||||
#include <QBuffer>
|
|
||||||
#include <QImage>
|
|
||||||
#include <QDataStream>
|
|
||||||
#include <QButtonGroup>
|
|
||||||
#include <QGroupBox>
|
|
||||||
#include <backend.hpp>
|
#include <backend.hpp>
|
||||||
#include <options.hpp>
|
#include <options.hpp>
|
||||||
#include <cats.hpp>
|
|
||||||
#include <log.hpp>
|
|
||||||
using namespace Looper::Options;
|
using namespace Looper::Options;
|
||||||
PrefsWindow::PrefsWindow() {
|
PrefsWindow::PrefsWindow() {
|
||||||
for (auto &cat : get_cat_data()) {
|
|
||||||
switch (cat.get_type()) {
|
|
||||||
case CatDataType::Memory: {
|
|
||||||
auto mem_cat = cat.get_memory_cat();
|
|
||||||
QPixmap pixmap;
|
|
||||||
pixmap.loadFromData((const uchar*)mem_cat.get_ptr(), mem_cat.get_len());
|
|
||||||
cats[cat.get_name()] = pixmap;
|
|
||||||
} break;
|
|
||||||
case CatDataType::File: {
|
|
||||||
try {
|
|
||||||
cats[cat.get_name()] = QPixmap(cat.get_path().c_str());
|
|
||||||
} catch (std::exception e) {
|
|
||||||
WARNING.writefln("Failed to load cat %s at path %s: %s", cat.get_name().c_str(), cat.get_path().c_str(), e.what());
|
|
||||||
}
|
|
||||||
} break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
auto *root_layout = new QBoxLayout(QBoxLayout::TopToBottom, this);
|
auto *root_layout = new QBoxLayout(QBoxLayout::TopToBottom, this);
|
||||||
this->setLayout(root_layout);
|
this->setLayout(root_layout);
|
||||||
restart_warning = new QLabel("A restart is needed to apply some changes.", this);
|
restart_warning = new QLabel("A restart is needed to apply some changes.", this);
|
||||||
|
@ -50,7 +26,8 @@ PrefsWindow::PrefsWindow() {
|
||||||
}
|
}
|
||||||
frontend_btn->setMenu(frontend_menu);
|
frontend_btn->setMenu(frontend_menu);
|
||||||
root_layout->addWidget(frontend_btn);
|
root_layout->addWidget(frontend_btn);
|
||||||
QGroupBox *frame = new QGroupBox("Labels and Icons", this);
|
QFrame *frame = new QFrame(this);
|
||||||
|
frame->setWindowTitle("Labels and Icons");
|
||||||
auto *label_settings_group = new QBoxLayout(QBoxLayout::TopToBottom, this);
|
auto *label_settings_group = new QBoxLayout(QBoxLayout::TopToBottom, this);
|
||||||
frame->setLayout(label_settings_group);
|
frame->setLayout(label_settings_group);
|
||||||
labels_only = new QRadioButton("Labels Only", frame);
|
labels_only = new QRadioButton("Labels Only", frame);
|
||||||
|
@ -72,40 +49,6 @@ PrefsWindow::PrefsWindow() {
|
||||||
label_settings_group->addWidget(icons_only);
|
label_settings_group->addWidget(icons_only);
|
||||||
label_settings_group->addWidget(both_labels_icons);
|
label_settings_group->addWidget(both_labels_icons);
|
||||||
root_layout->addWidget(frame);
|
root_layout->addWidget(frame);
|
||||||
cat_enable = new QCheckBox("Enable Cat", this);
|
|
||||||
QObject::connect(cat_enable, &QCheckBox::toggled, [=,this]() {
|
|
||||||
this->enable_cat = cat_enable->isChecked();
|
|
||||||
this->set_options_changed(true);
|
|
||||||
});
|
|
||||||
root_layout->addWidget(cat_enable);
|
|
||||||
QGroupBox *catFrame = new QGroupBox("Cat Selection", this);
|
|
||||||
auto *cat_btns_layout = new QBoxLayout(QBoxLayout::TopToBottom, this);
|
|
||||||
catFrame->setLayout(cat_btns_layout);
|
|
||||||
QButtonGroup *cat_btn_group = new QButtonGroup(catFrame);
|
|
||||||
cat_btn_group->setExclusive(true);
|
|
||||||
for (auto &kv : cats) {
|
|
||||||
auto id = kv.first;
|
|
||||||
auto pixmap = kv.second;
|
|
||||||
QWidget *cat_view = new QWidget(this);
|
|
||||||
QBoxLayout *cat_box = new QBoxLayout(QBoxLayout::LeftToRight, this);
|
|
||||||
QRadioButton *cat_radio = new QRadioButton(id.c_str(), cat_view);
|
|
||||||
cat_btn_group->addButton(cat_radio);
|
|
||||||
cat_view->setLayout(cat_box);
|
|
||||||
cat_box->addWidget(cat_radio);
|
|
||||||
QLabel *cat_img = new QLabel(cat_radio);
|
|
||||||
cat_img->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
|
|
||||||
float w = cat_img->width(), h = cat_img->height();
|
|
||||||
cat_img->setPixmap(pixmap.scaled(w, h, Qt::KeepAspectRatio));
|
|
||||||
cat_img->setAlignment(Qt::Alignment::enum_type::AlignRight);
|
|
||||||
cat_box->addWidget(cat_img);
|
|
||||||
QObject::connect(cat_radio, &QRadioButton::pressed, [=,this]() {
|
|
||||||
this->cat_setting = id;
|
|
||||||
this->set_options_changed(true);
|
|
||||||
});
|
|
||||||
cat_btns_layout->addWidget(cat_view);
|
|
||||||
cat_btns[id] = cat_radio;
|
|
||||||
}
|
|
||||||
root_layout->addWidget(catFrame);
|
|
||||||
QWidget *btn_view = new QWidget(this);
|
QWidget *btn_view = new QWidget(this);
|
||||||
QBoxLayout *btn_box = new QBoxLayout(QBoxLayout::LeftToRight, this);
|
QBoxLayout *btn_box = new QBoxLayout(QBoxLayout::LeftToRight, this);
|
||||||
revert_btn = new QPushButton("Revert", btn_view);
|
revert_btn = new QPushButton("Revert", btn_view);
|
||||||
|
@ -115,7 +58,6 @@ PrefsWindow::PrefsWindow() {
|
||||||
btn_view->setLayout(btn_box);
|
btn_view->setLayout(btn_box);
|
||||||
btn_box->addWidget(revert_btn);
|
btn_box->addWidget(revert_btn);
|
||||||
btn_box->addWidget(apply_btn);
|
btn_box->addWidget(apply_btn);
|
||||||
btn_view->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Minimum);
|
|
||||||
root_layout->addWidget(btn_view);
|
root_layout->addWidget(btn_view);
|
||||||
revert();
|
revert();
|
||||||
setWindowTitle("Looper Preferences");
|
setWindowTitle("Looper Preferences");
|
||||||
|
@ -136,34 +78,13 @@ void PrefsWindow::update_label_setting() {
|
||||||
}
|
}
|
||||||
void PrefsWindow::revert() {
|
void PrefsWindow::revert() {
|
||||||
set_options_changed(false);
|
set_options_changed(false);
|
||||||
load_options();
|
|
||||||
new_label_setting = get_option<std::string>("ui.label_setting", "icons");
|
new_label_setting = get_option<std::string>("ui.label_setting", "icons");
|
||||||
new_frontend = get_option<std::string>("ui.frontend", "qt");
|
new_frontend = get_option<std::string>("ui.frontend", "qt");
|
||||||
if (new_frontend != "qt") restart_warning->show();
|
if (new_frontend != "qt") restart_warning->show();
|
||||||
else restart_warning->hide();
|
else restart_warning->hide();
|
||||||
frontend_btn->setText(new_frontend.c_str());
|
frontend_btn->setText(new_frontend.c_str());
|
||||||
enable_cat = get_option<bool>("ui.enable_cat");
|
|
||||||
cat_enable->setCheckState(enable_cat ? Qt::CheckState::Checked : Qt::CheckState::Unchecked);
|
|
||||||
cat_setting = get_option<std::string>("ui.cat", cats.empty() ? "" : cats.begin()->first);
|
|
||||||
std::map<QRadioButton*, bool> radio_btn_values = {{labels_only, false}, {icons_only, false}, {both_labels_icons, false}};
|
|
||||||
if (new_label_setting == "labels") {
|
|
||||||
radio_btn_values[labels_only] = true;
|
|
||||||
} else if (new_label_setting == "icons") {
|
|
||||||
radio_btn_values[icons_only] = true;
|
|
||||||
} else if (new_label_setting == "both") {
|
|
||||||
radio_btn_values[both_labels_icons] = true;
|
|
||||||
}
|
|
||||||
for (auto &kv : radio_btn_values) {
|
|
||||||
kv.first->setChecked(kv.second);
|
|
||||||
}
|
|
||||||
if (cat_btns.contains(cat_setting)) cat_btns[cat_setting]->setChecked(true);
|
|
||||||
send_cat_signal();
|
|
||||||
update_label_setting();
|
update_label_setting();
|
||||||
}
|
}
|
||||||
void PrefsWindow::send_cat_signal() {
|
|
||||||
if (enable_cat && cats.contains(cat_setting)) emit(cat_set(cats[cat_setting]));
|
|
||||||
else emit(cat_unset());
|
|
||||||
}
|
|
||||||
void PrefsWindow::apply() {
|
void PrefsWindow::apply() {
|
||||||
set_options_changed(false);
|
set_options_changed(false);
|
||||||
set_option<std::string>("ui.label_setting", new_label_setting);
|
set_option<std::string>("ui.label_setting", new_label_setting);
|
||||||
|
@ -172,8 +93,4 @@ void PrefsWindow::apply() {
|
||||||
else restart_warning->hide();
|
else restart_warning->hide();
|
||||||
frontend_btn->setText(new_frontend.c_str());
|
frontend_btn->setText(new_frontend.c_str());
|
||||||
update_label_setting();
|
update_label_setting();
|
||||||
set_option<bool>("ui.enable_cat", enable_cat);
|
|
||||||
set_option<std::string>("ui.cat", cat_setting);
|
|
||||||
send_cat_signal();
|
|
||||||
save_options();
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,26 +18,18 @@ class PrefsWindow : public QWidget {
|
||||||
QPushButton *frontend_btn;
|
QPushButton *frontend_btn;
|
||||||
QMenu *frontend_menu;
|
QMenu *frontend_menu;
|
||||||
std::vector<QAction*> frontend_options;
|
std::vector<QAction*> frontend_options;
|
||||||
std::map<std::string, QPixmap> cats;
|
|
||||||
std::map<std::string, QRadioButton*> cat_btns;
|
|
||||||
QCheckBox *menu_icons;
|
QCheckBox *menu_icons;
|
||||||
QRadioButton *labels_only;
|
QRadioButton *labels_only;
|
||||||
QRadioButton *icons_only;
|
QRadioButton *icons_only;
|
||||||
QRadioButton *both_labels_icons;
|
QRadioButton *both_labels_icons;
|
||||||
QPushButton *revert_btn;
|
QPushButton *revert_btn;
|
||||||
QPushButton *apply_btn;
|
QPushButton *apply_btn;
|
||||||
QCheckBox *cat_enable;
|
|
||||||
bool enable_cat;
|
|
||||||
std::string cat_setting;
|
|
||||||
void update_label_setting();
|
void update_label_setting();
|
||||||
void set_options_changed(bool changed);
|
void set_options_changed(bool changed);
|
||||||
void revert();
|
void revert();
|
||||||
void apply();
|
void apply();
|
||||||
public:
|
public:
|
||||||
void send_cat_signal();
|
|
||||||
PrefsWindow();
|
PrefsWindow();
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void cat_set(QPixmap &img);
|
|
||||||
void cat_unset();
|
|
||||||
void settings_changed(bool use_labels, bool use_icons);
|
void settings_changed(bool use_labels, bool use_icons);
|
||||||
};
|
};
|
|
@ -76,11 +76,6 @@ void LooperSlider::set_value(double value) {
|
||||||
void LooperSlider::SetValue(double value) {
|
void LooperSlider::SetValue(double value) {
|
||||||
set_value(value);
|
set_value(value);
|
||||||
}
|
}
|
||||||
void LooperSlider::SetValueNoSignal(double value) {
|
|
||||||
this->slider_value_updating = true;
|
|
||||||
set_value(value);
|
|
||||||
this->slider_value_updating = false;
|
|
||||||
}
|
|
||||||
void LooperSlider::set_min(double min) {
|
void LooperSlider::set_min(double min) {
|
||||||
settings_changed = true;
|
settings_changed = true;
|
||||||
this->min = min;
|
this->min = min;
|
||||||
|
|
|
@ -78,7 +78,6 @@ class LooperSlider : public QWidget {
|
||||||
const char *MaxLabel();
|
const char *MaxLabel();
|
||||||
void SetLimitLabels(const char *min, const char *max);
|
void SetLimitLabels(const char *min, const char *max);
|
||||||
void SetValue(double value);
|
void SetValue(double value);
|
||||||
void SetValueNoSignal(double value);
|
|
||||||
double Value();
|
double Value();
|
||||||
void SetLogarithmic(bool logarithmic);
|
void SetLogarithmic(bool logarithmic);
|
||||||
bool IsLogarithmic();
|
bool IsLogarithmic();
|
||||||
|
|
11
base85.cpp
|
@ -4,11 +4,10 @@ using std::vector;
|
||||||
static unsigned int DecodeBase85Byte(char c) {
|
static unsigned int DecodeBase85Byte(char c) {
|
||||||
return c >= '\\' ? c-36 : c-35;
|
return c >= '\\' ? c-36 : c-35;
|
||||||
}
|
}
|
||||||
vector<unsigned char> *DecodeBase85(const char *src) {
|
vector<unsigned char> DecodeBase85(const char *src) {
|
||||||
vector<unsigned char> *dst_vec = new vector<unsigned char>();
|
vector<unsigned char> dst_vec;
|
||||||
dst_vec->resize(((strlen(src) + 4) / 5) * 4);
|
dst_vec.resize(((strlen(src) + 4) / 5) * 4);
|
||||||
unsigned char *dst = dst_vec->data();
|
unsigned char *dst = dst_vec.data();
|
||||||
memset(dst, 0, dst_vec->size());
|
|
||||||
size_t dst_size = 0;
|
size_t dst_size = 0;
|
||||||
while (*src)
|
while (*src)
|
||||||
{
|
{
|
||||||
|
@ -18,6 +17,6 @@ vector<unsigned char> *DecodeBase85(const char *src) {
|
||||||
dst += 4;
|
dst += 4;
|
||||||
dst_size += 4;
|
dst_size += 4;
|
||||||
}
|
}
|
||||||
dst_vec->resize(dst_size);
|
dst_vec.resize(dst_size);
|
||||||
return dst_vec;
|
return dst_vec;
|
||||||
}
|
}
|
6
base85.h
|
@ -3,4 +3,8 @@
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <string>
|
#include <string>
|
||||||
// Modified from Dear ImGui
|
// Modified from Dear ImGui
|
||||||
std::vector<unsigned char> *DecodeBase85(const char *src);
|
std::vector<unsigned char> DecodeBase85(const char *src);
|
||||||
|
// May not be needed now, but could be useful in the future.
|
||||||
|
static inline std::vector<unsigned char> DecodeBase85(const std::string src) {
|
||||||
|
return DecodeBase85(src.c_str());
|
||||||
|
}
|
|
@ -79,7 +79,7 @@ def main() -> None:
|
||||||
os.chdir(basedir)
|
os.chdir(basedir)
|
||||||
os.makedirs("build", exist_ok=True)
|
os.makedirs("build", exist_ok=True)
|
||||||
os.chdir("build")
|
os.chdir("build")
|
||||||
args=["cmake", "..", "-DBUILD_SDL=ON", "-DBUILD_SOUNDTOUCH=ON"]
|
args=["cmake", ".."]
|
||||||
for definition in p.cmake_vars:
|
for definition in p.cmake_vars:
|
||||||
args.append("-D%s" % definition)
|
args.append("-D%s" % definition)
|
||||||
ret = call(args);
|
ret = call(args);
|
||||||
|
|
88
cats.hpp
|
@ -1,88 +0,0 @@
|
||||||
#pragma once
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <string>
|
|
||||||
#include <filesystem>
|
|
||||||
#include <vector>
|
|
||||||
namespace fs = std::filesystem;
|
|
||||||
class MemoryCat {
|
|
||||||
const void *ptr;
|
|
||||||
size_t len;
|
|
||||||
bool owned;
|
|
||||||
public:
|
|
||||||
inline size_t get_len() {
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
inline const void *get_ptr() {
|
|
||||||
return (const void*)ptr;
|
|
||||||
}
|
|
||||||
inline ~MemoryCat() {
|
|
||||||
if (owned) free((void*)ptr);
|
|
||||||
}
|
|
||||||
/// \brief Constructor that doesn't take ownership of the pointer
|
|
||||||
inline MemoryCat(const void *ptr, size_t len) {
|
|
||||||
this->owned = false;
|
|
||||||
this->ptr = ptr;
|
|
||||||
this->len = len;
|
|
||||||
}
|
|
||||||
/// \brief Constructor that takes ownership of the pointer
|
|
||||||
inline MemoryCat(void *ptr, size_t len) {
|
|
||||||
this->owned = true;
|
|
||||||
this->ptr = ptr;
|
|
||||||
this->len = len;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
enum class CatDataType {
|
|
||||||
Memory,
|
|
||||||
File
|
|
||||||
};
|
|
||||||
class CatData {
|
|
||||||
std::optional<MemoryCat> mem;
|
|
||||||
fs::path path;
|
|
||||||
CatDataType type;
|
|
||||||
public:
|
|
||||||
std::string name;
|
|
||||||
inline std::string get_name() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
inline CatDataType get_type() {
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
inline fs::path get_path() {
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
inline MemoryCat get_memory_cat() {
|
|
||||||
if (type == CatDataType::Memory) {
|
|
||||||
return mem.value();
|
|
||||||
} else {
|
|
||||||
throw std::exception();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
inline MemoryCat as_memory_cat() {
|
|
||||||
if (mem.has_value()) return mem.value();
|
|
||||||
if (type == CatDataType::File) {
|
|
||||||
FILE *file = fopen(path.c_str(), "rb");
|
|
||||||
fseek(file, 0, SEEK_END);
|
|
||||||
size_t len = ftell(file);
|
|
||||||
fseek(file, 0, SEEK_SET);
|
|
||||||
void *ptr = malloc(len);
|
|
||||||
len = fread(ptr, 1, len, file);
|
|
||||||
ptr = realloc(ptr, len);
|
|
||||||
MemoryCat output(ptr, len);
|
|
||||||
this->mem = output;
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
throw std::exception();
|
|
||||||
}
|
|
||||||
inline CatData(const void *ptr, size_t len, std::string name, fs::path virtual_path) {
|
|
||||||
this->type = CatDataType::Memory;
|
|
||||||
this->name = name;
|
|
||||||
this->path = virtual_path;
|
|
||||||
this->mem = MemoryCat(ptr, len);
|
|
||||||
}
|
|
||||||
inline CatData(fs::path path) {
|
|
||||||
this->name = path.stem();
|
|
||||||
this->type = CatDataType::File;
|
|
||||||
this->path = path;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
extern std::vector<CatData> &get_cat_data();
|
|
|
@ -2,7 +2,6 @@
|
||||||
#define TAG "@TAG@"
|
#define TAG "@TAG@"
|
||||||
#define LOCALE_DIR "@LOCALE_DIR@"
|
#define LOCALE_DIR "@LOCALE_DIR@"
|
||||||
#cmakedefine01 DEBUG_MODE_VALUE
|
#cmakedefine01 DEBUG_MODE_VALUE
|
||||||
#cmakedefine01 OLD_SDBUS
|
|
||||||
#if DEBUG_MODE_VALUE==1
|
#if DEBUG_MODE_VALUE==1
|
||||||
#define DEBUG_MODE
|
#define DEBUG_MODE
|
||||||
#endif
|
#endif
|
||||||
|
|
26
dbus.cpp
|
@ -6,7 +6,7 @@
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
#ifdef DBUS_ENABLED
|
#ifdef DBUS_ENABLED
|
||||||
MprisAPI::MprisAPI(sdbus::IConnection &connection, std::string objectPath, DBusAPI *dbus_api)
|
MprisAPI::MprisAPI(sdbus::IConnection &connection, std::string objectPath, DBusAPI *dbus_api)
|
||||||
: AdaptorInterfaces(connection, OBJECT_PATH(objectPath))
|
: AdaptorInterfaces(connection, std::move(objectPath))
|
||||||
, dbus_api(dbus_api)
|
, dbus_api(dbus_api)
|
||||||
, connection(connection)
|
, connection(connection)
|
||||||
{
|
{
|
||||||
|
@ -57,12 +57,12 @@ void MprisAPI::Rate(const double &value) {
|
||||||
std::map<std::string, sdbus::Variant> MprisAPI::Metadata() {
|
std::map<std::string, sdbus::Variant> MprisAPI::Metadata() {
|
||||||
std::map<std::string, sdbus::Variant> output;
|
std::map<std::string, sdbus::Variant> output;
|
||||||
if (!dbus_api->IsStopped()) {
|
if (!dbus_api->IsStopped()) {
|
||||||
output["mpris:length"] = VARIANT((int64_t)(dbus_api->Length() * 1000000));
|
output["mpris:length"] = (int64_t)(dbus_api->Length() * 1000000);
|
||||||
output["mpris:trackid"] = VARIANT(playing_track_id);
|
output["mpris:trackid"] = playing_track_id;
|
||||||
output["xesam:title"] = VARIANT(dbus_api->FileTitle());
|
output["xesam:title"] = dbus_api->FileTitle();
|
||||||
output["xesam:url"] = VARIANT(dbus_api->FilePath());
|
output["xesam:url"] = dbus_api->FilePath();
|
||||||
} else {
|
} else {
|
||||||
output["mpris:trackid"] = VARIANT(empty_track_id);
|
output["mpris:trackid"] = empty_track_id;
|
||||||
}
|
}
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
@ -93,8 +93,8 @@ std::vector<meta_t> MprisAPI::GetTracksMetadata(const std::vector<track_id_t> &T
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (auto stream : streams) {
|
for (auto stream : streams) {
|
||||||
std::map<std::string, sdbus::Variant> meta;
|
std::map<std::string, sdbus::Variant> meta;
|
||||||
meta["mpris:trackid"] = VARIANT(fmt::format("{}{}", streamPrefix, i));
|
meta["mpris:trackid"] = fmt::format("{}{}", streamPrefix, i);
|
||||||
meta["xesam:title"] = VARIANT(stream.name);
|
meta["xesam:title"] = stream.name;
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -123,7 +123,7 @@ std::vector<track_id_t> MprisAPI::Tracks() {
|
||||||
auto streams = dbus_api->playback->get_streams();
|
auto streams = dbus_api->playback->get_streams();
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (auto stream : streams) {
|
for (auto stream : streams) {
|
||||||
output.push_back(OBJECT_PATH(fmt::format("{}{}", streamPrefix, i)));
|
output.push_back(fmt::format("{}{}", streamPrefix, i));
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
return output;
|
return output;
|
||||||
|
@ -143,14 +143,14 @@ DBusAPI::DBusAPI(Playback *playback, bool daemon)
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
DBusAPI::DBusAPI(Playback *playback, sdbus::IConnection &connection, std::string objectPath, bool daemon)
|
DBusAPI::DBusAPI(Playback *playback, sdbus::IConnection &connection, std::string objectPath, bool daemon)
|
||||||
: AdaptorInterfaces(connection, OBJECT_PATH(objectPath))
|
: AdaptorInterfaces(connection, std::move(objectPath))
|
||||||
, daemon(daemon)
|
, daemon(daemon)
|
||||||
, playback(playback)
|
, playback(playback)
|
||||||
, connection(connection)
|
, connection(connection)
|
||||||
{
|
{
|
||||||
registerAdaptor();
|
registerAdaptor();
|
||||||
playback->register_handle(this);
|
playback->register_handle(this);
|
||||||
auto mprisConnection = sdbus::createSessionBusConnection(SERVICE_NAME("org.mpris.MediaPlayer2.Looper"));
|
auto mprisConnection = sdbus::createSessionBusConnection("org.mpris.MediaPlayer2.Looper");
|
||||||
auto &mprisConRef = *mprisConnection.release();
|
auto &mprisConRef = *mprisConnection.release();
|
||||||
mpris = new MprisAPI(mprisConRef, "/org/mpris/MediaPlayer2", this);
|
mpris = new MprisAPI(mprisConRef, "/org/mpris/MediaPlayer2", this);
|
||||||
threadFunc = std::thread([this]() {
|
threadFunc = std::thread([this]() {
|
||||||
|
@ -166,7 +166,7 @@ const char *DBusAPI::objectPath = "/com/complecwaft/looper";
|
||||||
const char *DBusAPI::busName = "com.complecwaft.looper";
|
const char *DBusAPI::busName = "com.complecwaft.looper";
|
||||||
DBusAPI *DBusAPI::Create(Playback *playback, bool daemon) {
|
DBusAPI *DBusAPI::Create(Playback *playback, bool daemon) {
|
||||||
#ifdef DBUS_ENABLED
|
#ifdef DBUS_ENABLED
|
||||||
auto connection = sdbus::createSessionBusConnection(sdbus::ServiceName(busName));
|
auto connection = sdbus::createSessionBusConnection(busName);
|
||||||
auto &con_ref = *connection.release();
|
auto &con_ref = *connection.release();
|
||||||
return new DBusAPI(playback, con_ref, objectPath, daemon);
|
return new DBusAPI(playback, con_ref, objectPath, daemon);
|
||||||
#else
|
#else
|
||||||
|
@ -590,7 +590,7 @@ DBusAPISender *DBusAPISender::Create() {
|
||||||
}
|
}
|
||||||
#ifdef DBUS_ENABLED
|
#ifdef DBUS_ENABLED
|
||||||
DBusAPISender::DBusAPISender(sdbus::IConnection &connection, std::string busName, std::string objectPath)
|
DBusAPISender::DBusAPISender(sdbus::IConnection &connection, std::string busName, std::string objectPath)
|
||||||
: ProxyInterfaces(connection, BUS_NAME(busName), OBJECT_PATH(objectPath)) {
|
: ProxyInterfaces(connection, std::move(busName), std::move(objectPath)) {
|
||||||
registerProxy();
|
registerProxy();
|
||||||
DEBUG.writeln("Pinging DBus API to check for its existance.");
|
DEBUG.writeln("Pinging DBus API to check for its existance.");
|
||||||
Ping();
|
Ping();
|
||||||
|
|
30
dbus.hpp
|
@ -12,26 +12,6 @@
|
||||||
#include <random>
|
#include <random>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#ifdef DBUS_ENABLED
|
#ifdef DBUS_ENABLED
|
||||||
#if OLD_SDBUS
|
|
||||||
#define OBJECT_PATH(path) path
|
|
||||||
#define VARIANT(value) value
|
|
||||||
#define BUS_NAME(name) name
|
|
||||||
#define SERVICE_NAME(name) name
|
|
||||||
#define MEMBER_NAME(name) name
|
|
||||||
#define INTERFACE_NAME(name) name
|
|
||||||
namespace sdbus {
|
|
||||||
typedef std::string MemberName;
|
|
||||||
typedef std::string ServiceName;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
#define OBJECT_PATH(path) sdbus::ObjectPath{path}
|
|
||||||
#define VARIANT(value) sdbus::Variant{value}
|
|
||||||
#define BUS_NAME(name) sdbus::BusName{name}
|
|
||||||
#define SERVICE_NAME(name) sdbus::ServiceName{name}
|
|
||||||
#define MEMBER_NAME(name) sdbus::MemberName{name}
|
|
||||||
#define INTERFACE_NAME(name) sdbus::InterfaceName{name}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
class DBusAPI;
|
class DBusAPI;
|
||||||
class MprisAPI : public sdbus::AdaptorInterfaces<org::mpris::MediaPlayer2_adaptor, org::mpris::MediaPlayer2::Player_adaptor, org::mpris::MediaPlayer2::TrackList_adaptor, sdbus::Properties_adaptor> {
|
class MprisAPI : public sdbus::AdaptorInterfaces<org::mpris::MediaPlayer2_adaptor, org::mpris::MediaPlayer2::Player_adaptor, org::mpris::MediaPlayer2::TrackList_adaptor, sdbus::Properties_adaptor> {
|
||||||
friend class DBusAPI;
|
friend class DBusAPI;
|
||||||
|
@ -43,17 +23,17 @@ class MprisAPI : public sdbus::AdaptorInterfaces<org::mpris::MediaPlayer2_adapto
|
||||||
const std::string playerInterface = "org.mpris.MediaPlayer2.Player";
|
const std::string playerInterface = "org.mpris.MediaPlayer2.Player";
|
||||||
const std::string trackInterface = "org.mpris.MediaPlayer2.TrackList";
|
const std::string trackInterface = "org.mpris.MediaPlayer2.TrackList";
|
||||||
inline void sendPropertiesChanged(const std::string interface, const std::initializer_list<std::string> properties) {
|
inline void sendPropertiesChanged(const std::string interface, const std::initializer_list<std::string> properties) {
|
||||||
std::vector<sdbus::MemberName> property_vec;
|
std::vector<std::string> property_vec;
|
||||||
for (auto property : properties) {
|
for (auto property : properties) {
|
||||||
property_vec.push_back(MEMBER_NAME(property));
|
property_vec.push_back(property);
|
||||||
}
|
}
|
||||||
emitPropertiesChangedSignal(INTERFACE_NAME(interface), property_vec);
|
emitPropertiesChangedSignal(interface, property_vec);
|
||||||
}
|
}
|
||||||
public:
|
public:
|
||||||
#define meta_t std::map<std::string, sdbus::Variant>
|
#define meta_t std::map<std::string, sdbus::Variant>
|
||||||
#define track_id_t sdbus::ObjectPath
|
#define track_id_t sdbus::ObjectPath
|
||||||
const sdbus::ObjectPath playing_track_id = OBJECT_PATH("/com/complecwaft/Looper/PlayingTrack");
|
const sdbus::ObjectPath playing_track_id = "/com/complecwaft/Looper/PlayingTrack";
|
||||||
const sdbus::ObjectPath empty_track_id = OBJECT_PATH("/org/mpris/MediaPlayer2/TrackList/NoTrack");
|
const sdbus::ObjectPath empty_track_id = "/org/mpris/MediaPlayer2/TrackList/NoTrack";
|
||||||
|
|
||||||
inline void Raise() override { }
|
inline void Raise() override { }
|
||||||
void Quit() override;
|
void Quit() override;
|
||||||
|
|
23
debian/changelog
vendored
|
@ -1,23 +0,0 @@
|
||||||
looper (1.dev4) UNRELEASED; urgency=medium
|
|
||||||
|
|
||||||
* Add cat support
|
|
||||||
|
|
||||||
-- Zachary Hall <catmeow@complecwaft.com> Mon, 23 Dec 2024 13:15:00 -0800
|
|
||||||
looper (1.dev3) UNRELEASED; urgency=medium
|
|
||||||
|
|
||||||
* Set window class in ImGui UI and also only use one StartupWMClass in the
|
|
||||||
desktop launcher file.
|
|
||||||
|
|
||||||
-- Zachary Hall <catmeow@complecwaft.com> Thu, 19 Dec 2024 14:00:00 -0800
|
|
||||||
looper (1.dev2) UNRELEASED; urgency=medium
|
|
||||||
|
|
||||||
* Fix QT UI endlessly setting parameters and seeking
|
|
||||||
* Fix icon being named incorrectly
|
|
||||||
* Update icon
|
|
||||||
|
|
||||||
-- Zachary Hall <catmeow@complecwaft.com> Thu, 19 Dec 2024 11:38:00 -0800
|
|
||||||
looper (1.dev) UNRELEASED; urgency=medium
|
|
||||||
|
|
||||||
* Initial release.
|
|
||||||
|
|
||||||
-- Zachary Hall <catmeow@complecwaft.com> Tue, 17 Dec 2024 11:21:55 -0800
|
|
35
debian/control
vendored
|
@ -1,35 +0,0 @@
|
||||||
Source: looper
|
|
||||||
Section: x11
|
|
||||||
Priority: optional
|
|
||||||
Maintainer: Zachary Hall <catmeow@complecwaft.com>
|
|
||||||
Rules-Requires-Root: no
|
|
||||||
Build-Depends:
|
|
||||||
debhelper-compat (= 13),
|
|
||||||
cmake,
|
|
||||||
git,
|
|
||||||
python3,
|
|
||||||
libprotobuf-dev,
|
|
||||||
protobuf-compiler,
|
|
||||||
libsoundtouch-dev,
|
|
||||||
libsdl2-dev,
|
|
||||||
libsdl2-image-dev,
|
|
||||||
qt6-base-dev,
|
|
||||||
liburiparser-dev,
|
|
||||||
libexpat1-dev,
|
|
||||||
libsdbus-c++-dev,
|
|
||||||
libsdbus-c++-bin,
|
|
||||||
build-essential,
|
|
||||||
libfmt-dev,
|
|
||||||
Standards-Version: 4.6.2
|
|
||||||
Homepage: https://complecwaft.com/catmeow/looper
|
|
||||||
Vcs-Browser: https://complecwaft.com/catmeow/looper
|
|
||||||
Vcs-Git: https://complecwaft.com/catmeow/looper.git
|
|
||||||
|
|
||||||
Package: looper
|
|
||||||
Architecture: any
|
|
||||||
Depends:
|
|
||||||
${shlibs:Depends},
|
|
||||||
${misc:Depends},
|
|
||||||
Description: Audio player designed for video game music.
|
|
||||||
Looper is an audio player, which is capable of handling music not designed to loop end-to-end.
|
|
||||||
It has multiple UI frontends, which can be modified in the program.
|
|
33
debian/copyright
vendored
|
@ -1,33 +0,0 @@
|
||||||
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
|
||||||
Source: https://complecwaft.com/catmeow/looper
|
|
||||||
Upstream-Name: looper
|
|
||||||
Upstream-Contact: catmeow@complecwaft.com
|
|
||||||
|
|
||||||
Files:
|
|
||||||
*
|
|
||||||
Copyright:
|
|
||||||
2024 Zachary Hall <catmeow@complecwaft.com>
|
|
||||||
License: GPL-3.0+
|
|
||||||
|
|
||||||
Files:
|
|
||||||
debian/*
|
|
||||||
Copyright:
|
|
||||||
2024 Zachary Hall <catmeow@complecwaft.com>
|
|
||||||
License: GPL-3.0+
|
|
||||||
|
|
||||||
License: GPL-3.0+
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
Comment:
|
|
||||||
On Debian systems, the complete text of the GNU General
|
|
||||||
Public License version 3 can be found in "/usr/share/common-licenses/GPL-3".
|
|
3
debian/looper-docs.docs
vendored
|
@ -1,3 +0,0 @@
|
||||||
README
|
|
||||||
README.source
|
|
||||||
README.Debian
|
|
1
debian/looper.debhelper.log
vendored
|
@ -1 +0,0 @@
|
||||||
dh_auto_configure
|
|
20
debian/looper.doc-base.ex
vendored
|
@ -1,20 +0,0 @@
|
||||||
Document: looper
|
|
||||||
Title: Debian looper Manual
|
|
||||||
Author: <insert document author here>
|
|
||||||
Abstract: This manual describes what looper is
|
|
||||||
and how it can be used to
|
|
||||||
manage online manuals on Debian systems.
|
|
||||||
Section: unknown
|
|
||||||
|
|
||||||
Format: debiandoc-sgml
|
|
||||||
Files: /usr/share/doc/looper/looper.sgml.gz
|
|
||||||
|
|
||||||
Format: postscript
|
|
||||||
Files: /usr/share/doc/looper/looper.ps.gz
|
|
||||||
|
|
||||||
Format: text
|
|
||||||
Files: /usr/share/doc/looper/looper.text.gz
|
|
||||||
|
|
||||||
Format: HTML
|
|
||||||
Index: /usr/share/doc/looper/html/index.html
|
|
||||||
Files: /usr/share/doc/looper/html/*.html
|
|
56
debian/manpage.1.ex
vendored
|
@ -1,56 +0,0 @@
|
||||||
.\" Hey, EMACS: -*- nroff -*-
|
|
||||||
.\" (C) Copyright 2024 unknown <catmeow@complecwaft.com>,
|
|
||||||
.\"
|
|
||||||
.\" First parameter, NAME, should be all caps
|
|
||||||
.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
|
|
||||||
.\" other parameters are allowed: see man(7), man(1)
|
|
||||||
.TH Looper SECTION "December 17 2024"
|
|
||||||
.\" Please adjust this date whenever revising the manpage.
|
|
||||||
.\"
|
|
||||||
.\" Some roff macros, for reference:
|
|
||||||
.\" .nh disable hyphenation
|
|
||||||
.\" .hy enable hyphenation
|
|
||||||
.\" .ad l left justify
|
|
||||||
.\" .ad b justify to both left and right margins
|
|
||||||
.\" .nf disable filling
|
|
||||||
.\" .fi enable filling
|
|
||||||
.\" .br insert line break
|
|
||||||
.\" .sp <n> insert n+1 empty lines
|
|
||||||
.\" for manpage-specific macros, see man(7)
|
|
||||||
.SH NAME
|
|
||||||
looper \- program to do something
|
|
||||||
.SH SYNOPSIS
|
|
||||||
.B looper
|
|
||||||
.RI [ options ] " files" ...
|
|
||||||
.br
|
|
||||||
.B bar
|
|
||||||
.RI [ options ] " files" ...
|
|
||||||
.SH DESCRIPTION
|
|
||||||
This manual page documents briefly the
|
|
||||||
.B looper
|
|
||||||
and
|
|
||||||
.B bar
|
|
||||||
commands.
|
|
||||||
.PP
|
|
||||||
.\" TeX users may be more comfortable with the \fB<whatever>\fP and
|
|
||||||
.\" \fI<whatever>\fP escape sequences to invode bold face and italics,
|
|
||||||
.\" respectively.
|
|
||||||
\fBlooper\fP is a program that...
|
|
||||||
.SH OPTIONS
|
|
||||||
These programs follow the usual GNU command line syntax, with long
|
|
||||||
options starting with two dashes ('\-').
|
|
||||||
A summary of options is included below.
|
|
||||||
For a complete description, see the Info files.
|
|
||||||
.TP
|
|
||||||
.B \-h, \-\-help
|
|
||||||
Show summary of options.
|
|
||||||
.TP
|
|
||||||
.B \-v, \-\-version
|
|
||||||
Show version of program.
|
|
||||||
.SH SEE ALSO
|
|
||||||
.BR bar (1),
|
|
||||||
.BR baz (1).
|
|
||||||
.br
|
|
||||||
The programs are documented fully by
|
|
||||||
.IR "The Rise and Fall of a Fooish Bar" ,
|
|
||||||
available via the Info system.
|
|
126
debian/manpage.md.ex
vendored
|
@ -1,126 +0,0 @@
|
||||||
% looper(SECTION) | User Commands
|
|
||||||
%
|
|
||||||
% "December 17 2024"
|
|
||||||
|
|
||||||
[comment]: # The lines above form a Pandoc metadata block. They must be
|
|
||||||
[comment]: # the first ones in the file.
|
|
||||||
[comment]: # See https://pandoc.org/MANUAL.html#metadata-blocks for details.
|
|
||||||
|
|
||||||
[comment]: # pandoc -s -f markdown -t man package.md -o package.1
|
|
||||||
[comment]: #
|
|
||||||
[comment]: # A manual page package.1 will be generated. You may view the
|
|
||||||
[comment]: # manual page with: nroff -man package.1 | less. A typical entry
|
|
||||||
[comment]: # in a Makefile or Makefile.am is:
|
|
||||||
[comment]: #
|
|
||||||
[comment]: # package.1: package.md
|
|
||||||
[comment]: # pandoc --standalone --from=markdown --to=man $< --output=$@
|
|
||||||
[comment]: #
|
|
||||||
[comment]: # The pandoc binary is found in the pandoc package. Please remember
|
|
||||||
[comment]: # that if you create the nroff version in one of the debian/rules
|
|
||||||
[comment]: # file targets, such as build, you will need to include pandoc in
|
|
||||||
[comment]: # your Build-Depends control field.
|
|
||||||
|
|
||||||
[comment]: # Remove the lines starting with '[comment]:' in this file in order
|
|
||||||
[comment]: # to avoid warning messages from pandoc.
|
|
||||||
|
|
||||||
# NAME
|
|
||||||
|
|
||||||
looper - program to do something
|
|
||||||
|
|
||||||
# SYNOPSIS
|
|
||||||
|
|
||||||
**looper** **-e** _this_ [**\-\-example=that**] [{**-e** | **\-\-example**} _this_]
|
|
||||||
[{**-e** | **\-\-example**} {_this_ | _that_}]
|
|
||||||
|
|
||||||
**looper** [{**-h** | *\-\-help**} | {**-v** | **\-\-version**}]
|
|
||||||
|
|
||||||
# DESCRIPTION
|
|
||||||
|
|
||||||
This manual page documents briefly the **looper** and **bar** commands.
|
|
||||||
|
|
||||||
This manual page was written for the Debian distribution because the
|
|
||||||
original program does not have a manual page. Instead, it has documentation
|
|
||||||
in the GNU info(1) format; see below.
|
|
||||||
|
|
||||||
**looper** is a program that...
|
|
||||||
|
|
||||||
# OPTIONS
|
|
||||||
|
|
||||||
The program follows the usual GNU command line syntax, with long options
|
|
||||||
starting with two dashes ('-'). A summary of options is included below. For
|
|
||||||
a complete description, see the **info**(1) files.
|
|
||||||
|
|
||||||
**-e** _this_, **\-\-example=**_that_
|
|
||||||
: Does this and that.
|
|
||||||
|
|
||||||
**-h**, **\-\-help**
|
|
||||||
: Show summary of options.
|
|
||||||
|
|
||||||
**-v**, **\-\-version**
|
|
||||||
: Show version of program.
|
|
||||||
|
|
||||||
# FILES
|
|
||||||
|
|
||||||
/etc/foo.conf
|
|
||||||
: The system-wide configuration file to control the behaviour of
|
|
||||||
looper. See **foo.conf**(5) for further details.
|
|
||||||
|
|
||||||
${HOME}/.foo.conf
|
|
||||||
: The per-user configuration file to control the behaviour of
|
|
||||||
looper. See **foo.conf**(5) for further details.
|
|
||||||
|
|
||||||
# ENVIRONMENT
|
|
||||||
|
|
||||||
**FOO_CONF**
|
|
||||||
: If used, the defined file is used as configuration file (see also
|
|
||||||
the section called “FILES”).
|
|
||||||
|
|
||||||
# DIAGNOSTICS
|
|
||||||
|
|
||||||
The following diagnostics may be issued on stderr:
|
|
||||||
|
|
||||||
Bad configuration file. Exiting.
|
|
||||||
: The configuration file seems to contain a broken configuration
|
|
||||||
line. Use the **\-\-verbose** option, to get more info.
|
|
||||||
|
|
||||||
**looper** provides some return codes, that can be used in scripts:
|
|
||||||
|
|
||||||
Code Diagnostic
|
|
||||||
0 Program exited successfully.
|
|
||||||
1 The configuration file seems to be broken.
|
|
||||||
|
|
||||||
# BUGS
|
|
||||||
|
|
||||||
The program is currently limited to only work with the foobar library.
|
|
||||||
|
|
||||||
The upstream BTS can be found at http://bugzilla.foo.tld.
|
|
||||||
|
|
||||||
# SEE ALSO
|
|
||||||
|
|
||||||
**bar**(1), **baz**(1), **foo.conf**(5)
|
|
||||||
|
|
||||||
The programs are documented fully by The Rise and Fall of a Fooish Bar
|
|
||||||
available via the **info**(1) system.
|
|
||||||
|
|
||||||
# AUTHOR
|
|
||||||
|
|
||||||
unknown <catmeow@complecwaft.com>
|
|
||||||
: Wrote this manpage for the Debian system.
|
|
||||||
|
|
||||||
# COPYRIGHT
|
|
||||||
|
|
||||||
Copyright © 2007 unknown
|
|
||||||
|
|
||||||
This manual page was written for the Debian system (and may be used by
|
|
||||||
others).
|
|
||||||
|
|
||||||
Permission is granted to copy, distribute and/or modify this document under
|
|
||||||
the terms of the GNU General Public License, Version 2 or (at your option)
|
|
||||||
any later version published by the Free Software Foundation.
|
|
||||||
|
|
||||||
On Debian systems, the complete text of the GNU General Public License
|
|
||||||
can be found in /usr/share/common-licenses/GPL.
|
|
||||||
|
|
||||||
[comment]: # Local Variables:
|
|
||||||
[comment]: # mode: markdown
|
|
||||||
[comment]: # End:
|
|
154
debian/manpage.sgml.ex
vendored
|
@ -1,154 +0,0 @@
|
||||||
<!doctype refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN" [
|
|
||||||
|
|
||||||
<!-- Process this file with docbook-to-man to generate an nroff manual
|
|
||||||
page: 'docbook-to-man manpage.sgml > manpage.1'. You may view
|
|
||||||
the manual page with: 'docbook-to-man manpage.sgml | nroff -man |
|
|
||||||
less'. A typical entry in a Makefile or Makefile.am is:
|
|
||||||
|
|
||||||
manpage.1: manpage.sgml
|
|
||||||
docbook-to-man $< > $@
|
|
||||||
|
|
||||||
|
|
||||||
The docbook-to-man binary is found in the docbook-to-man package.
|
|
||||||
Please remember that if you create the nroff version in one of the
|
|
||||||
debian/rules file targets (such as build), you will need to include
|
|
||||||
docbook-to-man in your Build-Depends control field.
|
|
||||||
|
|
||||||
-->
|
|
||||||
|
|
||||||
<!-- Fill in your name for FIRSTNAME and SURNAME. -->
|
|
||||||
<!ENTITY dhfirstname "<firstname>FIRSTNAME</firstname>">
|
|
||||||
<!ENTITY dhsurname "<surname>SURNAME</surname>">
|
|
||||||
<!-- Please adjust the date whenever revising the manpage. -->
|
|
||||||
<!ENTITY dhdate "<date>December 17 2024</date>">
|
|
||||||
<!-- SECTION should be 1-8, maybe w/ subsection other parameters are
|
|
||||||
allowed: see man(7), man(1). -->
|
|
||||||
<!ENTITY dhsection "<manvolnum>SECTION</manvolnum>">
|
|
||||||
<!ENTITY dhemail "<email>catmeow@complecwaft.com</email>">
|
|
||||||
<!ENTITY dhusername "unknown">
|
|
||||||
<!ENTITY dhucpackage "<refentrytitle>Looper</refentrytitle>">
|
|
||||||
<!ENTITY dhpackage "looper">
|
|
||||||
|
|
||||||
<!ENTITY debian "<productname>Debian</productname>">
|
|
||||||
<!ENTITY gnu "<acronym>GNU</acronym>">
|
|
||||||
<!ENTITY gpl "&gnu; <acronym>GPL</acronym>">
|
|
||||||
]>
|
|
||||||
|
|
||||||
<refentry>
|
|
||||||
<refentryinfo>
|
|
||||||
<address>
|
|
||||||
&dhemail;
|
|
||||||
</address>
|
|
||||||
<author>
|
|
||||||
&dhfirstname;
|
|
||||||
&dhsurname;
|
|
||||||
</author>
|
|
||||||
<copyright>
|
|
||||||
<year>2003</year>
|
|
||||||
<holder>&dhusername;</holder>
|
|
||||||
</copyright>
|
|
||||||
&dhdate;
|
|
||||||
</refentryinfo>
|
|
||||||
<refmeta>
|
|
||||||
&dhucpackage;
|
|
||||||
|
|
||||||
&dhsection;
|
|
||||||
</refmeta>
|
|
||||||
<refnamediv>
|
|
||||||
<refname>&dhpackage;</refname>
|
|
||||||
|
|
||||||
<refpurpose>program to do something</refpurpose>
|
|
||||||
</refnamediv>
|
|
||||||
<refsynopsisdiv>
|
|
||||||
<cmdsynopsis>
|
|
||||||
<command>&dhpackage;</command>
|
|
||||||
|
|
||||||
<arg><option>-e <replaceable>this</replaceable></option></arg>
|
|
||||||
|
|
||||||
<arg><option>--example <replaceable>that</replaceable></option></arg>
|
|
||||||
</cmdsynopsis>
|
|
||||||
</refsynopsisdiv>
|
|
||||||
<refsect1>
|
|
||||||
<title>DESCRIPTION</title>
|
|
||||||
|
|
||||||
<para>This manual page documents briefly the
|
|
||||||
<command>&dhpackage;</command> and <command>bar</command>
|
|
||||||
commands.</para>
|
|
||||||
|
|
||||||
<para>This manual page was written for the &debian; distribution
|
|
||||||
because the original program does not have a manual page.
|
|
||||||
Instead, it has documentation in the &gnu;
|
|
||||||
<application>Info</application> format; see below.</para>
|
|
||||||
|
|
||||||
<para><command>&dhpackage;</command> is a program that...</para>
|
|
||||||
|
|
||||||
</refsect1>
|
|
||||||
<refsect1>
|
|
||||||
<title>OPTIONS</title>
|
|
||||||
|
|
||||||
<para>These programs follow the usual &gnu; command line syntax,
|
|
||||||
with long options starting with two dashes ('-'). A summary of
|
|
||||||
options is included below. For a complete description, see the
|
|
||||||
<application>Info</application> files.</para>
|
|
||||||
|
|
||||||
<variablelist>
|
|
||||||
<varlistentry>
|
|
||||||
<term><option>-h</option>
|
|
||||||
<option>--help</option>
|
|
||||||
</term>
|
|
||||||
<listitem>
|
|
||||||
<para>Show summary of options.</para>
|
|
||||||
</listitem>
|
|
||||||
</varlistentry>
|
|
||||||
<varlistentry>
|
|
||||||
<term><option>-v</option>
|
|
||||||
<option>--version</option>
|
|
||||||
</term>
|
|
||||||
<listitem>
|
|
||||||
<para>Show version of program.</para>
|
|
||||||
</listitem>
|
|
||||||
</varlistentry>
|
|
||||||
</variablelist>
|
|
||||||
</refsect1>
|
|
||||||
<refsect1>
|
|
||||||
<title>SEE ALSO</title>
|
|
||||||
|
|
||||||
<para>bar (1), baz (1).</para>
|
|
||||||
|
|
||||||
<para>The programs are documented fully by <citetitle>The Rise and
|
|
||||||
Fall of a Fooish Bar</citetitle> available via the
|
|
||||||
<application>Info</application> system.</para>
|
|
||||||
</refsect1>
|
|
||||||
<refsect1>
|
|
||||||
<title>AUTHOR</title>
|
|
||||||
|
|
||||||
<para>This manual page was written by &dhusername; &dhemail; for
|
|
||||||
the &debian; system (and may be used by others). Permission is
|
|
||||||
granted to copy, distribute and/or modify this document under
|
|
||||||
the terms of the &gnu; General Public License, Version 2 any
|
|
||||||
later version published by the Free Software Foundation.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
On Debian systems, the complete text of the GNU General Public
|
|
||||||
License can be found in /usr/share/common-licenses/GPL.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
</refsect1>
|
|
||||||
</refentry>
|
|
||||||
|
|
||||||
<!-- Keep this comment at the end of the file
|
|
||||||
Local variables:
|
|
||||||
mode: sgml
|
|
||||||
sgml-omittag:t
|
|
||||||
sgml-shorttag:t
|
|
||||||
sgml-minimize-attributes:nil
|
|
||||||
sgml-always-quote-attributes:t
|
|
||||||
sgml-indent-step:2
|
|
||||||
sgml-indent-data:t
|
|
||||||
sgml-parent-document:nil
|
|
||||||
sgml-default-dtd-file:nil
|
|
||||||
sgml-exposed-tags:nil
|
|
||||||
sgml-local-catalogs:nil
|
|
||||||
sgml-local-ecat-files:nil
|
|
||||||
End:
|
|
||||||
-->
|
|
291
debian/manpage.xml.ex
vendored
|
@ -1,291 +0,0 @@
|
||||||
<?xml version='1.0' encoding='UTF-8'?>
|
|
||||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
|
|
||||||
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
|
||||||
|
|
||||||
<!--
|
|
||||||
|
|
||||||
`xsltproc -''-nonet \
|
|
||||||
-''-param man.charmap.use.subset "0" \
|
|
||||||
-''-param make.year.ranges "1" \
|
|
||||||
-''-param make.single.year.ranges "1" \
|
|
||||||
/usr/share/xml/docbook/stylesheet/docbook-xsl/manpages/docbook.xsl \
|
|
||||||
manpage.xml`
|
|
||||||
|
|
||||||
A manual page <package>.<section> will be generated. You may view the
|
|
||||||
manual page with: nroff -man <package>.<section> | less'. A typical entry
|
|
||||||
in a Makefile or Makefile.am is:
|
|
||||||
|
|
||||||
DB2MAN = /usr/share/sgml/docbook/stylesheet/xsl/docbook-xsl/manpages/docbook.xsl
|
|
||||||
XP = xsltproc -''-nonet -''-param man.charmap.use.subset "0"
|
|
||||||
|
|
||||||
manpage.1: manpage.xml
|
|
||||||
$(XP) $(DB2MAN) $<
|
|
||||||
|
|
||||||
The xsltproc binary is found in the xsltproc package. The XSL files are in
|
|
||||||
docbook-xsl. A description of the parameters you can use can be found in the
|
|
||||||
docbook-xsl-doc-* packages. Please remember that if you create the nroff
|
|
||||||
version in one of the debian/rules file targets (such as build), you will need
|
|
||||||
to include xsltproc and docbook-xsl in your Build-Depends control field.
|
|
||||||
Alternatively use the xmlto command/package. That will also automatically
|
|
||||||
pull in xsltproc and docbook-xsl.
|
|
||||||
|
|
||||||
Notes for using docbook2x: docbook2x-man does not automatically create the
|
|
||||||
AUTHOR(S) and COPYRIGHT sections. In this case, please add them manually as
|
|
||||||
<refsect1> ... </refsect1>.
|
|
||||||
|
|
||||||
To disable the automatic creation of the AUTHOR(S) and COPYRIGHT sections
|
|
||||||
read /usr/share/doc/docbook-xsl/doc/manpages/authors.html. This file can be
|
|
||||||
found in the docbook-xsl-doc-html package.
|
|
||||||
|
|
||||||
Validation can be done using: `xmllint -''-noout -''-valid manpage.xml`
|
|
||||||
|
|
||||||
General documentation about man-pages and man-page-formatting:
|
|
||||||
man(1), man(7), http://www.tldp.org/HOWTO/Man-Page/
|
|
||||||
|
|
||||||
-->
|
|
||||||
|
|
||||||
<!-- Fill in your name for FIRSTNAME and SURNAME. -->
|
|
||||||
<!ENTITY dhfirstname "FIRSTNAME">
|
|
||||||
<!ENTITY dhsurname "SURNAME">
|
|
||||||
<!-- dhusername could also be set to "&dhfirstname; &dhsurname;". -->
|
|
||||||
<!ENTITY dhusername "unknown">
|
|
||||||
<!ENTITY dhemail "catmeow@complecwaft.com">
|
|
||||||
<!-- SECTION should be 1-8, maybe w/ subsection other parameters are
|
|
||||||
allowed: see man(7), man(1) and
|
|
||||||
http://www.tldp.org/HOWTO/Man-Page/q2.html. -->
|
|
||||||
<!ENTITY dhsection "SECTION">
|
|
||||||
<!-- TITLE should be something like "User commands" or similar (see
|
|
||||||
http://www.tldp.org/HOWTO/Man-Page/q2.html). -->
|
|
||||||
<!ENTITY dhtitle "looper User Manual">
|
|
||||||
<!ENTITY dhucpackage "Looper">
|
|
||||||
<!ENTITY dhpackage "looper">
|
|
||||||
]>
|
|
||||||
|
|
||||||
<refentry>
|
|
||||||
<refentryinfo>
|
|
||||||
<title>&dhtitle;</title>
|
|
||||||
<productname>&dhpackage;</productname>
|
|
||||||
<authorgroup>
|
|
||||||
<author>
|
|
||||||
<firstname>&dhfirstname;</firstname>
|
|
||||||
<surname>&dhsurname;</surname>
|
|
||||||
<contrib>Wrote this manpage for the Debian system.</contrib>
|
|
||||||
<address>
|
|
||||||
<email>&dhemail;</email>
|
|
||||||
</address>
|
|
||||||
</author>
|
|
||||||
</authorgroup>
|
|
||||||
<copyright>
|
|
||||||
<year>2007</year>
|
|
||||||
<holder>&dhusername;</holder>
|
|
||||||
</copyright>
|
|
||||||
<legalnotice>
|
|
||||||
<para>This manual page was written for the Debian system
|
|
||||||
(and may be used by others).</para>
|
|
||||||
<para>Permission is granted to copy, distribute and/or modify this
|
|
||||||
document under the terms of the GNU General Public License,
|
|
||||||
Version 2 or (at your option) any later version published by
|
|
||||||
the Free Software Foundation.</para>
|
|
||||||
<para>On Debian systems, the complete text of the GNU General Public
|
|
||||||
License can be found in
|
|
||||||
<filename>/usr/share/common-licenses/GPL</filename>.</para>
|
|
||||||
</legalnotice>
|
|
||||||
</refentryinfo>
|
|
||||||
<refmeta>
|
|
||||||
<refentrytitle>&dhucpackage;</refentrytitle>
|
|
||||||
<manvolnum>&dhsection;</manvolnum>
|
|
||||||
</refmeta>
|
|
||||||
<refnamediv>
|
|
||||||
<refname>&dhpackage;</refname>
|
|
||||||
<refpurpose>program to do something</refpurpose>
|
|
||||||
</refnamediv>
|
|
||||||
<refsynopsisdiv>
|
|
||||||
<cmdsynopsis>
|
|
||||||
<command>&dhpackage;</command>
|
|
||||||
<!-- These are several examples, how syntaxes could look -->
|
|
||||||
<arg choice="plain"><option>-e <replaceable>this</replaceable></option></arg>
|
|
||||||
<arg choice="opt"><option>--example=<parameter>that</parameter></option></arg>
|
|
||||||
<arg choice="opt">
|
|
||||||
<group choice="req">
|
|
||||||
<arg choice="plain"><option>-e</option></arg>
|
|
||||||
<arg choice="plain"><option>--example</option></arg>
|
|
||||||
</group>
|
|
||||||
<replaceable class="option">this</replaceable>
|
|
||||||
</arg>
|
|
||||||
<arg choice="opt">
|
|
||||||
<group choice="req">
|
|
||||||
<arg choice="plain"><option>-e</option></arg>
|
|
||||||
<arg choice="plain"><option>--example</option></arg>
|
|
||||||
</group>
|
|
||||||
<group choice="req">
|
|
||||||
<arg choice="plain"><replaceable>this</replaceable></arg>
|
|
||||||
<arg choice="plain"><replaceable>that</replaceable></arg>
|
|
||||||
</group>
|
|
||||||
</arg>
|
|
||||||
</cmdsynopsis>
|
|
||||||
<cmdsynopsis>
|
|
||||||
<command>&dhpackage;</command>
|
|
||||||
<!-- Normally the help and version options make the programs stop
|
|
||||||
right after outputting the requested information. -->
|
|
||||||
<group choice="opt">
|
|
||||||
<arg choice="plain">
|
|
||||||
<group choice="req">
|
|
||||||
<arg choice="plain"><option>-h</option></arg>
|
|
||||||
<arg choice="plain"><option>--help</option></arg>
|
|
||||||
</group>
|
|
||||||
</arg>
|
|
||||||
<arg choice="plain">
|
|
||||||
<group choice="req">
|
|
||||||
<arg choice="plain"><option>-v</option></arg>
|
|
||||||
<arg choice="plain"><option>--version</option></arg>
|
|
||||||
</group>
|
|
||||||
</arg>
|
|
||||||
</group>
|
|
||||||
</cmdsynopsis>
|
|
||||||
</refsynopsisdiv>
|
|
||||||
<refsect1 id="description">
|
|
||||||
<title>DESCRIPTION</title>
|
|
||||||
<para>This manual page documents briefly the
|
|
||||||
<command>&dhpackage;</command> and <command>bar</command>
|
|
||||||
commands.</para>
|
|
||||||
<para>This manual page was written for the Debian distribution
|
|
||||||
because the original program does not have a manual page.
|
|
||||||
Instead, it has documentation in the GNU <citerefentry>
|
|
||||||
<refentrytitle>info</refentrytitle>
|
|
||||||
<manvolnum>1</manvolnum>
|
|
||||||
</citerefentry> format; see below.</para>
|
|
||||||
<para><command>&dhpackage;</command> is a program that...</para>
|
|
||||||
</refsect1>
|
|
||||||
<refsect1 id="options">
|
|
||||||
<title>OPTIONS</title>
|
|
||||||
<para>The program follows the usual GNU command line syntax,
|
|
||||||
with long options starting with two dashes ('-'). A summary of
|
|
||||||
options is included below. For a complete description, see the
|
|
||||||
<citerefentry>
|
|
||||||
<refentrytitle>info</refentrytitle>
|
|
||||||
<manvolnum>1</manvolnum>
|
|
||||||
</citerefentry> files.</para>
|
|
||||||
<variablelist>
|
|
||||||
<!-- Use the variablelist.term.separator and the
|
|
||||||
variablelist.term.break.after parameters to
|
|
||||||
control the term elements. -->
|
|
||||||
<varlistentry>
|
|
||||||
<term><option>-e <replaceable>this</replaceable></option></term>
|
|
||||||
<term><option>--example=<replaceable>that</replaceable></option></term>
|
|
||||||
<listitem>
|
|
||||||
<para>Does this and that.</para>
|
|
||||||
</listitem>
|
|
||||||
</varlistentry>
|
|
||||||
<varlistentry>
|
|
||||||
<term><option>-h</option></term>
|
|
||||||
<term><option>--help</option></term>
|
|
||||||
<listitem>
|
|
||||||
<para>Show summary of options.</para>
|
|
||||||
</listitem>
|
|
||||||
</varlistentry>
|
|
||||||
<varlistentry>
|
|
||||||
<term><option>-v</option></term>
|
|
||||||
<term><option>--version</option></term>
|
|
||||||
<listitem>
|
|
||||||
<para>Show version of program.</para>
|
|
||||||
</listitem>
|
|
||||||
</varlistentry>
|
|
||||||
</variablelist>
|
|
||||||
</refsect1>
|
|
||||||
<refsect1 id="files">
|
|
||||||
<title>FILES</title>
|
|
||||||
<variablelist>
|
|
||||||
<varlistentry>
|
|
||||||
<term><filename>/etc/foo.conf</filename></term>
|
|
||||||
<listitem>
|
|
||||||
<para>The system-wide configuration file to control the
|
|
||||||
behaviour of <application>&dhpackage;</application>. See
|
|
||||||
<citerefentry>
|
|
||||||
<refentrytitle>foo.conf</refentrytitle>
|
|
||||||
<manvolnum>5</manvolnum>
|
|
||||||
</citerefentry> for further details.</para>
|
|
||||||
</listitem>
|
|
||||||
</varlistentry>
|
|
||||||
<varlistentry>
|
|
||||||
<term><filename>${HOME}/.foo.conf</filename></term>
|
|
||||||
<listitem>
|
|
||||||
<para>The per-user configuration file to control the
|
|
||||||
behaviour of <application>&dhpackage;</application>. See
|
|
||||||
<citerefentry>
|
|
||||||
<refentrytitle>foo.conf</refentrytitle>
|
|
||||||
<manvolnum>5</manvolnum>
|
|
||||||
</citerefentry> for further details.</para>
|
|
||||||
</listitem>
|
|
||||||
</varlistentry>
|
|
||||||
</variablelist>
|
|
||||||
</refsect1>
|
|
||||||
<refsect1 id="environment">
|
|
||||||
<title>ENVIRONMENT</title>
|
|
||||||
<variablelist>
|
|
||||||
<varlistentry>
|
|
||||||
<term><envar>FOO_CONF</envar></term>
|
|
||||||
<listitem>
|
|
||||||
<para>If used, the defined file is used as configuration
|
|
||||||
file (see also <xref linkend="files"/>).</para>
|
|
||||||
</listitem>
|
|
||||||
</varlistentry>
|
|
||||||
</variablelist>
|
|
||||||
</refsect1>
|
|
||||||
<refsect1 id="diagnostics">
|
|
||||||
<title>DIAGNOSTICS</title>
|
|
||||||
<para>The following diagnostics may be issued
|
|
||||||
on <filename class="devicefile">stderr</filename>:</para>
|
|
||||||
<variablelist>
|
|
||||||
<varlistentry>
|
|
||||||
<term><errortext>Bad configuration file. Exiting.</errortext></term>
|
|
||||||
<listitem>
|
|
||||||
<para>The configuration file seems to contain a broken configuration
|
|
||||||
line. Use the <option>--verbose</option> option, to get more info.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
</varlistentry>
|
|
||||||
</variablelist>
|
|
||||||
<para><command>&dhpackage;</command> provides some return codes, that can
|
|
||||||
be used in scripts:</para>
|
|
||||||
<segmentedlist>
|
|
||||||
<segtitle>Code</segtitle>
|
|
||||||
<segtitle>Diagnostic</segtitle>
|
|
||||||
<seglistitem>
|
|
||||||
<seg><errorcode>0</errorcode></seg>
|
|
||||||
<seg>Program exited successfully.</seg>
|
|
||||||
</seglistitem>
|
|
||||||
<seglistitem>
|
|
||||||
<seg><errorcode>1</errorcode></seg>
|
|
||||||
<seg>The configuration file seems to be broken.</seg>
|
|
||||||
</seglistitem>
|
|
||||||
</segmentedlist>
|
|
||||||
</refsect1>
|
|
||||||
<refsect1 id="bugs">
|
|
||||||
<!-- Or use this section to tell about upstream BTS. -->
|
|
||||||
<title>BUGS</title>
|
|
||||||
<para>The program is currently limited to only work
|
|
||||||
with the <package>foobar</package> library.</para>
|
|
||||||
<para>The upstreams <acronym>BTS</acronym> can be found
|
|
||||||
at <ulink url="http://bugzilla.foo.tld"/>.</para>
|
|
||||||
</refsect1>
|
|
||||||
<refsect1 id="see_also">
|
|
||||||
<title>SEE ALSO</title>
|
|
||||||
<!-- In alpabetical order. -->
|
|
||||||
<para><citerefentry>
|
|
||||||
<refentrytitle>bar</refentrytitle>
|
|
||||||
<manvolnum>1</manvolnum>
|
|
||||||
</citerefentry>, <citerefentry>
|
|
||||||
<refentrytitle>baz</refentrytitle>
|
|
||||||
<manvolnum>1</manvolnum>
|
|
||||||
</citerefentry>, <citerefentry>
|
|
||||||
<refentrytitle>foo.conf</refentrytitle>
|
|
||||||
<manvolnum>5</manvolnum>
|
|
||||||
</citerefentry></para>
|
|
||||||
<para>The programs are documented fully by <citetitle>The Rise and
|
|
||||||
Fall of a Fooish Bar</citetitle> available via the <citerefentry>
|
|
||||||
<refentrytitle>info</refentrytitle>
|
|
||||||
<manvolnum>1</manvolnum>
|
|
||||||
</citerefentry> system.</para>
|
|
||||||
</refsect1>
|
|
||||||
</refentry>
|
|
||||||
|
|
39
debian/postinst
vendored
|
@ -1,39 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
# postinst script for looper.
|
|
||||||
#
|
|
||||||
# See: dh_installdeb(1).
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
# Summary of how this script can be called:
|
|
||||||
# * <postinst> 'configure' <most-recently-configured-version>
|
|
||||||
# * <old-postinst> 'abort-upgrade' <new version>
|
|
||||||
# * <conflictor's-postinst> 'abort-remove' 'in-favour' <package>
|
|
||||||
# <new-version>
|
|
||||||
# * <postinst> 'abort-remove'
|
|
||||||
# * <deconfigured's-postinst> 'abort-deconfigure' 'in-favour'
|
|
||||||
# <failed-install-package> <version> 'removing'
|
|
||||||
# <conflicting-package> <version>
|
|
||||||
# for details, see https://www.debian.org/doc/debian-policy/ or
|
|
||||||
# the debian-policy package.
|
|
||||||
|
|
||||||
|
|
||||||
case "$1" in
|
|
||||||
configure)
|
|
||||||
xdg-mime install /usr/share/mime/audio/x-zsound.xml
|
|
||||||
;;
|
|
||||||
abort-upgrade|abort-remove|abort-deconfigure)
|
|
||||||
;;
|
|
||||||
|
|
||||||
*)
|
|
||||||
echo "postinst called with unknown argument '$1'" >&2
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
# dh_installdeb will replace this with shell code automatically
|
|
||||||
# generated by other debhelper scripts.
|
|
||||||
|
|
||||||
#DEBHELPER#
|
|
||||||
|
|
||||||
exit 0
|
|
37
debian/postrm.ex
vendored
|
@ -1,37 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
# postrm script for looper.
|
|
||||||
#
|
|
||||||
# See: dh_installdeb(1).
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
# Summary of how this script can be called:
|
|
||||||
# * <postrm> 'remove'
|
|
||||||
# * <postrm> 'purge'
|
|
||||||
# * <old-postrm> 'upgrade' <new-version>
|
|
||||||
# * <new-postrm> 'failed-upgrade' <old-version>
|
|
||||||
# * <new-postrm> 'abort-install'
|
|
||||||
# * <new-postrm> 'abort-install' <old-version>
|
|
||||||
# * <new-postrm> 'abort-upgrade' <old-version>
|
|
||||||
# * <disappearer's-postrm> 'disappear' <overwriter>
|
|
||||||
# <overwriter-version>
|
|
||||||
# for details, see https://www.debian.org/doc/debian-policy/ or
|
|
||||||
# the debian-policy package.
|
|
||||||
|
|
||||||
|
|
||||||
case "$1" in
|
|
||||||
purge|remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear)
|
|
||||||
;;
|
|
||||||
|
|
||||||
*)
|
|
||||||
echo "postrm called with unknown argument '$1'" >&2
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
# dh_installdeb will replace this with shell code automatically
|
|
||||||
# generated by other debhelper scripts.
|
|
||||||
|
|
||||||
#DEBHELPER#
|
|
||||||
|
|
||||||
exit 0
|
|
35
debian/preinst.ex
vendored
|
@ -1,35 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
# preinst script for looper.
|
|
||||||
#
|
|
||||||
# See: dh_installdeb(1).
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
# Summary of how this script can be called:
|
|
||||||
# * <new-preinst> 'install'
|
|
||||||
# * <new-preinst> 'install' <old-version>
|
|
||||||
# * <new-preinst> 'upgrade' <old-version>
|
|
||||||
# * <old-preinst> 'abort-upgrade' <new-version>
|
|
||||||
# for details, see https://www.debian.org/doc/debian-policy/ or
|
|
||||||
# the debian-policy package.
|
|
||||||
|
|
||||||
|
|
||||||
case "$1" in
|
|
||||||
install|upgrade)
|
|
||||||
;;
|
|
||||||
|
|
||||||
abort-upgrade)
|
|
||||||
;;
|
|
||||||
|
|
||||||
*)
|
|
||||||
echo "preinst called with unknown argument '$1'" >&2
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
# dh_installdeb will replace this with shell code automatically
|
|
||||||
# generated by other debhelper scripts.
|
|
||||||
|
|
||||||
#DEBHELPER#
|
|
||||||
|
|
||||||
exit 0
|
|
38
debian/prerm
vendored
|
@ -1,38 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
# prerm script for looper.
|
|
||||||
#
|
|
||||||
# See: dh_installdeb(1).
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
# Summary of how this script can be called:
|
|
||||||
# * <prerm> 'remove'
|
|
||||||
# * <old-prerm> 'upgrade' <new-version>
|
|
||||||
# * <new-prerm> 'failed-upgrade' <old-version>
|
|
||||||
# * <conflictor's-prerm> 'remove' 'in-favour' <package> <new-version>
|
|
||||||
# * <deconfigured's-prerm> 'deconfigure' 'in-favour'
|
|
||||||
# <package-being-installed> <version> 'removing'
|
|
||||||
# <conflicting-package> <version>
|
|
||||||
# for details, see https://www.debian.org/doc/debian-policy/ or
|
|
||||||
# the debian-policy package.
|
|
||||||
|
|
||||||
|
|
||||||
case "$1" in
|
|
||||||
remove|upgrade|deconfigure)
|
|
||||||
xdg-mime uninstall /usr/share/mime/audio/x-zsound.xml
|
|
||||||
;;
|
|
||||||
failed-upgrade)
|
|
||||||
;;
|
|
||||||
|
|
||||||
*)
|
|
||||||
echo "prerm called with unknown argument '$1'" >&2
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
# dh_installdeb will replace this with shell code automatically
|
|
||||||
# generated by other debhelper scripts.
|
|
||||||
|
|
||||||
#DEBHELPER#
|
|
||||||
|
|
||||||
exit 0
|
|
33
debian/rules
vendored
|
@ -1,33 +0,0 @@
|
||||||
#!/usr/bin/make -f
|
|
||||||
|
|
||||||
# See debhelper(7) (uncomment to enable).
|
|
||||||
# Output every command that modifies files on the build system.
|
|
||||||
#export DH_VERBOSE = 1
|
|
||||||
|
|
||||||
|
|
||||||
# See FEATURE AREAS in dpkg-buildflags(1).
|
|
||||||
#export DEB_BUILD_MAINT_OPTIONS = hardening=+all
|
|
||||||
|
|
||||||
# See ENVIRONMENT in dpkg-buildflags(1).
|
|
||||||
# Package maintainers to append CFLAGS.
|
|
||||||
#export DEB_CFLAGS_MAINT_APPEND = -Wall -pedantic
|
|
||||||
# Package maintainers to append LDFLAGS.
|
|
||||||
#export DEB_LDFLAGS_MAINT_APPEND = -Wl,--as-needed
|
|
||||||
|
|
||||||
|
|
||||||
%:
|
|
||||||
dh $@
|
|
||||||
|
|
||||||
|
|
||||||
# dh_make generated override targets.
|
|
||||||
# This is an example for Cmake (see <https://bugs.debian.org/641051>).
|
|
||||||
override_dh_auto_configure:
|
|
||||||
git submodule update --init --recursive -- backends/ui/imgui/imgui subprojects/vgmstream subprojects/SDL-Mixer-X
|
|
||||||
dh_auto_configure -- \
|
|
||||||
-DBUILD_SOUNDTOUCH=OFF \
|
|
||||||
-DMIXERX_ENABLE_GPL=ON \
|
|
||||||
-DMIXERX_ENABLE_LGPL=ON \
|
|
||||||
-DUSE_G719=OFF \
|
|
||||||
-DUSE_SPEEX=OFF \
|
|
||||||
-DUSE_ATRAC9=OFF \
|
|
||||||
-DCMAKE_LIBRARY_PATH=$(DEB_HOST_MULTIARCH)
|
|
11
debian/salsa-ci.yml.ex
vendored
|
@ -1,11 +0,0 @@
|
||||||
# For more information on what jobs are run see:
|
|
||||||
# https://salsa.debian.org/salsa-ci-team/pipeline
|
|
||||||
#
|
|
||||||
# To enable the jobs, go to your repository (at salsa.debian.org)
|
|
||||||
# and click over Settings > CI/CD > Expand (in General pipelines).
|
|
||||||
# In "CI/CD configuration file" write debian/salsa-ci.yml and click
|
|
||||||
# in "Save Changes". The CI tests will run after the next commit.
|
|
||||||
---
|
|
||||||
include:
|
|
||||||
- https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/salsa-ci.yml
|
|
||||||
- https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/pipeline-jobs.yml
|
|
1
debian/source/format
vendored
|
@ -1 +0,0 @@
|
||||||
3.0 (native)
|
|
|
@ -1,7 +1,6 @@
|
||||||
#include "file_backend.hpp"
|
#include "file_backend.hpp"
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <cassert>
|
|
||||||
|
|
||||||
File::File() {
|
File::File() {
|
||||||
}
|
}
|
||||||
|
@ -57,18 +56,9 @@ bool CFile::is_open() {
|
||||||
return file != NULL;
|
return file != NULL;
|
||||||
}
|
}
|
||||||
MemFile::MemFile() {
|
MemFile::MemFile() {
|
||||||
memory_owned = false;
|
|
||||||
ptr = NULL;
|
ptr = NULL;
|
||||||
len = 0;
|
len = 0;
|
||||||
}
|
}
|
||||||
void MemFile::open_memory(void *ptr, size_t len, const char *name) {
|
|
||||||
assert(name != NULL);
|
|
||||||
this->name = strdup(name);
|
|
||||||
this->ptr = ptr;
|
|
||||||
this->len = len;
|
|
||||||
this->pos = 0;
|
|
||||||
memory_owned = false;
|
|
||||||
}
|
|
||||||
void MemFile::open(const char *path) {
|
void MemFile::open(const char *path) {
|
||||||
CFile file;
|
CFile file;
|
||||||
file.open(path);
|
file.open(path);
|
||||||
|
@ -77,10 +67,9 @@ void MemFile::open(const char *path) {
|
||||||
this->len = file.read(this->ptr, 1, file.get_len());
|
this->len = file.read(this->ptr, 1, file.get_len());
|
||||||
file.close();
|
file.close();
|
||||||
this->pos = 0;
|
this->pos = 0;
|
||||||
memory_owned = true;
|
|
||||||
}
|
}
|
||||||
void MemFile::close() {
|
void MemFile::close() {
|
||||||
if (memory_owned) free(this->ptr);
|
free(this->ptr);
|
||||||
free((void*)this->name);
|
free((void*)this->name);
|
||||||
this->ptr = NULL;
|
this->ptr = NULL;
|
||||||
this->name = NULL;
|
this->name = NULL;
|
||||||
|
|
|
@ -93,10 +93,8 @@ class MemFile : public File {
|
||||||
void *ptr;
|
void *ptr;
|
||||||
size_t len;
|
size_t len;
|
||||||
int64_t pos;
|
int64_t pos;
|
||||||
bool memory_owned = true;
|
|
||||||
public:
|
public:
|
||||||
MemFile();
|
MemFile();
|
||||||
void open_memory(void *ptr, size_t len, const char *name = "<mem_file>");
|
|
||||||
void open(const char *path) override;
|
void open(const char *path) override;
|
||||||
void close() override;
|
void close() override;
|
||||||
size_t read(void *ptr, size_t size, size_t len) override;
|
size_t read(void *ptr, size_t size, size_t len) override;
|
||||||
|
|
|
@ -13,6 +13,12 @@ message RenderResponse {
|
||||||
uint64 len = 302;
|
uint64 len = 302;
|
||||||
bytes data = 303;
|
bytes data = 303;
|
||||||
};
|
};
|
||||||
|
message Ping {
|
||||||
|
bytes data = 1;
|
||||||
|
};
|
||||||
|
message Pong {
|
||||||
|
bytes data = 1;
|
||||||
|
};
|
||||||
message LogMessage {
|
message LogMessage {
|
||||||
uint64 timespec = 6000;
|
uint64 timespec = 6000;
|
||||||
uint32 level = 6001;
|
uint32 level = 6001;
|
||||||
|
@ -45,6 +51,8 @@ message RPCCall {
|
||||||
QuitCmd quit = 6;
|
QuitCmd quit = 6;
|
||||||
InitCommand init = 7;
|
InitCommand init = 7;
|
||||||
GetPropertyListCommand get_property_list = 8;
|
GetPropertyListCommand get_property_list = 8;
|
||||||
|
Ping = 9;
|
||||||
|
Pong = 10;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
message PropertyList {
|
message PropertyList {
|
||||||
|
@ -59,5 +67,7 @@ message RPCResponse {
|
||||||
ResetResponse reset = 5;
|
ResetResponse reset = 5;
|
||||||
ErrorResponse err = 6;
|
ErrorResponse err = 6;
|
||||||
PropertyList property_list = 7;
|
PropertyList property_list = 7;
|
||||||
|
Ping = 8;
|
||||||
|
Pong = 9;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
114
main.cpp
|
@ -16,9 +16,6 @@
|
||||||
#include <image.h>
|
#include <image.h>
|
||||||
#endif
|
#endif
|
||||||
#include "web_functions.hpp"
|
#include "web_functions.hpp"
|
||||||
#include "cats.hpp"
|
|
||||||
#include <json/value.h>
|
|
||||||
#include <chrono>
|
|
||||||
using namespace Looper;
|
using namespace Looper;
|
||||||
using namespace Looper::Options;
|
using namespace Looper::Options;
|
||||||
using namespace Looper::Log;
|
using namespace Looper::Log;
|
||||||
|
@ -26,13 +23,7 @@ using namespace Looper::Log;
|
||||||
extern "C" {
|
extern "C" {
|
||||||
void quit();
|
void quit();
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
#include <curl/curl.h>
|
|
||||||
#endif
|
#endif
|
||||||
std::vector<CatData> &get_cat_data() {
|
|
||||||
static std::vector<CatData> data;
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
std::unordered_set<LicenseData> license_data;
|
std::unordered_set<LicenseData> license_data;
|
||||||
std::unordered_set<LicenseData> &get_license_data() {
|
std::unordered_set<LicenseData> &get_license_data() {
|
||||||
return license_data;
|
return license_data;
|
||||||
|
@ -184,108 +175,6 @@ extern "C" int looper_run_as_executable(std::vector<std::string> args) {
|
||||||
}
|
}
|
||||||
DEBUG.writeln("Loading options file...");
|
DEBUG.writeln("Loading options file...");
|
||||||
load_options();
|
load_options();
|
||||||
{
|
|
||||||
auto &cat_data = get_cat_data();
|
|
||||||
cat_data.push_back(CatData(catoc_data, catoc_size, "Cat OC (Built-In)", "catoc.png"));
|
|
||||||
#ifndef __EMSCRIPTEN__
|
|
||||||
fs::path baseDir = get_prefs_path() / fs::path("looper") / fs::path("cats");
|
|
||||||
if (!fs::exists(baseDir)) {
|
|
||||||
fs::create_directories(baseDir);
|
|
||||||
}
|
|
||||||
for (auto const&dir_entry : std::filesystem::directory_iterator(baseDir)) {
|
|
||||||
if (dir_entry.is_regular_file()) {
|
|
||||||
cat_data.push_back(CatData(dir_entry.path()));
|
|
||||||
} else if (dir_entry.is_directory()) {
|
|
||||||
fs::path json_path = dir_entry.path() / fs::path("catpack.json");
|
|
||||||
if (fs::exists(json_path)) {
|
|
||||||
std::ifstream stream(json_path);
|
|
||||||
Json::Value config;
|
|
||||||
stream >> config;
|
|
||||||
std::string name = dir_entry.path().stem().string();
|
|
||||||
if (config.isMember("name")) {
|
|
||||||
name = config["name"].asString();
|
|
||||||
}
|
|
||||||
if (!config.isMember("default")) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
std::string str = config["default"].asString();
|
|
||||||
if (config.isMember("variants")) {
|
|
||||||
Json::Value variants = config["variants"];
|
|
||||||
int prev_score = INT_MAX;
|
|
||||||
auto now = std::chrono::system_clock::now();
|
|
||||||
time_t now_tt = std::chrono::system_clock::to_time_t(now);
|
|
||||||
tm local_tm = *localtime(&now_tt);
|
|
||||||
auto cur_day = local_tm.tm_mday;
|
|
||||||
auto cur_month = local_tm.tm_mon;
|
|
||||||
auto cur_yday = local_tm.tm_yday;
|
|
||||||
DEBUG.writefln("Current date: %d ([MM/DD] %02d/%02d)", cur_yday, cur_month + 1, cur_day);
|
|
||||||
|
|
||||||
for (auto &variant : variants) {
|
|
||||||
if (variant.isMember("startTime") && variant.isMember("endTime")) {
|
|
||||||
Json::Value startTime = variant["startTime"];
|
|
||||||
Json::Value endTime = variant["endTime"];
|
|
||||||
int score = 0;
|
|
||||||
int start = 0;
|
|
||||||
int end = 0;
|
|
||||||
tm start_tm;
|
|
||||||
tm end_tm;
|
|
||||||
if (startTime.isMember("day") && startTime.isMember("month")) {
|
|
||||||
int day = startTime["day"].asInt();
|
|
||||||
int month = startTime["month"].asInt();
|
|
||||||
tm tmp{};
|
|
||||||
tmp.tm_year = local_tm.tm_year;
|
|
||||||
tmp.tm_mon = month - 1;
|
|
||||||
tmp.tm_mday = day;
|
|
||||||
time_t t = std::mktime(&tmp);
|
|
||||||
tmp = *std::localtime(&t);
|
|
||||||
start = tmp.tm_yday;
|
|
||||||
start_tm = tmp;
|
|
||||||
}
|
|
||||||
if (endTime.isMember("day") && endTime.isMember("month")) {
|
|
||||||
int day = endTime["day"].asInt();
|
|
||||||
int month = endTime["month"].asInt();
|
|
||||||
tm tmp{};
|
|
||||||
tmp.tm_year = local_tm.tm_year;
|
|
||||||
tmp.tm_mon = month - 1;
|
|
||||||
tmp.tm_mday = day;
|
|
||||||
time_t t = std::mktime(&tmp);
|
|
||||||
tmp = *std::localtime(&t);
|
|
||||||
end = tmp.tm_yday;
|
|
||||||
end_tm = tmp;
|
|
||||||
}
|
|
||||||
if (variant.isMember("path")) DEBUG.writefln("Variant %s: %d-%d ([MM/DD] %02d/%02d-%02d/%02d)", variant["path"].asCString(), start, end, start_tm.tm_mon+1, start_tm.tm_mday, end_tm.tm_mon+1, end_tm.tm_mday);
|
|
||||||
if (end < start) {
|
|
||||||
if (cur_yday > end && cur_yday < start) continue;
|
|
||||||
score = end - start + 365;
|
|
||||||
} else {
|
|
||||||
if (cur_yday > end || cur_yday < start) continue;
|
|
||||||
score = end - start;
|
|
||||||
}
|
|
||||||
DEBUG.writefln("Score: %d (prev: %d)", score, prev_score);
|
|
||||||
if (variant.isMember("path")) {
|
|
||||||
if (prev_score > score) {
|
|
||||||
auto newPath = variant["path"].asString();
|
|
||||||
if (!fs::exists(dir_entry.path() / fs::path(newPath))) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
str = newPath;
|
|
||||||
prev_score = score;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fs::path usedPath = dir_entry.path() / fs::path(str);
|
|
||||||
if (fs::exists(usedPath)) {
|
|
||||||
auto data = CatData(usedPath);
|
|
||||||
data.name = name;
|
|
||||||
cat_data.push_back(data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
std::string backend_id = get_option<std::string>("ui.frontend", "imgui");
|
std::string backend_id = get_option<std::string>("ui.frontend", "imgui");
|
||||||
UIBackend *backend = UIBackend::get_backend(ui_backend_option).value_or(UIBackend::get_backend(backend_id).value_or(UIBackend::get_first_backend()));
|
UIBackend *backend = UIBackend::get_backend(ui_backend_option).value_or(UIBackend::get_backend(backend_id).value_or(UIBackend::get_first_backend()));
|
||||||
int output = 0;
|
int output = 0;
|
||||||
|
@ -375,9 +264,6 @@ int main(int argc, char **argv) {
|
||||||
app.add_option("-l, --log-level", LogStream::log_level, "Sets the minimum log level to display in the logs.");
|
app.add_option("-l, --log-level", LogStream::log_level, "Sets the minimum log level to display in the logs.");
|
||||||
app.allow_extras();
|
app.allow_extras();
|
||||||
init_logging();
|
init_logging();
|
||||||
#ifndef __EMSCRIPTEN__
|
|
||||||
//curl_global_init(CURL_GLOBAL_ALL);
|
|
||||||
#endif
|
|
||||||
try {
|
try {
|
||||||
app.parse(argc, argv);
|
app.parse(argc, argv);
|
||||||
executable_path = argv[0];
|
executable_path = argv[0];
|
||||||
|
|
17
playback.cpp
|
@ -174,8 +174,6 @@ void PlaybackInstance::Load(const char *file, int idx) {
|
||||||
paused = false;
|
paused = false;
|
||||||
just_started.store(true);
|
just_started.store(true);
|
||||||
flag_mutex.unlock();
|
flag_mutex.unlock();
|
||||||
set_signal(PlaybackSignalStarted);
|
|
||||||
set_signal(PlaybackSignalFileChanged);
|
|
||||||
}
|
}
|
||||||
void PlaybackInstance::Unload() {
|
void PlaybackInstance::Unload() {
|
||||||
if (process == nullptr) return;
|
if (process == nullptr) return;
|
||||||
|
@ -187,7 +185,6 @@ void PlaybackInstance::Unload() {
|
||||||
if (buf) free(buf);
|
if (buf) free(buf);
|
||||||
buf = nullptr;
|
buf = nullptr;
|
||||||
UnlockAudioDevice();
|
UnlockAudioDevice();
|
||||||
set_signal(PlaybackSignalStopped);
|
|
||||||
}
|
}
|
||||||
void PlaybackInstance::UpdateST() {
|
void PlaybackInstance::UpdateST() {
|
||||||
bool any_changed = false;
|
bool any_changed = false;
|
||||||
|
@ -468,14 +465,16 @@ PlaybackInstance::PlaybackInstance() {
|
||||||
|
|
||||||
}
|
}
|
||||||
std::optional<std::string> PlaybackInstance::get_current_file() {
|
std::optional<std::string> PlaybackInstance::get_current_file() {
|
||||||
if (process == nullptr) return {};
|
current_file_mutex.lock();
|
||||||
if (!process->process_running()) return {};
|
std::optional<std::string> output = current_file;
|
||||||
return process->get_file_path();
|
current_file_mutex.unlock();
|
||||||
|
return output;
|
||||||
}
|
}
|
||||||
std::optional<std::string> PlaybackInstance::get_current_title() {
|
std::optional<std::string> PlaybackInstance::get_current_title() {
|
||||||
if (process == nullptr) return {};
|
current_file_mutex.lock();
|
||||||
if (!process->process_running()) return {};
|
std::optional<std::string> output = current_title;
|
||||||
return process->get_title();
|
current_file_mutex.unlock();
|
||||||
|
return output;
|
||||||
}
|
}
|
||||||
PlaybackInstance::~PlaybackInstance() {
|
PlaybackInstance::~PlaybackInstance() {
|
||||||
Stop();
|
Stop();
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <SDL.h>
|
#include <SDL.h>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <limits.h>
|
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include "util.hpp"
|
#include "util.hpp"
|
||||||
#include "ipc/internal.pb.h"
|
#include "ipc/internal.pb.h"
|
||||||
|
@ -21,13 +20,13 @@ class PlaybackBackend {
|
||||||
size_t minSamples;
|
size_t minSamples;
|
||||||
size_t maxSamples;
|
size_t maxSamples;
|
||||||
protected:
|
protected:
|
||||||
uint64_t length;
|
double length;
|
||||||
std::vector<PlaybackStream> streams;
|
std::vector<PlaybackStream> streams;
|
||||||
std::string current_file;
|
std::string current_file;
|
||||||
std::optional<std::string> current_title;
|
std::string current_title;
|
||||||
bool open;
|
bool open;
|
||||||
SDL_AudioSpec spec;
|
SDL_AudioSpec spec;
|
||||||
uint64_t position;
|
double position;
|
||||||
std::map<std::string, google::protobuf::Any> property_defaults;
|
std::map<std::string, google::protobuf::Any> property_defaults;
|
||||||
std::map<std::string, google::protobuf::Any> properties;
|
std::map<std::string, google::protobuf::Any> properties;
|
||||||
size_t min_sample_estimate;
|
size_t min_sample_estimate;
|
||||||
|
@ -35,8 +34,8 @@ class PlaybackBackend {
|
||||||
size_t max_sample_requirement = std::numeric_limits<size_t>::max();
|
size_t max_sample_requirement = std::numeric_limits<size_t>::max();
|
||||||
size_t min_sample_requirement = std::numeric_limits<size_t>::min();
|
size_t min_sample_requirement = std::numeric_limits<size_t>::min();
|
||||||
double rate;
|
double rate;
|
||||||
uint64_t loop_start = 0;
|
double loop_start = 0.0;
|
||||||
uint64_t loop_end = UINT64_MAX;
|
double loop_end = -1.0;
|
||||||
void setMinSamples(size_t samples) {
|
void setMinSamples(size_t samples) {
|
||||||
this->minSamples = samples;
|
this->minSamples = samples;
|
||||||
adjustSampleEstimates();
|
adjustSampleEstimates();
|
||||||
|
@ -54,12 +53,6 @@ class PlaybackBackend {
|
||||||
max_sample_estimate = (size_t)ceill(tmpMaxSamples * tmpRate);
|
max_sample_estimate = (size_t)ceill(tmpMaxSamples * tmpRate);
|
||||||
if (max_sample_estimate > max_sample_requirement) max_sample_estimate = max_sample_requirement;
|
if (max_sample_estimate > max_sample_requirement) max_sample_estimate = max_sample_requirement;
|
||||||
}
|
}
|
||||||
inline double samples_to_time(uint64_t samples) {
|
|
||||||
return ((double)samples) / ((double)spec.freq);
|
|
||||||
}
|
|
||||||
inline uint64_t time_to_samples(double time) {
|
|
||||||
return time * spec.freq;
|
|
||||||
}
|
|
||||||
public:
|
public:
|
||||||
using map = std::map<std::string, PlaybackBackend*>;
|
using map = std::map<std::string, PlaybackBackend*>;
|
||||||
using iterator = map::iterator;
|
using iterator = map::iterator;
|
||||||
|
@ -69,12 +62,8 @@ class PlaybackBackend {
|
||||||
inline virtual void add_licenses() { }
|
inline virtual void add_licenses() { }
|
||||||
inline virtual std::string get_id() {return "";}
|
inline virtual std::string get_id() {return "";}
|
||||||
inline virtual std::string get_name() {return "";}
|
inline virtual std::string get_name() {return "";}
|
||||||
inline virtual void seek(double position) { seek_samples(time_to_samples(position)); }
|
inline virtual void seek(double position) { }
|
||||||
inline virtual void seek_samples(uint64_t position) { }
|
inline virtual double get_position() {
|
||||||
inline virtual double get_position_time() {
|
|
||||||
return ((double)get_position_samples()) / ((double)spec.freq);
|
|
||||||
}
|
|
||||||
inline virtual uint64_t get_position_samples() {
|
|
||||||
return position;
|
return position;
|
||||||
}
|
}
|
||||||
inline virtual SDL_AudioSpec get_spec() {
|
inline virtual SDL_AudioSpec get_spec() {
|
||||||
|
@ -113,42 +102,19 @@ class PlaybackBackend {
|
||||||
virtual void cleanup();
|
virtual void cleanup();
|
||||||
virtual size_t render(void *buf, size_t maxlen);
|
virtual size_t render(void *buf, size_t maxlen);
|
||||||
inline virtual double get_length() {
|
inline virtual double get_length() {
|
||||||
return samples_to_time(get_length_samples());
|
return open ? length : 0.0;
|
||||||
}
|
|
||||||
inline virtual uint64_t get_length_samples() {
|
|
||||||
return open ? length : 0;
|
|
||||||
}
|
|
||||||
inline virtual uint64_t get_loop_start_samples() {
|
|
||||||
return open ? loop_start : 0;
|
|
||||||
}
|
}
|
||||||
inline virtual double get_loop_start() {
|
inline virtual double get_loop_start() {
|
||||||
return samples_to_time(get_loop_start_samples());
|
return open ? loop_start : 0.0;
|
||||||
}
|
|
||||||
inline virtual uint64_t get_loop_end_samples() {
|
|
||||||
return open ? loop_end == UINT64_MAX ? get_length_samples() : loop_end : 0;
|
|
||||||
}
|
}
|
||||||
inline virtual double get_loop_end() {
|
inline virtual double get_loop_end() {
|
||||||
return samples_to_time(get_loop_end_samples());
|
return open ? loop_end < 0.0 ? get_length() : loop_end : 0.0;
|
||||||
}
|
}
|
||||||
inline virtual std::optional<std::string> get_current_file() {
|
inline virtual std::optional<std::string> get_current_file() {
|
||||||
return open ? current_file : std::optional<std::string>();
|
return open ? current_file : std::optional<std::string>();
|
||||||
}
|
}
|
||||||
inline virtual std::optional<std::string> get_title() {
|
inline virtual std::optional<std::string> get_title() {
|
||||||
if (open) {
|
return open ? current_title : std::optional<std::string>();
|
||||||
if (current_title.has_value()) {
|
|
||||||
return current_title;
|
|
||||||
} else {
|
|
||||||
auto file = get_current_file();
|
|
||||||
if (file.has_value()) {
|
|
||||||
std::filesystem::path path(file.value());
|
|
||||||
return path.stem().string();
|
|
||||||
} else {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
inline virtual int get_stream_idx() {return 0;}
|
inline virtual int get_stream_idx() {return 0;}
|
||||||
inline virtual ~PlaybackBackend() { }
|
inline virtual ~PlaybackBackend() { }
|
||||||
|
|
|
@ -25,9 +25,6 @@
|
||||||
#ifdef __WINDOWS__
|
#ifdef __WINDOWS__
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#endif
|
#endif
|
||||||
#ifdef __HAIKU__
|
|
||||||
#include <kernel/scheduler.h>
|
|
||||||
#endif
|
|
||||||
#include <google/protobuf/message.h>
|
#include <google/protobuf/message.h>
|
||||||
#include "util.hpp"
|
#include "util.hpp"
|
||||||
using namespace google::protobuf;
|
using namespace google::protobuf;
|
||||||
|
@ -184,7 +181,7 @@ PropertyDataOrError PlaybackProcessServiceImpl::Get(const GetProperty *request)
|
||||||
} break;
|
} break;
|
||||||
case PropertyId::PositionProperty: {
|
case PropertyId::PositionProperty: {
|
||||||
DoubleProperty pos;
|
DoubleProperty pos;
|
||||||
pos.set_value(cur_backend->get_position_time());
|
pos.set_value(cur_backend->get_position());
|
||||||
data->mutable_value()->PackFrom(pos);
|
data->mutable_value()->PackFrom(pos);
|
||||||
} break;
|
} break;
|
||||||
case PropertyId::BackendSpecific: {
|
case PropertyId::BackendSpecific: {
|
||||||
|
@ -338,7 +335,6 @@ MaybeError PlaybackProcessServiceImpl::Init(const InitCommand *cmd) {
|
||||||
}
|
}
|
||||||
lock.set(backend.second, false);
|
lock.set(backend.second, false);
|
||||||
DEBUG.writefln("Using backend: %s", backend.second->get_name().c_str());
|
DEBUG.writefln("Using backend: %s", backend.second->get_name().c_str());
|
||||||
backend.second->seek(0.0);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!cur_backend_lock.has_value()) {
|
if (!cur_backend_lock.has_value()) {
|
||||||
|
@ -400,9 +396,6 @@ PlaybackProcess::PlaybackProcess(PlaybackProcess *parent) {
|
||||||
DEBUG.writeln("Host process address: (in-process)");
|
DEBUG.writeln("Host process address: (in-process)");
|
||||||
}
|
}
|
||||||
PlaybackProcess::PlaybackProcess(std::vector<std::string> args) {
|
PlaybackProcess::PlaybackProcess(std::vector<std::string> args) {
|
||||||
#ifdef __HAIKU__
|
|
||||||
set_thread_priority(find_thread(NULL), suggest_thread_priority(B_LIVE_AUDIO_MANIPULATION));
|
|
||||||
#endif
|
|
||||||
SDL_InitSubSystem(SDL_INIT_AUDIO);
|
SDL_InitSubSystem(SDL_INIT_AUDIO);
|
||||||
done = false;
|
done = false;
|
||||||
is_playback_process = true;
|
is_playback_process = true;
|
||||||
|
@ -420,11 +413,7 @@ PlaybackProcess::PlaybackProcess(std::vector<std::string> args) {
|
||||||
}
|
}
|
||||||
PlaybackProcess::PlaybackProcess(std::string filename, int idx) {
|
PlaybackProcess::PlaybackProcess(std::string filename, int idx) {
|
||||||
// multi_process = Looper::Options::get_option<bool>("playback.multi_process", true);
|
// multi_process = Looper::Options::get_option<bool>("playback.multi_process", true);
|
||||||
#ifdef __EMSCRIPTEN__
|
|
||||||
multi_process = false;
|
|
||||||
#else
|
|
||||||
multi_process = true;
|
multi_process = true;
|
||||||
#endif
|
|
||||||
done = false;
|
done = false;
|
||||||
this->done = false;
|
this->done = false;
|
||||||
if (multi_process) {
|
if (multi_process) {
|
||||||
|
|
1
setup.sh
|
@ -1,5 +1,4 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
pushd "$(dirname "$0")/subprojects/vgmstream"
|
pushd "$(dirname "$0")/subprojects/vgmstream"
|
||||||
git apply ../../vgmstream.patch
|
git apply ../../vgmstream.patch
|
||||||
git submodule update --init --recursive
|
|
||||||
popd
|
popd
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 0f7e551b59372cdad6c7475d50b6d0b8a9ac2765
|
Subproject commit 22aed1f6bcfa6912a34d3241edf3bd90498a6bc2
|
|
@ -1 +1 @@
|
||||||
Subproject commit e3ddede6c4ee818825c4e5a6dfa1d384860c27d9
|
Subproject commit 720da57baba83b3b1829e20133575e57aa1a8a4f
|
|
@ -1 +1 @@
|
||||||
Subproject commit 6dae7eb4a5c3a169f3e298392bff4680224aa94a
|
Subproject commit d144031940543e15423a25ae5a8a74141044862f
|
|
@ -1 +1 @@
|
||||||
Subproject commit dca8a24cf8da1fc61b5cf0422cad03474124196c
|
Subproject commit 8214f717e7c7d361f002b6c3d1b1086ddd096315
|
9
util.hpp
|
@ -519,13 +519,6 @@ inline std::string resolve_value<std::string>(google::protobuf::Any value) {
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
template<>
|
template<>
|
||||||
inline int resolve_value<int>(google::protobuf::Any value) {
|
|
||||||
IntProperty *property = resolve_any<IntProperty>(value);
|
|
||||||
int output = property->value();
|
|
||||||
delete property;
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
template<>
|
|
||||||
inline DynPtr resolve_value<DynPtr>(google::protobuf::Any value) {
|
inline DynPtr resolve_value<DynPtr>(google::protobuf::Any value) {
|
||||||
BytesProperty *property = resolve_any<BytesProperty>(value);
|
BytesProperty *property = resolve_any<BytesProperty>(value);
|
||||||
std::string output = property->value();
|
std::string output = property->value();
|
||||||
|
@ -534,7 +527,7 @@ inline DynPtr resolve_value<DynPtr>(google::protobuf::Any value) {
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
inline double resolve_value<double>(google::protobuf::Any value) {
|
inline double resolve_value(google::protobuf::Any value) {
|
||||||
DoubleProperty *property = resolve_any<DoubleProperty>(value);
|
DoubleProperty *property = resolve_any<DoubleProperty>(value);
|
||||||
double output = property->value();
|
double output = property->value();
|
||||||
delete property;
|
delete property;
|
||||||
|
|