はじめまして、やしのみと申します。
MIDIファイルからプログラムチェンジ等の情報はどうやって抜き出すのでしょうか。
B#などのSMF解説ページにいっても、それをどうやって抜き出すのかわからず・・。
初心者質問ですみません。
TMemoryStreamとかで、一バイトずつ読んでいって、
プログラムチェンジコードを見つけたら、その次のバイトを取得する
といったところでしょう。
(だったと思います、実際はB#とかを見ながら、正確なほうでいくといいでしょう)
ただし、プログラムチェンジと同一の16進数値で、プログラムチェンジ以外を表すもの(メタテキストだとか、デルタタイムの数値だとか)もありますから、
その辺をうまく管理しておかないとだめなんですよね。
音楽系の定数を、うちのおんぷむらのうら>おんぷ村倉庫>Delphiユニット>MusicConst でまとめてるので、
表示のときにはそれを使うといいでしょう。
(楽器の名前とか)
まだアップロードされてたかな
前作ったプログラムチェンジ差し替えのCUIソフトがあるんですけど…。
ああ、あったあった、ここからどうぞ、
http://Onpu.jpn.ch/Village/softs/SoftArcive/midChanger.lzh
とりあえず、midChanger /dialog と書いたバッチファイルを、
同じフォルダに入れておけば、
動作してくれると思いますよ。
(midiファイルと同じフォルダに、変換済みファイルができるはず)
まあ、一部判断が抜けてますから、
たまに(テンポとかが)がたがたになるファイルも存在しますけど。
なんかいま見てみたら、ヘルプで結構とんでもないこといってますね^^;
(プレイヤーのほうはまだ作らないのか、
シーケンサも作ろうかというのに、こんなのじゃいつまでたつのやら(^^ゞ)
ありがとうございます。たかみちえさん。
そのソース等を使わしてもらいながらやりましたが、なかなかできません。
例えば、1曲めのプログラムチェンジを取得する・・などはどうするんでしょうか・・。
ごめんなさい、凄く初心者ですね。申し訳ございません。
> ごめんなさい、凄く初心者ですね。申し訳ございません。
あやまることなんてないですよ、みんな最初は初心者なんですし。
さて、本題。
察するに、中から最初のプログラムチェンジ情報を抜き出して、
それを表示したりするんでしょうか?
それならたしかに、上のソースじゃ、そのまんまじゃ使えませんね。
(あれはとりあえず、総当たりなので)
でも、ちょっとした工夫で、何とかなりませんか?
たとえば、プログラムチェンジが見つかったら、フラグを立てて、次のプログラムチェンジは素通りするようにする。
MIDIには16のチャンネルがありますから、一つ一つのチャンネルで、
プログラムチェンジが見つかったのか否か、調べないといけません。
わたしなら、あらかじめ0〜15の数値配列(Byte型でいいでしょう、0〜126しかないんですから)をつくり、
プログラムチェンジコードを見つけたら、配列のチャンネル番目のますに、見つけたプログラムチェンジの楽器番号を入れておきます。
(たとえば、1チャンネルめのプログラムチェンジを見つけたら、array[0] := 10 などのように)
もう取得済みかどうか確かめるには、
そのチャンネル番目のますにちゃんとした番号が入っているかどうか調べればわかりますね。
(あらかじめ全部に255とかを入れておけば、一目瞭然でしょう)
そしてファイル内のプログラムチェンジを調べ終わったら、
MusicConstユニット内の定数配列と照らし合わせて、
楽器名に変換。
こんなんでどうでしょう?
そうそう、チャンネルの番号の取得方法ですけど。
and や orの論理演算を使えば、何とかならないでしょうか?
この辺はあまりとっさにはわかりませんけど、
何とかして、下位4ビットだけを抽出できればいいんですよね。
(
????0000=0
????0001=1
????0010=2
????0011=3
・
・
・
????1111=15
わかればいいのは、ここだけです。
まあ、しらみつぶしにやってもできないことはないですけど、
それじゃまともな速度で抽出できないでしょう
)
まあ、その辺まったく知らないので。
がんばってとしかいえませんね(-_-;)
1バイトに16($F)をAnd演算で足せばいいようです。
i := Byte And 16;
(iに下位4ビットの数値が入る)
VBのサイトを参考にしましたけど、Delphiならshlやshrなどの演算で、
もっと手っ取り早く済ませられる・・・かもしれません。
たかみちえさんのプログラムのソースを参考にしてみましたが。
どうもタイトルなどのメタイベントも取得してしまうようですね(言ってただろ
if Bin.inParamHeader(i,bin.Size,$C0,$CF) Then
begin
showMessage('Get!!! ProgramChanges!!');
showMessage(IntToStr(i));
bin.Position := i+1;
bin.Read(pcBuf,4);
showMessage('INT: '+IntToStr(pcBuf)+' ;');
end;
どうも私のやり方がちがうみたいですね。
う〜ん、どうすればいいんだ(話し聞け
ツイート | ![]() |