IronPythonでDirectSoundでWaveファイルの再生

import clr

clr.AddReference('System.Windows.Forms')
clr.AddReference('Microsoft.DirectX.DirectSound')

from System.Windows.Forms import *
from Microsoft.DirectX.DirectSound import *

class PlaySound(Form):
    def __init__(self, soundFile):
        self.device = Device()
        self.device.SetCooperativeLevel(self, CooperativeLevel.Normal)

        self.buffer = SecondaryBuffer(soundFile, self.device)
        self.buffer.Play(0 ,BufferPlayFlags.Default)

    def Dispose(self, disposing):
        if(disposing):
            if(self.buffer):
                self.buffer.Stop()
                self.buffer.Dispose()

            if(self.device):
                self.device.Dispose()

        Form.Dispose(self, disposing)

Application.Run(PlaySound("x:/test/wav/a.wav"))

再生部分でPlay(0,0)って呼ぼうとしたら(参考にしたC#コードがそうなってた)enumよこせボケって怒られた。
enumは"BufferPlayFlags.Default"見たいに使うようだ。

コードの好み

ギター的な意味で。バックグラウンド的はうるさめロック全般好きです。


コードの好み - higepon blog

いわゆるFのコード、6弦ルートのメジャーコードを、
握りこむロックスタイルでやるのは見た目ももちろん、
機能としてストラップ長くても大丈夫な利点が。


ストラップは長さに比例して偉い教に熱心な頃だと、
自然ロックスタイルになりました。



Gは6弦3Fを親指、そのまま親指で5弦ミュート、1弦3Fを人差し指で。

3
0
0
0
X
3

これだと2弦を押さえたり押さえなかったり、
ミュートしたりしなかったりで3度を抜けてお得。
あとなにより押さえるのがすごく楽。指2本。


一般的なローコードのGって難しいし。
むしろハイコードのGにすることも多々ありますね。


昔はコードってたくさん弦がなってないといけない!
全部押さえないと!F押さえられなきゃ半人前!

見たいな固定観念強かったけど最近は3本位でも全然平気。
セッティング次第だけど逆に濁ったりするし。



ついでに好きなコードフォームでも。

2
3
4
5
X
3

これはGmaj7だけど、6弦ルートのmaj7全般。
これは握り具合の良さ、シーケンシャルなポジション、あと和音の並び的に
1357度が並んできれい、等で好きなコードであります。

ゴルフ用ブルートフォースのでSEGV

[ruby-dev:36698] Segmentation fault in eval
を寝ぼけ眼にみてて、SEGVかーうちでも落ちるかなあ、
とコードをコピー、Emacsに貼り付けたところで色がついて、
あれ、なんか見たようなコード、と思って、元としたというURL良く見たら俺のだった。
るびまゴルフ 【第 4 回】といた - mamamotoの日記


ということでなんか他人事でない気がしたので、条件を絞りました。3行になりました。

n=0
$*=n
n=$*
./ruby c.rb
c.rb:3: [BUG] Segmentation fault
ruby 1.9.0 (2008-10-10 revision 0) [i686-linux]

-- control frame ----------
c:0003 p:0016 s:0007 b:0007 l:000006 d:000006 TOP    c.rb:3
c:0002 p:---- s:0004 b:0004 l:000003 d:000003 FINISH :inherited
c:0001 p:0000 s:0002 b:0002 l:000001 d:000001 TOP    <dummy toplevel>:17
---------------------------
DBG> : "c.rb:3:in `<main>'"
-- backtrace of native function call (Use addr2line) --
0x811ed54
0x814dd6c
0x814dddb
0x80d1c21
0xb7f4c440
0x81136f3
0x811a06a
0x811a291
0x805ca9f
0x805e282
0x805b990
0xb7d83450
0x805b8c1
-------------------------------------------------------

Compilation aborted (core dumped) at Fri Oct 10 10:01:59

evalは関係ないみたいだ。

るびまゴルフ 【第 4 回】といた

るびま
ブルートフォースで。だって考えても分からなかったから。

def f(s)
  l = lambda{|n|
    begin
      eval(s)
    rescue Exception
      nil
    end
  }

  if l[0] == 1 && l[-1] == 0 && (1..100).all?{|e| l[e]==0}
    p s
    exit
  end
end

a = (?\ ..?~).to_a - (?0..?9).to_a - (?A..?Z).to_a - (?a..?z).to_a

9.times{|i|
  a.permutation(i+1){|b|
    c = ['n', '0', '1']
    d = b + c
    c.size.step(0, -1){|j|
      d.permutation(d.size-j){|e|
        f(e.join)
      }
    }
  }
}

しかもブルートフォースすら無駄、不備だらけ。1.9用。

----略----
(eval):1: warning: string literal in condition
(eval):1: warning: string literal in condition
(eval):1: warning: string literal in condition
(eval):1: warning: string literal in condition
(eval):1: warning: string literal in condition
(eval):1: warning: string literal in condition
(eval):1: warning: string literal in condition
(eval):1: warning: string literal in condition
(eval):1: warning: regex literal in condition
(eval):1: warning: regex literal in condition
(eval):1: warning: regex literal in condition
(eval):1: warning: regex literal in condition
(eval):1: warning: regex literal in condition
(eval):1: warning: regex literal in condition
(eval):1: warning: regex literal in condition
(eval):1: warning: regex literal in condition
(eval):1: warning: regex literal in condition
(eval):1: warning: regex literal in condition
(eval):1: warning: regex literal in condition
(eval):1: warning: regex literal in condition
(eval):1: warning: regex literal in condition
(eval):1: warning: regex literal in condition
(eval):1: warning: regex literal in condition
(eval):1: warning: regex literal in condition
(eval):1: warning: found = in conditional, should be ==
(eval):1: warning: found = in conditional, should be ==
(eval):1: warning: found = in conditional, should be ==
(eval):1: warning: found = in conditional, should be ==
(eval):1: warning: variable $= is no longer effective
(eval):1: warning: variable $= is no longer effective
(eval):1: warning: variable $= is no longer effective
(eval):1: warning: variable $= is no longer effective
(eval):1: warning: variable $= is no longer effective
(eval):1: warning: variable $= is no longer effective
(eval):1: warning: invalid character syntax; use ?\s
(eval):1: warning: invalid character syntax; use ?\s
(eval):1: warning: invalid character syntax; use ?\s
(eval):1: warning: invalid character syntax; use ?\s
(eval):1: warning: invalid character syntax; use ?\s
(eval):1: warning: invalid character syntax; use ?\s
(eval):1: warning: invalid character syntax; use ?\s
(eval):1: warning: invalid character syntax; use ?\s
(eval):1: warning: invalid character syntax; use ?\s
(eval):1: warning: invalid character syntax; use ?\s
(eval):1: warning: invalid character syntax; use ?\s
(eval):1: warning: invalid character syntax; use ?\s
(eval):1: warning: invalid character syntax; use ?\s
(eval):1: warning: invalid character syntax; use ?\s
(eval):1: warning: invalid character syntax; use ?\s
(eval):1: warning: invalid character syntax; use ?\s
(eval):1: warning: string literal in condition
(eval):1: warning: string literal in condition
(eval):1: warning: string literal in condition
"1[n]"

なるほどねー。

Mp3TagFS

FUSEじゃねーのだけど。DokanというWINDOWS用のFUSE的なもの用なのだけど。
でもたぶんちょっといじればFUSE用になるはず。


えーとMp3のTagでファイルシステムを作ります。指定したディレクトリ以下のMP3をさらい、
タグを読み込んで"/アーティスト名/アルバム/曲"という階層を作ります。
iPodがさー、ファイルネームを独自形式で保存するのでそっから取り出したい場合、
こんなんあればいいなあと思って作った。


Dokanとmp3infoに依存します。別途入れてください。
Dokan: user-mode file system for Windows
http://rubyforge.org/projects/ruby-mp3info

#!ruby -Ku

require 'dokanfs'
require 'delegate'

class DokanProxy
  def read(path, offset, length, fileinfo)
    return "" unless @root.file?(path)
    if @root.respond_to?(:read_offset)
      @root.read_offset(path, offset, length)
    else
      str = @root.read_file(path)
      if offset < str.length
        str[offset, length]
      else
        false
      end
    end
  end
end

class InsensitiveString < DelegateClass(String)
  def hash
    __getobj__.downcase.hash
  end
  def eql?(oth)
    __getobj__.downcase.eql?(oth.downcase)
  end
  def ==(oth)
    eql?(oth)
  end
end

class Mp3Tag
  require 'mp3info'
  require 'jcode'
  require 'kconv'

  def cleaning(s)
    InsensitiveString.new(s.gsub(/[\/\\:]/, "_").kconv(Kconv::SJIS))
  end

  def initialize(path)
    @map = Hash.new
    Dir.glob(path+"/**/*.mp3").each{|filename|
      p filename

      info = Mp3Info.new(filename)
      tag = info.tag
      tag2 = info.tag2

      ar = tag.artist || tag2.TP1 || '不明なアーティスト'
      al = tag.album  || tag2.TAL || '不明なアルバム'
      ti = tag.title  || tag2.TT2 || '不明な曲'

      artist_album = ((@map[cleaning(ar)] ||= {})[cleaning(al)] ||= {})
      i = 0; tmp = ti
      while artist_album[title = cleaning(tmp+".mp3")]
        tmp = "%s-%04d" % [ti, i+=1]
      end

      artist_album[title] = filename
    }
  end

  def split(path)
    path.split("/")[1..-1].to_a.map{|e| InsensitiveString.new(e)}
  end

  def contents path
    if path == "/"
      @map.keys
    else
      a = split(path)
      case a.size
      when 1
        @map[a[0]].keys
      when 2
        @map[a[0]][a[1]].keys
      else
        []
      end
    end.compact
  end

  def file? path
    a = split(path)
    a.to_a.size == 3 && @map[a[0]][a[1]][a[2]]
  end

  def directory? path
    a = split(path)
    case a.size
    when 0
      true
    when 1
      @map[a[0]]
    when 2
      @map[a[0]][a[1]]
    end
  end

  def read_offset(path, offset, len)
    a = split(path)
    open(@map[a[0]][a[1]][a[2]], 'rb'){|port|
      port.pos = offset
      return port.read(len)
    }
  end

  def size path
    a = split(path)
    file?(path) ? FileTest.size(@map[a[0]][a[1]][a[2]]) : 0
  end
end

if __FILE__ == $0
  DokanFS.set_root(Mp3Tag.new(ARGV[0]))
  DokanFS.mount_under("r")
  DokanFS.run
end

sshfs

このFUSEをつかってssh接続をファイルシステムにするプログラム。

なんとなく存在は知っていた気がしたけど実際試してみた。Cygwinsshd立ててそれをVMwareLinuxからマウント。
これはいいね。Windows上で編集作業をやることというのはどうしてもあってたとえばこないだ書いたAutePagerizeのとかはインストールフォルダ決まってるからEmacs使えないで困るんだけど、このケースのような時にまさにぴったり。

Filesystem in Userspace

FUSEファイルシステムを作る仕組み。ハードディスクとかCDドライブとかをマウントしてファイル群として扱うように、自分の好きな何かをファイル群として見せかけさせ、扱わせる。


まずrubyバインディングを。http://rubyforge.org/projects/fusefsからソース持ってきてruby setup.rb実行。
サンプル動かそうとするとfuseがother権限で動かないので動くようにしてしまいます。

以下root。

chmod o+x /bin/fusermount
chmod o+rw /dev/fuse
chmod o+r /etc/fuse.conf

んでユーザーに戻ってサンプル実行してみる

mkdir hell
ruby sample/hello.rb hell &
ls hell

適当にruby sample/hello.rbをkillすると中途半端な状態にhellディレクトリがなるので

fusermount -u hell

でアンマウント。