Articles
RubyでMIDI(12)
前回、「読み込んだシーケンスに直接イベントを挿入する方法がない」と書きましたが、間違いでした。
直前のスクリプトは配列の挿入の方法を使って、次の通り書けます。
sq = Sequence.load("schoenberg.mid") sq[1][0,0] = ProgramChange.new(10, 0, 40) sq[2][0,0] = ProgramChange.new(10, 1, 0) sq.save("midiwirtetest1.mid")
マニュアルには「イベントはソートされます (安定)」とあるので、« を使って、以下の通り書いても、OKでした。
sq = Sequence.load("schonberg.mid") sq[1] << ProgramChange.new(10, 0, 40) sq[2] << ProgramChange.new(10, 1, 0) sq.save("midiwirtetest1.mid")
ただ、この方法はどんな場合でもOKではないようですね。
(computer) 2009/12/10
RubyでMIDI(11)
作成済のMidiファイルにMidiイベントを挿入するスクリプト。 シェーンベルクのヴィイオリン協奏曲の12音列の提示部分のピアノ譜(Midiデータはここにあります)。Midiデータに楽器の指定がされていないので、プログラムチェンジを頭の部分にセットします。チャネル0(トラック1)はヴァイオリン、チャネル1(トラック2)はピアノを設定。
require 'midi-win' sq = Sequence.load("schoenberg.mid") sqn = Sequence.new(1, 120, nil) set_os = 10 sq.each {|tr| os_old = 0 trn = Track.new sqn << trn tr.each {|ev| trn << ProgramChange.new(set_os, 0, 40) if os_old <= set_os && set_os < ev.offset && ev.ch == 0 trn << ProgramChange.new(set_os, 1, 0) if os_old <= set_os && set_os < ev.offset && ev.ch == 1 os_old = ev.offset trn << ev } } sqn.save("midiwirtetest1.mid")
読み込んだシーケンスに直接イベントを挿入する方法がないので、新しいシーケンスを用意し、そちらに全てのイベントを移しながら、冒頭にプログラムチェンジを入れるという方法をとっています。
(computer) 2009/12/06
グレン・グールド演奏術
「眼から鱗が落ちる」という諺にピッタリの一冊。
グレン・グールド関連の書籍は数十冊出版されていると思いますが、彼の演奏解釈を主題にした本って、案外無いのですよね。僕の知る限りではこの本だけです。そして、その分析内容が素晴らしい。
- 何故、彼の演奏がバッハで成功したか
- 何故、彼のモーツアルトやベートーヴェンがあんなに風変わりになったのか
- 何故、彼のロマン派のレパートリーが偏っているけど、魅力的なのか
- 何故、彼は一部のルネサンス作曲家の鍵盤作品をピアノで演奏したのか
- 何故、彼のウィーン楽派やリハルト・シュトラウスの演奏が説得力があるのか
といったような謎が綺麗に解かれる。
以下、ちょっと長くなりますが、第一部「前提」で述べられる筆者の分析のポイントを引用します(文章は一部変更しています)。
- グールドの美学の基本は、音楽はまず精神的なものであり、物理的な要素は従属的なものであるということである。それは「音楽は精神的なものであり、頭のなかだけで完全に理解しうる抽象的な存在」という観念論に基づく。西欧音楽の歴史で、このような美学は19世紀からあるものであり、珍しいものではない。ただ、グールドが違うのは、自身の音楽観を、演奏に関する習慣的な問題と融和させなかったことにある。彼は自分の考えを、演奏解釈に直接的かつ特異な方法で適用した。そして自分の音楽観に適合させるために、演奏を「調節」するのも厭わなかった。この態度が、さまざまな解釈の源となり、共感と反論を呼ぶことになった。
- グールドのレパートリーではバッハとシェーンベルクが最も重要であり、音楽的価値のモデルと考えられる。この二人は、グールドにとって、音楽に対する観念主義的姿勢の手本である。二人の作品はそれぞれの時代の対位法の模範であり、構造的に密度の高い音楽を作品の代表であり、グールドの音楽的価値基準に一致するものであった。グールドは、このバッハとシェーンベルクにみられる共通な価値を基準として、レパートリーの他の重要な作品(ヴァージナル用の音楽や、ヴィーン古典派の音楽、さらに19世紀後半と20世紀前半の音楽)を分析し、判断し、演奏したのだった。
- 観念主義により音楽作品は演奏とは別に存在すると信じていたグールドは、演奏における音楽の輪郭(つまり音楽がどう「聞こえるか」)は個々の演奏者による解釈の目的のひとつにすぎず、作品に不可欠な部分ではないと考えていた。グールドにとって、対位法的なバランス、リズムのニュアンス、強弱のレヴェル、アーティキュレーション、音色、楽器法などは、たとえ作曲家が特定したものであっても、演奏者の意志次第でどうにでもなることであり、演奏者それを変えたからといって、作品の本質を損なうことにはならないのだった。
(以上第一章「グールドの美学とレパートリー」)
- 常に観念主義者であったグールドは音楽の意義と音楽の構造を同一視していたようだった。その「構造」とは作品の記譜、つまり音高とリズムに見出されるものであり、演奏記号に見出されるものではない。演奏の準備段階でグールドは、まづ記譜のみに基づいて作品を解釈したように思える。その後で解釈を表現するのに必要な演奏手段、つまりテンポ、強弱法、フレージングなどを考えたのであろう。そして作曲家の書いた演奏記号は、音楽構造を考えるための指針とは考えず、自分の解釈と演奏記号に食い違いがある場合は、躊躇せず演奏記号を無視した。 - 「ロマン派」というレッテルを軽蔑し、またその表現様式においては「反ロマン派」を謳っていたものの、グールドの気質や前提はロマン派音楽家たちのそれを思わせる。 グールドが敬服した音楽家たち(カザロス、フルトヴェングラー、メンゲルベルク、メニューイン、リヒテル、ルービンシュタイン、シュヴァルスコプフ、ストコフスキー)のほとんどはクールドがロマン派的な気質をもつと考えた人びとであるという事実は、いかにも暗示的ではないか。 - グールドの美学のロマン主義的性質は、理屈にはあわないようだが、バッハに大いに関心を抱いていたからこそ、形成されたのだった。バッハのオープンなスコアは、非常に詳細な表記や、特定の楽器に対する偏向が創作上の概念に繰り込まれて強いる19世紀の音楽とは反対であり、構造上の緻密さと即興のための選択の自由という奇妙な組み合わせをつくり上げている。そしてこの組み合わせはグールドによれば、演奏者の個性を反映して演奏するよう仕向けるものなのだった。
(以上第二章「演奏者の役割」)
- グールドの分析はその演奏習慣と同様、非常に特殊であり、折衷主義の最たるものでもあった。それはまたそのときどきに手がけている曲に合わせて変化した。グールドは作品ひとつひとつを個別に考え、総括的に捉えることはあまりしない傾向にあったが、分析も同様であった。その分析は個別の構造に応じたものであって、ある一定の分析体系の論証ではなかった。またそれは暫定的であって,決定的でばなかった。グールドは同じ曲を違う解釈で演奏して見せることがあったが、それは演奏にはある一つだけの理想的で正しい分析があるという考え方を拒絶することを意味した。
- モーツアルトやベートーヴェンの音楽を挑発し、茶化したときのグールドは徹底してモダニストのあるはポストモダニストの皮肉屋であったかもしれない。しかし、自身の芸術に対するグールドの態度は古めかしく思えるほど生まじめであった。グールドは、音楽が倫理的、社会的に、さらには政治的、宗教的にどういう意味をもつかまで考えていたのである。
- バードやバッハやシェーンベルクの対位法的音楽は、グールドにとってコンサートより、プライベートな場で演奏するのに適した音楽であり、感覚より理性に訴える音楽なのだった。またこれは自己顕示のためのものではなく、内省的な音楽であり、落ち着きを促すものであって、興奮状態に陥らせたりはしないのであった。こうした要素すべては、グールドが道徳的に健全だと考える生活習慣と一致していた。
- 上記のものと対照的な音楽、つまりは音楽家が名人芸をひけらかすような音楽、芝居がかっていると思われる音楽、あるいは大勢の人びとを集めてきかせるが目的の音楽をグールドは非難していた。このような音楽は、グールドの考えでは快楽主義的正解を助長するものだった。この音楽の範疇には高度なテクニックを要求するロマン派のピアノ音楽、イタリアオペラ、ベートーヴェンの「英雄的」時期の大型作品など多くが含まれる。
(以上第三章「論述としての演奏」)
どうですか。事実に則していて、なかなか刺激的な「前提」でしょ。
この本の凄いところは以上の分析の論点を徹底して具体的にグールドの演奏例で証明していることです。よく出来た推理小節以上に鮮やかに謎解きしてくれる。CDや楽譜まで付いていて、証拠を確認することができます。証明は長くなるので、一つだけ、第二章「演奏者の役割」でのワグナー「マイタージンガー」での例を示します。
- 1973年に録音されたヴァグナーの「マイスタージングー」の前奏曲のグールドの編曲は、スコアに自分の偏好を強く反映させた典型的な例である。この演奏においてまずグールドが目指したのは、ヴァグナーの半音階的対位法の妙味を強調することであったが、それは、この曲の勇壮な性格を大幅に弱めることを意味した。前奏曲の前半はヴァグナーのスコアでは、ほとんどの部分が大きな音で演奏されるよう指示されているが、グールドは強弱記号の多くをかなり弱く書き換え、リズムも相当に自由に扱った。しかしそのように基本的な強弱のレヴェルを低くしたことにより,対位法的テクスチュアを明確にするたのめ微妙な強弱の変化が可能となったのである。下属音調で冒頭の行進曲の主題が続く第14小節~第27小節では、グールドはさらにヴァグナーの指示したフォルティシモをメゾヒアノに近い音量で弾いており、第20小節あたりでは、さらに弱くピアノになっている。・・(以下このような具体的証明の記述が数十行続きます)・・(証明が終わって)・・。一般的にいって、行進曲風な管弦楽曲がピアノに編作された場合には打楽器的な騒々しさがあるが、グールドの演奏にはそれがないからだろう。グールド自身が設定した基準によれば、この編作は成功である。実際、この演奏のいくつかの箇所では、どのオーケストラ演奏より対位旋律がはっきり聞き取れるのである。しかし強弱法とリズムがあまりに自由に変えられるため、少なくも表現に富む曲の前半は変化してしまった。堂々たる行進曲はしばしばもの憂い、あるいは悲しみを誘うような曲になってしまい、厳格なテクスチュアはポリフォニーの流れにに溶けて消えてしまったのである。いってみれば曲の一側面だけを取り上げて引き離し、それを強く浮き彫りにした。というのがこの編作である。それは、まるで「マイスタージングー」のなかに「トリタントとイゾルデ」を見出して、われわれに見せようとしたかの思えるのである。
グールドがどのように独自な演奏解釈したか。見事な例示でしょ。「マイタースジンガー」が「トリスタン」になっちゃうというのは凄い。全編、このような証明だらけで、冒頭で書いたように「眼から鱗」となります。長くなるので、省略しますが、第一部「前提」では、他にヘンデル「ハープシコード組曲イ長調」、モーツアルト「ピアノソナタ イ長調(K331) 、ベルク「ピアノソナタ」、ブラームス「間奏曲イ短調」などの詳細な分析があります。いずれも素晴らしい内容で、ただただ納得。
同じ手口でフルトヴェングラーやブーレーズなどの手口を解析できるかなと思いました。
(review) 2009/11/28
リュデルのトルバドゥールの歌
RubyでMIDI(10)のスクリプリトを使って、ステップ入力したジョフレ・リュデルのトルバドゥールの歌(出典 図解音楽辞典)を編集してみました。加工前のMidiファイルと加工後のMidiファイルをリンクしておきますので、ご参考にどうぞ。
ステップ入力もRubyのスクリプリトでやっていますが、こちらはもうちょっと改良してから、公開するつもりです。
(music) 2009/11/22
「大仏より抹茶アイス」
オバマ大統領の日本での演説の冒頭のジョークのようですが、なるほどねぇ。いまなら、鎌倉だと、「大仏より紫芋アイス」ですけどね。
6歳の子供が抹茶アイスを好むとは随分ませた味覚をしていたのだね(僕なんか、あれはオバサンの食べるものだと思っていまして、注文したことがありません)。前日の会談後の夕食会でも、鳩山首相と抹茶アイスの話題で盛り上がったというから、このお二人、普天間じゃ一致できないけど、食べ物の話だと気が合うのですかね。そういえばピッツバーグでもオバマ大統領は「ユキオが食べた名物のパンケーキを食べられなくて残念」と記者会見で言っていましたね。
しかし、抹茶アイスクリームって40年も前にあったのかしらと調べたら、こういうことらしい。ということは、オバマ少年はまだ登場したての最先端のアイスを鎌倉で食べたということになりますね。
(others) 2009/11/14
バティアシュヴィリのショスタコーヴィチ バイオリン協奏曲 第1番
NHK教育テレビのN響アワーで聴きました。素晴らしい作品、見事な演奏でしたね。
演奏終了後の解説で西村朗がこの作品を「やりたい放題の傑作」といっていたけど、なるほどなぁ。西村さんも相当に「やりたい放題の作曲家」ですが、その人が「やりたい放題」と評するのだから、面白いですね。ショスタコーヴィチの暗い悲劇情念の世界をやりたい放題に表現した傑作という意味なのかな。
第二次世界大戦終了直後(1948年)に書かれた曲ですけど、戦勝気分はまったくなく、粛清と戦争で死んでいった人々を悼むレクイイエムという感じの暗い悲劇的情念を感じさせる曲です。こんな曲、発表当時のソ連で公開したら、たちまちシベリア行きとなるだろうから、7年たって、スターリンが死んで、ほとぼりがさめたころに初演されたということらしい。
リサ・バティアシュヴィリの演奏はこの暗い気分(悲劇情念)をしっかり表現したもの。
バティアシュヴィリにショスタコーヴィチの魂がのり移ったかのような演奏で、特に第三楽章カデンツアから終楽章にかけて凄い迫力でした。第一楽章の陰々滅々たる雰囲気も良かったし、第二楽章もやけっぱち気味の死の行進曲という感じで楽しみました。ジンマンとN響の演奏もバティアシュヴィリを必死に追っかけているという感じだったけど、よいサポートでしたね。
(music) 2009/11/08
永田町・権力の興亡=情念戦争
細川政権の誕生から、民主党政権成立までの16年間の永田町の政治ドラマを描いたドキュンタリー。政権交代で攻める小沢一郎と様々な手口で政権維持を図る自民党の対決を描く。ナポレオン フーシェ タレイラン 情念戦争1989-1815の最後に書いたのだけど、こんなにはやくNHKテレビ番組になるとは思いませんでしたね。
こちらの情念戦争は、変革情念で政権奪取を進める小沢に対して、陰謀情念の野中と熱狂情念の小泉が必死に自民党の延命を図るという構図です。それぞれの情念の確執を関係者のインタビューで浮かびあがるという構成が見事に成功していて、面白かったです。野中さんって、フーシェに匹敵する陰謀家だったのですねぇ。よく分かりました。
しかし、2年前の福田、小沢での大連立の動きについてはまったく触れられいなかったのですが、なぜかしら。あれが実現していたら今回のような形での政権交代はなかっただろうから、まったく無視というのは変だなぁ。取材拒否されたのかな。
(others) 2009/11/04
RubyでMIDI(10)
直前のスクリプトはあまり使い勝手がよくないので、ヒューマンインタフェースを全面的に変更してみました。CUIなので、限界はあるけど、まあまあ使えるようになったかなと思います。120行とかなり大きいのですけが、貼り付けます。
require 'midi-win' class Sequence def meas_tbl_set # meas_tbl = [offset, measure_ticks, beat_ticks] timebase = self.division t, buf = [], [] self[0].each {|ev| case ev when TimeSignature if buf == [] buf = [ev.offset, ev.nn*((timebase*4)/(ev.dd**2)), (timebase*4)/(ev.dd**2)] else buf[0] = ev.offset t << buf buf = [ev.offset, ev.nn*((timebase*4)/(ev.dd**2)), (timebase*4)/(ev.dd**2)] end end } buf[0] = 128*128*128 t << buf end def meas_number_get(o) # o=offset, return(measure,beat,step+-) t = self.meas_tbl_set i_old, m = 0, 0 t.each {|i| if o <= i[0] return m+(o-i_old)/i[1]+1, ((o-i_old)%i[1])/i[2]+1, ((o-i_old)%i[1])%i[2] end m += i[0] / i[1] i_old = i[0] } end def meas_note(t) # t=track_no, return [[note_on_ev, measure, beat, steps], note_off_ev] n_tbl, tbl = [], [] tr = self[t] tr.each {|ev| case ev when NoteOn m, b, s = self.meas_number_get(ev.offset) tbl << [ev, m, b, s] when NoteOff tbl.each {|i| if ev.note == i[0].note n_tbl << [i, ev] tbl.delete(i) end } end } n_tbl end end class String def set_value print "#{self} ?\n" STDIN.gets.chop.to_i end end def edit_line(t, m, sp, cp) n = ["C", "C#", "D", "D#", "E", "F","F#", "G", "G#" ,"A", "A#", "B"] t.each_with_index {|i, n| if sp == 0 if i[0][1] == m && i[0][2] == 1 sp, cp = n+1, n+1 redo end elsif sp-1 <= n && n < sp+3 print "*" if n == cp-1 print "#{i[0][1]}-#{i[0][2]} %#{i[0][3]} #{n[i[0][0].note%12]} #{i[0][0].note/12\ } #{i[1].offset-i[0][0].offset} v#{i[0][0].vel}|" end } print "\n" return sp, cp end fname = "midifile.mid" fname = ARGV[0] if ARGV[0] != nil sq = Sequence.load(fname) getch = Win32API.new('msvcrt','_getch',[],'l') help = "# t:track m:meas b/B:before n/N:next o:on_s f:off_s v:vel p:play s:save h:help e:end\n" print help tr_no, m_no, sp, cp = 1, 1, 1, 1, 1 while true t = sq.meas_note(tr_no) sp, cp = edit_line(t, m_no, sp, cp) ch = getch.call break if ch.chr == "e" # end print help if ch.chr == "h" # help sq.save(fname) if ch.chr == "s" # save tr_no, m_no, sp, cp = "track no".set_value, 1, 1, 1 if ch.chr == "t" # track assign cp, sp = cp+6, cp+3 if ch.chr == "N" && cp+6 < t.length # 6 beats next cp, sp = cp-6, cp-3 if ch.chr == "B" && cp-6 > 1 # 6 beats before m_no, sp = "measure no".set_value, 0 if ch.chr == "m" # measure assign t[cp-1][1].offset += "note_off_step".set_value if ch.chr == "f" # note off step+- t[cp-1][0][0].offset += "note_on_step".set_value if ch.chr == "o" # note on step +- t[cp-1][0][0].vel = "velocity".set_value if ch.chr == "v" # velocity value set if ch.chr == "n" # next beat cp += 1 if cp < t.length sp = cp - 3 if cp > sp + 3 elsif ch.chr == "b" # before beat cp -= 1 if cp > 1 sp = cp if cp < sp elsif ch.chr == "p" # play if cp == 1 || cp == t.length sq.play(0) else sqp, trp = Sequence.new, Track.new sqp << trp 6.times {|i| trp << t[cp+i][0][0] trp << t[cp+i][1] } sqp.play(0) end end end
使い方はヘルプを見ればわかると思います。スクリプトの内容も個々の処理はシンプルなので、省略。
(computer) 2009/10/29
RubyでMIDI(9)
NoteOffの操作の例。
NoteOffをいじるのはテヌート、スタカート位なので、自動処理することはなさそうです。
ノートの情報を表示し、問い合わせ。指定されたティック値を増減しテヌートスやタカートにするというスクリプトです。
require 'midi-win' $note = ["C", "C#", "D", "D#", "E", "F","F#", "G", "G#" ,"A", "A#", "B"] class Sequence def meas_get(o) timebase = self.division t, buf = [], [] self[0].each {|ev| case ev when TimeSignature if buf == [] buf = [ev.offset, ev.nn*((timebase*4)/(ev.dd**2)), (timebase*4)/(ev.dd**2)] else buf[0] = ev.offset t << buf buf = [ev.offset, ev.nn*((timebase*4)/(ev.dd**2)), (timebase*4)/(ev.dd**2)] end end } buf[0] = 128*128*128 t << buf i_old, m = 0, 0 t.each {|i| if o <= i[0] return [m+(o-i_old)/i[1]+1, ((o-i_old)%i[1])/i[2]+1] end m += i[0] / i[1] i_old = i[0] } end end class String def is_int? return self == self.to_i.to_s end end fname = "midifile.mid" fname = ARGV[0] if ARGV[0] != nil sq = Sequence.load(fname) print "ussage : int(ticks to add NoteOff.offset) or measure-beat(move)\n" for i in 1..(sq.length-1) t, mp = [], "" sq[i].each {|ev| case ev when NoteOn t << [ev.offset, ev.note, "#{sq.meas_get(ev.offset)[0].to_s}-#{sq.meas_get(ev.offset)[1].to_s}"] when NoteOff t.each {|i| if ev.note == i[1] print "#{i[2]} #{$note[i[1]%12]}-#{(i[1]/12).to_s} #{(ev.offset-i[0]).to_s}\n" if mp == "" || mp == i[2] mp = "" c = STDIN.gets.chop exit if c == "e" if c.is_int? ev.offset += c.to_i print "* #{i[2]} #{$note[i[1]%12]}-#{(i[1]/12).to_s} #{(ev.offset-i[0]).to_s}\n" else mp = c end end t.delete(i) end } end } end sq.save(fname)
処理するmidファイル名を指定して起動します。小節、拍付きでノート情報を表示しますので、増減したいティック値を入力して下さい。10-2(小節-拍)と入力すると、その位置に移動できます。途中で終わらせる時は“e”。
このスクリプト、処理の前半(meas_get)はノートの小節、拍位置を取得するためのメソッドです。
コンダクタトラックのTimeSignature情報をもとに小節、拍位置を計算しています。
後半はNoteOnに対応するNoteOffを捜し、情報を表示して、指定された処理を行う部分です。
それぞれのアルゴリズムの意味は、Midi規格をご存じであれば、理解可能かと思います。
meas_getの中でMidiファイルの最終のoffset値を取得するのは面倒なので、適当な大きさ(128128128)をセットしています。超えると誤動作すると思います。
(computer) 2009/10/22
たとえ世界が不条理だったとしても
吉田秀和さんのおそらく最後(になるであろう)の音楽時評。2000年から2004年に朝日新聞に掲載された文章を集めたもの。出版は2005年。
著者の87歳から90歳までに書いたものということになります。高齢にもかかわらず、鋭い指摘は相変わらずですが、この時期の吉田さんの公私にかかわる様々な出来事が取り扱われているのが興味深いです。「たとえ世界が不条理だったとしても」という題名もそれを反映したもの。
「不条理」の「公」は9.11テロ事件後の社会の動き、「私」は吉田さんがつれあいを不治の病で亡くしたこと。 「取り扱われている」と書きましたが、全てが直接的に書かれているわけではありません。小泉政権の出来事のようにを露わに書かれることもあるのですが、それ以外は他の音楽の話題をテーマにしながら、間接的に表現されています。これが素晴らしい。
例えば、「不条理と秩序」(2000年5月)では不条理な災難に見舞われた(身内が不治の病と診断された)時、すべての音楽を聴く気にならなくなったが、唯一バッハが救いの音楽となったと書かれる。「なるほどなぁ」と思いました。
そして、妻が死んだ月(2003年11月)は「フェリアー没後五十周年」というタイトルでこの不世出の歌手を追悼する。まるで自らの身内への弔辞(レクイエム)のように読めました。
「公」の部分では直接的な表現の日本の話題(小泉首相の靖国参拝や田中真紀子外相の罷免)も面白いですが、それ以上に印象的なのは、9.11テロ事件発生後とアフガン戦争直前に書かれた「スターンのこと」(2001年10月)とイラン戦争直後の「ベートーヴェン考」(2003年4月)ですね。どちらもタイトルの内容で(事件とはまったく無関係に)音楽の話がされているのですが、必然的に掲載時点の事件を思い起こさせ、さらに筆者の事件への意見をわからせるというしかけになっています。「凄い手口だなぁ」と感心しました。
2003年11月、筆者は奥様を亡くし、一旦筆を休めますが翌年3月に再開。しかし、2回書いて(この2回分は明らかに他の時評と比較し、弱い)、断筆。
その後、吉田さんは2006年に文化勲章を受賞。新しいスタイルで執筆活動を再開されています。詩と音楽をテーマにした最新刊の二冊も素晴らしい。
(review) 2009/10/15
RubyでMIDI(8)
前回のスクリプトをマルチトラックに対応させたスクリプト。
ついでに、offsetのスタートタイムも中音部をひっこませています。
RubyでMIDI(3)で出力したmidi_test.midを処理してみました。
require 'midi-win' class Sequence def v_change(b) res = [1.05, 0.75, 0.85, 0.95] step = [2, 5, 3, 0] b = b.sort_by{|a| -a[4]} v = b[0][4] b = b.sort_by{|a| -a[3]} b.each_with_index {|a, i| if i == 0 self[a[0]][a[1]].vel = (v*res[0]).to_i self[a[0]][a[1]].offset += step[0] elsif i == b.length - 1 self[a[0]][a[1]].vel = (v*res[3]).to_i self[a[0]][a[1]].offset += step[3] elsif i == b.length - 2 self[a[0]][a[1]].vel = (v*res[2]).to_i self[a[0]][a[1]].offset += step[2] else self[a[0]][a[1]].vel = (v*res[1]).to_i self[a[0]][a[1]].offset += step[1] end } end end sq = Sequence.load("midi_test.mid") buf = [] sq.each_with_index {|tr, m| tr.each_with_index {|ev, n| case ev when NoteOn buf << [m, n, ev.offset, ev.note, ev.vel] end } } buf = buf.sort_by{|a| a[2]} b = [] buf.each {|l| if b == [] b << l elsif l[2] == b[0][2] b << l else if b.length > 1 sq.v_change(b) b = [] else b = [] end b << l end } sq.play(0) sq.save("miditestmulti.mid")
直前のスクリプトとほぼ同じですけど、マルチトラック処理するために、まず全シーケンスのノート情報を読み込んでoffsetでソートしているという点が相違点です。こっちの方がプログラムはシンプルになるので、スマートかな。
(computer) 2009/10/09
RubyでMIDI(7)
smf では、NoteOff <…, note, vel>の note とか vel は外部から操作可能なアクセサとして定義されています。前回のスクリプトでev.velとかtr[i].velという書き方でヴェロシティの内容を操作しています。それ以外の引数(offset. ch)についても同じです。他のイベントもいっしょで<…>内で定義されている名前で参照更新可能です。
これは便利ですねぇ。これでMidiファイルのイベントデータの完全に操作はできる。素晴らしい。手作業でやっていた定型的な処理を自動化できそうです。
Midiの定石でピアノの和音を鳴らすとき中声部をひっこませる(ヴェロシティを多少小さめにする)というのがあります。されを一括処理するスクリプト。前回のmiditest.midのカデンツでやってみます。
require 'midi-win' class Track def vel_change(b) res = [1.0,0.7,0.9] b = b.sort_by{|a| -a[3]} v = b[0][3] b = b.sort_by{|a| -a[2]} b.each_with_index {|a, i| if i == 0 self[a[0]].vel = (v*res[0]).to_i elsif i == b.length - 1 self[a[0]].vel = (v*res[2]).to_i else self[a[0]].vel = (v*res[1]).to_i end } end end sq = Sequence.load("miditest.mid") sq.each {|tr| buf = [] for i in 0..(tr.length - 1) case tr[i] when NoteOn if buf == [] buf << [i, tr[i].offset, tr[i].note, tr[i].vel] elsif buf[0][1] == tr[i].offset buf << [i, tr[i].offset, tr[i].note, tr[i].vel] else if buf.length > 1 tr.vel_change(buf) buf = [] else buf = [] end buf << [i, tr[i].offset, tr[i].note, tr[i].vel] end when EndOfTrack tr.vel_change(buf) if tr.length > 1 end end } sq.play(0) sq.save("miditest1.mid")
同時に発音している和音をメイン処理でテーブル化して、vel_changeというメソッドに渡す。vel_changeでは和音のを構成する最強音を求め、音高順にソート。最高音と最低音に強めのヴェロシティを設定。
という処理です。
これを手作業でやるとなると気が遠くなるほど大変ですから、「RubyでMIDI」は楽ですねぇ。
(computer) 2009/09/30
ナポレオン フーシェ タレイラン 情念戦争1989-1815
2003年に出版された本。最近、文庫本として再刊(2009年8月)されたものを読みました。
面白かったですね。本の紹介はあっちこっちにあるので、そちらをリンクするとして(ここが一番よく書けていると思います)、感想をちょっとだけ。
- この三人の伝記、自伝などいろいろありますが、こういう具合に(19世紀フランスの思想家シャルル・フーリエの「幸福を創る最終段階の要素としての情念」という思想を使って)、三人セットにして、熱狂情念(ナポレオン)、陰謀情念(フーシェ)、移気情念(タレイラン)という観点で分析した本はなかったですね。
- この観点と分析が凄い。フランス革命、ナポレオン皇帝、王政復古という激動の時代を見事に描き出していると思いました。
- 結果として革命、皇帝制、王制復古から民主制という近代への移行期の流れがよくわかる。ユニークな時代にユニークな人材が輩出し、お互いにからみあいながら、世界を変えたということらしい。
- 同じ手口で、例えば、明治維新とか、ロシア革命とか、中国毛沢東の時代とか取り扱ってみるという手がありそう。誰かやらないかしら(既にあるかな)。
- グッとスケールは小さくなるけど(^^;;;、民主党による政権交代劇なんてのも主役を見つけて、同じ観点で処理できるかな。まあ、それなりの情念をもっていそうな登場人物は何人かいるから、
あと、自民党にもうちょっと頑張って頂いて、情念型の党首を選んでもらい、丁々発止とやってくれれば、結構いい線いくのじゃないですかね。
(review) 2009/09/25
RubyでMIDI(6)
Midiファイルを読み込み、データを加工する方法。これも自在にできます。
Midiファイルを読んで、イベントを処理する基本スクリプトです。
RubyでMIDI(3)の最後のスクリプトで出力したmidファイルを読み込んヴェロシティを50に変換するスクリプト。
require 'midi-win' sq = Sequence.load("miditest.mid") sq.each {|tr| tr.each {|ev| case ev when NoteOn; ev.vel = 50 end } } sq.save("miditest1.mid")
これで36個の音符をまとめ処理できます。
TrackはAraayと同じように取り扱えるので、同じ処理は以下のスクリプトでもできます。
require 'midi-win' include SMF sq = Sequence.load("miditest.mid") sq.each {|tr| for i in 0..(tr.length - 1) case tr[i] when NoteOn; tr[i].vel = 50 end end } sq.save("miditest1.mid")
こっちの方がデータの加工には便利ですかね。
(computer) 2009/09/21
RubyでMIDI(5)
12音列を自動生成し原音列、逆行音列、反行音列、逆反行音列のそれぞれ12通りを試聴するスクリプト。
12音列はシェーンベルクが開発した音楽の技法です。ここに紹介があります。
require 'midi-win' class Array def gen_sq(i) ch = 0 offset = 0 note = 60 + i velocity = 100 tempo = 180 patch = 0 sq = Sequence.new(1,480,nil) tr = Track.new sq << tr tr << SetTempo.new(offset, 60000000 / tempo) tr << ProgramChange.new(offset, ch, patch) self.each {|c| tr << NoteOn.new(offset, ch, note + c, velocity) offset += 475 tr << NoteOff.new(offset, ch, note + c, velocity) offset += 5 } sq end end notename = ["C ", "C#", "D ", "D#", "E ", "F ","F#", "G ", "G#" ,"A ", "A#", "B "] tone = [0,1,2,3,4,5,6,7,8,9,10,11] org = [] 12.times { r = rand(tone.length) org << tone[r-1] tone.delete_at(r-1) } inv = [] inv << org[0] 11.times {|j| inv << (12 + (inv[j]-(org[j+1] - org[j])))%12} [org, org.reverse, inv.each, inv.reverse].each {|l| l.each {|m| print "#{notename[m]}(#{m.to_s}) "} print "\n" } org.gen_sq(0).play(0) c = "" while c!="e" print "which?\n" c, d = STDIN.gets.chop.split() if c == "o" org.gen_sq(d.to_i).play(0) elsif c == "i" org.reverse.gen_sq(d.to_i).play(0) elsif c == "r" inv.gen_sq(d.to_i).play(0) elsif c == "ir" inv.reverse.gen_sq(d.to_i).play(0) elsif c == "s" org.gen_sq(0).save("12tone.mid") end end
このスクリプト、起動すると自動生成した基本音列を鳴らし、音列の o 0、i 0、r 0、ir 0 の内容をコンソールに表示し、次の操作を問い合わせてきます。問い合わせに「o/i/r/ir 移動数値」で答えるとその音列を鳴らします。「s」で基本音列を 12tone.mid というファイル名でセーブ、「e」で終了します。
12音楽愛好家の皆様のために、Rubyなしで実行できるよう、ここに exberb化したEXEファイルを置いておきます。
さすがに Ruby のスクリプトだとシンプルに書けますね。データの定義を含めて基本音列の生成に6行、反行形は reverse ですむので 0行、転回形は 3行というのが凄い。
12音列の考え方そのものがプログラミング的だから、簡単にできるということですかね。
Midi処理の開始部分でテンポとパッチの設定を行っています。このあたりMidi規格を知らないと意味不明ですが、解説するのは面倒なので、ここを参照して下さい。
tr << SetTempo.new(offset, 60000000 / tempo) tr << ProgramChange.new(offset, ch, patch)
ProgramChangeだったら、リンク先からこのページとこのページをたどれば、暗号解読できますし、SetTempoはこのページのセットテンポの項に説明があります(SetTempoの方は1分は60秒というヒントが必要かな)。
解読すると smf のMidiデータのclassはMidi規格そのままということが、お分かりになるかと思います。
この「Midi規格そのまま」というのが smf の特徴です。RubyでMIDI(1)で紹介したmidilibだと、シーケンスやトラックの処理方法はだいたい smf と同じなのですが、ClassやMethodがいろいろ用意されていて、Midi規格を知らなくても操作できるようです。サイトのマニュアルによれば、例えばテンポの処理は、bpm_to_mpq(Translates beats per minute to microseconds per quarter note (beat))とmpq_to_bpm(Translates microseconds per quarter note (beat) to beats per minute)というクラスで処理できます。まあ、どっちがいいかは好みですね。
(computer) 2009/09/14
カンテレ(フィンランドの民族楽器)
これなんだか分かりますか。勿論、ブタの貯金箱じゃなくて、楽器のほう。
カンテレという名前のフィンランドの民族楽器です。楽器の内容はリンク先を読んで頂くとして、キットがあって、作ってみました。キットの入手先はカンテレ奏者としても著名な佐藤さんのサイトです。
キットですが、仕上がりは素晴らしいです。
夏休みの宿題という感じで、お盆休みをはさんで、10日間位かけて作りました。塗装のミスのやり直しもあったのですが、全工程の半分が木を磨くのにかかりました。あと、木を磨く前の接着に1日、木を磨いた後の接着に1日、塗装に2日、弦を張るのが1日というところ。とにかく、磨けば磨くほど仕上がりはよくなります。
塗装のミスは、アクセントをつけようと、ポンシ(写真右上の弦を支える出っ張りの)部分を色を変えようと塗装したのですが、色むらが出てしまったので、断念。もう、一度、磨き直して、ワックスをかけるだけで塗装はしないと方針変更しました(ワックスは制作マニュアルでお勧めの OSOMO を使いました)。もともと木の色が多少違っていたこともありますが、結果的にこれで正解でした。ポンシ部分が多少色合いが変わって、いい感じになりました。
あと、制作過程でのトラブルは、接着の工程。あらかじめ加工済の板をボンドをつけて接着、クランプを使って、固定するだけの簡単な工程なのですが、クランプのサイズと個数が計画的に選ばないとダメです。具体的にはクランプの圧着する幅サイズが65mm以上あるものを選ぶ必要があります。また数も最低三つ。できればその倍の六つ用意することが好ましいです。二回程、「あれー、数が足りない」「あれー、長さが足りない」とホームセンタに走りました。
大変というか、難しいのは弦の張り方と調音ですね。
弦の張り方は制作マニュアルにとても丁寧な説明があるので、問題はありません。ただ、最初、オクターブを間違えて、弦を一本切っちゃったのはしょうがないとして(ちゃんと添付のDVDで音を聞いて確認して置くべきでした。記憶でやったのがミスの原因)、なにせ金属の固い弦を張るので、その後も大変。うっかり先端を指に刺して血を出すとか、綺麗に巻き付けられなくて変な音になるとか、悪戦苦闘しました。これが綺麗に張れるかどうかで、随分音に影響が出ると思います。 チューニングはなかなか大変です。写真にあるチューニングハンマでピンを回すということになるのだけど、これがちょっと回しただけで、大きく変化。とても調整しきれない。ポンシ部分の弦を支える位置を変えるとか、ピンの方の弦を巻き取る加減を指で微妙に調整するとか、という方法が有効です。ただ、このあたりも巧くやらないと音色に影響を与えます。調音はチュナー(写真の黒い機械)がないと、ちょっと厳しいですかね。
で、最終的になんとか弦を張れて、音を出しました。素晴らしい音ですね。繊細にして微妙。とても美しい音です。弦を弾くポイントと弾き方で音色が大きく変わりますので、演奏は結構大変そうですが、これはいいなぁ。楽しめます。楽器の種類は違いますが、クラヴィコードってこんな感じなのかなと思いました。
とりあえず、楽譜捜しにインタネット検索というところですかね。
まあ、これ、演奏に慣れると、もっと弦の多いやつが欲しくなるから、泥沼だなぁ(^^;;;。
(music) 2009/09/06
チャルガ(ブルガリアンポップ)
直前の記事の「中東欧音楽の回路」という本はに論述している音楽のサンプルを収録したCDが付いているのですが、作者の伊東さんがチャルガについて「著作権の問題がクリアできないので紹介できない。インタネットでchalgaと検索して、是非聴いてほしい」とあったので、聴いてみました。凄いですねぇ。ロマやアラブの音楽要素が見事にポップ化されています。楽しみました。
「チャルガって何だ」という方が多いだろうから(僕もこの本で知りました)、ここ(WikiPedia)に紹介があります。
以下、YouTubeで見つけたお勧め。
マリーナという女性歌手。伊東さんの紹介では「造りモノのバービー人形のような顔立ち。それと不釣り合いなグラマラスな体。流行のベリーダンスを一番極端な形で取り入れている。音楽はかなり“民俗的”であることが多い。」とあります。
本でも紹介されている Strast(Passion) という曲の生演奏、ヴィデオクリップ。ズルナと太鼓の伴奏が印象的です。
アジスという歌手。こちらも伊東さん記述を引用します。「彼は、よく肥えていて、口ひげを生やしており、髪も髭も白く染めている。声は、きわめて高く、しかも非常に技巧的でちょっとカストラートを思わせる。男性も女性も相手にしているようなので、バイセクシャルである。この、ちょっと他に例をみないポップアイコンは、おそくら発想としてはプリンスだとかボーイ・ジョージだとかを基にしているのだろうが、それらと比べてもかなり異形であり、一度見ると忘れられない。そして歌は非常に巧い。」
マリーナとの共演のクリップ。
デシスラーヴァとの共演のクリップ、最近日本のマスコミを賑わせているテーマを取り扱った映像で、かなりあやしいです。日本じゃ公開不可でしょうね。
デシスラーヴァは伊東さん本でも紹介されている歌手ですが、myspace のオフィシャルサイトがあります。
グローリアとの共演の生演奏。この演奏も民俗音楽の要素が鮮明ですね。グローリアについてはここを参照)。
他にも上記リンクからいろいろ聴けます。なかなか楽しめますよ。
(music) 2009/08/31
中東欧音楽の回路
「中東欧」という題名を見て、アラブとヨーロッパ音楽の関係を取り扱った本かと勘違い。ハンガリー、ブルガリア、ルーマニアなど中部東欧地域の音楽をテーマにした論文を集めた本でした。
9編の論文を8つのコラムでつなぎ、序をつけるという構成で、九つの論文はそれぞれの関係はないのだけど、全体として中東欧音楽の汎民族的世界(グローバルな展開)を描き出されるという仕掛けになっています。とても興味深い本でした。
論じられる音楽は、ロマ(ジプシー)、クレズマー(ユダヤ)の音楽、東欧の農民音楽、ロシアの大衆芸能、チャルガというブルガリアン・ポップス、東欧のオペレッタ、バルトーク、エネスク、リゲティなど現代東欧クラシック音楽という具合に実に多彩。
「これらの“中東欧音楽の回路”を構成する要素が、クラシック、ポップス、民族音楽という枠を超えて共通の“世界音楽システム”を作り出しているのではないか」というのが作者の仮説です。個々の論文はその仮説を証明しようとする試みということになります。
この個々の論述が面白い。意表をつくユニークな指摘とそれを具体的にきれいに証明する記述で説得力があります。
たとえば第1章はクレズマーと呼ばれる東欧のユダヤ人音楽を扱っているのですが、シャガールの「ヴァイオリン弾き」の絵の解読からはじまり、このヴァイオリン弾きがユダヤのクレズマー音楽の弾き手であり、東欧のユダヤ人社会の結婚式の主役であったことを説明し、クレズマー音楽の特徴を解説し、最後にはショスタコーヴィチのユダヤ的主題を扱った作品、ピアノ三重奏曲の分析でまで及ぶという構成になっています。 以降、第2章ではストラヴィンスキーの「春の祭典」や「結婚」がロシアの農村の儀礼音楽との関係、第3章ではコダイとミラン・クンデラの民俗音楽の解釈の共通点と限界、第4章ではモルドァのロマのブラスバンドが民族をまたがる音楽通貨としての機能をもっていることの解説と続きます。
第5章はブルガリアンポップ、チャルガの紹介。YouTubeで聴いてこの音楽には、ビックリしたので、別の記事で紹介します。
第6章はオペレッタのジプシー的要素の解読。最後にレハール作「ジプシーの恋」のワグナーばりのライトモチーフ技法の解説があって、面白い。第7章はバルトークとエネスクの音楽とロマ的な要素の分析。第8章ではリゲティの音楽に中東欧音楽の回路がどう入り込んでいるか、リゲティとのインターヴューで炙りだす。 そして最終章でバルトークの民俗音楽採譜の旅とその旅で聴いた「豚飼いの笛の音楽」が彼の晩年の「オーケストラのための協奏曲」にどう適用されたか大胆な推測が論じられます。
これらの論述はエッセイ風のコラムでつなげられるのですが、これが章間の論述の接着剤という感じで書かれていて、こちらも面白かったです。
(review) 2009/08/28
インタネット・ラジオ(8)
tangent quattro mk2 の感想です。
使いはじめて三ヶ月位になりますが、とても満足しています。
机の上、すぐ手元で操作できるという状態で、インタネットラジオ、パソコンのスピーカ、目ざまし時計として使っています。
Linuxで動く、日本ではちょっと特殊なラジオとなりますが、立ち上げ時間は10秒位ですのですので、まあ我慢できる範囲内。音はとてもいいです。長時間聴いても疲れない音で、小さめの音で近距離で聴くという目的に最適。パソコンの音を外部のオーディオ装置に接続して聴いていたのですが、これに切り換えました。簡便だし、十分満足のいく音なので。
普段はインタネットラジオとして使っていますが、ちゃんと設定できれば、操作性もなかなかいいですね。プリセットでワンタッチで6局指定できるし、はみ出たやつは my stuff機能で簡単に選べます。6局のプリセットは古楽一局(Concertzender Early Music)、民族音楽一局(Concertzender Orient Express)、クラシック四局(CatClàssica カタロニア、musiq3 babel ベルギー、Polskie Radio Dwójka ポーランド、Radio România Muzical ルーマニア)にしました(何故かというのと、一般のクラシック専門局についてははまた書きます)。完全に自分の好みに設定できるのがいいですね。
インタネットラジオって、日本ではマイナーですが、グローバルではメイジャーだと思います。これだけ国内外間で落差のあるメディアは珍しいですね。まあ言語障壁でそうなったということなのだろうけど、音楽だけだったら、障壁は関係ないので、海外の貴重な音源を簡単に聴けないという点で、日本のクラシックファンは随分損をしているなぁ。無意味なテレビのデジタル化なんか、とっとやめて(推進キャラクタが裸で逮捕、その後、放免、結局、復帰というのは笑える)、早くこっちを普及させてほしいものです。
目ざまし時計としての機能もなかなかです。一回だけ、毎日、曜日だけという指定が可能で自分のスケジュールに合わせた設定が可能です。朝、目覚めはインドのラーガでという指定が出来るので、とてもいいです。操作性はホテルの目覚まし時計と同じ。sooze というボタンがあって、もうちょっと寝たいから、5分後にまた鳴るという機能です。ホテルの目覚ましには、少ないのかな。
(internet) 2009/08/22
RubyでMIDI(4)
Midiシーケンスを演奏させる方法。
直前の「カデンツを鳴らす」スクリプトの最初の1行
require 'midi-win'
と最後の1行
sq.play(0)
が演奏させる仕掛けです。
midi-win.rb はsmfの sampleフォルダーにあるWindows環境でのMidiファイル演奏用のスクリプリト(play-win.rb)から不要な部分を削除しただけのもの。削除したのは9行目の「require ‘gopt’」という行とスクリプトの終わりの「def usage」以降の12行程です。要するに、play-win.rbの「module SMF」だけ残したということです。このmidi-win.rb(ここに置いておきます) をライブラリのsmf.rbと同じフォルダー(僕の環境では C:\ruby\lib\ruby\site_ruby\1.8)に置く。これで音が出るようになります。簡単でしょ。
rubyは Win32API がインストールされている必要があります(以前にアプリケーションの移行(4)で紹介した ActiveScriptRubyであれば、最初から組み込まれています)。
ところで、前回のカデンツはちょっと単純すぎるので、図解音楽辞典(白水社)のサンプルを演奏してみました。
データ入力をテーブルを直接コーディングするのは大変なので、文字列で書いて変換する方式に変えました。全終止(正格)、全終止(変格)、半終止、フリギア、偽終止(D-Tp)、偽終止(D-tG)、カデンツ(長調)、カデンツ(短調)を休止をはさんで連続して演奏します。
require 'midi-win' data = <<"///" d g b 120 e g c1 240 120 / f a c1 120 e g c1 240 120 / e g c1 120 d g b 240 120 / a d1 120 g# b e1 240 120 / d g b 120 c e c1 240 120 / d g b 120 c e@ c1 240 120 / e g c1 240 f a c1 240 d g b 240 e g c1 240 120 / c e a 240 d f a 240 b-1 e g# 240 c e a 240 // g-1 120 c-1 240 120 / f-1 120 c-1 240 120 / c-1 120 g-1 240 120 / f-1 120 e-1 240 120 / g-1 120 a-1 240 120 / g-1 120 a@ 240 120 / c-1 240 f-1 240 g-1 240 c-1 240 120 / a-2 240 d-1 240 e-1 240 a-2 240 // /// class String def is_int? return self == self.to_i.to_s end def midi_table nn = {"c"=>60, "c#"=>61, "d@"=>61, "d"=>62, "d#"=>63, "e@"=>63, "e"=>64, "f"=>65, "f#"=>66, \ "g@"=>66, "g"=>67, "g#"=>68 , "a@"=>69, "a"=>69, "a#"=>70, "b@"=>70, "b"=>71} d = self.split() n = [] k, j = 0, 0 d.each {|i| if i =~ /[a-g].*/ i.scan(/([a-g][\#@]*)(.*)/) {|l| j = nn[l[0]] k = l[1].to_i if l[1].is_int? n << j + k * 12 k = 0 } elsif i.is_int? n << "o" + i elsif i == "//" n << "eot" end } n end end cadence = data.midi_table sq = Sequence.new(1,120,nil) ch = 0 note = [] velocity = 100 offset = 0 tr = Track.new sq << tr cadence.each {|c| if c == "eot" ch += 1 offset = 0 tr = Track.new sq << tr elsif c =~ /o\d?/ if note != [] o = offset offset += (c.delete("o").to_i - 5) note.each {|n| tr << NoteOn.new(o, ch, n, velocity) tr << NoteOff.new(offset, ch, n, velocity) } note = [] offset += 5 else offset += c.delete("o").to_i end else note << c end } sq.play(0) sq.save("midi_test.mid")
MIDI規格と Ruby をご存じであれば、解説は不要かもしれませんが、簡単にコードの説明します。
「class String」内の二つのメソッドは文字列で作成したカデンツ情報をテーブルに変換するためのもの。メイン処理の冒頭「cadence = data.midi_table」で以下のようなテーブルに変換しています。
62, 67, 71, “o120”, 64, 67, 72, “o240”, “o120”…., 45, “o240”, “eot”
数値は音高、“o999”という文字列はノート又は休符のオフセット値(ノートか休符かは文字列の前にノート情報があるかどうかで判定)。“eot”はトラックの終わりの意味。
メイン処理の最初の部分で Sequence、Trackと関連する変数を初期化。cadenceループ内でノートのオンオフをテーブルの内容に合わせて設定する。
cadenceループ内では、“eot”でトラックを切り換える、“o999”でため込んだノート情報をMIDI化、数値だったらノート情報として一時テーブルに保存という処理になります。
こうやって説明すると、ゴタゴタしますが、コードは随分シンプルに書けますね。
(computer) 2009/08/18
RubyでMIDI(3)
- smfのインストール仕方
- SMF紹介のページからパッケージをダウンロード。解凍したフォルダーのreadmeにインストールの仕方の説明があります。 解凍したフォルダーをカレントにして
ruby install.rb config
ruby install.rb setup
ruby install.rb install
で完了。 - smfの使い方
- このページにマニュアルがあります。これでわかる人にはわかるのかもしれませんが、僕にはチンプンカンプンでした(^^;;;。
参考になったのは解凍したフォルダーの下の sample というフォルダーにある rand1.rb というスクリプトで、ランダムに8チャネルの音楽(といえるのかな ? )を自動生成するもの。以下 rand1.rbのソースコードです。
require 'smf' sq = Sequence.new tr = Track.new sq << tr tr << SequenceName.new(0, 'rand1') srand for ch in 0..7 offset = 0 for i in 0..127 note = rand(128) vel = rand(127) + 1 tr << NoteOn .new(offset, ch, note, vel) offset += rand(128) tr << NoteOff.new(offset, ch, note, 64) end end sq.save('rand1.mid')
なるほど。
Midiファイル全体をSequenceというClassとして定義して、それにTrackというClassをもたせる。Trackは、同じく、Event(Midiイベント)をTrackの要素としてもつ。それぞれのMidiイベント(Event)は引数をもち、Classとして取り扱われる。時間の推移、チャネル番号、音高、ヴェロシティなどのMidi値は引数で設定できる。SequenceとTrackはArray(配列)と同じ振る舞い方をし、MIdiイベントやトラックを配列の要素のように処理できるということのようですね。
上記マニュアルページで各MidiイベントのClassの引数<…, note, vel>の「…」は上位のクラスの引数を引き継ぐという意味ですね。たとえばVoiceMessage配下のクラスであれば、EventクラスとChannelMessageクラスの引数であるoffset(Midiファイルの先頭からのTick値)とch(チャネル番号)を補えばよい。
最後の sq.save(‘rand1.mid’) は作成されたシーケンスをMidiファイルとして保存する Sequence Class の Methodです。
Midi規格というのは非常に複雑怪奇ですから、CでMidiデータを直接扱うことのと比較すると(マンデルブロ音楽作成プログラムで経験あり)、簡単ですね。
試しにやってみると、例えば、ハ長調カデンツを鳴らすなら
require 'midi-win' cadence = [[0,4,7],[0,5,9],[-1,2,7],[0,4,7]] sq = Sequence.new(1,120,nil) tr = Track.new sq << tr ch = 0 offset = 0 note = 60 velocity = 100 tr << ProgramChange.new(offset, ch, 0) # 0 = piano(GM) cadence.each {|c| c.each {|d| tr << NoteOn.new(offset, ch, note + d, velocity)} offset += 475 c.each {|d| tr << NoteOff.new(offset, ch, note + d, velocity)} offset += 5 } sq.play(0)
となります。これって、Midiの「 hello world 」みたいなものですね。
note=60は中央のハ音になりますが、この数値を変えれば、調性を変えることができます。例えば
require 'midi-win' cadence = [[0,4,7],[0,5,9],[-1,2,7],[0,4,7]] sq = Sequence.new(1,480,nil) ch = -1 offset = -480 note = 59 velocity = 100 for i in 0..12 ch += 1 next if i == 9 tr = Track.new sq << tr offset += 480 note += 1 cadence.each {|c| c.each {|d| tr << NoteOn.new(offset, ch, note + d, velocity)} offset += 475 c.each {|d| tr << NoteOff.new(offset, ch, note + d, velocity)} offset += 5 } end sq.play(0) sq.save("miditest.mid")
これで、CからはじまってBで終わるカデンツをチャネルを変えて演奏し、miditest.midというファイル名で保存することができます。 スクリプトの内容は直前の「 hello world 」をベースに for ループで括っただけだから、解説不要でしょう。for ループの中の「 next if i == 9 」という行はMIDIのGM規格だとチャネル10は無条件に打楽器が指定されるので、これを回避するためのおまじないですね。
(computer) 2009/08/15
Rubyスクリプトのexe化(Exerbとmkexyの使い方)
RubyでMIDI(1)で紹介したスクリプトをexe(実行形式)化するのにexerbというプログラムを使っています。これでRuby環境がなくてもスクリプトを試すことができるようになるので、便利です。
このexerb化の方法については右の「Ruby on Windows」という本を参考にしましたが、結構、悪戦苦闘したので、何にトラブったか、exerbとmkexyの使い方の紹介を兼ねて書いておきます。
ExerbはWindows環境でRubyのスクリプトを実行形式にするツールです。ライブラリを含めて単一のEXEファイルにすることができて、作成されたファイルはRubyをインストールしていないパソコンでも動かすことが出来ます。
Exerbの使い方は簡単で
exerb スクリプトファイル名 or レシピファイル名
です。 レシピファイルというのはライブラリを含めてEXEファイル化するためのもので、通常はこちらを使うことになります。このExerb用のレシピファイルを生成してくれるツールが mkexy というコマンドです。
mkexy の使い方は
mkexy スクリプトファイル名
だけで OK です。
exerb と mkexy は ActiveScriptRuby 1.8.7 をインストールすれば、使えるようになります。
で、やってみましたが、これが巧くいかない。下の画面のコピーのようにファイルがないというエラーになるのですよね。
レシピファイルはテキストファイルですので、内容を見てみると
# Generated by mkexy # on 2009-08-10 21:15 general: startup: E:/MD-2008/midi.rb core: cui kcode: none file: E:/MD-2008/midi.rb: smf/io.rb: file: C:/ruby/lib/ruby/site_ruby/1.8/smf/io.rb forwardable.rb: file: C:/ruby/lib/ruby/1.8/forwardable.rb smf.rb: file: C:/ruby/lib/ruby/site_ruby/1.8/smf.rb smf/toy/searchsegment.rb: file: C:/ruby/lib/ruby/site_ruby/1.8/smf/toy/searchsegment.rb rational.rb: file: C:/ruby/lib/ruby/1.8/rational.rb smf/toy/tempomap.rb: file: C:/ruby/lib/ruby/site_ruby/1.8/smf/toy/tempomap.rb Win32API.so: file: C:/ruby/lib/ruby/1.8/i386-mswin32/Win32API.so type: extension-library midi-win.rb: file: C:/ruby/lib/ruby/site_ruby/1.8/midi-win.rb
最初の generalブロックでスクリプトの属性を指定し、後半のfileブロックでライブラりをしてするということらしい。逆スラッシャがスラッシュになっているのは気になるが、特に問題はなさそう。
「変だなぁ」と思って、「Ruby on Windows」の例をみると、スクリプト名にディレクトリ部分がない。
general: startup: midi.rb . . file: midi.rb: . .
と変更して、実行してみる(midi.rb、midi.exyはカレントディレクトリに置く必要あり)。
今度は巧くEXEファイルを生成してくれました。
あと、mkexy は
- 引数の Rubyスクリプトを実際に実行する
- 正常に処理が進む時、まったくメッセージを出さない
という風変わりな仕様になっているので、かなり面食らいます。 midi.rbの場合、起動されても、キーが押されなければ、ダンマリという状態ですので、あれハングしちゃったのかなと焦りました(画面のコピーではエスケープキーを押してmidi.rbスクリプトを終わらせています)。
(computer) 2009/08/10
RubyでMIDI(2)
RubyのMIDIライブラリとしては以下の二つのものがあります。
- midilib
- 海外製のMIDIライブラリ(Jim Menardさん作)。Midiデータの操作とファイルへの読み書きができる。ChangeLogによると2004年から開発が開始され、現在もサポートされています。特徴はドキュメントが非常によくできていること。すべてのClass、Methodについて詳細な説明があり、英語ですが、簡単にわかります。Midiデータの操作についてはMidi規格プラスアルファ(テンポ、音名、小節の処理など)というレベルでで、Midiの仕様にそんなに詳しくなくても操作できるようになっています。
- SMF
- こちらは日本製(舟迫忠佳さん作)です。Midiデータの操作とファイルへの読み書き以外にサンプルスクリプトを使えば、OSS ドライバでの演奏、 spkr(4) での演奏、ウィンドウズでの演奏、wavファイルへの書き出しなどができるようです(ライブラリとしての機能はこちらの方が豊富)。チェンジログがないのでよくわからないのですが2006年ころに開発され、現在もサポートされているようです。残念ながら、ドキュメントは貧弱です。ClassやMethodの説明はHTMLファイル 1ページのメモだけで、ある程度のMidi規格の知識がないと使えないかもしれません。
一般的にはドキュメントがしっかりしているmidilibの方がお勧めだと思いますが、日本製、ウィンドウズでの演奏ができる、紹介のページ(上記リンク先です)のバッハ演奏が素敵だったので、僕は SMF を使うことにしました。ドキュメントの不足部分は、ソースを読めば、何とかなるだろうと思って。
SMFでのウィンドウズでの演奏は、SMFをインストールすると作成される gems\1.8\smf-0.15.12\sampleフォルダーにある play-win.rb というスクリプトで可能です。
直前の二つの記事のスクリプトが組み込んでいる midi-win.rb というモジュールは、この play-win.rb の main 部分をカットして、演奏用の module だけにしたものです。play-win.rb をそのまま使ってもいいのてですが、動かすには、goptという引数解釈をするモジュールを組み込む必要があるので、goptを使っている main 部分を削除したということです。
この sampleフォルダーはSMFの使い方を知るには必見のフォルダーです。上記の OSS ドライバでの演奏、 spkr(4) での演奏、ウィンドウズでの演奏、wavファイルへの書き出しの他に、STT 編集、ストリーム編集 (クォンタイズ、シャッフル、グルーヴ、ヴェロシティコンプレッサ、など)、モールス符号化、プレーンテキストや XML としてのよみかき などのサンプルがあり、これらのスクリプトを読めば、SMF の使い方がわかります。
舟迫さんは、使用マニュアルなんて退屈なものを書くより、これらサンプルを作ることで、使い方を解説しようとしたのかなと思います。
というわけで、SMF の使い方の紹介をかね、RubyでMIDIの仕方を解説します。
(computer) 2009/08/07
RubyでMIDI(1)
直前のスクリプトをCUIにしてみました。たったの24行でパソコンのキーボードがMidiキーボードになります。
require 'midi-win' ktable={113=>[54,"F#"], 97=>[55,"G "], 119=>[56,"G#"], 115=>[57,"A "], 101=>[58,"A#"], \ 100=>[59,"B"], 102=>[60,"C "], 116=>[61,"C#"], 103=>[62,"D "], 121=>[63,"D#"], 104=>[64,"E "], \ 106=>[65,"F "],105=>[66,"F#"], 107=>[67,"G "], 111=>[68,"G#"], 108=>[69,"A "], 112=>[70,"A#"], \ 59=>[71,"B "], 58=>[72,"C "], 91=>[73,"C#"], 93=>[74,"D "]} def n_on(c,n,v) sq = Sequence.new tr = Track.new sq << tr tr << NoteOn .new(0,0,n,v) tr << NoteOff .new(120,0,n,v) sq.play(c) end c = Win32API.new('msvcrt','_getch',[],'l') while true k = c.call n_on(0, ktable[k][0], 127) if ktable.key?(k) if k == 27 break end puts ktable[k][1] if ktable.key?(k) end
シンプルでしょ。一番情報量が多いのはハッシュテーブルかもしれない。スクリプトの処理部分はハッシュで定義されたキーが入力されたら、対応するノート番号を n_on メソッドに送り、鳴らしているだけ。エスケープキーで終了します。
せっかくなので(?)、上記スクリプリトをreverb化してここ(zip圧縮してあります)においておきます。Windows環境であれば、rubyがインストールされていなくても、動くはずです。
(computer) 2009/08/05
RubyでMIDI(0)
案外簡単ですね。苦労したのはGTKの画面更新の仕方でした。以下のスクリプトでWindows環境であれば、音を出すことができると思います。require ‘midi-win’はsmfのsampleにあるwin-playからwindowsの演奏に必要な部分だけ取り出したmoduleでここに置いておきます。smf.rbが置かれているライブラリフォルダーと同じフォルダーに置いて下さい。
require 'gtk2' require 'midi-win' Height = 100 HLength = 30 $ktable={65=>[54,"F#"], 90=>[55,"G "], 83=>[56,"G#"], 88=>[57,"A "], 68=>[58,"A#"], 67=>[59,"B "], \ 86=>[60,"C "], 71=>[61,"C#"], 66=>[62,"D "], 72=>[63,"D#"], 78=>[64,"E "], 77=>[65,"F "], \ 75=>[66,"F#"], 188=>[67,"G "], 76=>[68,"G#"], 190=>[69,"A "], 187=>[70,"A#"], 191=>[71,"B "], \ 226=>[72,"C "],221=>[73,"C#"], 81=>[72,"C "], 50=>[73,"C#"], 87=>[74,"D "], 51=>[75,"D#"], \ 69=>[76,"E "], 82=>[77,"F "], 53=>[78,"F#"], 84=>[79,"G "], 54=>[80,"G#"], 89=>[81,"A "], \ 55=>[82,"A#"], 85=>[83,"B "], 73=>[84,"C "], 57=>[85,"C#"], 79=>[86,"D "], 48=>[87,"D#"], \ 80=>[88,"E "], 192=>[89,"F "], 222=>[90,"F#"], 219=>[91,"G "], 220=>[92,"G#"]} def n_on(c,n,v) sq = Sequence.new tr = Track.new sq << tr tr << SequenceName.new(0, 'step') tr << NoteOn.new(0,0,n,v) tr << NoteOff.new(120,0,n,v) sq.play(c) end window = Gtk::Window.new window.set_size_request(200, 120) window.set_app_paintable(true) window.realize drawable = window.window keymap = Gdk::Keymap.default gc = Gdk::GC.new(drawable) window.set_events(Gdk::Event::KEY_PRESS_MASK) window.set_events(Gdk::Event::KEY_RELEASE_MASK) red = Gdk::Color.new(65535, 0, 0) blue = Gdk::Color.new(0, 0, 50000) white = Gdk::Color.new(65535, 65535, 65535) colormap = Gdk::Colormap.system colormap.alloc_color(red, false, true) colormap.alloc_color(blue, false, true) colormap.alloc_color(white, false, true) fontdesc = Pango::FontDescription.new fontdesc.set_family("Comic Sans MS") fontdesc.set_style(Pango::STYLE_NORMAL) fontdesc.set_weight(Pango::WEIGHT_BOLD) fontdesc.set_size(20*600) layout = Pango::Layout.new(window.pango_context) layout.font_description=fontdesc window.signal_connect("expose_event") do gc.set_foreground(red) layout.text=" " drawable.draw_layout(gc, 10, 10, layout) end window.signal_connect("key_press_event") do |w, e| k = e.hardware_keycode layout.text="#{$ktable[k][1]} #{($ktable[k][0]/12).to_s} " if $ktable.key?(k) drawable.draw_layout(gc, 10, 10, layout, blue, white) n_on(0,$ktable[k][0],127) if $ktable.key?(k) end window.signal_connect('delete_event') do false end window.signal_connect("destroy") do puts "destroy event occurred" Gtk.main_quit end window.show_all Gtk.main
2/3以上はGUIのための処理です。MIDIの処理にかかっているのは 8行目からのキー定義部分と16行目からのノートオンさせるためのメソッド、そして後半部分の window.signal_connect(“key_press_event”) の中でノートオンメソッドを呼び出している
n_on(0,$ktable[k][0],127) if $ktable.key?(k)
という一行だけで、全部足しても20行たらずです。
苦労したのは、スクリプト終わり近くのシグナルハンドラ window.signal_connect(“key_press_event”) の中で音名を表示していますが、この表示方法です。
drawable.draw_layout(gc, 10, 10, layout, blue, white)
として、 blue, white と前景色と背景色の指定をしています。
日本語のウェブサイトの情報では
drawable.draw_layout(gc, 10, 10, layout)
となっていて、これだと前に表示した文字が消去されないのですよね。消去するには前景色と背景色の指定が必要と気が付くに時間がかかりました(英語の,Python-Gtk紹介のサイトに情報がありました)。
以下何回かにわけて、RubyでMIDI処理する方法をご紹介します。