Class: Reight::Sound::Note
- Inherits:
-
Object
- Object
- Reight::Sound::Note
- Defined in:
- lib/reight/sound.rb
Constant Summary collapse
- MAX =
127- TONES =
i[ sine triangle square sawtooth pulse12_5 pulse25 noise ]
- INDEX2NOTE =
-> { notes = %w[ c c+ d d+ e f f+ g g+ a a+ b ].map {_1.sub '+', '#'} octaves = (-1..9).to_a octaves.product(notes) .each_with_object({}).with_index do |((octave, note), hash), index| hash[index] = "#{note}#{octave}" end }.call
Instance Attribute Summary collapse
-
#index ⇒ Object
readonly
Returns the value of attribute index.
-
#tone ⇒ Object
readonly
Returns the value of attribute tone.
Class Method Summary collapse
- .create_samples(type, size) ⇒ Object
- .envelope(seconds) ⇒ Object
- .gain(gain = 0.2) ⇒ Object
- .oscillator(type, size, **kwargs) ⇒ Object
- .restore(hash) ⇒ Object
- .seconds(length, bpm) ⇒ Object
Instance Method Summary collapse
- #frequency ⇒ Object
-
#initialize(index, tone = TONES.first) ⇒ Note
constructor
A new instance of Note.
- #play(bpm) ⇒ Object
- #to_hash ⇒ Object
- #to_s ⇒ Object
- #to_sound(bpm) ⇒ Object
Constructor Details
#initialize(index, tone = TONES.first) ⇒ Note
Returns a new instance of Note.
153 154 155 156 157 |
# File 'lib/reight/sound.rb', line 153 def initialize(index, tone = TONES.first) raise "Invalid note index: #{index}" unless (0..MAX).include? index raise "Invalid tone: #{tone}" unless TONES.include? tone @index, @tone = index, tone end |
Instance Attribute Details
#index ⇒ Object (readonly)
Returns the value of attribute index.
159 160 161 |
# File 'lib/reight/sound.rb', line 159 def index @index end |
#tone ⇒ Object (readonly)
Returns the value of attribute tone.
159 160 161 |
# File 'lib/reight/sound.rb', line 159 def tone @tone end |
Class Method Details
.create_samples(type, size) ⇒ Object
204 205 206 207 208 209 210 211 212 213 |
# File 'lib/reight/sound.rb', line 204 def self.create_samples(type, size) input = size.times.map {_1.to_f / size} duty = {pulse12_5: 0.125, pulse25: 0.25, pulse75: 0.75}[type] || 0.5 case type when :sine then input.map {Math.sin _1 * Math::PI * 2} when :triangle then input.map {_1 < 0.5 ? _1 * 4 - 1 : 3 - _1 * 4} when :sawtooth then input.map {_1 * 2 - 1} else input.map {_1 < duty ? 1 : -1} end end |
.envelope(seconds) ⇒ Object
215 216 217 218 219 220 |
# File 'lib/reight/sound.rb', line 215 def self.envelope(seconds) Beeps::Envelope.new release: seconds * 0.05 do note_on note_off seconds * 0.95 end end |
.gain(gain = 0.2) ⇒ Object
222 223 224 |
# File 'lib/reight/sound.rb', line 222 def self.gain(gain = 0.2) Beeps::Gain.new gain end |
.oscillator(type, size, **kwargs) ⇒ Object
195 196 197 198 199 200 201 202 |
# File 'lib/reight/sound.rb', line 195 def self.oscillator(type, size, **kwargs) case type when :noise then Beeps::Oscillator.new type, **kwargs else samples = (@samples ||= {})[type] ||= create_samples type, size Beeps::Oscillator.new samples: samples, **kwargs end end |
.restore(hash) ⇒ Object
232 233 234 235 236 |
# File 'lib/reight/sound.rb', line 232 def self.restore(hash) index, tone = hash.values_at :index, :tone #hash => {index:, tone:} new index, TONES[tone] end |
.seconds(length, bpm) ⇒ Object
226 227 228 229 230 |
# File 'lib/reight/sound.rb', line 226 def self.seconds(length, bpm) raise ArgumentError, "Invalid length: #{length}" if length <= 0 raise ArgumentError, "Invalid bpm: #{bpm}" if bpm <= 0 60.0 / bpm / length end |
Instance Method Details
#frequency ⇒ Object
165 166 167 |
# File 'lib/reight/sound.rb', line 165 def frequency() 440 * (2 ** ((@index - 69).to_f / 12)) end |
#play(bpm) ⇒ Object
161 162 163 |
# File 'lib/reight/sound.rb', line 161 def play(bpm) to_sound(bpm).play end |
#to_hash ⇒ Object
182 183 184 |
# File 'lib/reight/sound.rb', line 182 def to_hash() {index: @index, tone: TONES.index(@tone)} end |
#to_s ⇒ Object
178 179 180 |
# File 'lib/reight/sound.rb', line 178 def to_s() "#{INDEX2NOTE[@index]}:#{@tone}" end |
#to_sound(bpm) ⇒ Object
186 187 188 189 190 191 192 193 |
# File 'lib/reight/sound.rb', line 186 def to_sound(bpm) osc = self.class.oscillator tone, 32, freq: frequency sec = self.class.seconds 4, bpm seq = Beeps::Sequencer.new.tap {_1.add osc, 0, sec} env = self.class.envelope sec gain = self.class.gain RubySketch::Sound.new Beeps::Sound.new(seq >> env >> gain, sec) end |