Add Psytrance Visualizer macOS app with Metal rendering
A complete audio-reactive visualizer for psytrance music featuring: Audio Analysis (DSPEngine): - FFT spectrum analysis via Accelerate/vDSP - 64-band Mel spectrogram - Sub-bass energy extraction (<100Hz) - Automatic sidechain pump detection - Harmonic-to-Noise ratio (HNR) calculation - Peak/transient detection 8 Visualization Modes (Metal Shaders): 1. FFT Classic - Frequency spectrum bars with glow 2. Mel Spectrogram - Waterfall display 3. Sub-Bass - Pulsating rings 4. Sidechain Pump - Breathing zoom effect 5. Harmonic/Noise - Geometric vs chaotic particles 6. Mandelbrot - Audio-reactive fractal zoom 7. Tunnel Warp - Infinite tunnel with distortion 8. DMT Geometry - Sacred geometry patterns Features: - Selectable audio input device (BlackHole support) - Configurable buffer size (512/1024) - Reactivity slider for visual intensity - Auto-hiding control panel - Fullscreen support with keyboard shortcuts (1-8, F, ESC) - Persistent settings via UserDefaults - Psytrance-inspired neon/UV color palette
This commit is contained in:
@@ -0,0 +1,90 @@
|
||||
//
|
||||
// AppSettings.swift
|
||||
// PsytranceVisualizer
|
||||
//
|
||||
// Persistent application settings
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
/// Application settings that are persisted between sessions
|
||||
struct AppSettings: Codable {
|
||||
/// Selected audio input device UID
|
||||
var selectedAudioDeviceUID: String?
|
||||
|
||||
/// Audio buffer size (512 or 1024 samples)
|
||||
var bufferSize: Int
|
||||
|
||||
/// Last used visualization mode (1-8)
|
||||
var lastVisualizationMode: Int
|
||||
|
||||
/// Reactivity slider value (0.0 - 1.0)
|
||||
var reactivity: Float
|
||||
|
||||
/// Whether app was in fullscreen mode
|
||||
var isFullscreen: Bool
|
||||
|
||||
/// Last window frame (for restoration)
|
||||
var windowFrame: CodableRect?
|
||||
|
||||
/// Volume/gain adjustment
|
||||
var inputGain: Float
|
||||
|
||||
/// Whether to show FPS counter
|
||||
var showFPS: Bool
|
||||
|
||||
/// Default settings
|
||||
static var `default`: AppSettings {
|
||||
AppSettings(
|
||||
selectedAudioDeviceUID: nil,
|
||||
bufferSize: 1024,
|
||||
lastVisualizationMode: 1,
|
||||
reactivity: 0.5,
|
||||
isFullscreen: false,
|
||||
windowFrame: nil,
|
||||
inputGain: 1.0,
|
||||
showFPS: false
|
||||
)
|
||||
}
|
||||
|
||||
/// Available buffer sizes
|
||||
static let availableBufferSizes = [512, 1024]
|
||||
|
||||
/// Validates and clamps settings to valid ranges
|
||||
mutating func validate() {
|
||||
// Clamp buffer size to valid options
|
||||
if !AppSettings.availableBufferSizes.contains(bufferSize) {
|
||||
bufferSize = 1024
|
||||
}
|
||||
|
||||
// Clamp visualization mode
|
||||
if lastVisualizationMode < 1 || lastVisualizationMode > 8 {
|
||||
lastVisualizationMode = 1
|
||||
}
|
||||
|
||||
// Clamp reactivity
|
||||
reactivity = max(0.0, min(1.0, reactivity))
|
||||
|
||||
// Clamp input gain
|
||||
inputGain = max(0.0, min(2.0, inputGain))
|
||||
}
|
||||
}
|
||||
|
||||
/// Codable wrapper for CGRect
|
||||
struct CodableRect: Codable {
|
||||
var x: Double
|
||||
var y: Double
|
||||
var width: Double
|
||||
var height: Double
|
||||
|
||||
init(from rect: CGRect) {
|
||||
self.x = Double(rect.origin.x)
|
||||
self.y = Double(rect.origin.y)
|
||||
self.width = Double(rect.size.width)
|
||||
self.height = Double(rect.size.height)
|
||||
}
|
||||
|
||||
var cgRect: CGRect {
|
||||
CGRect(x: x, y: y, width: width, height: height)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user