Hatena::Grouprubyist

たばさの RSSフィード

07/30(水) 2014

サイン波など

サイン波など - たばさの を含むブックマーク はてなブックマーク - サイン波など - たばさの

練習

# original is on

# http://d.hatena.ne.jp/ku-ma-me/20100901/p1

cf. http://d.hatena.ne.jp/korinchan/20071021/p1


require 'optparse'
wtype=:sine
vol=100
puls=0.5
noise=0
tempo=100
opt = OptionParser.new
opt.on('-w i',"wave type [sine, nokogiri, pulse, triangle]") {|v|
  v=case v
    when /^noko/ ; "noko"
    when /^puls/ ; "pulse"
    when /^tri/  ; "tri"
    else         ; "sine"
    end
  wtype=:"#{v}"
}
opt.on('-v i',"volume[100]") {|v|
  vol=v.to_i
}
opt.on('-p i',"pulse param[0-100]") {|v|
  puls=v.to_i/100.0
}
opt.on('-n i',"add noise[0-100]") {|v|
  noise=v.to_i/100.0
}
opt.on('-t i',"tempo (not bpm)") {|v|
  tempo=v.to_i
}

opt.parse!(ARGV)
puts "type: #{wtype}, vol: #{vol}, noiseAdd: #{noise}"


Tone = {
  "a"  =>  0, "a+" =>  1, "b" =>  2, "c"  => -9, "c+" => -8, "d"  => -7,
  "d+" => -6, "e"  => -5, "f" => -4, "f+" => -3, "g"  => -2, "g+" => -1,
}
MTone = {
  "a"  =>  0, "A" =>  1, "b" =>  2, "c"  => -9, "C" => -8, "d"  => -7,
  "D" => -6, "e"  => -5, "f" => -4, "F" => -3, "g"  => -2, "G" => -1,
}

def smml_compile(mml)
  scores = ["", "", "", ""]
  mml.each_line do |line|
    next unless line =~ /^(\d+):/
    scores[$1.to_i - 1] << $'
  end
  seqs = scores.map { [] }
  scores.zip(seqs, [2, 2, 0, -1]) do |score, seq, octave|
    gate=1.0
    score.split.join.scan(/([a-gA-Gr\+\-,])([\d\.]+)?|\(g:([\d\.]+)\)/) do |tone, length, gaterate|
      (gate=gaterate.to_f ;next) if gaterate
      length="1" if not length
      length = eval(length)*8 if length
      soundlen=length*gate
      restlen=length-soundlen
      case tone
      when ","
      when "+"; octave += 1
      when "-"; octave -= 1
      when "r"; seq.concat([nil] * length)
      else seq.concat([octave * 12 + MTone[tone]] * soundlen + [nil] * restlen)
      end
    end
  end
  seqs
end

def mml2smml(mml)
  scores = ["", "", "", ""]
  mml.each_line do |line|
    next unless line =~ /^(\d+):/
    scores[$1.to_i - 1] << $'
  end
  seqs = scores.map { [] }
  scores.zip(seqs, [2, 2, 0, -1]) do |score, seq, octave|
    score.split.join.scan(/([a-gr<>,][\-\+]?)([\d\-+]+)?/) do |tone, length|
      length="4" if not length
      length = eval(length.gsub(/\d+/) { 32 / $&.to_i })/8.0 if length
      length=length.to_i if length==length.to_i
      length="" if length==1
      case tone
      when ","
      when ">"; seq << "+"
      when "<"; seq << "-"
      when "r"; seq << "r"; seq << "#{length}"
      when /([a-g])\+/
        seq << $1.tr("abcdefg","ABCDEFG")
        seq << "#{length}"
      when /([a-g])\-/
        seq << $1.tr("abcdefg","GAbCDeF")
        seq << "#{length}"
      else ; seq << tone; seq << "#{length}"
      end
    end
  end
  r=[]
  seqs.each_with_index{|i,n|r << "#{n}: #{i*""}"}
  r
end

