Created
December 22, 2013 14:51
-
-
Save shinokaro/8083646 to your computer and use it in GitHub Desktop.
Rubyコードによるサウンド・ジェネレーター試作版
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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