Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Rubyコードによるサウンド・ジェネレーター試作版
require "dxruby"
# extend
class Array
def to_sound
::DXRuby::SoundEffect.new(self)
end
end
class Object
def to_proc
proc { |*| self }
end
end
class Module
private
def attr_caller(*attr_names)
attr_names.each do |name|
class_eval(%Q{
def #{name}
@#{name}.call
end
def #{name}=(obj)
@#{name} = obj.to_proc
end
})
end
end
end
# VTE
require 'singleton'
class MasterTicks < Enumerator
include Singleton
attr_reader :ticks
def initialize
@ticks = 0
super { |output| begin output << tick! end until nil}
end
def tick!
@ticks += 1
end
def new_proc
Ticks.new(@ticks).to_proc
end
end
class Ticks
attr_reader :epoc
def initialize(epoc=MasterTicks.instance.ticks)
@epoc = epoc
end
def call
ticks
end
def ticks
MasterTicks.instance.ticks - @epoc
end
def to_proc
method(:ticks).to_proc
end
end
SAMPLE_RATE = 44_100
class VTE < Enumerator
# Virtual Time Enumerator or Vicarious Trial and Error
attr_caller :input, :ticks
def initialize(*, **kwargs, &block)
@ticks = Ticks.new
kwargs.each do |kw, obj|
__send__([kw, :'='].join, obj)
end
super(&block)
end
def t
Rational(ticks, SAMPLE_RATE)
end
def to_proc
->(*){ self.next }
end
end
# primitive classes
class Sin < VTE
include Math
attr_caller :frequency, :multiple, :detune, :phase
def initialize(input:0.0, frequency:0.0, multiple:1.0, detune:0.0, phase:0.0)
super { |output|
while true
proccess(output)
end
}
end
def proccess(output)
f = 2 * PI * multiple * (frequency + detune)
p = phase / (2 * PI * f)
output << sin(f * (t + p) + input)
end
end
class Amp < VTE
attr_caller :input, :volume
def initialize(input:0.0, volume:1.0)
super { |output|
while true
proccess(output)
end
}
end
def proccess(output)
output << input * volume
end
end
sin1 = Sin.new(frequency: 440, multiple: 1.4)
gain = Amp.new(input: sin1, volume: 3)
sin2 = Sin.new(input: gain, frequency: 440)
sin3 = Sin.new(frequency: 440, multiple: 1.4, detune: 3)
MasterTicks.instance.lazy.map(&sin2).take(SAMPLE_RATE).to_a.to_sound.play
sleep 1
MasterTicks.instance.lazy.map{sin2.next + sin3.next}.take(SAMPLE_RATE).to_a.to_sound.play
sleep 2
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment