git.haldean.org qb / b340f54 nodeui.cpp
b340f54

Tree @b340f54 (Download .tar.gz)

nodeui.cpp @b340f54raw · history · blame

#include "qb.hpp"
#include "colors.hpp"
#include "nodeui.hpp"

#include "AudioFile/AudioFile.h"
#include "imgui.h"

#include <cmath>

namespace qb {

void draw(const std::shared_ptr<qb::audio_node> &node)
{
  ImGui::Text(node->path().c_str());

  switch (node->loadstate().stage) {
  case load_state::loading:
    ImGui::Text("%c loading: %s",
                (node->ctx()->spinstep / 90 % 2) ? '.' : ' ',
                node->loadstate().message.c_str());
    return;

  case load_state::failed:
    ImGui::Text("failed to load file");
    return;

  case load_state::loaded: {
    qb::audio_file_cptr data = node->data();
    if (!data) {
      ImGui::Text("audio file is invalid\n");
    }
    double seconds = data->getLengthInSeconds();
    const int minutes = (int) floor(seconds / 60.0);
    seconds -= 60 * minutes;

    ImGui::Text("sample rate %d depth %d samples %d channels %d length %dm%0.3fs",
                data->getSampleRate(),
                data->getBitDepth(),
                data->getNumSamplesPerChannel(),
                data->getNumChannels(),
                minutes, seconds);

    const std::vector<float> &r = node->rendered();

    const context *c = node->ctx();
    const int rad = 40;
    const double rsamplerate = node->rsamplerate();
    const int64_t s0 = (long) floor(rsamplerate * (c->playhead - c->visrad));
    const int64_t s1 = (long) ceil(rsamplerate * (c->playhead + c->visrad));

    ImGui::InvisibleButton("##empty", ImVec2(-1, 2 * rad));
    const ImVec2 origin = ImVec2(0, ImGui::GetItemRectMin().y);
    const ImVec2 corner =
        ImVec2(ImGui::GetWindowWidth(), ImGui::GetItemRectMax().y);
    const double width = corner.x - origin.x;
    const double scale = width / (s1 - s0);

    ImDrawList * const drawlist = ImGui::GetWindowDrawList();
    for (int64_t s = std::max(int64_t(1), s0 + 1);
         s <= s1 && s < (int64_t) r.size(); s++) {
      const ImVec2 a(origin.x + scale * (s - 1 - s0),
                     origin.y + rad * (1.0 - r[s - 1]));
      const ImVec2 b(origin.x + scale * (s - s0),
                     origin.y + rad * (1.0 - r[s]));
      drawlist->AddLine(a, b, theme::colors[theme::color::waveform]);
    }
  }
  }
}

template <class To, class From>
std::shared_ptr<To> checked_cast(const std::shared_ptr<From> &p) {
  const auto res = std::dynamic_pointer_cast<To>(p);
  if (!res) {
    throw ("bad cast to " + std::string(typeid(To).name()));
  }
  return res;
}

void draw_node(const qb::node_ptr &node)
{
  switch (node->type()) {
  case qb::node_type::audio:
    draw(checked_cast<qb::audio_node>(node));
    return;
  case qb::node_type::midi:
    ImGui::Text("no drawing for midi nodes yet");
    break;
  case qb::node_type::osc:
    ImGui::Text("no drawing for osc nodes yet");
    break;
  }
}

}