feat: add stereo waveform orbit rings
Two perpendicular line-loop rings orbit the sphere, the blue ring modulated by CH1 and the orange ring by CH2, toggled with key 2.
This commit is contained in:
@@ -0,0 +1,50 @@
|
||||
#include "OrbitRings.h"
|
||||
#include <cmath>
|
||||
|
||||
void OrbitRings::setup(int pointsPerRing) {
|
||||
n_ = pointsPerRing;
|
||||
ring1_.clear();
|
||||
ring2_.clear();
|
||||
ring1_.setMode(OF_PRIMITIVE_LINE_LOOP);
|
||||
ring2_.setMode(OF_PRIMITIVE_LINE_LOOP);
|
||||
for (int i = 0; i < n_; ++i) {
|
||||
ring1_.addVertex(glm::vec3(0.0f));
|
||||
ring2_.addVertex(glm::vec3(0.0f));
|
||||
}
|
||||
}
|
||||
|
||||
void OrbitRings::setWaveform(const std::vector<float>& ch1,
|
||||
const std::vector<float>& ch2) {
|
||||
const float twoPi = 6.28318530718f;
|
||||
auto rebuild = [&](ofVboMesh& ring, const std::vector<float>& src,
|
||||
bool xzPlane) {
|
||||
const int n = static_cast<int>(src.size());
|
||||
for (int i = 0; i < n_; ++i) {
|
||||
const float theta = twoPi * static_cast<float>(i) / n_;
|
||||
float s = 0.0f;
|
||||
if (n > 0) {
|
||||
int idx = static_cast<int>(
|
||||
static_cast<long long>(i) * n / n_);
|
||||
if (idx >= n) idx = n - 1;
|
||||
s = src[idx];
|
||||
}
|
||||
const float r = baseRadius_ + amp_ * s;
|
||||
const glm::vec3 p = xzPlane
|
||||
? glm::vec3(r * std::cos(theta), 0.0f, r * std::sin(theta))
|
||||
: glm::vec3(r * std::cos(theta), r * std::sin(theta), 0.0f);
|
||||
ring.setVertex(i, p);
|
||||
}
|
||||
};
|
||||
rebuild(ring1_, ch1, true);
|
||||
rebuild(ring2_, ch2, false);
|
||||
}
|
||||
|
||||
void OrbitRings::draw() {
|
||||
ofPushStyle();
|
||||
ofSetLineWidth(2.0f);
|
||||
ofSetColor(80, 200, 255);
|
||||
ring1_.draw();
|
||||
ofSetColor(255, 140, 80);
|
||||
ring2_.draw();
|
||||
ofPopStyle();
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
#include "ofMain.h"
|
||||
#include <vector>
|
||||
|
||||
// GL visual unit: two line-loop rings orbiting the sphere in
|
||||
// perpendicular planes. Ring 1 follows CH1, ring 2 follows CH2; each
|
||||
// point's orbit radius is modulated by the live waveform.
|
||||
class OrbitRings {
|
||||
public:
|
||||
void setup(int pointsPerRing);
|
||||
void setWaveform(const std::vector<float>& ch1,
|
||||
const std::vector<float>& ch2);
|
||||
void draw();
|
||||
|
||||
private:
|
||||
int n_ = 0;
|
||||
float baseRadius_ = 300.0f;
|
||||
float amp_ = 70.0f;
|
||||
ofVboMesh ring1_; // CH1, XZ plane
|
||||
ofVboMesh ring2_; // CH2, XY plane
|
||||
};
|
||||
@@ -12,6 +12,7 @@ void ofApp::setup() {
|
||||
cam_.setFarClip(5000.0f);
|
||||
|
||||
sphere_.setup(5, 512, 256, 1024);
|
||||
rings_.setup(512);
|
||||
|
||||
hantek_.setSampleRate(16000000u);
|
||||
const oscope::HantekStatus st = hantek_.start();
|
||||
@@ -47,6 +48,7 @@ void ofApp::update() {
|
||||
sphere_.pushSpectrogramColumn(analyzerCh1_.magDown(),
|
||||
analyzerCh2_.magDown());
|
||||
sphere_.setWaveform(buf1_, buf2_);
|
||||
rings_.setWaveform(buf1_, buf2_);
|
||||
}
|
||||
|
||||
void ofApp::draw() {
|
||||
@@ -54,6 +56,7 @@ void ofApp::draw() {
|
||||
ofPushMatrix();
|
||||
ofRotateYDeg(ofGetElapsedTimef() * 6.0f);
|
||||
if (layerA_) sphere_.drawSkin();
|
||||
if (layerB_) rings_.draw();
|
||||
ofPopMatrix();
|
||||
cam_.end();
|
||||
drawHud();
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "AudioAnalyzer.h"
|
||||
#include "DemoSignal.h"
|
||||
#include "SphereViz.h"
|
||||
#include "OrbitRings.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@@ -23,6 +24,7 @@ private:
|
||||
oscope::DemoSignal demo_{48000.0f};
|
||||
|
||||
SphereViz sphere_;
|
||||
OrbitRings rings_;
|
||||
ofEasyCam cam_;
|
||||
|
||||
std::vector<float> buf1_;
|
||||
|
||||
Reference in New Issue
Block a user