Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
142 changes: 49 additions & 93 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,95 +1,51 @@
name: ci-pr
on: [pull_request, workflow_dispatch]
name: Build
on: [push, pull_request]
defaults:
run:
shell: pwsh
jobs:
x64-linux-gcc:
runs-on: ubuntu-latest
build:
name: ${{ matrix.platform.name }} ${{ matrix.config.name }}
runs-on: ${{ matrix.platform.os }}
env:
CMAKE_BUILD_PARALLEL_LEVEL: 4
strategy:
fail-fast: false
matrix:
platform:
- { name: "Windows VS2022", os: windows-2022, flags: "" }
- { name: "Linux GCC", os: ubuntu-latest, flags: "" }
- { name: "Linux Clang", os: ubuntu-latest, flags: "-DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++" }
- { name: "macOS AppleClang", os: macos-latest, flags: "" }
config:
- { name: "Static", flags: "-DBUILD_SHARED_LIBS=FALSE" }
steps:
- uses: actions/checkout@v4
- name: init
run: uname -m; sudo apt update -yqq && sudo apt install -yqq ninja-build mesa-common-dev libwayland-dev libxkbcommon-dev wayland-protocols extra-cmake-modules
- name: configure
run: cmake -S . --preset=ninja-gcc -B build -DGLFW_BUILD_X11=OFF -DJUKE_USE_LIBXMP=OFF -DCMAKE_C_COMPILER=gcc-14 -DCMAKE_CXX_COMPILER=g++-14
- name: build debug
run: cmake --build build --config=Debug -- -v
- name: build release
run: cmake --build build --config=Release -- -v
- name: test debug
run: cd build && ctest -V -C Debug
- name: test release
run: cd build && ctest -V -C Release
x64-linux-clang:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: init
run: uname -m; sudo apt update -yqq && sudo apt install -yqq ninja-build clang-19 mesa-common-dev libwayland-dev libxkbcommon-dev wayland-protocols extra-cmake-modules
- name: configure
run: cmake -S . --preset=ninja-clang -B build -DGLFW_BUILD_X11=OFF -DJUKE_USE_LIBXMP=OFF -DCMAKE_C_COMPILER=clang-19 -DCMAKE_CXX_COMPILER=clang++-19
- name: build debug
run: cmake --build build --config=Debug -- -v
- name: build release
run: cmake --build build --config=Release -- -v
- name: test debug
run: cd build && ctest -V -C Debug
- name: test release
run: cd build && ctest -V -C Release
arm64-linux-gcc:
runs-on: ubuntu-24.04-arm
steps:
- uses: actions/checkout@v4
- name: init
run: uname -m; sudo apt update -yqq && sudo apt install -yqq ninja-build mesa-common-dev libwayland-dev libxkbcommon-dev wayland-protocols extra-cmake-modules
- name: configure
run: cmake -S . --preset=ninja-gcc -B build -DGLFW_BUILD_X11=OFF -DJUKE_USE_LIBXMP=OFF -DCMAKE_C_COMPILER=gcc-14 -DCMAKE_CXX_COMPILER=g++-14
- name: build debug
run: cmake --build build --config=Debug -- -v
- name: build release
run: cmake --build build --config=Release -- -v
- name: test debug
run: cd build && ctest -V -C Debug
- name: test release
run: cd build && ctest -V -C Release
arm64-linux-clang:
runs-on: ubuntu-24.04-arm
steps:
- uses: actions/checkout@v4
- name: init
run: uname -m; sudo apt update -yqq && sudo apt install -yqq ninja-build clang-19 mesa-common-dev libwayland-dev libxkbcommon-dev wayland-protocols extra-cmake-modules
- name: configure
run: cmake -S . --preset=ninja-clang -B build -DGLFW_BUILD_X11=OFF -DJUKE_USE_LIBXMP=OFF -DCMAKE_C_COMPILER=clang-19 -DCMAKE_CXX_COMPILER=clang++-19
- name: build debug
run: cmake --build build --config=Debug -- -v
- name: build release
run: cmake --build build --config=Release -- -v
- name: test debug
run: cd build && ctest -V -C Debug
- name: test release
run: cd build && ctest -V -C Release
x64-windows-vs22:
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
- name: configure
run: cmake -S . --preset=vs22 -B build -DJUKE_USE_LIBXMP=OFF
- name: build debug
run: cmake --build build --config=Debug --parallel
- name: build release
run: cmake --build build --config=Release --parallel
- name: test debug
run: cd build && ctest -V -C Debug
- name: test release
run: cd build && ctest -V -C Release
x64-windows-clang:
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
- name: configure
run: cmake -S . --preset=ninja-clang -B build -DJUKE_USE_LIBXMP=OFF
- name: build debug
run: cmake --build build --config=Debug -- -v
- name: build release
run: cmake --build build --config=Release -- -v
- name: test debug
run: cd build && ctest -V -C Debug
- name: test release
run: cd build && ctest -V -C Release
- name: Checkout
uses: actions/checkout@v4
- name: Install Dependencies
run: |
if ($env:RUNNER_OS -eq 'Windows') {
choco install ninja -y
} elseif ($env:RUNNER_OS -eq 'Linux') {
sudo apt-get update
sudo apt-get install -y ninja-build libxrandr-dev libxcursor-dev libxi-dev libudev-dev libflac-dev libvorbis-dev libgl1-mesa-dev libegl1-mesa-dev libfreetype-dev
} elseif ($env:RUNNER_OS -eq 'macOS') {
brew install ninja
} else {
Write-Error "Unsupported OS: $env:RUNNER_OS"
exit 1
}
- name: Configure
run: |
if ($env:RUNNER_OS -eq 'Windows') {
. "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\Tools\Launch-VsDevShell.ps1" -Arch amd64 -HostArch amd64
Set-Location $env:GITHUB_WORKSPACE
}
cmake -B build -G "Ninja Multi-Config" ${{ matrix.platform.flags }} ${{ matrix.config.flags }}
- name: Build
run: |
if ($env:RUNNER_OS -eq 'Windows') {
. "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\Tools\Launch-VsDevShell.ps1" -Arch amd64 -HostArch amd64
Set-Location $env:GITHUB_WORKSPACE
}
cmake --build build --config Release
16 changes: 16 additions & 0 deletions app/include/app/MediaPlayer.hpp
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
#pragma once