# not yet completed
def smml2mml(mml)
  scores = ["", "", "", ""]
  mml.each_line do |line|
    next unless line =~ /^(\d+):/
    scores[$1.to_i - 1] << $'
  end
  seqs = scores.map { [] }
  scores.zip(seqs, [2, 2, 0, -1]) do |score, seq, octave|
    score.split.join.scan(/([a-gA-Gr\-\+,])([\d\.]+)?/) do |tone, length|
      length="4" if not length
      length = 32/(eval(length)/0.125).to_i if length
      case tone
      when ","
      when "+"; seq << ">"
      when "-"; seq << "<"
      when "r"; seq << "r"; seq << "#{length}"
      when /[a-g]/
        seq << tone
        seq << "#{length}"
      when /[A-G]/
        seq << tone.downcase+"+"
        seq << "#{length}"
      else ; seq << tone; seq << "#{length}"
      end
    end
  end
  r=[]
  seqs.each_with_index{|i,n|r << "#{n}: #{i*""}"}
  r
end

seqs1 = smml_compile(<<END)
1: d4d-b+C0.875-b0.125a+a2a0.25F0.25c0.25-b0.25+e0.25D0.25a0.25g0.25g2g0.25e0.25-b0.25a0.25+d0.25C0.25g0.25F0.25-a2a0.5G0.25a0.25b0.5G0.5a0.5aG0.5e2+
2: F4F0.5b0.25g0.25e0.25d0.25C0.25d0.25-a2a0.5+c0.25-b0.25+c0.5a0.25c0.25-b0.5+r0.5r-b0.5+e0.25d0.25e0.25F0.25g0.25e0.25-a0.5r0.5r+FF0.5G0.25a0.25d0.5d0.125e0.125F0.5e0.25e0.25d0.25C0.25-b0.25b0.125+C0.125d0.25d0.5C0.25-b0.25a2+
3: (g:0.25)d0.5+d0.5C0.5-C0.5-b0.5+b0.5a0.5-a0.5g0.5+g0.5G0.5-G0.5+e2e0.5De0.5F0.5r0.5re0.5be0.5e0.5r0.5rdd0.5e0.5F0.5d0.5b0.5e0.5e0.5F0.5b0.5e0.5C2
4: a2b2-b+e-a0.5+a0.5g0.5-g0.5F0.5+F0.5e0.5-e0.5D0.5+D0.5-b0.5+b0.5-e0.5+e0.5d0.5-d0.5C0.5+C0.5-a0.5+a0.5d0.5+d0.5C0.5-C0.5-b0.5+b0.5G0.5e0.5a0.5d0.5e0.5-e0.5a0.25b0.25+C0.25d0.25e0.25g0.25F0.25e0.25
END

seqs2 = smml_compile(<<END)
1: C1.25d0.125C0.125-b0.125+C0.125-a0.25+aa0.5c0.5-b0.5+b0.75a0.25g0.25F0.25g1.125F0.125e0.125d0.125C0.25-b0.25A0.25b0.25+C0.75d0.25e0.75F0.25gF0.5e0.25d0.25C0.25-b0.25+C0.25d0.125e0.125d0.5-b2+d1.25F0.25e0.25d0.25b1.5a0.25G0.25F0.125e0.125a0.25-aG0.5a2a0.5b0.25+c0.25-b0.25+C0.25dC0.25-b0.25+C0.25D0.25e0.5e0.5D0.25C0.25D0.25e0.25F0.5g2-a1.25+C0.25e0.25g0.25g0.25e0.25F1.25g0.125a0.125d1.25F0.25a0.25+c0.25-b1.5d0.5C0.25e0.25gd0.5-a0.5+e0.25F0.125g0.375F0.5e0.25d0.125C0.125-b0.5+C0.25d0.5C0.25d0.25d2
2: -a2.25b0.25+c0.75-b0.25a0.25g0.25F1.5b0.5e0.5+e0.5d0.5-d0.5C0.5+C0.5-b0.5-b0.5A0.5b0.5+C0.5-A0.5+-b0.5+g0.5e0.5F0.5-b0.5+b0.5a0.5-a0.5+eF-b0.5+e0.25F0.25G0.25a0.25b0.5b0.5a0.5b0.75+C0.125d0.125C0.75-b0.25a+d1.5F0.25e0.25e1.5g0.25F0.25F1.5a0.25g0.25r0.25D0.25e0.25-b0.25ee0.25C0.25e0.25a0.25+C0.5-a+C0.25d0.25-dd0.5e0.5Fd2e0.25-b0.25+e0.25g0.25b0.25a0.25g0.25F0.25e0.5ag0.5ag0.25F0.25g0.5F2+
3: e2e0.5D0.25e0.25FF0.25g0.25a0.25g0.25D0.5+D0.5e2e2.25d0.25C0.25-b0.25A0.25b0.25+C0.5-b0.5b0.5b0.5A0.5F2-b0.5+b0.5a0.25G0.25a0.5G0.75F0.25ee0.5e0.5F0.5e0.5e0.75d0.25C0.25d0.25F0.25C0.25-F0.5+F0.5g0.5-g0.5G0.5+G0.5a0.5-a0.5A0.5+A0.5b0.5-b0.5+e0.5+e0.5d0.5-d0.5a0.5g0.5F0.5e0.5daa0.5g0.5ag2g0.5b0.5+e1.25d0.25C0.25-b0.25a0.5b0.5Fe0.5a0.5a2
4: -a0.5+a0.5g0.5-g0.5F0.5+F0.5e0.5-e0.5D0.5+D0.5F0.5-b0.5+b-b+C0.25d0.25e0.25F0.25g0.25F0.25g0.25e0.25F0.5e0.25d0.25C0.5F0.5F0.5e0.25d0.25g0.5F0.25e0.25d2-G0.5+G0.5F0.5-F0.5e0.5+e0.5d0.5-d0.5C0.5+C0.5d0.5e0.5-a0.5+a0.5g0.5-g0.5a0.5+d-b+eC0.5C0.5FD0.5-b1.25+b0.25g0.25e0.25C0.5+C0.5-a0.5+C0.5d0.5-d0.5c0.5+c0.5-b0.5-b0.5a0.5+a0.5g0.5-g0.5F0.5+F0.5e0.5-e0.5d0.5+d0.5C0.5-a0.5+d0.5g0.5a0.5g0.5a0.5-a0.5d2
END


