Files
dusklight/src/dusk/imgui/ImGuiAudio.cpp
T

340 lines
11 KiB
C++

#include "ImGuiConsole.hpp"
#include "ImGuiMenuTools.hpp"
#include <cmath>
#include "JSystem/JAudio2/JAISeq.h"
#include "JSystem/JAudio2/JAISeMgr.h"
#include "JSystem/JAudio2/JAISeqMgr.h"
#include "JSystem/JAudio2/JAIStreamMgr.h"
#include "JSystem/JAudio2/JASCriticalSection.h"
#include "JSystem/JAudio2/JASDSPChannel.h"
#include "JSystem/JAudio2/JASDSPInterface.h"
#include "JSystem/JAudio2/JASTrack.h"
#include "dusk/audio/DuskAudioSystem.h"
#include "dusk/audio/DuskDsp.hpp"
static std::array<u8, DSP_CHANNELS> channelSortIndices = {};
static std::array<u32, DSP_CHANNELS> lastResetCounts = {};
static bool sortUpdateCount = true;
static void DrawDirectionGauge(float pan, float dolby) {
constexpr float R = 20.0f;
constexpr float SIZE = R * 2.0f + 4.0f;
ImVec2 origin = ImGui::GetCursorScreenPos();
ImGui::Dummy(ImVec2(SIZE, SIZE));
ImDrawList* dl = ImGui::GetWindowDrawList();
ImVec2 c = ImVec2(origin.x + SIZE * 0.5f, origin.y + SIZE * 0.5f);
dl->AddCircle(c, R, IM_COL32(90, 90, 90, 255), 32);
float dx = (pan - 0.5f) * 2.0f;
float dy = dolby * 2.0f - 1.0f;
float len = sqrtf(dx * dx + dy * dy);
if (len > 1.0f) { dx /= len; dy /= len; }
dl->AddLine(c, ImVec2(c.x + dx * R, c.y + dy * R), IM_COL32(255, 200, 50, 255), 1.5f);
}
static void DisplayDspChannel(int i) {
using namespace dusk::audio;
auto& channel = JASDsp::CH_BUF[i];
auto& jasChannel = JASDSPChannel::sDspChannels[i];
if (!channel.mIsActive) {
return;
}
char buf[64];
snprintf(buf, sizeof(buf), "%d", i);
if (ImGui::BeginChild(buf, ImVec2(), ImGuiChildFlags_Border | ImGuiChildFlags_AutoResizeY)) {
ImGui::Text("[%02X]", i);
ImGui::SameLine();
auto resetCount = GetResetCount(i);
ImColor color = IM_COL32_WHITE;
if (lastResetCounts[i] != resetCount) {
lastResetCounts[i] = resetCount;
color = IM_COL32(0, 0xFF, 0, 0xFF);
}
ImGui::TextColored(color, "Update count: %d, reset count: %ud", jasChannel.mUpdateCounter, resetCount);
ImGui::TextUnformatted(channel.mLoopFlag ? "Loop: true" : "Loop: false");
ImGui::SameLine();
ImGui::Text("Priority: %hd", jasChannel.mPriority);
ImGui::Text("Format: %02X/%02X", channel.mSamplesPerBlock, channel.mBytesPerBlock);
ImGui::Text("Position: %08X/%08X", channel.mSamplePosition, channel.mEndSample);
ImGui::SameLine();
ImGui::Text("Memory: %08X/%08X", channel.mWaveAramAddress, channel.mAramStreamPosition);
if (channel.mAutoMixerBeenSet) {
auto pan = (channel.mAutoMixerPanDolby >> 8) / 127.5f;
auto dolby = (channel.mAutoMixerPanDolby & 0xFF) / 127.5f;
auto fxMix = (channel.mAutoMixerFxMix >> 8) / 127.5f;
auto volume = VolumeFromU16(channel.mAutoMixerVolume);
auto pitch = channel.mPitch / 4096.0f;
DrawDirectionGauge(pan, dolby);
ImGui::SameLine();
ImGui::Text(
"pan: %.2f dolby: %.2f\nfx: %.2f vol: %.2f pitch: %.2f",
pan, dolby, fxMix, volume, pitch);
} else {
ImGui::Text(
"Bus connect: %04X(%.2f),%04X(%.2f),%04X(%.2f),%04X(%.2f),%04X(%.2f),%04X(%.2f)",
channel.mOutputChannels[0].mBusConnect,
VolumeFromU16(channel.mOutputChannels[0].mTargetVolume),
channel.mOutputChannels[1].mBusConnect,
VolumeFromU16(channel.mOutputChannels[1].mTargetVolume),
channel.mOutputChannels[2].mBusConnect,
VolumeFromU16(channel.mOutputChannels[2].mTargetVolume),
channel.mOutputChannels[3].mBusConnect,
VolumeFromU16(channel.mOutputChannels[3].mTargetVolume),
channel.mOutputChannels[4].mBusConnect,
VolumeFromU16(channel.mOutputChannels[4].mTargetVolume),
channel.mOutputChannels[5].mBusConnect,
VolumeFromU16(channel.mOutputChannels[5].mTargetVolume));
}
}
ImGui::EndChild();
}
static void InitChannelSortIndices() {
for (int i = 0; i < channelSortIndices.size(); i++) {
channelSortIndices[i] = i;
}
}
static void SortChannelsByUpdateCount() {
InitChannelSortIndices();
std::ranges::stable_sort(
channelSortIndices,
[](u8 a, u8 b) {
auto& jasChannelA = JASDSPChannel::sDspChannels[a];
auto& jasChannelB = JASDSPChannel::sDspChannels[b];
return jasChannelA.mUpdateCounter > jasChannelB.mUpdateCounter;
});
}
static void ShowAllDspChannels() {
int activeChannels = 0;
for (int i = 0; i < DSP_CHANNELS; i++) {
if (JASDsp::CH_BUF[i].mIsActive) {
activeChannels++;
}
}
ImGui::Text("Active channels: %d", activeChannels);
ImGui::Checkbox("Dump channels to disk", &dusk::audio::DumpAudio);
ImGui::Checkbox("Sort by update count", &sortUpdateCount);
if (sortUpdateCount) {
SortChannelsByUpdateCount();
for (u8 index : channelSortIndices) {
DisplayDspChannel(index);
}
} else {
for (int i = 0; i < DSP_CHANNELS; i++) {
DisplayDspChannel(i);
}
}
}
static void ShowAllTracks() {
if (ImGui::Button("Pause all")) {
for (auto& track : JASTrack::sTrackList) {
track.pause(true);
}
}
for (auto& track : JASTrack::sTrackList) {
char buf[32];
snprintf(buf, sizeof(buf), "%p", &track);
if (ImGui::BeginChild(buf, ImVec2(), ImGuiChildFlags_Border | ImGuiChildFlags_AutoResizeY)) {
ImGui::Text("[%p]", &track);
bool paused = track.mFlags.pause;
ImGui::Checkbox("Paused", &paused);
track.mFlags.pause = paused;
bool muted = track.mFlags.mute;
ImGui::Checkbox("Muted", &muted);
track.mFlags.mute = muted;
for (int i = 0; i < JASTrack::MAX_CHILDREN; i++) {
const auto child = track.getChild(i);
if (child != nullptr) {
ImGui::Text("child: [%p]", child);
}
}
}
ImGui::EndChild();
}
}
static void ShowAllJAIStreams() {
auto& mgr = *JAIStreamMgr::getInstance();
for (auto streamLink = mgr.getStreamList()->getFirst(); streamLink != nullptr; streamLink = streamLink->getNext()) {
auto& stream = *streamLink->getObject();
char buf[32];
snprintf(buf, sizeof(buf), "%p", &stream);
if (ImGui::BeginChild(buf, ImVec2(), ImGuiChildFlags_Border | ImGuiChildFlags_AutoResizeY)) {
ImGui::Text("[%p]", &stream);
bool paused = stream.status_.field_0x0.flags.paused;
ImGui::Checkbox("Paused", &paused);
stream.status_.field_0x0.flags.paused = paused;
}
ImGui::EndChild();
}
}
static void ShowAllJAISes() {
auto& mgr = *JAISeMgr::getInstance();
for (int i = 0; i < JAISeMgr::NUM_CATEGORIES; i++) {
const auto category = mgr.getCategory(i);
char buf[32];
snprintf(buf, sizeof(buf), "%i", i);
if (ImGui::BeginChild(buf, ImVec2(), ImGuiChildFlags_Border | ImGuiChildFlags_AutoResizeY)) {
ImGui::Text("Category: %i", i);
if (ImGui::Button("Pause All")) {
category->pause(true);
}
ImGui::SameLine();
if (ImGui::Button("Resume All")) {
category->pause(false);
}
for (auto seLink = category->getSeList()->getFirst(); seLink != nullptr; seLink = seLink->getNext()) {
const auto se = seLink->getObject();
ImGui::Text("[%p]", se);
ImGui::Text(se->status_.field_0x0.flags.paused ? "Paused" : "Not paused");
}
}
ImGui::EndChild();
}
}
static void ShowSeqTracks(JAISeq& seq) {
JASTrack& root = seq.inner_.outputTrack;
for (int group = 0; group < 2; group++) {
JASTrack* groupTrack = root.getChild(group);
if (groupTrack == nullptr) {
continue;
}
for (int j = 0; j < JASTrack::MAX_CHILDREN; j++) {
JASTrack* track = groupTrack->getChild(j);
if (track == nullptr) {
continue;
}
int trackIdx = group * 16 + j;
char label[64];
snprintf(label, sizeof(label), "Track %d (bank %hu, prog %hu)##%p",
trackIdx, track->getBankNumber(), track->getProgNumber(), track);
bool muted = track->mFlags.mute;
if (ImGui::Checkbox(label, &muted)) {
track->mute(muted);
}
}
}
}
static void ShowAllJAISeqs() {
auto& mgr = *JAISeqMgr::getInstance();
if (ImGui::Button("Pause")) {
mgr.pause(true);
}
ImGui::SameLine();
if (ImGui::Button("Unpause")) {
mgr.pause(false);
}
ImGui::Text("Active sequences: %d", mgr.getNumActiveSeqs());
auto* seqList = mgr.getSeqList();
for (auto* link = seqList->getFirst(); link != nullptr; link = link->getNext()) {
JAISeq* seq = link->getObject();
if (seq == nullptr) {
continue;
}
char buf[32];
snprintf(buf, sizeof(buf), "%p", seq);
if (ImGui::BeginChild(buf, ImVec2(), ImGuiChildFlags_Border | ImGuiChildFlags_AutoResizeY)) {
ImGui::Text("Seq [%p]", seq);
ShowSeqTracks(*seq);
}
ImGui::EndChild();
}
}
void dusk::ImGuiMenuTools::ShowAudioDebug() {
if (!getSettings().backend.enableAdvancedSettings ||
!ImGuiConsole::CheckMenuViewToggle(ImGuiKey_F10, m_showAudioDebug))
{
return;
}
if (!ImGui::Begin("Audio Debug", &m_showAudioDebug)) {
ImGui::End();
return;
}
{
JASCriticalSection cs;
if (ImGui::BeginTabBar("Tabs")) {
if (ImGui::BeginTabItem("DSP channels")) {
ShowAllDspChannels();
ImGui::EndTabItem();
}
if (ImGui::BeginTabItem("JAITrack")) {
ShowAllTracks();
ImGui::EndTabItem();
}
if (ImGui::BeginTabItem("JAIStream")) {
ShowAllJAIStreams();
ImGui::EndTabItem();
}
if (ImGui::BeginTabItem("JAISe")) {
ShowAllJAISes();
ImGui::EndTabItem();
}
if (ImGui::BeginTabItem("JAISeq")) {
ShowAllJAISeqs();
ImGui::EndTabItem();
}
ImGui::EndTabBar();
}
}
ImGui::End();
}
void dusk::ImGuiMenuTools::ShowSaveEditor() {
if (!getSettings().backend.enableAdvancedSettings ||
!ImGuiConsole::CheckMenuViewToggle(ImGuiKey_F6, m_showSaveEditor))
{
return;
}
m_saveEditor.draw(m_showSaveEditor);
}