#include <imgui.h>
#include <capo/engine.hpp>
#include <juke/juke.hpp>
#include <filesystem>
#include <memory>
#include <string>
#include <thread>

namespace juke {

Expand All @@ -14,8 +16,22 @@ class MediaPlayer {
bool load_media(std::filesystem::path const& path);
void handle_input();

[[nodiscard]] auto get_content_size() const -> ImVec2 { return m_content_size; }
[[nodiscard]] auto has_size_changed() const -> bool { return m_content_size.x != m_previous_content_size.x || m_content_size.y != m_previous_content_size.y; }

private:
void generate_soundtrack();

private:
Jukebox m_jukebox;
ImVec2 m_content_size{};
ImVec2 m_previous_content_size{};
std::filesystem::path m_source_folder{};

// threaded soundtrack variables
std::jthread m_loader_thread;
std::atomic<float> m_progress = 0.0f;
std::atomic<bool> m_loading = false;
};

} // namespace juke
1 change: 1 addition & 0 deletions app/src/Application.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ void Application::run() {
while (m_context->next_frame()) {
m_player->handle_input();
m_context->render();
// if (m_player->get_content_size().x > 0 && m_player->get_content_size().y > 0 && !m_player->has_size_changed()) { glfwSetWindowSize(m_context->get_window(), m_player->get_content_size().x, m_player->get_content_size().y); }
}
}

Expand Down
104 changes: 77 additions & 27 deletions app/src/MediaPlayer.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@

#include <imgui.h>
#include <app/Colors.hpp>
#include <app/MediaPlayer.hpp>
#include <capo/engine.hpp>
Expand All @@ -14,10 +13,17 @@ using namespace std::chrono_literals;

