è¶
絶æå·§ Ruby ããã°ã©ãã³ã°ã®è³ªçã§ãã©ããã£ã¦é³ãé³´ããã¦ããã®ããã¨ãã質åããã£ãã®ã§ãèªåã®ããã®è¨é²ãå
¼ãã¦ç°¡åã«ç´¹ä»ã
ã¨ãã£ã¦ã Linux Sound programming with OSS API ã«ããéããRuby ã§æ¸ãã¨ãããªæãã
# ããã©ã«ãã§ã¯ 8bit 8000 Hz SampleSize = 256 SamplingRate = 8000 # ... 0:ã© 1:ã©# 2:ã· 3:ã 4:ã# 5:㬠6:ã¬# 7:ã 8:ãã¡ 9:ãã¡# 10:ã½ 11:ã½# 12:ã© ... tone = 3 # ããªã¥ã¼ã : 0 ã SampleSize/2 ã¾ã§ volume = 60 # åçããé·ã: ç§ length = 2 # å¨æ³¢æ°: åºæºã®ã©ã¯ 440Hz ã1 ãªã¯ã¿ã¼ãä¸ããã¨åã«ãªã freq = 440 * 2**(tone / 12.0) open("/dev/dsp", "wb") do |f| phase = freq.to_f / SamplingRate wave = (0 ... length * SamplingRate).map do |i| Math.sin(2 * Math::PI * phase * i) # æ£å¼¦æ³¢ #(1 - 2 * ((phase * i) % 1)) # ãã³ã®ãªæ³¢ end wave = wave.map {|v| (SampleSize / 2 + volume * v).round } f.print(wave.pack("C*")) end
ãã³ã®ãªæ³¢ã¯倍音ããã£ã±ãæ··ãã£ã波形ãªã®ã§ããã¤ãªãªã³ç³»ã®è±ããªé³ã«ãªããããã
以ä¸ã¯è¶
絶æå·§ Ruby ããã°ã©ãã³ã°ã§ä½¿ã£ãé³æ¥½ (G ç·ä¸ã®ã¢ãªã¢) ãåçããã³ã¼ããããã«æ¸
æ¸ãã¦ãªãã®ã§æ±ãããã¨å¤æ°å (score ã¨ã tone ã¨ã) ã¯å®ç¾©ããã調ã¹ãªãã§ä½¿ã£ã¦ãã®ã§å½ã¦ã«ããªããã¨ããã¨ãã㯠8000 Hz ãªã®ã§é³è³ªãæªããçºè¡¨ã§ã¯ããµã³ããªã³ã°ã¬ã¼ãã 44100 Hz ã«ä¸ãã¦ããããã®ããã«ã¯ ioctl ãå¼ã¶å¿
è¦ããã£ã¦ããã®ããã«ã¯ sys/soundcard.h ã¨ãã§å®ç¾©ããã¦ãã SOUND_PCM_WRITE_RATE ã®å¤ãå¿
è¦ã§ããã®ããã« gcc ãå¼ãã§ãããããã
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, } def mml_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| score.split.join.scan(/([a-gr<>,]\+?)([\d\-+]+)?/) do |tone, length| length = eval(length.gsub(/\d+/) { 32 / $&.to_i }) if length case tone when "," when ">"; octave += 1 when "<"; octave -= 1 when "r"; seq.concat([nil] * length) else seq.concat([octave * 12 + Tone[tone]] * length) end end end seqs end seqs1 = mml_compile(<<END) 1:d1 ,d4<b4>c+4-32<b32a4 ,>a2a16f+16c16<b16>e16d+16a16g16, 2:f+1 ,f+8b16g16e16d16c+16d16<a2,a8>c16<b16>c8a16c16<b8>r8r4 , 3:d8>d8c+8<c+8<b8>b8a8<a8,g8>g8g+8<g+8>e2 ,e8d+4e8f+8r8r4 , 4:a2b2 ,<b4>e4<a8>a8g8<g8 ,f+8>f+8e8<e8d+8>d+8<b8>b8 , 1:g2g16e16<b16a16>d16c+16g16f+16,<a2a8g+16a16b8g+8 ,a8a4g+8e2> , 2:<b8>e16d16e16f+16g16e16<a8r8r4,>f+4f+8g+16a16d8d32e32f+8e16e16d16,c+16<b16b32>c+32d16d8c+16<b16a2> , 3:e8b4e8e8r8r4 ,d4d8e8f+8d8b8e8 ,e8f+8b8e8c+2 , 4:<e8>e8d8<d8c+8>c+8<a8>a8 ,d8>d8c+8<c+8<b8>b8g+8e8 ,a8d8e8<e8a16b16>c+16d16e16g16f+16e16, END seqs2 = mml_compile(<<END) 1:c+4+16d32c+32<b32>c+32<a16>a4a8c8,<b8>b8+16a16g16f+16g4+32f+32e32d32c+16<b16, 2:<a2+16b16>c8+16<b16a16g16 ,f+4+8b8e8>e8d8<d8 , 3:e2e8d+16e16f+4 ,f+16g16a16g16d+8>d+8e2 , 4:<a8>a8g8<g8f+8>f+8e8<e8 ,d+8>d+8f+8<b8>b4<b4> , 1:a+16b16>c+8+16d16e8+16f+16g4f+8 ,e16d16c+16<b16>c+16d32e32d8<b2, 2:c+8>c+8<b8<b8a+8b8>c+8<a+8> ,<b8>g8e8f+8<b8>b8a8<a8> , 3:e2+16d16c+16<b16a+16b16>c+8 ,<b8b8b8a+8f+2 , 4:c+16d16e16f+16g16f+16g16e16f+8e16d16c+8f+8,f+8e16d16g8f+16e16d2 , 1:>d4+16f+16e16d16b4+8a16g+16,f+32e32a16<a4g+8a2 ,a8b16>c16<b16>c+16d8+8c+16<b16>c+16d+16e8, 2:e4f+4<b8>e16f+16g+16a16b8 ,b8a8b8+16>c+32d32c+8+16<b16a4 ,>d4+8f+16e16e4+8g16f+16 , 3:<b8>b8a16g+16a8g+8+16f+16e4,e8e8f+8e8e8+16d16c+16d16f+16c+16,<f+8>f+8g8<g8g+8>g+8a8<a8 , 4:<g+8>g+8f+8<f+8e8>e8d8<d8 ,c+8>c+8d8e8<a8>a8g8<g8 ,a8>d4<b8+8>e4c+8 , 1:e8d+16c+16d+16e16f+8g2 ,<a4+16>c+16e16g16g16e16f+8+8+16g32a32,d4+16f+16a16>c16<b4+8d8, 2:f+4+8a16g16r16d+16e16<b16e4,e16c+16e16a16>c+8<a8+8>c+16d16<d4 ,d8e8f+4d2 , 3:a+8>a+8b8<b8>e8>e8d8<d8 ,a8g8f+8e8d4a4 ,a8g8a4g2 , 4:c+8f+4d+8<b4+16>b16g16e16 ,c+8>c+8<a8>c+8d8<d8c8>c8< ,b8<b8a8>a8g8<g8f+8>f+8 , 1:c+16e16g4d8<a8>e16f+32g32+16f+8e16,d32c+32<b8>c+16d8c+16d16d2, 2:e16<b16>e16g16b16a16g16f+16e8a4g8 ,a4g16f+16g8f+2> , 3:g8b8>e4+16d16c+16<b16a8b8 ,f+4e8a8a2 , 4:e8<e8d8>d8c+8<a8>d8g8 ,a8g8a8<a8d2 , END seqs = seqs1.zip(seqs1, seqs2, seqs2).map {|seqs| seqs.flatten } seqs[3][370,14] = [-24] * 14; seqs = seqs.transpose def play(rate, seqs) unit = rate * 10000 / 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) } end yield wave.pack("C*") end end if true # output to /dev/dsp open("/dev/dsp", "wb") do |f| play(8000, seqs) 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) {|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
ã¡ãªã¿ã«æå¾ã® if æã false ã«ãã㨠44100 Hz ã¢ãã©ã«ã® wav ãåºåããã¾ããç¡å§ç¸®ã® wav ã¯ã¨ã¦ãç°¡åã§ããã