Skip to content

Commit 5f92017

Browse files
committed
GUI - various visualiser improvements
1 parent 5112d02 commit 5f92017

10 files changed

Lines changed: 384 additions & 191 deletions

File tree

app/api/include/api/audio/audio_processor.h

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
#include <vector>
2222
#include "server_shm.hpp"
2323

24-
#include "kiss_fft.h"
24+
#include "kiss_fftr.h"
2525

2626
#include "api/sonicpi_api.h"
2727

@@ -43,6 +43,7 @@ class AudioProcessor
4343
void Enable(bool start);
4444
void SetConsumed(bool consumed);
4545
void SetMaxBuckets(int maxBuckets);
46+
void SetSampleRate(int sampleRate);
4647
void Quit();
4748
// Force re-attach to the scope shared memory — public so callers can
4849
// invoke after a cold-swap device change to refresh the stale reader.
@@ -73,8 +74,7 @@ class AudioProcessor
7374
native_stats GetNativeStats(); // synthdef count, allocated buffers + bytes
7475

7576
private:
76-
void GenLogSpace(uint32_t limit, uint32_t n);
77-
void GenLinSpace(uint32_t limit, uint32_t n);
77+
void GenFreqPartitions(uint32_t buckets, int sampleRate);
7878
void SetupFFT();
7979
void CalculateFFT(ProcessedAudio& audio);
8080

@@ -92,16 +92,26 @@ class AudioProcessor
9292
std::atomic<int> m_maxBuckets = { 0 };
9393
std::atomic<bool> m_quit = { false };
9494
std::atomic<bool> m_consumed = { false };
95+
std::atomic<int> m_sampleRate = { 48000 };
9596

96-
// FFT
97-
kiss_fft_cfg m_cfg;
98-
std::vector<std::complex<float>> m_fftIn[2];
97+
// FFT (real-input: N real samples in, N/2+1 complex bins out)
98+
kiss_fftr_cfg m_cfg;
99+
std::vector<kiss_fft_scalar> m_fftIn[2];
99100
std::vector<std::complex<float>> m_fftOut[2];
100-
std::vector<float> m_fftMag[2];
101+
// Per-bin power (|X|^2 amplitude-corrected), bucket-averaged in the
102+
// power domain before conversion to dB
103+
std::vector<float> m_fftPower[2];
101104
std::vector<float> m_window;
102-
std::vector<float> m_spectrumPartitions;
105+
// Bucket edges in bin space (buckets+1 entries), log-spaced in frequency
106+
std::vector<uint32_t> m_spectrumPartitions;
103107
std::pair<uint32_t, uint32_t> m_lastSpectrumPartitions = { 0, 0 };
104108

109+
// Display ballistics: instant attack / timed release per bucket, plus
110+
// slowly-falling peak-hold markers
111+
std::vector<float> m_bucketSmoothed[2];
112+
std::vector<float> m_bucketPeak[2];
113+
std::vector<int> m_bucketPeakAge[2];
114+
105115
// Output data, double buffered
106116
ProcessedAudio m_processedAudio;
107117

app/api/include/api/sonicpi_api.h

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include <atomic>
44
#include <fstream>
55
#include <map>
6+
#include <memory>
67
#include <string>
78
#include <thread>
89
#include <vector>
@@ -123,12 +124,21 @@ struct CueInfo
123124
// This is the processed audio data from the thread
124125
struct ProcessedAudio
125126
{
126-
std::vector<float> m_spectrum[2];
127+
// Per-bucket display values (ballistics applied: instant attack,
128+
// timed release) and slowly-falling peak-hold markers. Buckets are
129+
// log-spaced in frequency between m_spectrumFreqMin/Max.
127130
std::vector<float> m_spectrumQuantized[2];
131+
std::vector<float> m_spectrumPeaks[2];
132+
float m_spectrumFreqMin = 30.0f;
133+
float m_spectrumFreqMax = 20000.0f;
128134
std::vector<float> m_samples[2];
129135
std::vector<float> m_monoSamples;
130136
};
131137

138+
// Immutable per-frame snapshot shared between the audio-processor thread
139+
// and the GUI without further copying.
140+
using ProcessedAudioPtr = std::shared_ptr<const ProcessedAudio>;
141+
132142
enum class MessageType
133143
{
134144
StartupError,
@@ -295,7 +305,7 @@ struct IAPIClient
295305
virtual void Cue(const CueInfo& info) = 0;
296306
virtual void Midi(const MidiInfo& info) = 0;
297307
virtual void Version(const VersionInfo& info) = 0;
298-
virtual void AudioDataAvailable(const ProcessedAudio& audio) = 0;
308+
virtual void AudioDataAvailable(ProcessedAudioPtr audio) = 0;
299309
virtual void Buffer(const BufferInfo& info) = 0;
300310
virtual void ActiveLinks(const int numLinks) = 0;
301311
virtual void BPM(const double bpm) = 0;
@@ -424,6 +434,10 @@ class SonicPiAPI
424434
// Set Max FFT buckets to generate
425435
virtual void AudioProcessor_SetMaxFFTBuckets(uint32_t buckets);
426436

437+
// Engine sample rate — used to map FFT bins to frequencies for the
438+
// log-spaced spectrum buckets
439+
virtual void AudioProcessor_SetSampleRate(int sampleRate);
440+
427441
// Force the audio processor to reconnect to the scope shared memory.
428442
// Call after a cold-swap device change so the scope picks up the
429443
// freshly-allocated scope buffer from the rebuilt World.

0 commit comments

Comments
 (0)