Class: Vizcore::Analysis::Pipeline
- Inherits:
-
Object
- Object
- Vizcore::Analysis::Pipeline
- Defined in:
- lib/vizcore/analysis/pipeline.rb
Overview
End-to-end analysis pipeline from PCM samples to renderer-ready features.
Constant Summary collapse
- BEAT_PULSE_DECAY =
0.86- BEAT_PULSE_FLOOR =
0.001- DEFAULT_NOISE_GATE =
0.01- DEFAULT_AUDIO_NORMALIZE =
{ mode: :off }.freeze
- SILENCE_RESET_FRAMES =
90
Instance Attribute Summary collapse
-
#band_splitter ⇒ Object
readonly
Returns the value of attribute band_splitter.
-
#beat_detector ⇒ Object
readonly
Returns the value of attribute beat_detector.
-
#bpm_estimator ⇒ Object
readonly
Returns the value of attribute bpm_estimator.
-
#fft_processor ⇒ Object
readonly
Returns the value of attribute fft_processor.
-
#smoother ⇒ Object
readonly
Returns the value of attribute smoother.
Instance Method Summary collapse
-
#audio_normalize=(settings) ⇒ Hash
Normalized settings.
- #bpm_lock=(settings) ⇒ Float?
-
#call(samples) ⇒ Hash
Normalized analysis payload consumed by frame broadcaster.
-
#initialize(sample_rate: 44_100, fft_size: 1024, window: :hamming, beat_detector: nil, bpm_estimator: nil, smoother: nil, noise_gate: DEFAULT_NOISE_GATE, audio_normalize: nil, bpm: nil, bpm_lock: false) ⇒ Pipeline
constructor
A new instance of Pipeline.
Constructor Details
#initialize(sample_rate: 44_100, fft_size: 1024, window: :hamming, beat_detector: nil, bpm_estimator: nil, smoother: nil, noise_gate: DEFAULT_NOISE_GATE, audio_normalize: nil, bpm: nil, bpm_lock: false) ⇒ Pipeline
Returns a new instance of Pipeline.
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
# File 'lib/vizcore/analysis/pipeline.rb', line 25 def initialize(sample_rate: 44_100, fft_size: 1024, window: :hamming, beat_detector: nil, bpm_estimator: nil, smoother: nil, noise_gate: DEFAULT_NOISE_GATE, audio_normalize: nil, bpm: nil, bpm_lock: false) @fft_processor = FFTProcessor.new(sample_rate: sample_rate, fft_size: fft_size, window: window) @band_splitter = BandSplitter.new(sample_rate: sample_rate, fft_size: fft_size) @beat_detector = beat_detector || BeatDetector.new @analysis_frame_rate = sample_rate.to_f / fft_size.to_f @bpm_estimator = bpm_estimator || BPMEstimator.new(frame_rate: @analysis_frame_rate) @smoother = smoother || Smoother.new(alpha: 0.35) @noise_gate = normalize_noise_gate(noise_gate) self.bpm_lock = { bpm: bpm, locked: bpm_lock } self.audio_normalize = audio_normalize @beat_pulse = 0.0 @last_bpm = 0.0 @silent_frame_count = 0 @previous_onset_amplitude = 0.0 @previous_onset_bands = {} end |
Instance Attribute Details
#band_splitter ⇒ Object (readonly)
Returns the value of attribute band_splitter.
13 14 15 |
# File 'lib/vizcore/analysis/pipeline.rb', line 13 def band_splitter @band_splitter end |
#beat_detector ⇒ Object (readonly)
Returns the value of attribute beat_detector.
13 14 15 |
# File 'lib/vizcore/analysis/pipeline.rb', line 13 def beat_detector @beat_detector end |
#bpm_estimator ⇒ Object (readonly)
Returns the value of attribute bpm_estimator.
13 14 15 |
# File 'lib/vizcore/analysis/pipeline.rb', line 13 def bpm_estimator @bpm_estimator end |
#fft_processor ⇒ Object (readonly)
Returns the value of attribute fft_processor.
13 14 15 |
# File 'lib/vizcore/analysis/pipeline.rb', line 13 def fft_processor @fft_processor end |
#smoother ⇒ Object (readonly)
Returns the value of attribute smoother.
13 14 15 |
# File 'lib/vizcore/analysis/pipeline.rb', line 13 def smoother @smoother end |
Instance Method Details
#audio_normalize=(settings) ⇒ Hash
Returns normalized settings.
44 45 46 47 |
# File 'lib/vizcore/analysis/pipeline.rb', line 44 def audio_normalize=(settings) @audio_normalize = normalize_audio_normalize(settings) @normalizer = build_normalizer(@audio_normalize) end |
#bpm_lock=(settings) ⇒ Float?
51 52 53 54 55 |
# File 'lib/vizcore/analysis/pipeline.rb', line 51 def bpm_lock=(settings) values = symbolize_hash(settings) @locked_bpm = normalize_locked_bpm(values[:bpm], bpm_lock: values[:locked]) @last_bpm = @locked_bpm if @locked_bpm end |
#call(samples) ⇒ Hash
Returns normalized analysis payload consumed by frame broadcaster.
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 |
# File 'lib/vizcore/analysis/pipeline.rb', line 59 def call(samples) amplitude = rms(samples) if silence?(amplitude) track_silent_frame(samples) return silent_frame(reset_tempo: sustained_silence?) end @silent_frame_count = 0 fft = @fft_processor.call(samples) bands = @band_splitter.call(fft[:magnitudes]) beat = @beat_detector.call(samples) beat_detected = beat[:beat] confidence = beat_confidence(beat) @beat_pulse = beat_detected ? 1.0 : @beat_pulse * BEAT_PULSE_DECAY @beat_pulse = 0.0 if @beat_pulse < BEAT_PULSE_FLOOR bpm = resolve_bpm(beat_detected) normalized = normalize_features( amplitude: amplitude, bands: bands, fft: preview_spectrum(fft[:magnitudes]) ) onsets = detect_onsets(amplitude: normalized[:amplitude], bands: normalized[:bands]) drums = detect_drum_sources(bands: normalized[:bands], onsets: onsets[:bands]) { amplitude: @smoother.smooth(:amplitude, normalized[:amplitude]), bands: @smoother.smooth_hash(normalized[:bands], namespace: :bands), fft: @smoother.smooth_array(normalized[:fft], namespace: :fft), onset: onsets[:amplitude], onsets: onsets[:bands], drums: drums, beat: beat_detected, beat_confidence: confidence, beat_pulse: @beat_pulse, beat_count: beat[:beat_count], bpm: bpm, peak_frequency: fft[:peak_frequency] } end |