seqs = seqs1.zip(seqs1, seqs2, seqs2).map {|seqs| seqs.flatten }
seqs[3][370,14] = [-24] * 14;
seqs = seqs.transpose

def play(rate, seqs, vol=100, wtype=:sine, tempo=100, puls=0.5, noise=0 )
  prc=case wtype
      when :pulse ; Proc.new{|t|10 - 20 * (t % 1>puls ? 1 : 0)}            # パルス波
      when :noko  ; Proc.new{|t|10 - 20 * (t % 1)   }                       # ノコギリ波
      when :tri   ; Proc.new{|t|s=(t%1)*2 ; s=2-s if s>1 ; 10 - 20 * (s) }  # 三角波
      else        ; Proc.new{|t|10 * Math.sin(2 * Math::PI * t )}           # 正弦波
      end
  noise*=10
  noisep= noise==0 ? Proc.new{0} : Proc.new{rand(noise)/10.0}
  sp=1000000/tempo
  unit = rate * sp / 44100
  seqs.each_with_index do |tones, w|
    wave = [128] * unit
    tones.each do |tone|
      next unless tone
      tone = 440.0 / rate * 2**(tone / 12.0)
      unit.times {|i|
        # wave[i] += 10 - 20 * ((tone * (w * unit + i)) % 1) ##(1 - 2 * ((phase * i) % 1))       
       #  wave[i] += 10 * Math.sin(2 * Math::PI * (tone * (w * unit + i))) 
         current=prc.call(tone * (w * unit + i))*(vol/100.0)*(1-noisep.call)
         wave[i] += current
      }
      print"," if w%10==0
    end
    yield wave.pack("C*")
  end
end

if false
  # output to /dev/dsp
  open("/dev/dsp", "wb") do |f|
    play(8000, seqs, vol, wtype, tempo, puls, noise) do |s|
      f << s
      f.flush
    end
  end
else
  # generate air.wav
  header = ["WAVEfmt ", 16, 1, 1, 44100, 44100, 1, 8].pack("A8VvvVVvv")
  data = ""
  play(44100, seqs, vol, wtype, tempo, puls, noise) {|s| data << s }
  data = ["data", data.size].pack("A4V") << data
  open("air.wav", "wb") do |f|
    f << ["RIFF", header.size + data.size].pack("A4V") << header << data
  end
end

トラックバック - http://rubyist.g.hatena.ne.jp/hatecha/20140730
カレンダー
<< 2014/07 >>
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
archive Error : RSSが取得できませんでした。