ruby_dsp 0.0.7 → 0.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +22 -19
- data/ext/ruby_dsp/ruby_dsp.cpp +166 -24
- data/lib/ruby_dsp/version.rb +1 -1
- data/stubs/ruby_dsp/audio_track.rb +74 -0
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d0352100ed3bc4d5984dd4b59ca7540eea006a7234eb2ed9a87ca88c61af3c91
|
|
4
|
+
data.tar.gz: 94b1b8182701c588618dbbe6e44f9135a73c62c9b8f174d745f5e807df379145
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 17e977dd018f850f37210a0d4cc9abd209ad276f51f62792fb240ccb94a8d096f8f8ff7d59a201b21cab38e048b901ed93e4ff9c89809c281d2b923816bb2641
|
|
7
|
+
data.tar.gz: d807466791df6a0f6cac661dc77e763cd03c5aeb2dd251d969054ff2bda5d0321735f4615819233f9ed9fdb9bb51f3b8b0eaf2e886d7269f29c1595aa616bc0d
|
data/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# [RubyDSP](https://github.com/cichrrad/rubyDSP) | [Documentation](https://www.rubydoc.info/gems/ruby_dsp/0.0.
|
|
1
|
+
# [RubyDSP](https://github.com/cichrrad/rubyDSP) | [Documentation](https://www.rubydoc.info/gems/ruby_dsp/0.0.8)
|
|
2
2
|
|
|
3
3
|
[](https://github.com/cichrrad/rubyDSP/actions/workflows/test.yml)
|
|
4
4
|
|
|
@@ -19,6 +19,8 @@ I made this gem to try hands-on binding these two languages together, as I would
|
|
|
19
19
|
|
|
20
20
|
* **Audio Synthesis & Sequencing:** Build multitrack, polyphonic audio from scratch using a (very limited) set of built-in mathematically generated waveforms (sine, square, sawtooth, and white noise).
|
|
21
21
|
|
|
22
|
+
* **DSP Filters & EQ:** A suite of filters (Low-pass, High-pass, Band-pass, Notch, and Shelving EQs) via `miniaudio`.
|
|
23
|
+
|
|
22
24
|
* **Format Agnostic Loading:** Automatically decodes standard audio formats (WAV, MP3, FLAC) via `miniaudio`.
|
|
23
25
|
> **Note:** While the loading of these formats is supported, `miniaudio` saves only in `.wav`. While other encodings might be considered in the future, they would require more dependencies and thus are not available right now.
|
|
24
26
|
|
|
@@ -26,6 +28,16 @@ I made this gem to try hands-on binding these two languages together, as I would
|
|
|
26
28
|
|
|
27
29
|
* **YARD Support:** Includes pure-Ruby stubs (in `stubs`, duh) for IDE autocomplete and inline documentation.
|
|
28
30
|
|
|
31
|
+
## Overview of Capabilities
|
|
32
|
+
|
|
33
|
+
* **File Operations:** `save_track`
|
|
34
|
+
* **Mutations:** `to_mono!`, `resample!`, `trim_silence!`, `normalize!`, `fade_in!`, `fade_out!`, `pad!`, `pad_to_duration!`, `clip!`
|
|
35
|
+
* **DSP Filters:** `low_pass!`, `high_pass!`, `band_pass!`, `notch!`, `peak_eq!`, `low_shelf!`, `high_shelf!`
|
|
36
|
+
* **Synthesis:** `add_wave!`
|
|
37
|
+
* **Analysis:** `duration`, `peak_amp`, `rms`, `framed_rms`, `zcr`, `framed_zcr`, `silence_bounds`
|
|
38
|
+
|
|
39
|
+
*(For full parameters and usage, please check the [API Documentation](https://www.rubydoc.info/gems/ruby_dsp/0.0.8))*
|
|
40
|
+
|
|
29
41
|
## Benchmarks & Performance
|
|
30
42
|
|
|
31
43
|
My primary motivation (love for Ruby aside) was to try and bring C++ speed to Ruby, avoiding the massive memory and garbage collection overhead of native Ruby math for audio/DSP tasks.
|
|
@@ -41,10 +53,10 @@ Benchmark script files are in `benchmark` directory. If you clone the repo for d
|
|
|
41
53
|
-----------------------------------------------------------------------------------------------
|
|
42
54
|
| Benchmark | C++ Speedup | Ruby Allocation | C++ Allocation |
|
|
43
55
|
-----------------------------------------------------------------------------------------------
|
|
44
|
-
| Read-Only (RMS) |
|
|
45
|
-
| Mutation (Normalize) |
|
|
46
|
-
| Complex (Framed RMS) |
|
|
47
|
-
| Dynamic (Add Wave) | 11.
|
|
56
|
+
| Read-Only (RMS) | 48.71x | 40 B (1 obj) | 64 B (1 obj) |
|
|
57
|
+
| Mutation (Normalize) | 69.47x | 3,528,040 B (1 obj) | 0 B (0 obj) |
|
|
58
|
+
| Complex (Framed RMS) | 48.68x | 41,264 B (860 obj) | 64 B (1 obj) |
|
|
59
|
+
| Dynamic (Add Wave) | 11.67x | N/A | N/A |
|
|
48
60
|
-----------------------------------------------------------------------------------------------
|
|
49
61
|
```
|
|
50
62
|
### Why is it faster?
|
|
@@ -75,7 +87,7 @@ $ gem install ruby_dsp
|
|
|
75
87
|
|
|
76
88
|
*(Note: Installing this gem requires a modern C++ compiler, as it builds the native extensions directly on your machine upon installation. It requires Ruby 3.0+).*
|
|
77
89
|
|
|
78
|
-
##
|
|
90
|
+
## Audio Processing
|
|
79
91
|
|
|
80
92
|
Here is a quick look at what you can do with a loaded `AudioTrack`. Thanks to the fluent API, you can process audio in a single readable chain:
|
|
81
93
|
|
|
@@ -91,6 +103,8 @@ puts track
|
|
|
91
103
|
# Process, edit, and save in one chain
|
|
92
104
|
track.to_mono! # Averages channels into mono
|
|
93
105
|
.resample!(44100) # Linearly resamples to target rate
|
|
106
|
+
.high_pass!(100) # Cuts out low-end rumble below 100Hz
|
|
107
|
+
.peak_eq!(1000, 3.0) # Boosts 1000Hz by 3dB for vocal clarity
|
|
94
108
|
.trim_silence!(-60.0) # Strips leading/trailing silence below -60dB
|
|
95
109
|
.normalize!(-1.0) # Scales audio to target peak dBFS
|
|
96
110
|
.pad_to_duration!(15.0) # Centers audio evenly into a 15s window
|
|
@@ -98,7 +112,7 @@ track.to_mono! # Averages channels into mono
|
|
|
98
112
|
.fade_out!(0.5) # Adds a 0.5s linear fade-out
|
|
99
113
|
.save_track("processed.wav") # Export the final result
|
|
100
114
|
|
|
101
|
-
# Analysis & Math
|
|
115
|
+
# Analysis & Math
|
|
102
116
|
puts "Peak Amp: #{track.peak_amp}"
|
|
103
117
|
puts "Overall RMS: #{track.rms}"
|
|
104
118
|
puts "Overall ZCR: #{track.zcr}"
|
|
@@ -107,7 +121,7 @@ puts "Overall ZCR: #{track.zcr}"
|
|
|
107
121
|
framed_rms_data = track.framed_rms(frame_length: 2048, hop_length: 512)
|
|
108
122
|
```
|
|
109
123
|
|
|
110
|
-
##
|
|
124
|
+
## Synthesis & Sequencing
|
|
111
125
|
|
|
112
126
|
Initialize an empty track and generate your own jam using `add_wave!`:
|
|
113
127
|
|
|
@@ -133,28 +147,17 @@ track.normalize!(-30.0) # This goes a long way for your hearing
|
|
|
133
147
|
|
|
134
148
|
#### **TWINKLE**
|
|
135
149
|
|
|
136
|
-
|
|
137
|
-
|
|
138
150
|
https://github.com/user-attachments/assets/af6dbaee-630f-49e3-9704-8ff3440334cb
|
|
139
151
|
|
|
140
|
-
|
|
141
|
-
|
|
142
152
|
#### **TETRIS**
|
|
143
153
|
|
|
144
|
-
|
|
145
|
-
|
|
146
154
|
https://github.com/user-attachments/assets/b3ad6886-3552-4200-b725-f14083f96792
|
|
147
155
|
|
|
148
|
-
|
|
149
|
-
|
|
150
156
|
#### **SUPER MARIO BROS**
|
|
151
157
|
|
|
152
|
-
|
|
153
|
-
|
|
154
158
|
https://github.com/user-attachments/assets/5193d72d-4c32-4c83-8253-206402ac2889
|
|
155
159
|
|
|
156
160
|
|
|
157
|
-
|
|
158
161
|
## Development
|
|
159
162
|
|
|
160
163
|
If you want to clone the repo and work on C++ guts, start with:
|
data/ext/ruby_dsp/ruby_dsp.cpp
CHANGED
|
@@ -170,7 +170,7 @@ struct AudioTrack
|
|
|
170
170
|
float max_val = 0.0f;
|
|
171
171
|
for (const auto &sample : samples)
|
|
172
172
|
{
|
|
173
|
-
max_val = std::
|
|
173
|
+
max_val = std::fmax(max_val, std::fabs(sample));
|
|
174
174
|
}
|
|
175
175
|
return max_val;
|
|
176
176
|
}
|
|
@@ -592,7 +592,7 @@ struct AudioTrack
|
|
|
592
592
|
float scale_factor = target_linear / current_peak;
|
|
593
593
|
|
|
594
594
|
// already at the target peak -- do nothing
|
|
595
|
-
if (std::
|
|
595
|
+
if (std::fabs(scale_factor - 1.0f) < 1e-5f)
|
|
596
596
|
return *this;
|
|
597
597
|
|
|
598
598
|
for (auto &sample : samples)
|
|
@@ -662,18 +662,13 @@ struct AudioTrack
|
|
|
662
662
|
unsigned long long head_samples = head_frames * channels;
|
|
663
663
|
unsigned long long tail_samples = tail_frames * channels;
|
|
664
664
|
|
|
665
|
-
//
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
samples.insert(samples.begin(), head_samples, 0.0f);
|
|
669
|
-
}
|
|
670
|
-
|
|
671
|
-
// pad the end
|
|
672
|
-
if (tail_samples > 0)
|
|
673
|
-
{
|
|
674
|
-
samples.insert(samples.end(), tail_samples, 0.0f);
|
|
675
|
-
}
|
|
665
|
+
// calculate total new size
|
|
666
|
+
unsigned long long new_size = head_samples + sample_count + tail_samples;
|
|
667
|
+
std::vector<float> new_samples(new_size, 0.0f);
|
|
676
668
|
|
|
669
|
+
// move old samples in
|
|
670
|
+
std::move(samples.begin(), samples.end(), new_samples.begin() + head_samples);
|
|
671
|
+
samples = std::move(new_samples);
|
|
677
672
|
sample_count = samples.size();
|
|
678
673
|
|
|
679
674
|
return *this;
|
|
@@ -700,18 +695,12 @@ struct AudioTrack
|
|
|
700
695
|
unsigned long long head_samples = head_frames * channels;
|
|
701
696
|
unsigned long long tail_samples = tail_frames * channels;
|
|
702
697
|
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
{
|
|
706
|
-
samples.insert(samples.begin(), head_samples, 0.0f);
|
|
707
|
-
}
|
|
708
|
-
|
|
709
|
-
// pad the end
|
|
710
|
-
if (tail_samples > 0)
|
|
711
|
-
{
|
|
712
|
-
samples.insert(samples.end(), tail_samples, 0.0f);
|
|
713
|
-
}
|
|
698
|
+
unsigned long long new_size = head_samples + sample_count + tail_samples;
|
|
699
|
+
std::vector<float> new_samples(new_size, 0.0f);
|
|
714
700
|
|
|
701
|
+
// move old samples in
|
|
702
|
+
std::move(samples.begin(), samples.end(), new_samples.begin() + head_samples);
|
|
703
|
+
samples = std::move(new_samples);
|
|
715
704
|
sample_count = samples.size();
|
|
716
705
|
|
|
717
706
|
return *this;
|
|
@@ -775,6 +764,137 @@ struct AudioTrack
|
|
|
775
764
|
return *this;
|
|
776
765
|
}
|
|
777
766
|
|
|
767
|
+
AudioTrack &clip_bang()
|
|
768
|
+
{
|
|
769
|
+
for (auto &s : samples)
|
|
770
|
+
{
|
|
771
|
+
s = std::clamp(s, -1.0f, 1.0f);
|
|
772
|
+
}
|
|
773
|
+
return *this;
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
AudioTrack &low_pass_bang(int cutoffFreq)
|
|
777
|
+
{
|
|
778
|
+
// High order low-pass filter (Butterworth)
|
|
779
|
+
// [https://miniaud.io/docs/manual/index.html#Filtering]
|
|
780
|
+
ma_lpf lpf;
|
|
781
|
+
ma_lpf_config config;
|
|
782
|
+
|
|
783
|
+
// last argument is MA_MAX_FILTER_ORDER, goes up to 4?
|
|
784
|
+
config = ma_lpf_config_init(ma_format_f32, channels, sample_rate, (double)cutoffFreq, 2);
|
|
785
|
+
|
|
786
|
+
if (ma_lpf_init(&config, NULL, &lpf) != MA_SUCCESS)
|
|
787
|
+
{
|
|
788
|
+
throw std::runtime_error("RubyDSP: Failed to initialize low-pass filter.");
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
// in-place filtering
|
|
792
|
+
unsigned long long frame_count = sample_count / channels;
|
|
793
|
+
ma_lpf_process_pcm_frames(&lpf, samples.data(), samples.data(), frame_count);
|
|
794
|
+
ma_lpf_uninit(&lpf, NULL);
|
|
795
|
+
|
|
796
|
+
return *this;
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
AudioTrack &high_pass_bang(int cutoff_freq)
|
|
800
|
+
{
|
|
801
|
+
ma_hpf hpf;
|
|
802
|
+
// 2nd order high-pass
|
|
803
|
+
ma_hpf_config config = ma_hpf_config_init(ma_format_f32, channels, sample_rate, (double)cutoff_freq, 2);
|
|
804
|
+
|
|
805
|
+
if (ma_hpf_init(&config, NULL, &hpf) != MA_SUCCESS)
|
|
806
|
+
{
|
|
807
|
+
throw std::runtime_error("RubyDSP: Failed to initialize high-pass filter.");
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
unsigned long long frame_count = sample_count / channels;
|
|
811
|
+
ma_hpf_process_pcm_frames(&hpf, samples.data(), samples.data(), frame_count);
|
|
812
|
+
|
|
813
|
+
return *this;
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
AudioTrack &band_pass_bang(int cutoff_freq)
|
|
817
|
+
{
|
|
818
|
+
ma_bpf bpf;
|
|
819
|
+
// order MUST be even for band-pass
|
|
820
|
+
// [https://miniaud.io/docs/manual/index.html#Filtering]
|
|
821
|
+
ma_bpf_config config = ma_bpf_config_init(ma_format_f32, channels, sample_rate, (double)cutoff_freq, 2);
|
|
822
|
+
|
|
823
|
+
if (ma_bpf_init(&config, NULL, &bpf) != MA_SUCCESS)
|
|
824
|
+
{
|
|
825
|
+
throw std::runtime_error("RubyDSP: Failed to initialize band-pass filter.");
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
unsigned long long frame_count = sample_count / channels;
|
|
829
|
+
ma_bpf_process_pcm_frames(&bpf, samples.data(), samples.data(), frame_count);
|
|
830
|
+
|
|
831
|
+
return *this;
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
AudioTrack ¬ch_bang(int center_freq, double q = 0.707)
|
|
835
|
+
{
|
|
836
|
+
ma_notch2 notch;
|
|
837
|
+
ma_notch2_config config = ma_notch2_config_init(ma_format_f32, channels, sample_rate, q, (double)center_freq);
|
|
838
|
+
|
|
839
|
+
if (ma_notch2_init(&config, NULL, ¬ch) != MA_SUCCESS)
|
|
840
|
+
{
|
|
841
|
+
throw std::runtime_error("RubyDSP: Failed to initialize notch filter.");
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
unsigned long long frame_count = sample_count / channels;
|
|
845
|
+
ma_notch2_process_pcm_frames(¬ch, samples.data(), samples.data(), frame_count);
|
|
846
|
+
|
|
847
|
+
return *this;
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
AudioTrack &peak_eq_bang(int center_freq, double gain_db, double q = 0.707)
|
|
851
|
+
{
|
|
852
|
+
ma_peak2 peak;
|
|
853
|
+
ma_peak2_config config = ma_peak2_config_init(ma_format_f32, channels, sample_rate, gain_db, q, (double)center_freq);
|
|
854
|
+
|
|
855
|
+
if (ma_peak2_init(&config, NULL, &peak) != MA_SUCCESS)
|
|
856
|
+
{
|
|
857
|
+
throw std::runtime_error("RubyDSP: Failed to initialize peaking EQ filter.");
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
unsigned long long frame_count = sample_count / channels;
|
|
861
|
+
ma_peak2_process_pcm_frames(&peak, samples.data(), samples.data(), frame_count);
|
|
862
|
+
|
|
863
|
+
return *this;
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
AudioTrack &low_shelf_bang(int cutoff_freq, double gain_db, double q = 0.707)
|
|
867
|
+
{
|
|
868
|
+
ma_loshelf2 shelf;
|
|
869
|
+
ma_loshelf2_config config = ma_loshelf2_config_init(ma_format_f32, channels, sample_rate, gain_db, q, (double)cutoff_freq);
|
|
870
|
+
|
|
871
|
+
if (ma_loshelf2_init(&config, NULL, &shelf) != MA_SUCCESS)
|
|
872
|
+
{
|
|
873
|
+
throw std::runtime_error("RubyDSP: Failed to initialize low-shelf filter.");
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
unsigned long long frame_count = sample_count / channels;
|
|
877
|
+
ma_loshelf2_process_pcm_frames(&shelf, samples.data(), samples.data(), frame_count);
|
|
878
|
+
|
|
879
|
+
return *this;
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
AudioTrack &high_shelf_bang(int cutoff_freq, double gain_db, double q = 0.707)
|
|
883
|
+
{
|
|
884
|
+
ma_hishelf2 shelf;
|
|
885
|
+
ma_hishelf2_config config = ma_hishelf2_config_init(ma_format_f32, channels, sample_rate, gain_db, q, (double)cutoff_freq);
|
|
886
|
+
|
|
887
|
+
if (ma_hishelf2_init(&config, NULL, &shelf) != MA_SUCCESS)
|
|
888
|
+
{
|
|
889
|
+
throw std::runtime_error("RubyDSP: Failed to initialize high-shelf filter.");
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
unsigned long long frame_count = sample_count / channels;
|
|
893
|
+
ma_hishelf2_process_pcm_frames(&shelf, samples.data(), samples.data(), frame_count);
|
|
894
|
+
|
|
895
|
+
return *this;
|
|
896
|
+
}
|
|
897
|
+
|
|
778
898
|
std::string to_s()
|
|
779
899
|
{
|
|
780
900
|
std::ostringstream stream;
|
|
@@ -849,5 +969,27 @@ extern "C"
|
|
|
849
969
|
Arg("duration_sec"),
|
|
850
970
|
Arg("start_sec") = -1.0f,
|
|
851
971
|
Arg("amplitude") = 1.0f)
|
|
972
|
+
.define_method("clip!", &AudioTrack::clip_bang)
|
|
973
|
+
.define_method("low_pass!", &AudioTrack::low_pass_bang,
|
|
974
|
+
Arg("cutoff_freq"))
|
|
975
|
+
.define_method("high_pass!", &AudioTrack::high_pass_bang,
|
|
976
|
+
Arg("cutoff_freq"))
|
|
977
|
+
.define_method("band_pass!", &AudioTrack::band_pass_bang,
|
|
978
|
+
Arg("cutoff_freq"))
|
|
979
|
+
.define_method("notch!", &AudioTrack::notch_bang,
|
|
980
|
+
Arg("center_freq"),
|
|
981
|
+
Arg("q") = 0.707)
|
|
982
|
+
.define_method("peak_eq!", &AudioTrack::peak_eq_bang,
|
|
983
|
+
Arg("center_freq"),
|
|
984
|
+
Arg("gain_db"),
|
|
985
|
+
Arg("q") = 0.707)
|
|
986
|
+
.define_method("low_shelf!", &AudioTrack::low_shelf_bang,
|
|
987
|
+
Arg("cutoff_freq"),
|
|
988
|
+
Arg("gain_db"),
|
|
989
|
+
Arg("q") = 0.707)
|
|
990
|
+
.define_method("high_shelf!", &AudioTrack::high_shelf_bang,
|
|
991
|
+
Arg("cutoff_freq"),
|
|
992
|
+
Arg("gain_db"),
|
|
993
|
+
Arg("q") = 0.707)
|
|
852
994
|
.define_method("to_s", &AudioTrack::to_s);
|
|
853
995
|
}
|
data/lib/ruby_dsp/version.rb
CHANGED
|
@@ -179,6 +179,80 @@ module RubyDSP
|
|
|
179
179
|
def add_wave!(wave_type, frequency, duration_sec, start_sec = -1.0, amplitude = 1.0)
|
|
180
180
|
end
|
|
181
181
|
|
|
182
|
+
# Destructively clamps all audio samples to the standard [-1.0, 1.0] range.
|
|
183
|
+
#
|
|
184
|
+
# This prevents harsh digital clipping when exporting polyphonic or boosted audio.
|
|
185
|
+
#
|
|
186
|
+
# @return [AudioTrack] self for method chaining.
|
|
187
|
+
def clip!
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
# Applies a high-order low-pass filter (Butterworth) to the track.
|
|
191
|
+
#
|
|
192
|
+
# Attenuates frequencies above the cutoff, letting lower frequencies pass through.
|
|
193
|
+
#
|
|
194
|
+
# @param cutoff_freq [Integer, Float] The threshold frequency in Hz.
|
|
195
|
+
# @return [AudioTrack] self for method chaining.
|
|
196
|
+
def low_pass!(cutoff_freq)
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
# Applies a 2nd-order high-pass filter to the track.
|
|
200
|
+
#
|
|
201
|
+
# Attenuates frequencies below the cutoff, letting higher frequencies pass through.
|
|
202
|
+
#
|
|
203
|
+
# @param cutoff_freq [Integer, Float] The threshold frequency in Hz.
|
|
204
|
+
# @return [AudioTrack] self for method chaining.
|
|
205
|
+
def high_pass!(cutoff_freq)
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
# Applies a 2nd-order band-pass filter to the track.
|
|
209
|
+
#
|
|
210
|
+
# Preserves frequencies around the cutoff, heavily attenuating both higher and lower frequencies.
|
|
211
|
+
#
|
|
212
|
+
# @param cutoff_freq [Integer, Float] The center frequency in Hz.
|
|
213
|
+
# @return [AudioTrack] self for method chaining.
|
|
214
|
+
def band_pass!(cutoff_freq)
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
# Applies a 2nd-order notch filter to surgically remove a specific frequency.
|
|
218
|
+
#
|
|
219
|
+
# @param center_freq [Integer, Float] The exact frequency to eliminate in Hz.
|
|
220
|
+
# @param q [Float] The resonance/width of the notch. Defaults to 0.707 (Butterworth).
|
|
221
|
+
# @return [AudioTrack] self for method chaining.
|
|
222
|
+
def notch!(center_freq, q = 0.707)
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
# Applies a 2nd-order peaking EQ filter to boost or cut a specific frequency band.
|
|
226
|
+
#
|
|
227
|
+
# @param center_freq [Integer, Float] The target frequency in Hz.
|
|
228
|
+
# @param gain_db [Float] The amount to boost (positive) or cut (negative) in decibels.
|
|
229
|
+
# @param q [Float] The resonance/width of the bell curve. Defaults to 0.707.
|
|
230
|
+
# @return [AudioTrack] self for method chaining.
|
|
231
|
+
def peak_eq!(center_freq, gain_db, q = 0.707)
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
# Applies a 2nd-order low-shelf filter.
|
|
235
|
+
#
|
|
236
|
+
# Boosts or cuts frequencies below the cutoff without affecting higher frequencies.
|
|
237
|
+
#
|
|
238
|
+
# @param cutoff_freq [Integer, Float] The threshold frequency in Hz.
|
|
239
|
+
# @param gain_db [Float] The amount to boost (positive) or cut (negative) in decibels.
|
|
240
|
+
# @param q [Float] The resonance/slope of the shelf. Defaults to 0.707.
|
|
241
|
+
# @return [AudioTrack] self for method chaining.
|
|
242
|
+
def low_shelf!(cutoff_freq, gain_db, q = 0.707)
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
# Applies a 2nd-order high-shelf filter.
|
|
246
|
+
#
|
|
247
|
+
# Boosts or cuts frequencies above the cutoff without affecting lower frequencies.
|
|
248
|
+
#
|
|
249
|
+
# @param cutoff_freq [Integer, Float] The threshold frequency in Hz.
|
|
250
|
+
# @param gain_db [Float] The amount to boost (positive) or cut (negative) in decibels.
|
|
251
|
+
# @param q [Float] The resonance/slope of the shelf. Defaults to 0.707.
|
|
252
|
+
# @return [AudioTrack] self for method chaining.
|
|
253
|
+
def high_shelf!(cutoff_freq, gain_db, q = 0.707)
|
|
254
|
+
end
|
|
255
|
+
|
|
182
256
|
# @return [String] a formatted summary of the track.
|
|
183
257
|
def to_s
|
|
184
258
|
end
|