MediaPlayer::MediaPlayer(capo::IEngine& audio_engine) : m_jukebox(audio_engine) {}

bool MediaPlayer::load_media(std::filesystem::path const& path) { return m_jukebox.load_media(path); }
bool MediaPlayer::load_media(std::filesystem::path const& path) {
m_source_folder = path.parent_path();
return m_jukebox.load_media(path);
}

void MediaPlayer::handle_input() {
ImGuiWindowFlags flags = ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoMove;
ImGuiViewport* vp = ImGui::GetMainViewport();

ImGui::SetNextWindowPos(vp->WorkPos);
ImGui::SetNextWindowSize(vp->WorkSize);
ImGuiWindowFlags flags = ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize;
if (ImGui::Begin("Player", nullptr, flags)) {

/* ImGui variables */
Expand All @@ -26,13 +32,19 @@ void MediaPlayer::handle_input() {
static auto gain{1.f};
static auto pan{0.f};
static auto pitch{1.f};
static auto lo_cutoff{sample_rate_v};
static auto hi_cutoff{0.f};
static float pos[] = {0.f, 0.f, 0.f};

/* Metadata & Info */
ImGui::Text("Folder: %s", m_source_folder.string().c_str());
ImGui::Text("File Name: ");
ImGui::SameLine();
m_jukebox.has_file() ? ImGui::TextColored(colors::blue, "%s", m_jukebox.get_filename().c_str()) : ImGui::TextColored(colors::grey, "<no file>");
ImGui::Text("Media Status: %s", m_jukebox.is_playing() ? "playing" : "paused");
if (m_jukebox.has_file()) {
ImGui::Text("Media Status: %s", m_jukebox.is_playing() ? "playing" : "paused");
ImGui::ProgressBar(m_jukebox.get_percent_complete(), {300.f, 4.f}, "");
}

ImGui::Separator();

Expand All @@ -42,35 +54,73 @@ void MediaPlayer::handle_input() {
if (ImGui::Button("pause")) { m_jukebox.pause(); }
ImGui::SameLine();
if (ImGui::Button("stop")) { m_jukebox.stop(); }
if (ImGui::TreeNode("advanced", "advanced")) {
ImGui::Separator();
if (m_jukebox.has_file()) {
if (ImGui::TreeNode("advanced", "advanced")) {

if (ImGui::Button("reset")) {
gain = 1.f;
pitch = 1.f;
pan = 0.f;
}
if (ImGui::Button("reset")) {
gain = 1.f;
pitch = 1.f;
pan = 0.f;
}

ImGui::Checkbox("loop", &looping);

ImGui::SliderFloat("volume", &gain, 0.f, 1.f);
ImGui::SliderFloat("pitch", &pitch, 0.f, 2.f);
ImGui::SliderFloat("pan", &pan, -1.f, 1.f);
m_jukebox.set_gain(gain);
m_jukebox.set_pitch(pitch);
m_jukebox.set_pan(pan);

ImGui::Checkbox("loop", &looping);

ImGui::SliderFloat("volume", &gain, 0.f, 1.f);
ImGui::SliderFloat("pitch", &pitch, 0.f, 2.f);
ImGui::SliderFloat("pan", &pan, -1.f, 1.f);
m_jukebox.set_gain(gain);
m_jukebox.set_pitch(pitch);
m_jukebox.set_pan(pan);

ImGui::Checkbox("spatialized", &spatialized);
m_jukebox.set_spatialized(spatialized);
if (m_jukebox.is_spatialized()) {
ImGui::Separator();
ImGui::SliderFloat3("position", pos, -1.f, 1.f, "%.1f");
m_jukebox.set_position(capo::Vec3f{pos[0], pos[1], pos[2]});
if (ImGui::Button("reset")) { pos[0] = pos[1] = pos[2] = 0.f; }
ImGui::Checkbox("spatialized", &spatialized);
m_jukebox.set_spatialized(spatialized);
if (m_jukebox.is_spatialized()) {
ImGui::Separator();
ImGui::SliderFloat3("position", pos, -1.f, 1.f, "%.1f");
m_jukebox.set_position(capo::Vec3f{pos[0], pos[1], pos[2]});
if (ImGui::Button("reset")) { pos[0] = pos[1] = pos[2] = 0.f; }
}

ImGui::SliderFloat("Low Pass", &lo_cutoff, 0.f, sample_rate_v, "%.1f", ImGuiSliderFlags_Logarithmic);
m_jukebox.set_cutoff(FilterType::low, lo_cutoff, sample_rate_v);
ImGui::SliderFloat("High Pass:", &hi_cutoff, 0.f, sample_rate_v, "%.1f", ImGuiSliderFlags_Logarithmic);
m_jukebox.set_cutoff(FilterType::high, hi_cutoff, sample_rate_v);
ImGui::TreePop();
}
if (ImGui::TreeNode("export", "export")) {
if (ImGui::Button("write to .wav")) { m_jukebox.write_to_wav(); }
if (ImGui::Button("generate soundtrack")) { generate_soundtrack(); }
if (m_loading) {
ImGui::TextColored(colors::grey, "generating soundtrack...");
ImGui::ProgressBar(m_progress);
}
ImGui::TreePop();
}
ImGui::TreePop();
}
}
ImVec2 required = ImGui::GetCursorPos();
ImGuiStyle const& style = ImGui::GetStyle();

required.x += style.WindowPadding.x;
required.y += style.WindowPadding.y;
auto size = ImVec2{std::ceil(required.x), std::ceil(required.y)};
m_previous_content_size = m_content_size;
m_content_size = size;
ImGui::End();
}

void MediaPlayer::generate_soundtrack() {
m_loading = true;
m_loader_thread = std::jthread([this](std::stop_token stop) {
auto total = std::ranges::distance(std::filesystem::recursive_directory_iterator(m_source_folder));
int current = 0;
for (auto const& file : std::filesystem::recursive_directory_iterator(m_source_folder)) {
if (m_jukebox.load_media(file)) { m_jukebox.write_to_wav(); }
m_progress = static_cast<float>(++current) / total;
}
m_loading = false;
});
}

} // namespace juke
16 changes: 16 additions & 0 deletions deps/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,21 @@ if(JUKE_USE_LIBXMP)
GIT_SHALLOW TRUE
)
list(APPEND fetch_list libxmp)

#dr_wav
FetchContent_Declare(
dr_wav
GIT_REPOSITORY https://github.com/mackron/dr_libs.git
GIT_TAG master
GIT_SHALLOW TRUE
)
FetchContent_MakeAvailable(dr_wav)
message(STATUS "dr_wav_SOURCE_DIR = ${dr_wav_SOURCE_DIR}")

add_library(dr_wav INTERFACE)
target_include_directories(dr_wav INTERFACE
${dr_wav_SOURCE_DIR}
)
endif()

set(BUILD_SHARED OFF CACHE BOOL "" FORCE)
Expand All @@ -34,4 +49,5 @@ add_library(jukebox::deps ALIAS jukebox-deps)

target_link_libraries(jukebox-deps INTERFACE
capo::capo
dr_wav
)
5 changes: 5 additions & 0 deletions library/include/juke/core/AudioFile.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once

#include <capo/buffer.hpp>
#include <juke/core/Common.hpp>
#include <juke/core/MediaFile.hpp>

namespace juke {
Expand All @@ -10,6 +11,10 @@ class AudioFile : public IMediaFile {
explicit AudioFile(std::filesystem::path const& path);

bool bind_to(capo::ISource& source) final { return source.bind_to(m_buffer); }
void set_cutoff(FilterType type, float to_cutoff, float sample_rate) override {}
void write_to_wav() override {}

[[nodiscard]] auto get_progress() const -> float { return 0.f; }

private:
std::shared_ptr<capo::Buffer> m_buffer{std::make_shared<capo::Buffer>()};
Expand Down
10 changes: 10 additions & 0 deletions library/include/juke/core/Common.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@

#pragma once

namespace juke {

enum class FilterType : std::uint8_t { high, low };

constexpr auto sample_rate_v = 44100.0f;

} // namespace juke
Loading
Loading