Add bpm light changer

This commit is contained in:
illyum 2024-08-09 14:05:51 -06:00
parent 9b738c359d
commit 332d3e3b33
4 changed files with 256 additions and 6 deletions

View File

@ -15,7 +15,7 @@ set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_STANDARD_REQUIRED True)
set(FETCHCONTENT_QUIET OFF)
add_executable(${PROJECT_NAME} main.cpp tinyfiledialogs.c)
add_executable(${PROJECT_NAME} main.cpp tinyfiledialogs.c timeline.cpp)
include(FetchContent)
FetchContent_Declare(

79
ImSequencer.h Normal file
View File

@ -0,0 +1,79 @@
// https://github.com/CedricGuillemet/ImGuizmo
// v 1.89 WIP
//
// The MIT License(MIT)
//
// Copyright(c) 2021 Cedric Guillemet
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files(the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions :
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
#pragma once
#include <cstddef>
struct ImDrawList;
struct ImRect;
namespace ImSequencer
{
enum SEQUENCER_OPTIONS
{
SEQUENCER_EDIT_NONE = 0,
SEQUENCER_EDIT_STARTEND = 1 << 1,
SEQUENCER_CHANGE_FRAME = 1 << 3,
SEQUENCER_ADD = 1 << 4,
SEQUENCER_DEL = 1 << 5,
SEQUENCER_COPYPASTE = 1 << 6,
SEQUENCER_EDIT_ALL = SEQUENCER_EDIT_STARTEND | SEQUENCER_CHANGE_FRAME
};
struct SequenceInterface
{
bool focused = false;
virtual int GetFrameMin() const = 0;
virtual int GetFrameMax() const = 0;
virtual int GetItemCount() const = 0;
virtual void BeginEdit(int /*index*/) {}
virtual void EndEdit() {}
virtual int GetItemTypeCount() const { return 0; }
virtual const char* GetItemTypeName(int /*typeIndex*/) const { return ""; }
virtual const char* GetItemLabel(int /*index*/) const { return ""; }
virtual const char* GetCollapseFmt() const { return "%d Frames / %d entries"; }
virtual void Get(int index, int** start, int** end, int* type, unsigned int* color) = 0;
virtual void Add(int /*type*/) {}
virtual void Del(int /*index*/) {}
virtual void Duplicate(int /*index*/) {}
virtual void Copy() {}
virtual void Paste() {}
virtual size_t GetCustomHeight(int /*index*/) { return 0; }
virtual void DoubleClick(int /*index*/) {}
virtual void CustomDraw(int /*index*/, ImDrawList* /*draw_list*/, const ImRect& /*rc*/, const ImRect& /*legendRect*/, const ImRect& /*clippingRect*/, const ImRect& /*legendClippingRect*/) {}
virtual void CustomDrawCompact(int /*index*/, ImDrawList* /*draw_list*/, const ImRect& /*rc*/, const ImRect& /*clippingRect*/) {}
virtual ~SequenceInterface() = default;
};
// return true if selection is made
bool Sequencer(SequenceInterface* sequence, int* currentFrame, bool* expanded, int* selectedEntry, int* firstFrame, int sequenceOptions);
}

148
main.cpp
View File

@ -21,6 +21,7 @@ void sendDMXData(HANDLE hSerial, unsigned char* data, int length);
void setupImGui(GLFWwindow* window);
void renderImGui();
void renderImGuiBpm();
void renderTestImGui();
// ui timeline stuff
@ -34,6 +35,9 @@ float bpm = 120.0f; // Default BPM
float zoom_level = 1.0f; // Zoom level
float pan_offset = 0.0f; // Pan offset
// Calculate time per beat based on BPM
float beat_interval = 60.0f / bpm;
// audio stuff
ma_sound sound;
ma_engine engine;
@ -120,8 +124,10 @@ int main() {
ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame();
renderImGui();
renderImGuiBpm();
// renderImGui();
// renderImGuiBpm();
renderTestImGui();
ImGui::Render();
@ -346,9 +352,6 @@ void setupImGui(GLFWwindow* window) {
}
void renderImGui() {
// Calculate time per beat based on BPM
float beat_interval = 60.0f / bpm;
// Temporary variables to hold the slider values
int channel1 = buffer[0];
int channel2 = buffer[1];
@ -671,3 +674,138 @@ void renderImGuiBpm() {
ImGui::End();
}
void renderTestImGui() {
ImGui::Begin("Timeline");
// Time Slider (Timeline Position)
ImGui::SliderFloat("Timeline Position", &timeline_position, 0.0f, timeline_duration, "%.2f sec");
// Custom timeline rendering with grid lines
ImGui::Text("Timeline");
ImGui::PushID("CustomTimeline");
ImGui::BeginChild("##Timeline", ImVec2(ImGui::GetContentRegionAvail().x, 150), true);
// Draw grid lines for beats
ImDrawList* draw_list = ImGui::GetWindowDrawList();
ImVec2 cursor_pos = ImGui::GetCursorScreenPos();
float timeline_width = ImGui::GetContentRegionAvail().x;
// Draw the audio waveform if loaded
if (audioDataLoaded && !downsampledAudioSamples.empty()) {
float timelineHeight = 100.0f; // Total height of the timeline
float waveformHeight = timelineHeight / 2.0f; // Waveform takes half the height of the timeline
float yOffset = cursor_pos.y + timelineHeight / 2.0f; // Center the waveform vertically
int sampleCount = static_cast<int>(downsampledAudioSamples.size()) / 2;
// Adjust the scaling to fit the timeline duration
float pixelsPerSample = (timeline_width * zoom_level) / timeline_duration;
for (int i = 0; i < sampleCount - 1; ++i) {
float x1 = cursor_pos.x + i * pixelsPerSample;
float x2 = cursor_pos.x + (i + 1) * pixelsPerSample;
float y1_max = yOffset - (downsampledAudioSamples[i * 2] * waveformHeight);
float y1_min = yOffset - (downsampledAudioSamples[i * 2 + 1] * waveformHeight);
float y2_max = yOffset - (downsampledAudioSamples[(i + 1) * 2] * waveformHeight);
float y2_min = yOffset - (downsampledAudioSamples[(i + 1) * 2 + 1] * waveformHeight);
draw_list->AddLine(ImVec2(x1, y1_max), ImVec2(x2, y2_max), IM_COL32(0, 255, 0, 255), 1.0f);
draw_list->AddLine(ImVec2(x1, y1_min), ImVec2(x2, y2_min), IM_COL32(0, 255, 0, 255), 1.0f);
}
}
for (int i = 0; i <= static_cast<int>(timeline_duration / beat_interval); ++i) {
float beat_position = i * beat_interval * zoom_level - pan_offset;
float x_position = cursor_pos.x + (beat_position / timeline_duration) * timeline_width;
if (x_position >= cursor_pos.x && x_position <= cursor_pos.x + timeline_width) {
// Draw major beat line
if (i % 4 == 0) {
draw_list->AddLine(ImVec2(x_position, cursor_pos.y), ImVec2(x_position, cursor_pos.y + 100), IM_COL32(255, 0, 0, 255), 2.0f);
}
else {
// Draw minor beat line
draw_list->AddLine(ImVec2(x_position, cursor_pos.y), ImVec2(x_position, cursor_pos.y + 100), IM_COL32(255, 255, 255, 255), 1.0f);
}
}
}
// Draw the current timeline position marker
float position_marker = (timeline_position * zoom_level - pan_offset) / timeline_duration * timeline_width;
draw_list->AddLine(ImVec2(cursor_pos.x + position_marker, cursor_pos.y), ImVec2(cursor_pos.x + position_marker, cursor_pos.y + 100), IM_COL32(0, 0, 255, 255), 2.0f);
// Allow adding markers with snapping to grid
if (ImGui::Button("Add Marker")) {
float snap_position = std::round(timeline_position / beat_interval) * beat_interval;
markers.emplace_back(snap_position / timeline_duration, buffer[0], buffer[1], buffer[2]);
}
// Add Random Marker button
ImGui::SameLine();
if (ImGui::Button("Add Random Marker")) {
float snap_position = std::round(timeline_position / beat_interval) * beat_interval;
// Generate random colors
unsigned char r = rand() % 256;
unsigned char g = rand() % 256;
unsigned char b = rand() % 256;
// Add the marker with random colors
markers.emplace_back(snap_position / timeline_duration, r, g, b);
}
// Draw markers on the timeline
for (const auto& marker : markers) {
float marker_position = std::get<0>(marker) * timeline_duration * zoom_level - pan_offset;
float x_position = cursor_pos.x + (marker_position / timeline_duration) * timeline_width;
if (x_position >= cursor_pos.x && x_position <= cursor_pos.x + timeline_width) {
draw_list->AddRectFilled(ImVec2(x_position - 2.0f, cursor_pos.y), ImVec2(x_position + 2.0f, cursor_pos.y + 100), IM_COL32(0, 255, 0, 255));
}
}
ImGui::EndChild();
ImGui::PopID();
// Playback logic: Update timeline position based on playback time
if (is_playing) {
current_time = static_cast<float>(glfwGetTime()) - playback_start_time;
timeline_position = current_time;
for (const auto& marker : markers) {
float marker_time = std::get<0>(marker) * timeline_duration;
if (current_time >= marker_time && current_time < marker_time + 0.025f) {
buffer[0] = std::get<1>(marker);
buffer[1] = std::get<2>(marker);
buffer[2] = std::get<3>(marker);
}
}
if (timeline_position >= timeline_duration) {
is_playing = false;
timeline_position = timeline_duration;
if (audioLoaded) {
ma_sound_stop(&sound);
}
}
}
// Display added markers with their RGB values and time
for (const auto& marker : markers) {
float marker_time = std::get<0>(marker) * timeline_duration;
ImGui::Text("Marker at %.2f sec: R=%d, G=%d, B=%d",
marker_time,
std::get<1>(marker),
std::get<2>(marker),
std::get<3>(marker));
}
ImGui::End();
}

33
notes.md Normal file
View File

@ -0,0 +1,33 @@
https://github.com/epezent/implot
licences for tinyfiledialog and miniaudio
Might need drigers?
https://ftdichip.com/drivers/
On windows you can find the com port stuff using the `mode` command:
```
C:\Users\illyum>mode
Status for device COM3:
-----------------------
Baud: 1200
Parity: None
Data Bits: 7
Stop Bits: 1
Timeout: OFF
XON/XOFF: OFF
CTS handshaking: OFF
DSR handshaking: OFF
DSR sensitivity: OFF
DTR circuit: ON
RTS circuit: ON
Status for device CON:
----------------------
Lines: 9001
Columns: 135
Keyboard rate: 31
Keyboard delay: 1
Code page: 437
```