クーの自由研究

かえるのクーが素朴な疑問を実験して報告します。

計算機音楽の自由研究(準備:その2.9.4)~機械学習用サウンドデータベースをつくる(開き直り編)

これまでのおはなし


危機に関する一般への情報開示はきわめてゆるやかに、そしてすこしづつ行われたので、蛙社会的パニックは発生しなかった。一部学生が「我々はだまって茹でられるつもりはない!」と大規模なデモを行ったが、冷気放射器によって強制冬眠させられてしまった。もう誰もクーに頼ろうとするものはいなかったが、クーはマイペースに「サウンドデータベース(真)」の開発を再開した。

次元圧縮によって、個体の特徴を極限まで強調された古代"平面"かえるのクーは、「根性」のほかにも「音響解析」の能力が飛躍的に向上していた。採取された異星の「神経様物質」はずば抜けた音響解析能力を持つことがわかっていたが、クーはそれをはるかにしのぐ能力を会得していた。ふとしたことから異星の「神経様物質」との意思疎通が可能であることに気づき、「みぃ.ちゃん」と名前を付けた。「みぃ.ちゃん」はなぜかクーのことを「教師せんせい」と呼んだ。そのことを打ち明けられた「モリあおがえるのユキ」は、クーが本当にもう昔のクーに戻れないことを悟り、悲しみにくれるのであった。「わたしのこと『ユキちゃん』と呼んでくれたことは一度もなかった・・・」


f:id:np2LKoo:20170615230040p:plain


蛙類滅亡の日まであと9日

11,328音/60,000音 (18.9%)  51.1%の遅れ さぼっているのバレバレ


6/15 旅はよいです

移動中はとても暇なので、蛙生の目的を考えてしまいました。戻った今日からは、とりあえずMIDIインターフェースのあるPC2台でのんびり録音していきます。

なお、前のページがすこし長くなり、間もあいたのでこのページで再開しました。

6/16 悪夢のWindows Update

そういえばWindows Updateをしばらくやっていなかった!とやってしまったのが運の尽き。なぜか1台のマシンのUSBオーディオが鳴らなくなってしまいました。。。

何が悪いのでしょう。。。もう一台のほうも最初は出なくなったけど、再起動したら音がでました。問題の方は何回あげなおしても音がでません。。。パソコンなんてそんなものとは分かっていますけど、このタイミングでかなり痛いです。

お話でも書いて気分転換します。


みぃ.ちゃん:「class 会話6864(音DB):def お話1(みぃ, 音):みぃ.この音みぃ.好き。」*1

"平面"かえるのクー:「これは、フォルテという楽器だよ。ハンマーで弦を叩いて音を出すんだ。」
みぃ.ちゃん:「def お話2(みぃ, 音):みぃ.もっとみぃ.いろんな音、みぃ.とっても、みぃ.return 聞きたい」
"平面"かえるのクー:「実は、ボク、いろんな音を生成できるようになったんだ。GANGAN聞かせてあげるね。」
みぃ.ちゃん:「def お話3(みぃ, 音):ゐ~、この音ぎゃんかわ!みぃ.こんな音みぃ.聞いたことみぃ.ない。教師せんせい!もっと、みぃretrun おしえて!!」
"平面"かえるのクー:「これはフォルテの音をストラディバリの方向に虚数展開した音だよ。」
みぃ.ちゃん:「def お話4(みぃ, 音):を~、みぃ.世界がみぃ.回る。。。」

いまや2つの生命体、いや1つの生命体と1つの疑似生命体の間に信頼以上の関係が芽生えていた。


 

6/17 見知らぬ方とお友達気分に弟子入り気分

 同じ悩みを持つ方は、なぜかとても親近感がわきます。ネット回線を通して握手。でもP2Pじゃないからハンドシェークできないかぁ。。。現象はまったく同じです。早速やってみます。

わ~。とっても感謝。音が鳴りました。教師せんせい。どうも有難うございます。

さらに、悩んでいたドライバの不安定動作についても、せんせいの教え通り、ひとつ前のドライバを使用することにより解決しました。本当にどうも有難うございます。US-2x2を使用されていて、同じような悩みのある方はドライバのバージョンを「1.0.2」(1つ前のバージョン)にすると小さな幸せが音ずれるかもしれません。

(せんせいはお酒が飲めるかわからないので、またボクもゲコなので気分だけ)蒸留酒で乾杯。*2

 サウンドデータベースは遅々としてすすみません。そういえばサウンドの"バリエーション"の例を貼っていなかったので、いまさらながら貼ります。下のサンプルは、同じトーンからの音です。

どうにか原音がわかる範囲で非破壊系のエフェクトを組み合わせてかけています。半音前後の音とはできるだけ違って聞こえるようにしています。リバーブはかけすぎで、残響がノイズにしか聞こえませんが、バリエーションとしてこれくらいはありかな?という感覚で設定しました。ついでにString系も貼ってみました。

 フォルテPianoほどエフェクトがのりませんが、この路線で録音しています。

う~んあたりまえですが、機材が2倍あると2倍はかどる~。(これまでは他の録音が)動作しなくて、結局1台でやっていましたが、待ち時間とチェック時間がほとんどなので、バランス的にはもう1台「録音機」が欲しい。。。

さらに、半日かけてRS232C-MIDI変換作成をやってみるか思案中。。。結局部品がなくて今日は断念。本当にそんなことできるか気になるので、RS232C(クロス)ケーブルとコネクタは(そんなに高価ではないので)クリックしてみました。ボクがなにかすると必ず道草をするのでいつものことではあります。(そして必ずといっていいほど、道端のトラップに「ことごとく」はまります。)アマゾンで合計2000円いかないので、よく見るブログの書籍紹介から気になった本もクリックしてみました。「逆説のスタートアップ思考」というのが、とてもおもしろそうでしたでので、ぽっちっとな。「読むドラッグ」とも評されたこの本を読んで本当に旅ができるのでしょうか。とても気になります。(Amazonの星2つの酷評もおもしろかったです。)

初盤「はかどる」ように思えましたが、結局今日もはかどりませんでした~。よくあることです。期日を設ければ少しはその気になるかな?と目標設定していますが、ボクの「マイペース」は筋金入りであることを改めて自覚しました。(でもまだ間に合わせる気でいるんですよ)

 6/18 禁断のボタン

単調作業のあいまに息抜きです。お話を書く方が楽しくなってきました。


真田技術長:「”モリあおがえるのユキ”から聞いたが、"神経様物質"とテレパシー通信できるようになったと聞いた。報告書にはそんなこと全く書かれていないぞ。どうなっている? 」技術長は何故かとても怒っているようだ。
"平面"がえるのクー:「だって、その報告書進み具合しか書くところないよ。」
真田技術長:「備考欄があるだろ。」
"平面"がえるのクー:「最初に説明してくれたとき、備考欄は空欄でいいといってたよ。」
真田技術長:「話がかみ合わない。どうやって話をしたのか知りたいのだ。」
"平面"がえるのクー:「それなら初めからそう言ってよ。みぃ.ちゃんとの会話は。。。」

弾道遊星の制御装置のボタンをおそうとしたクーの手を技術長はあわてて制止した。

真田技術長:「ボタンにはさわるなといったはずだ。これは食事、いやエネルギーチャージボタンと解析されたものだ。」
"平面"がえるのクー:「これお話ボタンだよ。」

あきれかえる真田技術長の手をおしのけ、クーはボタンを押した。

そのボタンにはおいしそうな「てんとうむし」のマークが印されていた。ウィーンという微かな音とともに表示版に何か異星の文字で表示があらわれた。

== Python maitreya(ver 5,670,000,000.0.0) System Debug Mode Ready! ==

 みぃ.ちゃん:「class 会話9296(音DB):def お話1(みぃ, 音):みぃ.最近の音もみぃ.結構みぃ.好き!」
"平面"がえるのクー:「いまの音はストラディバリとよばれるものだよ。体のいろんなところに挟んで音を出すんだ。ユニコーンのしっぽで擦って音をだすんだよ。」
そう言ってからクーは三角マークがすこしだけ進むような印のさっきとは別のボタンを押した。
  みぃ.ちゃん:「def お話2(みぃ, 音):みぃ.今回の音=音、ゑ~みぃ.今回の音似てるけどみぃ.前の音の特徴とみぃ.全然違う=みぃ.特徴比較(みぃ.今回の音、みぃ.前の音の特徴)!、教師せんせい!みぃ.もっとみぃ. return 聞きたい!」

真田技術長は何もいわず、口をぽかんとあけながら研究室をあとにした。


 6/19 アマゾンはとかげ?それともカメレオン?

Amazonに注文すると早く届くので驚きます。もちろんプレミアムではありません。早速届いた「本」を読んでいます。書評から読みすすめにくそうなイメージがありましたが、全く逆で驚くほと読みやすく感じました。(それって理解していないということかな?それともひねくれ者なので、逆説のほうがしっくりくるのかな?面白いからどちらでもいいかぁ。)今日の読書はこれくらいにして、RS232Cをつないでみます。クロスケーブルをたのんだつもりなのに、ラベルには「ヌルモデモケーブル」と書かれており、間違った!?とおもいましたが、同じもののようです。録音についてまったく焦らないジブンの性格に焦りを感じています。あれ?

う~ん時間切れ。ずぼらな悪い子よいこはねる時間になりました。今日は素直に寝ます。

6/21 〇マトの諸君!


館内放送:「♪緊急連絡♪、館内すべての方は至急最寄りの集会場、コントロールブリッジに集結、もしくは会議コンソールにアクセスください。」
あわただしく走り回る足音や、「早くしないか」との声が聞こえる。
"平面"かえるのクーがブリッジに顔を出すと、大型スクリーンには既に映像が映し出されていた。
異星人:「ハッハッハ。トマト星の諸君。いや君たちの言語では赤丸星というらしいが。。。これが本当の最終通告だ。無条件に降伏したまえ。」
映像は初めて公開されたが、その異星人は蛙族の最も嫌悪する生物に酷似していた。
異星人の青白い鱗に光が反射し、時折チョロと出される細い舌の先が2つに分かれるの見て蛙族はすくみあがり、脂汗を流した。映像では手足がどのような形態なのかは確認できなかった。
異星人:「諸君らにもう未来はない。巳々*3の総攻撃は最終段階を迎えている。回答の猶予をあたえる。」
...
沖田総司令蛙:「通信担当蛙。返信はこうだ。『ばかめ』」
通信担当蛙:「恐れながらそれは、やぶへびなのではないでしょうか。」
沖田総司令蛙:「そうだな。改めて言う。『ばかめ』だ!」
通信担当蛙:「は、はい!」
通信は所定のシーケンスで亜空間送信された。
異星人:「巳!!!」
星間通信の映像の異星人の瞳孔が怒りに収縮し、開かれた口の牙からは毒と思われる粘液が糸をひいたと思われた直後、映像が乱れ回線が切断された。
(ナレーション)はたして、蛙族に生き延びる術はあるのか?「宇宙音感 ア・バオア・クー」次回「たったひとつの冴えたやりかた」に、フィーチャー・エクストラクション!君は宇宙からの音を感じるか。


 

*1:翻訳注:会話構造に一定の枠組みを持つ構造言語とおもわれる音声が付加されており、一番類似すると思われる言語形式にのった翻訳している。みぃ.の記載は翻訳対象の星域では発音不可能な音声であるが、「自分自身」でありかつ「名前」であることの最も近い表記を代用した。将来別の解釈がされる可能性があることを添える。:星間翻訳システムggggleより

*2:蛙界の法律にはアルコール年齢制限はありませんが、おたまじゃくしは「アルコール」も「たばたば」も嫌う傾向があります。

*3:ggggle星間翻訳システム注:我々と訳したほうが理解しやすいと思われますが、原音に即して翻訳しています。

計算機音楽の自由研究(準備:その2.9.3)~機械学習用サウンドデータベースをつくる(ど根性編)

これまでのあらすじ


北の方角から星間弾道遊星の攻撃をうけた赤丸星の科学者は、その制御技術向上により命中精度が各段に進歩していることに愕然とする。このままでは赤丸星の住人、すなわち蛙類はあと1か月で滅亡するという高精度の予測が提示された。別の研究により特定の音波の組み合わせ(楽器音に近いもの)が、「弾道遊星」の制御に用いられているとされる、疑似神経様物質の制御を狂わすことが明らかになった。神経様物質は「音」に対しての非常に敏感な解析特性を示し、制御よりも音波の解析を優先してしまうことにより、「弾道遊星」の軌道制御システムが崩れるのであった。この「音波」の組み合わせを重力波を含むあらゆる帯域のエネルギー波にして放射する迎撃システムに組み込むべく、対遊星迎撃システムの中核をなす「サウンドデータ」を早急に創生しなければならない。それは60000音以上の楽器音が一定のまとまりと、ばらつきをほどよく以て構成されている必要があるという。


f:id:np2LKoo:20170602001056p:plain

このページのおはなしのヒロインを演じる「モリあおがえるのユキちゃん」

スレンダーな美少女です。

エストラインが魅力です。


はたして蛙類はサウンドデータベースを期限内に完成し、滅亡から逃れることができるのであろうか。

蛙類滅亡まで あと 22

現在 4,840音 / 60,000音 (8.1% / 約18.6%ぶんの遅れ)


6/2 それは理論でも技術でもない。心:精神である。

前のぺージがいっぱいになってきたので、6月はこのページで進み具合を報告します。あいかわらず、しばらくは「はてな自体の」日記形式無視ですすめます。あしからず。

今日は音源を探しました。KONTAKT Player(無償版)とライブラリ(無償版)をいれましたが、評判通り音がいいですね~。YAMAHA Motif系の音はKONTAKTのデモ版があったので使えそうか確認していました。デモ版は15分の使用時間制約があるようですが、どうにか使えそうな気がします。

6/3 勇気ある決断

善意の解釈では思考実験、醒めた視点では単なるギミック、批判的な分析では思考錯乱、診療的見地では〇〇病と思われるかもしれませんが、はじめてしまったものはしかたありません(開き直りの境地)。このページはこのお話の路線でいきます。(どう書いてもつまらないフェーズなので)


データベースも創生手法が確立し、軌道に乗り始め5%程度進んでいる。創生の効率化を検討している矢先に大きな問題が発覚した。

創生済のサウンドデータを入手・培養した「疑似神経様物質」に学習させたところ、まだデータ数が少ないとはいえ、いとも簡単に解析が完了し、このまま進んでも「遊星兵器の制御システムを継続的に攪乱させることができない」可能性が高まった。原因の分析結果をもとに戦略会議がひらかれた。


サンプラー音源を元にしているが、3~4音を同一の「サンプリング波形」から周波数だけをかえて音を出しているものがほとんどで、解析にほどよいばらつき」がでない。(楽器としてはこのようにしたほうが効率的で、演奏をさせると違和感がほとんどないケースが多い)

同一のメーカー系列では「波形」の使いまわしがある程度あるようで(上位互換や評判のいい音を後発のサンプラーにそのまま使うなど流れとしてはあたりまえではあるが)、機材をかえてもメーカが同じであれば「同じような音」もありバリエーションに乏しい

・一連の音を録音する場合にリバーブなどのエフェクトや音の強さを一定にして録音している。(フォルテならVolme=127固定にするなど)サンプラーによっては音の強さを変えると音のキャラクターを微妙に調整し、リアリティを増すものが多いが、バリエーションとしてその機能が使えていない*1

例えばピアノの音は周波数の違いもさることながら、『この音は「ピアノ」的と判断できる範囲の音をできだけ広範囲に、ある程度わざとばらつかせながらまんべんなく網羅する。』必要があります。基本的周波数の違い(:シフト)がポイントではなく、時系列で変化する相対的な周波数の組み合わせが重要なのです。この状況(サンプラーの音があまりに貧弱で、たとえばピアノの音に感動するくらいのピアノらしい音がない。ただし「どうにかピアノにきこえないこともない音」はこのデータベースでは網羅性の観点で結構貴重)では、スタジオ巡りをして生音を録音して回りたい衝動に駆られます。ですが、時間はやまほどあるが、お金がない。いや今回の設定では時間がない!!そこで。。。

別メーカの音源を追加で探す。

■網羅性の観点から、もっとひどい音のサウンドフォントも探す(これは探せばたくさんある認識)

■採用するより多くのサンプリングをあつめ、きわめて似たキャラクターのサンプリングセットは除外する。(オーディションする

■1音ごと「ある程度」ばらつくよう、音のエフェクトと音の強さをばらつかせる。(フォルテならVolume=100から127のランダム値、リバーブMIDIでリアルタイム調整できる場合は±30%程度ランダムにばらつかせる。)


「ここが引き返し可能の最終点かもしれない。。。」
長老蛙たちの会議はなかなか結論がでなかったが、ついに最高司令蛙は皆の前で宣言した。
沖田司令蛙:「もういちど初めからやりなおそう!我々は生存確率が最も高い方法を選択する。」
モリあおがえるのユキ:「古代クン、いえ、クー!あなたに蛙類の未来は託されたわ。」
古代かえるのクー:「ボク、がんばる!」

こうして改めて「サウンドデータベース(真)」の創生が開始されたのであった。

はたして蛙類は生きのびることができるのであろうか。

蛙類滅亡の日まで、あと27日

(つづく)


というわけで、リアルタイムにリバーブ等を調整するよう各機材のMIDIのインプリメンテーションチャートとにらめっこしています。さすがに全然わかりません。CM-32Pは全部MIDI経由でコントロールする必要があるので、たいへんです。(ボリュームと電源ボタンしかない。ディスプレイもない)SOUND CANVAS VAがあったのでノイズのひどいSC-55mkIIはあきらめてVSTから録音します。CM-64/32系の音もSOUND CANVAS VAにはいってはいますが、「一部」の音だけなので、CM-32L/P系の音は実機からがんばって録音します。

6/5 心機一転

もういちど、最初からやりなおしています。MIDI機器を制御するためのエクスクルーシブメッセージやコントロールチェンジについてはかなり熟練してきました。PythonMIDI制御をごりごりコーディングしています。MIDIインプリメンテーションチャートがあれば、だいたいの機器はコントロールできる感じになってきました。ボクの学習能力も捨てたものではありません。ソフトとハード機材ではコントロールの考え方が結構違うのでそれ毎にコーディングなので大変です。(ソフトはコントロールチェンジをマッピングして対応するものが多く、ソフトの設定にも手間がかかります。)

1音ごとに、エフェクト(おもにリバーブ、コンプレッサー、イコライザー系の元の音を破壊しないでやんわり変える系)を変化させてかけ、前後の音と「あえて」別な感じにしてばらつかせています。(エフェクト設定変更もMIDI制御です。) 音の録音時に(エフェクト系の)設定と確認(音のかぶりや処理結果)が増えてしまったので、以前にもまして進み具合が悪いです。その都度の設定もさることながら、リバーブ系の音が次の音にかぶり、音の開始検出に失敗することが多々あり、そのたびにパラメータを調整してやりなおすので、時間がかかっています。このままでは今月中に完了できそうにありません。何か対策を立てないとやばいですが、今のところ気力で乗り切るくらいしか思いつきません。。。

6/6 「46のガマ作戦」

もう引退したマシンに、(つかえるかどうかわかりませんが)Windows10の評価版をいれてみます。OSソフト自体は認証なしで1ヶ月使えると思いますが、問題はスペック的に音が途切れないで録音できるかどうか、(それよりそもそもWindows10が動くかどうか)です。やってみます。ちなみに現在1台(現役マシン)で録音していますが、あと3台増やして4台にします。それらしい名前をネットで検索し、コードネームを「46のガマ作戦」と命名しました。(サテお立合い。1台が2台。2台が4台。4台が。。。:ちなみにIT業界の計算方法では1人で60000分かかる仕事は60000人でやれば1分で終わるそうです。IT(業界)ってすごい!)ATOM機(Celeronですらない)でどこまでできるかわかりませんが、何事も挑戦です。早速インストールでつまずき中です。吉とでるか凶とでるか。。。あと、音源の追加のほうは、「KONTACT」の目途がつきました。助手の知り合いでKONTAKT/KOMPLETEの(半額キャンペーンの)注文をした人がいて協力いただくことになりました。

 

6/7 ボクの悩み事 解決するです?

上の記事はまさにボクの(リアルの)悩み事そのものです。「●経験的モード分解(不完全)」は初めて知りました。ウェーブレット変換しかないかなぁ。。。と思っていたので、とても参考になりました。どうも有難うございます。

さて、IT業界の人に聞いたら『「炎上プロジェクト」に人を大量投入したら、初期習熟(教育)コストで一層破綻し、全体統制がますます効かなくなる。火消しができるくらいの精鋭熟練者あつめないでどうするよ!!』は、IT現場あるあるだそうです。

ちなみに、ATOM機はいまだにディスク認識できずに停滞中です。始まる前に作戦失敗のきざし。。。→ソフトが原因とおもっていたらハードが原因だったあるあるでした。DISKのSATA電源が不安定(接触不良?)で別系統のSATA電源ケーブルをつかったらあっさり解決しました。→インストール完了。。。

机の上には3つのディスプレイと、4つのキーボード(うち一つは楽器)と、3つのマウスが並んでデイトレーダのようになりました。ヘッドフォンが1個しかないのが欠点です。(あと1台は別の部屋)

録音マシンではPythonは3系しか使わないので、AnacondaとPycharmを入れます。波形確認用にSoundEngine FreeとAudacityを入れます。SoundEngine FreeとAudacityは特定の目的で使い分けると便利なので両方入れます。あとで似たような環境をつくることもあるかもなので、何を入れたかメモしておきます。


OS:Windows 10 (64Bit): ダウンロード版(去年ダウンロードしたものを持っていましたが、3月下旬の時点のパッチ適用版に更新されているので、そちらを使いました。

アーカイブソフト:lhaplus

サウンド確認用:SoundEngine Free / Audacity

ASIOを使えるようにする:ASIO 4 ALL または USB Audioのドライバなど

ASIO動作確認用/録音用:SampleTank2 (Freeまたは10日お試し版)

Python環境:Anaconda (最新版 4.4.0/Python3.6だった)

開発環境(IDE):Pycharm Community(2017.1.3版)

・easy_install.exe pip (pipを使えるようにする)

・anaconda3とanaconda3\Scripts にpathを通す

・pip install pyaudio  と pip install  pygame

MIDI IN とMIDI OUTをMIDIケーブルで直接結線。あ、


6/8 なにかが足りない! 

やばい。この録音方法はMIDIインターフェースが必須なのでした。そしてボクはMIDIインターフェースを2つ持っています。録音に使いたいパソコンは4台です。さて、MIDIインターフェースがないと動作しないことに今まで気が付かなかったのは、何が足りなかったからでしょう???答えは秘密です!

助手に相談したら、RS-232C-MIDI変換ドライバを入れて2つのCOMポートをクロス接続(実結線)すれば、MIDIインターフェースがなくても動作させられる。と助言をもらいました。よくわかりません。

Windows10で動作しないといわれる昔のオーディオインターフェイスカード(MIDI付)でも、MIDI部分だけは動作する「かも」しれないとのことなので、昔のインターフェースカードを発掘中です。

助手からは「定義したあとは放っておいても次々に、1日中録音するようなしくみにしないと厳しいのでは?」との意見ももらいました。貴重なご意見有難うございます。a

6/9 縄文土器「こわれもの」「危機」どっちが好き?どっちもYES


真田技術蛙長:「このままでは到底今月中に完成することはできない。これが死守すべき進み具合のグラフ。。そしてこれに実際のグラフを重ねると。」

「・・・。」どこからともなく深いため息が漏れ、作戦会議には絶望とも言える重い空気が流れた。

沖田司令蛙:「なんとかならないのか・・・このままでは・・・」

真田技術蛙長:「現場のほうでは4倍の速度で作成する方法を模索したのですが、技術的な壁があり目途がたっていない状況です。私に秘策がひとつだけあるのですが、ただ・・・」

沖田司令蛙:「なんだね?言ってみたまえ。」

真田技術蛙長:「いままで成功例が1例しかなく、たいへん危険な方法なのですが。。。次元圧縮という禁忌の技法があるのです」

沖田司令蛙:「続けてくれ。」

真田技術蛙長:「我々はご存知のように4次元の世界に生きています。時間と空間的3次元をあわせて4次元です。目的達成のためにこのうちの1次元を圧縮して物事の本質・特徴を浮き彫りにする手法です。これを生身の蛙に適用するのです。」

説明は続いたが、ついに沖田指令蛙は最終決断を下した。

「これで学習能力・知的能力が飛躍的に向上し、解決できるめどがつくのなら。。。」

翌日、皆の期待のもと、次元転換装置の扉はあけられた。はたして成功なのか?

2次元という平面に次元圧縮された「古代かえるのクー」は皆の前に颯爽と姿を現した。

古代"平面"かえるのクー:「根性、根性。ど根性!!」

皆の表情は凍り付き、気を失うものもいた。どうしてTシャツに張り付いているのか疑問を呈するものもいた。

はたして蛙類に未来はあるのか。

蛙類滅亡の日まであと21日。。。


(編集部より) 連載休止のお知らせ。ご愛読いただいております「宇宙音感 ア・バオア・クー」は都合によりしばらく休止となります。誠に申し訳ございません。

再開ができるようになりましたら、改めてお知らせいたします。


1週間ばかり(リアルな)旅にでることになりました。その間データベース作成は休止となります。地道にやっていたのでは間に合わないことが明白ですが、まだあきらめたわけではありません。きっと、小人さんまたは妖精さんがなんとかしてくれます。

小人さんどうも有難う!RWC 研究用音楽データベース「楽器音データベース」(50 楽器, 29.1 Gbytes)ボクの探していたのはコレかもしれない。いや、まさにコレだ。

RWC研究用音楽データベース: 楽器音 15,000円 収録91時間

「例えば,RWC-MDB-I-2001 No. 01 のピアノでは, 3メーカー(Yamaha, B¨osendorfer, Steinway)のピア ノで,88鍵すべての鍵盤を,それぞれ4奏法(ノーマ ル,スタッカート,ペダル,同音の連打)で,強,中, 弱の3段階の強さで弾いたものを収録した」

おおお!本物だぁ

後藤真孝先生のページはみていたのに何で気が付かなかったのでしょう。(何か足りない!)

ほかにも

McGill University Master Sample」DVDなら3枚セット:入手方法未確認:もしかして有名図書館なら所蔵していて借りられるのかな?

Iowa Musical Instrument Samples」ホームページから$10以上の寄付と研究・利用目的を書いてダウンロードの模様です。

暫く悩んでみます。

 BGM:セカイシックに少年少女 / After The Rain (そらる×まふまふ)

 

*1:エフェクターの使用は原音重視の観点からは微妙ですが、ピアノや弦楽器はホールも楽器の一部(楽器からすればエフェクター)であるともいえると思います。実際サンプラー音は「エフェクター」を使ってはじめてそれらしい音に聞こえるものも多いため、積極的に使って調整する方向で考えます。エフェクターのパラメータも当然ばらつかせます。

計算機音楽の自由研究(準備:その2.9.2)~機械学習用サウンドデータベースをつくる(実践編)

はじめに

機械学習用のサウンドデータベースについては、「音の機械学習」に興味のある方に使ってもらえるレベルのもの(汎用性がある。統計的にもそこそこ多い要素数といえる。)を目指そうと思っていました。考え方を改め、「汎用性のあるサウンドデータベース」をつくることをやめます

f:id:np2LKoo:20170525203856p:plain

「汎用性はなくていいから(ボク専用でいいから)とにかく手持ちのサウンドでてっとり早くデータベースをつくり、実験を開始する」ことにシフトします。(泣く泣く「格付けチェック遊び」はあきらめます)音質もあきらめます。(涙)

とはいえ、60000音で11時間ぶん以上の音を扱うことになるので、整理してまとめるだけでもかなり時間がかかると思われます。

(6月末まで反省キャンペーン中です。内容を順次リファインします。準備:その2.6から、準備:その2.9.2までのブログを順次内容更新します。その間内容的には「カオス」な感じになるとおもいますが、ご容赦ください。)

目標設定します(ボール妥協は友達!)

6月末まで、60000音程度の「音のデータベース」を作成することに集中する。

7月からそのデータベースを使って「音の機械学習」の自由研究実験をはじめる。「音楽の学習」を目標にしているが、いきなりはむりポなので、まずは「音」についての自由研究をする。

8月くらいに自由研究での扱いやすさ、扱いにくさをみてデータベースを調整し「そこそこのレベル」にまでする。(ただし手持ちの音なのでしょぼいです)テスト用のデータベースも準備する(10000音)

9月くらいにデータベースを固め、それ以降不満があっても変えない。どうしても不満があるときは別のものを1から作る。データベースの(しょぼいけど)完成版とアクセス用のPythonクラス等をどこかに公開する。(ソースはGitHUBですが、データベースはどこかのフリーのネットストレージサービスにすると思います。)

9月以降はデータベースのことは忘れ(使うだけに集中し)今年の「音の自由研究」に専念をする。(そしてここが本当のスタートラインです)

・そしてまたきっとが訪れる。冬になる前になんとか今年の成果を出したいです。

このページはすこし特殊になります。

ボクはブログは日記形式にではなく、情報ごとにまとめる感覚です。とはいえ、最近は経過も含めてこまかめに書いています。「(追記)」をかいたり、1つの話題を細切れの時間を使って2~3日程度で編集することもよくあります。

このページは「実践編」として、データベースが完成する予定の6月末まで順次更新していきます。(他に話題があれば書きますが、サウンドデータベースに関する作成はこのページに報告していきます。(どちらかといえば、公開するというより、ジブンにハッパをかける意図です)データベースの仕様についても微調整していきますが、データベースの仕様については、(準備:2.X)の内容を更新していきます。追記ではなく一部書き換えます。)

ブログの読者の皆様には誠に申し訳ございませんが、6月末までは確実に諸々停滞することになります。ご容赦ください。


めざせ60,000音!

現在 2,816音 / 60,000音 (4.7%)

蛙類滅亡6月末まで、あと31日。イスカンダルは遠い。


そもそもできるの?

・1日あたり(単音で)2000音の整備を目標にします。(30日で60,000音の計算!)4オクターブの楽器なら40種類を目途に毎日録音です。

・1200種類くらいの音が必要ですが、ピアノなどは音量(タッチ)によって音質がかなり違いますので、(サンプリング音源のレイヤー構造にもよりますが)1種類の楽器選択で4(pp, mp, mf, ff)種類くらい採取するように考えていますので、充分まかなえると思います。

SampleTank 2 XLだけで 1500音色以上あるので、数的問題はありません

XV-5080なんていう骨董品もあります。XV-5080はファクトリーパッチで1200種類以上あります。Roland CL32-L/Pという化石も発掘するかもです。(悲しいことにkontaktは持っていない。だれか持っていないかなぁ。)もちろん?Roland SC-55系もあります。

ほかにも、古いデジタルシンセ(実機:メーカ保守にだして25年モノの現役)などいろいろあります。。。KORGレガシーコレクションもあります。どの音を使うか決めるだけて一苦労。ソフトも含めてどれも10年以上前の古い「遺産・遺跡」です。どれも「溶け込む」タイプの主張が弱い音ばかりで、単音で聞くと本当に「しょぼい音」です。問題は「音の品質」と、まとめる「時間」(というよりは精神力)ということになります。(機材等は助手の協力にて)

5/25 機械学習用情報(タグにいれるやつ)のフォーマット調整

・汎用性を少なくする代わりに、よりシンプルにします。

データベース(仮)の音をPythonを使って鳴らしてみました。ノイズがあることと、クリップ(飽和)している感じがあるので、まだ調整中です。*1この調整が完了したら、怒涛の「音の録音」をしていきます。 

 5/26 反省キャンペーン始動

6月末までサウンドデータベース作成期間とし、不都合な点、考え直した点をフィードバックします。その場合サウンドデータベースの仕様定義も変更となるので、準備:2.6~2.9.2までの内容を見直します。(わかりにくくなるので、追記、変更の記載をせずに書き換えます。この間のブログ日付はあまり意味がなくなります)完成版の仕様をあらためてかけばいいのですが、断片の時間にボク自身、このブログをみて思い出しながら修正していきますので、(ブログ的には禁じ手な感じがしますが)遡り修正します。

5/27 録音の音圧をそろえます

録音時に波形のピークで音量を調整するのをやめて、平均音圧を目標値にするよう音量調整します。短い音なので、音の立ち上がりなどのフレーム分析はせず、全体(32768sample/0.68Sec)の平均音圧を求めます。RMS(実行値計算)という音圧計算方法で求めます。

powerAvarage = 10.0 * np.log10((regFrame ** 2).mean())

regFrame は-1.0から1.0までの値に正規化された値を入れます。(平均音圧を出したい部分の全サンプルです) 最初の数字が20.0ではなく、10.0であるところがポイントです。(Powerの場合は10です)単位はdB(デシベル)です。0を超えることのない、マイナスの数字となります。元にするサンプル音には、ff(フォルテシモ)、pp(ピアニシモ)などのサンプリングがあり、ff(フォルテシモ)、の場合は調整目標音圧を-17.0dBにする(例)などの調整をします。0dBに近くないよう、もう少しレベルをあげたいのですが、アタックが強いとピークが飽和するので、範囲(16bit最大)を超えるような調整は行いません。

5/27 その2 ノイズが乗りやすいので、単音差し替え可能に

効率を考え、一連の音の連結は一度にやっていましたが、後で単音を再連結できる(=ノイズのある単音を差し替えて結合)ようにします。

(1)単音で録音する。(1音32768サンプル)

(2)単音の連結をして楽器スケール音にまとめる。(たとえばピアノだと88音)

(3)楽器スケール音を連結してサウンドデータベースにまとめる。

5/28 ハードウェア音源は録音の調整が難しい

 ハードウェア音源は立ちあがりがとても鋭いものがあり、録音の状況によっては立ち上がりにクリップノイズが混じるように聞こえる場合がありました。立ち上がりのノイズを聞こえないように極微小の(Pythonで)フェードイン処理をし、音質に影響しない程度に立ち上がりを「ほんの少しだけ」なだらかにしました。(感覚的には立ち上がりの2~3の波の山をフェードインする感じです)また、昔のハード音源はS/N比が悪い、というかノイズレベルが高く、(ノイズに反応して)音の立ち上がりの自動検出がうまく効かなかったので、音開始の検出閾値をかなり高めに設定しました。

ハード音源はRoland系ばかりでにピアノなどの似たような音はあとで除外(もちろんかわりに別の音源を入れる)するかもしれません。ピアノだけで6万音の1割程度(70種で6160音)をデータベースに入れようと思っています。「バランス・バリエーション的に」YAMAHA系のサンプラーがほしくなってきました。生ピアノサンプリング音でもいいけど。。。データベースのため「だけ」に中古のMOTIF-RACK ESなどを入手するのは「なし」です。クラビノーバで代用します。

楽器の種類(カテゴリ)は全体で10種類くらいを考えています。でも、民族音楽系の楽器もいれたいのでバリエーションはそれより増えるかもしれません。

サウンドフォントは探せばまだフリーで高音質のピアノ音源はある「かも」しれません。不足したら探すことにします。

SC-55mk2の録音で問題発生!純正のACアダプタを使っていますが、おそらくはACアダプタ電源ハムノイズ(波形整形の低周波のリプル系ノイズ:大昔のACアダプタなので、スイッチング系ではないです。)が無視できないくらいにひどいです。もとからこんな感じなのか、アダプタの劣化なのはは不明です。禁断の電池駆動させるか安定化ACアダプタもしくはスイッチング電源*2に交換してみます(今は手持ちがです。ないので、保留)次のXV-5080に進みます。

XV-5080にあるデジタル(コアキシャル)接続で48kHz接続で録音しようとしていますが、うまくつながりません。せっかくデジタル接続できるはずなのですが苦戦中です(US-2x2はデジタル入力がないので、QUAD-CAPTUREで入力)今日はこれでおわりそうです。SCノイズ問題とXV-5080接続問題で今日は成果なしです。そもそもXV-5080の操作がわかりません。アナログではもちろんつながりますが、XV-5080でもSC-55ほどひどくはないですが、(ラインの)ノイズが載ります。気にするのか、気にしないのか思案中です。(デジタル接続に歯が立たなければ、気にしない方向です)

XV-5080の録音を開始

コアキシャル接続できました。つながらなかった原因は「つながっていなかったから」でした。(笑)実は今回の録音に関して、オーディオ配線がかなり絡まっていまして、コアキシャルの配線を取り違えていました。もともとボクの部屋は、音の接続は全般的にデジタルアンプを使っていることもあり、ほとんどがコアキシャルと光デジタルですが、配線がどの御宅でもそうだと思いますが、ひどいことになっています。今回の接続替えでオーディオ系と録音系が入り乱れてしまい、裏にまわした配線を取り違えてしまいました。かっこわるくてもしばらくは裏に回さず机の上を横切っての配線にします。*3

デジタル接続はさすがにノイズがありません。(非力な処理系でどれだけノイズがのるかです)

SC-55についてはローノイズ電源を買う(汎用ACアダプタをキットで作る)ことにしたので、後回しにします。このあたりは助手が得意そうなのでお願いしようと思います。電源ノイズのひどさにがくぜんとしたので、部屋にある音の出る系のACアダプタは全部置き換えます。

5/30 ピアノ(ピアニシモ)の音量に問題があったので再録音

現在ピアノ系を録音中ですが、通して聞くと似たような音ばかりで、案外バリエーションがなく、「音」の学習としておもしろみを出すために「Eピアノ」系と「ローズ」系「クラビ、ハープシコード」系なども若干「ピアノ系」の音として録音します。MNISTの数字も「これが4かぁ?」というようなとんでもない文字がたまに(結構)含まれているのがおもしろいので、「音」もバリエーションがほしくなりました。(似てても一流のピアノ音ばかりなら(そのなかで識別を学習できるので)、そちらのほうがおもしろいのですが。。。)

5/31 毎日録音してますが、進みぐあいが悪いです

前後の音が(リバーブなどの余韻で重ならないように)十分間をあけたり、レベルやエラーの問題で再録音したりして1種類の音(ピアノなら88音)を録音するのにかなり時間がかかっています。(15分程度、やりなおすと30分くらい)ハード音源の設定やリバーブのかかり具合を調整しながら録音しています。(リバーブなしとありとをばらつかせてバリエーションがあるようにしているなど。プリセットのいろいろな波形の複合音+エフェクトではなく、音源のもつ元のサンプルをできるだけそのまま録音しています。リバーブがないと寂しすぎるので、かけたりかけなかったり、学習を意図してばらつかせています。)もっと効率よく録音できる方法を考えます。

記事が長くなってきたので6月号につづく。

雑記

波形情報をそのまま持つと容量がすごいことになりますが、あえてそうしています。学習だけを考えるとフーリエ変換mfcc(メル周波数ケプストラム係数)変換の前処理をしたものを素材にする考えもありますが、その方法を特定したくない(いろいろやりたい)ので、wave波形そのものを学習素材にしようとしています。

音声認識もおもしろそう。。。

 

音楽プロモーションのほうのキャンペンは終了

めざせ20Hit!最後のあがき。

f:id:np2LKoo:20170601000756p:plain

「カール」キャンペーンに便乗:この曲は東日本では6月以降再生できなくなります!!

目標到達ならず!!19Hitにおわりました。世の中の厳しさを学びました。

5月末日をもって、当ブログの音楽プロモーションキャンペーンは終了しました。

視聴いただいたみなさま。どうも有難うございました。

 

 

 

 

*1:とても元の音がsteinway(のサンプリング)だとはおもえません。

*2:スイッチング電源(スイッチング動作のACアダプタ)+高価ですが、超高性能電源ノイズフィルタの組み合わせが気になります。いろんなサイトにレビューが載っていますが、本当にすごいらしいです。お金がないのでボクはコチラかな。

*3:MIDI系やHDMI系の既存の各種接続や電源配線も含めてすごいことになっています。HDMIは1階と2階を接続し、2階から1階の機器をリモコン操作できるようにいろいろ組みあわせています。HDMI延長は市販品でリモコン延長(中継器)は自作です。

計算機音楽の自由研究(準備:その2.9.1)~機械学習用サウンドデータベースをつくる(特別編)

 

はじめに

連投はやっぱり無理です。ごめんなさい。

(6月末まで反省キャンペーン中です。内容を順次リファインします。)

サウンドデータベーステストサンプルです

準備:その2.9で結合した機械学習用の音です。聞くと、結合されただけでありがたみはありません。

SoundCloudはそういえばダウンロードできないんでした。

フリーのネットワークストレージを探します。

ちなみにタグはこんなふうについています。

f:id:np2LKoo:20170522002900p:plain

本当は「ソース」に楽器名などをのせるつもりでしたが、説明に「元データを提供した人または組織を書く」と例示で明記してありましたので、無難な「ソフトウェア」欄に入れました。

コメントには各音の情報をリスト形式で格納しました。

視聴頂いた方どうも有難うございます

 おかげ様でcarpet of the sunの視聴回数が16HITになりました。目標まであと「4」です!!

 

(ここから追記)

内容的にこまぎれになるので(連投もあきらめたことですし)こちらに追記します。

サウンドデータサンプルについてのお題のままです。

そもそも10万音無理でした

 10万音ぶんのデータ:50音×2000ファイル(内容は重複)を仮準備してテストとして結合してみました。待つこと1時間弱。ようやく出力!というところでエラーとなりました。数字がおおきすぎて、4バイトリトルエンディアンに変換できないエラー(エラーメッセージはひかえませんでしたが、もう一度やる元気はないです)が発生しました!

通常waveファイルフォーマットは4GBが最大なのに6GBくらいになるデータをつくってサイズをいれるとき、4バイトに収まらない数となりました。

機械学習用の情報も入れて1ファイルにするので、だいたい今のサンプル数(1音32,678サンプル(0.68秒)では6万音までです。0.34秒は少し短い(というよりあとで聞いてて楽しくない)ので倍にしましたが、0.34秒から0.68秒の間に調整する「かも」しれません。

f:id:np2LKoo:20170523214530p:plain

5000音で320MBくらい、6万音で3.8GBくらいです。6万音だと全部聞くのに11時間22分40秒かかります!音はちゃんとMediaPlayerなどで聞けることを確認しました。問題Pythonで、6万音ファイルを読み込んで配列にいれたとたん、メモリ不足で落ちることです。320MBのファイルでさえ、配列にいれる処理をPythonが内部でしているときに一時的にメモリを大量消費し、(いろいろ調整していないとはいえ)そのあたりが限界ぎりぎりセーフな感じです。

読み込んで、変数に格納する過程で大量に(一時的に)メモリを消費

 320MBのファイルを読み込んでメモリ消費量を確認しました。

f:id:np2LKoo:20170523222108p:plain

なんと、バイト配列からバイト列への結合(47行目の b''.join(バイト配列)でバイト配列(これは320MB)の約90倍もの作業領域を使って処理しています。内部的な作業領域が命令が完了するまで開放されずにいる感じです。この処理を3.8GBのファイルで行うと、すぐにPycharm(開発IDE:開発環境)ごと落ちます。*1これはよろしくありません。もう少し容量をおさえるとともに、安定してデータを扱う方法を確認(もしくはしくみを提供)する必要がありそうです。大量データを扱い、マシンの性能限界(レッドゾーン)近くで動く、それっぽい「いい感じ」の状況になってきました。(ちなみにボクのマシンはメモリ32GB MAXです)

(さらに追記)リソースを大量に消費する処理に気を付けてコーディングすれば、問題なく4GB近くのwavファイルを自由に操作できることがわかりました。ファイルをメモリ上に読み込み、各種情報へアクセスできるようにするまで、2秒程度でできるので、合格かと思います。

Pythonで番号指定で特定のサンプル音を再生できるようにしました。また、情報の持ち方についてもう少しシンプルにするよう調整中です。ちゃんと調整できたらGitHUBにアップすると思います。(さらに追記ここまで)

「音あつめ」もたいへんかも

今は、320MBでいっぱいいっぱいですが、アクセス方法も含めて容量など各種パラメータを調整していきます。枠組みがきまればあとはひたすら「仮面ライダー音あつめ」です。スタンウェイは比較的集めやすいと思いますが、ベーゼンドルファーとベヒシュタインの「いい音」集めはなかなか厳しそうです。全国スタジオ、ホールめぐりする余裕はとてもありません。。。

こんなサービス「ベーゼンドルファー東京レンタルスタジオに簡単・高音質な録音サービス「即レコ」を導入しました « ベーゼンドルファー・ジャパン

汐留ベヒシュタイン・サロン | ユーロピアノ株式会社

ピアノレンタルスタジオなどはいろいろある感じですね。。。)

みたいなのを地道に探すのもいいかもしれません。1時間2~3千円くらいだと、現実的かも。録音セッティング、収録、撤収作業含めても3時間あればOKだと思います。ピアノの音あて遊び(もちろん機械学習で!)をするにはちゃんとした「音」を集めないとおもしろくないですものね。。。

バイオリン等は奏者込じゃないと無理ですよねぇ。ストラディバリウスや名だたる銘器(しかも各種)は、どうやったら演奏してもらえる人(持っている人)を探せるのかわかりません。探せたとしても(スタジオ、できれば小さくてもそれなりの響きのあるホールで)演奏してもらうのはいくらかかるんでしょう。。。現実味がないけど、考えるのは楽しいです。

今年は「これ計算機音楽」にかけているので、中途半端なことはしたくないのですが、短期で作成するとなると、出来合いの(しかも手元にある)音源を集めるしかないのかもしれません。

(さらに追記)高級なピアノのあるスタジオにいってパッと録音できるよう、ICレコーダが無性に欲しくなってきています。これはいけません。そんな凝り始めたらいつまでたってもおわりません。。。最高のピアノの音を集めたら次は最高のストリング、次は最高のギター。。。際限なくなることは間違いないです。中途半端に留める勇気も必要だと感じました。ああ、手元のサンプリング音がもうすこしちゃんとサンプリング(全音フルサンプリング)してあれば、生音を録りたいとはそんなにおもわないはずなのですが。。。(手元の音は聞けばきくほど貧弱です。)市販のサンプルとくらべてもKeppyさんのSteinwayピアノのサンプリングはとてもよいことがわかります。。。。う~ん演奏から音の断片を切り取って(当然単音ではなく和音や旋律の経過音の断片かと)学習素材にすることも考えよーっと。それなら、Googleライブラリが使えるし~(さらに追記ここまで)

助手・元祖?現役?〇〇疑惑

以前、助手からSF好きなら「萩尾望都」先生を読むべきと勧められました。元祖○○なら「竹宮恵子」先生の「風と木の詩」です。最近リバイバルとの話題がどこかに載っていました。最近の傾向なのですが、身近で話題になったことが1~2ヶ月くらいあとでネットで「最近流行なんだって!」ときくことが本当によくあります。まわりじゅう、流行とは無縁の面々ばかりですが、案外自分たちが世間に近づけた(もしくはミーハー傾向な)のかもしれません。

f:id:np2LKoo:20170524001020p:plain

助手さん!早く「萩尾望都」先生の「銀の三角」貸してください。(どこかにあるはず。と言ってそれっきりですよ!)

キャンペーン効果!!

 毎度有難うございます。目標20Hitまであと「3」となりました!!

*1:落ちたのは最初はバイト列→バイト配列だと予想していたのですが、まさかのバイト配列→バイト列の処理でした。大容量のb''.join操作は要注意です!

計算機音楽の自由研究(準備:その2.9)~機械学習用サウンドデータベースをつくる(発動編)

はじめに

ファイルの結合ができたのでタグ情報を付加してみます。前回「結合編」と付けましたが、今回も続きのためXX編にしようと思いました。いいのが思いつかないので助手に意見を求めたところ「発動編がいいのでは?」「最初のは接触編にしたほうがよかったね。」と意味不明なことを言われました。他に思いつかないので、発動編にしました。内容と合っていない気がしますが、何かを発動します。

f:id:np2LKoo:20170521090240p:plain

(助手はコレジャナイとさらに意味不明。 井出の力って何?)

f:id:np2LKoo:20170521200508p:plain

これでもなさそうだし。

 

f:id:np2LKoo:20170521233059j:plain

見つけました!これですね。これ発動していいやつ?

なお、助手の井戸中を井出上に改名する案は却下します。

(6月末まで反省キャンペーン中です。内容を順次リファインします。)

 機械学習用に付加する情報について

各音の情報についてJSONにしようと思っていましたが、いざ書いてみると(1行表示なので)逆にとても読みにくかったです。JSONはあっさりヤメます。フツーの配列(リスト)表記にします。
以下はまだ案で、試行テストで不都合があれば変ます。(個人的な要件のメモなので読み飛ばしてください)
大きくわけて


(1)楽器の音の情報:ソース情報
(2)(1)の楽器の音の音階などの情報:各サンプル情報


のように2段階の情報にします。

(1)ソース情報は以下の案です。


[カテゴリ番号,ソース番号, [メーカー,地域,...],音源説明,補足],...


カテゴリ番号:

準備その1で決めた分類を使います。

当面99以下しか使わない前提で「今は」2桁にしてみます。

ソース番号:

カテゴリ番号での単なる順番です。

基本的に1から始めますが、分類上番号が連続していなくても可とします。

[メーカー,地域,...]:

別途きめます。

(ない場合は不明な場合は[]だけです。[ ]内の要素数は不定です。

(ex.[Steinway & Son's, Germany,Model A-188,NHK Hall]))

音源説明: 任意の文字(ただし全角、半角カナは不可)
補足: 任意の文字(〃)

 

(2)各サンプル情報は以下の案です。


[カテゴリ番号, ソース番号, 音階, 識別, [拡張情報]],...


とします。

カテゴリ番号:

準備その1で決めた分類を使います。(1)と同じ

当面99以下しか使わない前提で「今は」2桁にしてみます。

ソース番号:

カテゴリ番号での単なる順番です。(1)と同じ

基本的に1から始めますが、分類上番号が連続していなくても可とします。

音階:

1~127はMIDIノート番号,平均律(12クロマ)におしこめられるもののみ

0は音階なし(もしくは不明)

識別:

※音階、識別のどちらか一方は必須

音階でない音の識別1桁目が識別で2桁以降が識別詳細データ。

純正率などを調ごとに厳密にやりたい場合はこちらも使うことになると思います。(複数の調の音を識別する?)民族音楽系もおおくはこちらでしょうか。。。(サンプリング済のものは音階でよいと思います)

(識別の補足) 0は識別なし。
 言語音声の場合: VX(Xには発音記号半角アルファベットがはいるボカロ発音記号準拠。桁数任意)
 代表周波数の場合: Fnnnnn(nnnnには代表周波数(Hz)がはいります)
 そのた諸々 必要の都度、識別記号と識別内容を発案してくわえます(笑い声とか鳴き声とかetc)
[拡張情報]:

今はリザーブ、案として

サブカテゴリ:DBごとに任意
感情(その音で呼び出される感情の種類:主観でよい)
状態(機械動作音であれば、故障中(故障パターン識別)とか故障直前とか、初期起動音とか、エージング終了後の動作音とかの種類)
いずれも1桁目は分類のIDがはいり、2桁目以降は内容を記載します。
拡張情報は任意に複数持てる。ない場合は空の [ ] を書きます。

(1),(2)共通で以下のようにします。

なお、

■情報はすべてアルファベットと記号、数字とする。(漢字、カナは不可)
■文字にセミコロンは使用しない。
■, [ ] は配列の構造に使用するので、データとしては使用しない
■文字列は"や'で囲まない
情報の保存場所とファイル名
■データ作成の効率を考え、該当サウンドDB作成に仕様するフォルダをXXYYYX,Yは数字)の5桁とする。XXはカテゴリ番号、YYYはソース番号とする。
■情報とwaveファイルはは各フォルダ(0000199999)の中にフォルダ名と同じファイル名 (02001.txt,02001.wavなど)で保持する。

XX,YYYのペアは作成するサウンドDB内でのみ一意とする。(他のサウンドDBではまた別の音を入れてももちろんよい)

■登録用のファイルは、作成がしやすいように若干フォーマット調整する。
■ソース情報、サンプル情報は登録用はまとめて1ファイルのテキストにする。
■■1行目は(1)ソース情報とする。(カテゴリ番号,ソース番号, [メーカー,地域,...],音源説明, 補足)
■■2行目以降は(2)各サンプル情報とする。各行に(サンプル番号(1から連番),音階, 識別, [拡張情報])をかく
■■これら情報はwave登録用のフォーマットに整形のうえ、wavファイルの所定のタグに登録する。

----------------------------------------------
02002.txt
----------------------------------------------
2,2, [ ] ,Keppy Steinway Piano V6.x,SoundFont
1,21,0, [ ]
2,22,0, [ ]
3,23,0, [ ]
...
88,108,0, [ ]
----------------------------------------------
のようにします。サンプル番号を書くのは、登録ミスチェック用です。音階を全部書くのは、特定12半音がでない(近似該当がない)楽器があるためです。

プログラムソース

 すこし長いですが、切り出してもわかりにくいので、そのまま貼ります。

import numpy as np
import os.path
import re

STRCODE = 'utf-8'
'''
=====================================================================================
機械学習用waveファイル結合プログラム
(複数のファイルを結合するとともに、機械学習用の付加情報をwaveファイルに取り込みます)
=====================================================================================
'''

class VWave:
# 読み込んだwaveファイルの情報を格納するクラスです。
SAMPLING_COUNT = 32768
INSTR_TAG = 'ISFT'
NOTE_TAG = 'ICMT'
# 地道にwavフォーマット情報を定義していきます。
#
IFF_ALL = 0
IFF_ID, IFF_SIZE, IFF_FMT, IFF_SUBID, IFF_SUBSIZE = 1, 2, 3, 4, 5
IFF_WAVFOMT, IFF_CHANNEL, IFF_SAMPLING, IFF_BYTEPS, IFF_BLKSIZE = 6, 7, 8, 9, 10
IFF_BIT, IFF_DATAID, IFF_DATASIZE, IFF_DATA, IFF_LIST = 11, 12, 13, 14, 15
IFF_LISTID, IFF_LISTSIZE, IFF_INFOID = 16, 17, 18
TYPE_BYTE = "byte"
TYPE_STR = "string"
TYPE_LITTLE = "little"
DEF_METAID, DEF_TITLE, DEF_TYPE, DEF_START, DEF_BYTE, DEF_ENC = 0, 1, 2, 3, 4, 5
IFF_DEF = [
[IFF_ALL, "ALL DATA ", TYPE_BYTE, None, None, None ],
[IFF_ID, "ID ", TYPE_STR, 0, 4, STRCODE],
[IFF_SIZE, "Chunk Size", TYPE_LITTLE, 4, 4, None],
[IFF_FMT, "FormatName", TYPE_STR, 8, 4, STRCODE],
[IFF_SUBID, "Sub ID ", TYPE_STR, 12, 4, STRCODE],
[IFF_SUBSIZE, "Sub Size ", TYPE_LITTLE, 16, 4, None],
[IFF_WAVFOMT, "WavFomat ", TYPE_LITTLE, 20, 2, None],
[IFF_CHANNEL, "Channel ", TYPE_LITTLE, 22, 2, None],
[IFF_SAMPLING,"Sampling ", TYPE_LITTLE, 24, 4, None],
[IFF_BYTEPS, "BytePS ", TYPE_LITTLE, 28, 4, None],
[IFF_BLKSIZE, "BlockSize ", TYPE_LITTLE, 32, 2, None],
[IFF_BIT, "Bit ", TYPE_LITTLE, 34, 2, None],
[IFF_DATAID, "DataID ", TYPE_STR, 36, 4, STRCODE],
[IFF_DATASIZE,"DataSize ", TYPE_LITTLE, 40, 4, None],
[IFF_DATA, "IFF Data ", TYPE_BYTE, 44, None, None],
[IFF_LIST, "List ", TYPE_BYTE, 0, None, None ],
[IFF_LISTID, "List ID ", TYPE_STR, 0, 4, STRCODE ],
[IFF_LISTSIZE,"List Size ", TYPE_LITTLE, 4, 4, None],
[IFF_INFOID, "INFO ID ", TYPE_STR, 8, 4, STRCODE]
]
#読み込んだ情報を格納する配列です。最初はクラス変数を使っていましたが、多すぎてわかりにくくなったため、
#すべて配列で持つことにしました。
iff = []
iffSubChunkID = []
iffSubChunkSize = []
iffSubChunkData = []

def __init__(self, data):
self.iff =[b'', "", 0, "", "", 0, 0, 0, 0, 0, 0, 0, "", 0, b'', b'', "", 0, ""]
siff = self.iff
sALL = self.IFF_ALL
dMetaID, dTitle, dType, dStart, dByte, dEnc = self.DEF_METAID, self.DEF_TITLE, self.DEF_TYPE, self.DEF_START, self.DEF_BYTE, self.DEF_ENC
tByte, tStr, tLittle = self.TYPE_BYTE, self.TYPE_STR, self.TYPE_LITTLE
# 以降全体から特定部分へアクセスするためにバイト配列にして格納します。
siff[sALL] = np.frombuffer(data, dtype=self.IFF_DEF[sALL][dType])
#順次定義の内容に基づき、data内容を解釈して配列に格納します。
for i in range(14)[1:]:
iDEF = self.IFF_DEF[i]
if iDEF[dType] == tStr:
siff[i] = (b''.join(siff[sALL][iDEF[dStart]:iDEF[dStart] + iDEF[dByte]])).decode(iDEF[dEnc])
elif iDEF[dType] == tLittle:
siff[i] = int.from_bytes(siff[sALL][iDEF[dStart]:iDEF[dStart] + iDEF[dByte]], tLittle)

#Waveデータ部分を格納します。この部分が可変長なんです。
iDEF = self.IFF_DEF[self.IFF_DATA]
siff[self.IFF_DATA] = b''.join(siff[sALL][iDEF[dStart]:iDEF[dStart] + siff[self.IFF_DATASIZE]])
#タグの部分はIFF_LISTで示す配列に格納します。
siff[self.IFF_LIST] = siff[sALL][44 + siff[self.IFF_DATASIZE]:]

#タグの部分の範囲を解釈して配列「XXXiffSubChunk」に格納します。
if (siff[self.IFF_LIST].size != 0):
sList = siff[self.IFF_LIST]
iDEF = self.IFF_DEF[self.IFF_LISTID]
siff[self.IFF_LISTID] = (b''.join(sList[iDEF[dStart]:iDEF[dStart] + iDEF[dByte]])).decode(iDEF[dEnc])
iDEF = self.IFF_DEF[self.IFF_LISTSIZE]
siff[self.IFF_LISTSIZE] = int.from_bytes(sList[iDEF[dStart]:iDEF[dStart] + iDEF[dByte]], tLittle)
iDEF = self.IFF_DEF[self.IFF_INFOID]
siff[self.IFF_INFOID] = (b''.join(sList[iDEF[dStart]:iDEF[dStart] + iDEF[dByte]])).decode(iDEF[dEnc])
offset = 12
for i in range(999):
chunkID = (b''.join(sList[offset:offset + 4])).decode(STRCODE)
subChunkSize = int.from_bytes((b''.join(sList[offset + 4:offset + 8])), tLittle)
chunkData = (b''.join(sList[offset + 8:offset + 8 + subChunkSize]).decode('SJIS'))
offset += (8 + subChunkSize + (subChunkSize % 2))
self.iffSubChunkID.append(chunkID)
self.iffSubChunkSize.append(subChunkSize)
self.iffSubChunkData.append(chunkData)
if siff[self.IFF_LISTSIZE] <= offset + 12:
break

def print(self):
#読み込んだwavファイルの内容をレポートします。
siff = self.iff
sALL = self.IFF_ALL
dMetaID, dTitle, dType, dStart, dByte, dEnc = self.DEF_METAID, self.DEF_TITLE, self.DEF_TYPE, self.DEF_START, self.DEF_BYTE, self.DEF_ENC
tByte, tStr, tLittle = self.TYPE_BYTE, self.TYPE_STR, self.TYPE_LITTLE
print('Toral size = ' + "{0:,d}".format(siff[sALL].size))
for i in range(19)[1:]:
if (i == 14):
if (siff[self.IFF_LIST].size != 0):
print("-------------------------------------------")
continue
else:
#このブロックは調整中です
break
iDEF = self.IFF_DEF[i]
if iDEF[dType] == tStr:
print(iDEF[dTitle] + '=' + siff[i])
elif iDEF[dType] == tLittle:
print(iDEF[dTitle] + '=' + "{0:,d}".format(siff[i]))
print("<<This wave file contains [ " + "{0:,d}".format(siff[self.IFF_DATASIZE] // (self.SAMPLING_COUNT * siff[self.IFF_BLKSIZE])) + "] sound>>")
print("-------------------------------------------")

def printSize(self):
siff = self.iff
print("Chunk Size=" + siff[self.IFF_SIZE])

def getList(self):
return self.iffSubChunkID, self.iffSubChunkSize, self.iffSubChunkData

def cat(self, data):
#結合用のメソッドです。元のソースとチャンネル数、サンプリングレート、ビット数が異なればエラーにします。
#エラーがあれば結合しません。
if (self.iff[self.IFF_CHANNEL] != data.iff[data.IFF_CHANNEL]):
print("Channel is different base=" + "0:d".format(self.iff[self.IFF_CHANNEL]) +
"source=" + "0:d".format(data.iff[self.IFF_CHANNEL]))
return -1
if (self.iff[self.IFF_SAMPLING] != data.iff[data.IFF_SAMPLING]):
print("Samplint is different base=" + "0:d".format(self.iff[self.IFF_SAMPLING]) +
":source=" + "0:d".format(data.iff[self.IFF_SAMPLING]))
return -1
if (self.iff[self.IFF_BIT] != data.iff[data.IFF_BIT]):
print("Bit is different base=" + "0:d".format(self.iff[self.IFF_BIT]) +
":source=" + "0:d".format(data.iff[self.IFF_BIT]))
return -1
#結合するサンプリング数がSAMPLING_COUNTの整数倍でないと、エラーとします。
if (data.iff[data.IFF_DATASIZE] % self.SAMPLING_COUNT != 0):
print("Sampling count is not base on :" + "0:d".format(self.SAMPLING_COUNT) )

#結合は単純に足しているだけです。
self.iff[self.IFF_DATA] += data.iff[data.IFF_DATA]
self.iff[self.IFF_DATASIZE] += data.iff[data.IFF_DATASIZE]
self.iff[self.IFF_SIZE] += data.iff[data.IFF_DATASIZE]

def catInstrumentInfo(self, info):
#ファイルから読み込んだデータについて、楽器情報を結合します。
tagInstr = self.INSTR_TAG
if tagInstr in self.iffSubChunkID:
itagNo = self.iffSubChunkID.index(tagInstr)
else:
self.iffSubChunkID.append(tagInstr)
self.iffSubChunkData.append("")
self.iffSubChunkSize.append(0)
itagNo = self.iffSubChunkID.index(tagInstr)
sInfo = info.split('\n')
self.iffSubChunkData[itagNo] += '[' + sInfo[0] + "],"
self.iffSubChunkSize[itagNo] = len(self.iffSubChunkData[itagNo])

def catSoundInfo(self, info):
# ファイルから読み込んだデータについて、各音の情報を結合します。
tagNote = self.NOTE_TAG
if tagNote in self.iffSubChunkID:
itagNo = self.iffSubChunkID.index(tagNote)
else:
self.iffSubChunkID.append(tagNote)
self.iffSubChunkData.append("")
self.iffSubChunkSize.append(0)
itagNo = self.iffSubChunkID.index(tagNote)
sInfo = info.split('\n')
sInstr = sInfo[0]
sInstrInfo = sInstr.split(',')

for i in range(len(sInfo))[1:]:
sNoteInfo = sInfo[i].split(',')
if len(sInfo[i].strip(' ')) == 0:
#空の行があればそこで終了
break
self.iffSubChunkData[itagNo] += '[' + sInstrInfo[0] + ',' +\
sInstrInfo[1] + ',' +\
sNoteInfo[1] + ',' +\
sNoteInfo[2] + ',' +\
sNoteInfo[3] + "],"
self.iffSubChunkSize[itagNo] = len(self.iffSubChunkData[itagNo])

def getWave(self):
#Waveデータのフォーマットでバイナリで取り出すメソッドです。
dMetaID, dTitle, dType, dStart, dByte, dEnc = self.DEF_METAID, self.DEF_TITLE, self.DEF_TYPE, self.DEF_START, self.DEF_BYTE, self.DEF_ENC
work = b''
workInfo = b'INFO'
for i in range(len(self.iffSubChunkID)):
workInfo += self.iffSubChunkID[i].encode(STRCODE)
workInfo += (self.iffSubChunkSize[i]+1).to_bytes(4, 'little')
workInfo += self.iffSubChunkData[i].encode(STRCODE) + b'\x00'
if ((len(self.iffSubChunkData[i].encode(STRCODE)) + 1) % 2 == 1):
workInfo += b'\x00'
workList = b'LIST' + (len(workInfo)).to_bytes(4, 'little') + workInfo
self.iff[self.IFF_SIZE] = self.iff[self.IFF_SUBSIZE] + self.iff[self.IFF_DATASIZE] + len(workInfo) + 28
for i in range(14):
siffData = self.iff[i]
iDEF = self.IFF_DEF[i]
if (iDEF[dType] == self.TYPE_STR):
work = work + siffData.encode(iDEF[dEnc])
elif (iDEF[dType] == self.TYPE_LITTLE and iDEF[dByte] == 2 ):
work = work + siffData.to_bytes(2, 'little')
elif (iDEF[dType] == self.TYPE_LITTLE and iDEF[dByte] == 4):
work = work + siffData.to_bytes(4, 'little')
work = work + self.iff[self.IFF_DATA]
work += workList
return work

#出力するDBの名前です。
CAT_WAVE_FILE='.\\KooSoundDB.wav'
sCount = 0
#カレントディレクトリで、"00001"から"99999"(5桁)のフォルダがあれば名前を取得してソートします
output_path = "."
files = os.listdir(output_path)
list_dir = [f for f in files if os.path.isdir(os.path.join(output_path, f))]
sound_dir = [i for i in list_dir if re.search(r'[0-9][0-9][0-9][0-9][0-9]', i)]
sound_dir.sort()
print(sound_dir)
#フォルダ名と同じ番号のwavファイルがあるか調べます。
for dir_name in sound_dir:
fileName = dir_name + "\\" + dir_name + ".wav"
infoFileName = dir_name + "\\" + dir_name + ".txt"
if os.path.isfile(fileName):
if not os.path.isfile(infoFileName):
print("Not exist:" + infoFileName)
continue
sCount += 1
print ("exist:" + fileName)
f = open(fileName, 'rb')
fData = f.read()
t = open(infoFileName, 'r')
tData = t.read()
waveData = VWave(fData)
if (sCount == 1):
# 1個目は元データそのものです。
catWave = waveData
else:
# 2個目以降は結合していきます。
catWave.cat(waveData)
waveData.print()
waveData.catInstrumentInfo(tData)
waveData.catSoundInfo(tData)
#タグリストはget/setするので確認用です。setはまだ作ってません。
subChunkID, subChunkSize, subChunkData = waveData.getList()
for i in range(len(subChunkID)):
print(">" + subChunkID[i] + ":{0:4d}:".format(subChunkSize[i]) + subChunkData[i])
f.close()
t.close()
print("===========================================")
print("Output file name:" + CAT_WAVE_FILE)
print("===========================================")
catWave.print()
#出力用のファイルをオープンし、結合演算済の内容をwavファイルに出力します。
fw = open(CAT_WAVE_FILE, 'wb')
fw.write(catWave.getWave())
fw.close()

 前のプログラムからタグ関連の編集を追加しました。差分だけのせてもわかりにくいので、全部はりました。

 まとめ 

簡単なテストではOKでした。

このプログラムでファイルを2000個以上、容量で6GB(10万音でそれくらい)まで結合できるかテストが必要です。一度全部メモリに乗せる単純なつくりなので、問題があればPGを改変します。(テストはたいへんなわりにおもしろくないので、結果だけいずれ報告します。)最終的なファイルは1つあたり、アップロードの扱いやすさの感覚的な上限の1GB以下がいいと感じていますが、10万音だと6GBくらいになります。圧縮して1GB以下になればよしとしますが、それでも超えるようだとどこかを調整して「圧縮して1GB以下にします」(1ファイル2GBまでならOKなフリーのネットストレージサービスもあるようなので、2GBを上限にするかもしれません。。。)

他のタグの情報も若干追加してプログラムの完成となる予定です。 

祈りをいま君のもとへ。

もしもボクニューロンの1細胞ならばのです

1人称研究というのがあります。人類のいままでの科学や実験では「客観性」や「再現性」を重視してきました。ある特定の視点を欠落させている反省から、「1人称主観」による情報処理結果、判断を重要視する考え方がでてきたようです。(内容はあまり理解していないので説明できません。すみません)
1人称研究の本は読んだことがないのですが、是非読んでみたいです。*1それとは別ですが、ボクのブログで推奨している(といっても助手が推奨していて、ボクが同感しているだけですが)「自在主観」があります。*2自己符号化器の自由研究にあたっては「ジブンがもし1つのニューロン細胞であったら、どう成長し、何を日々の糧とし、何を喜びとし、何を目的に生き、どう死ぬのか」を考え続けています。

1人称といえば

ブログにつかう1人称を何にするかも話題です。
このブログは、複数によって運営されています。(人工知能はもちろん含まれていませんのでご安心ください。ただし開発できたらこっそりメンバーが増えるかもしれません。)このブログにはすこしだけ規定(レギュレーション)があり、「1人称については固有のものを使う」ことを決め事にしています。
性別や年齢、リアルの立場、(現在の)プライベートに関することは公開してはいけないことにしています。(そのほうがおもしろそうなので、という単純にして最強の理由です。)それ以外は各自の判断で自由です。このブログでは1人称はそれぞれ各者固有としています。*3


このおはなしの登場人物 / いきもの


ボク:かえるのクー (井戸中 空)/ Koo Wells
わたくし:井戸中 聖(イトナカ アキラ)
吾(あ):井戸中 芽守(イトナカ メモル)
未発言:井戸中 瑠璃(イトナカ ルリ)(るぅりぃ)
未発言:井戸中 明日良(イトナカ アスラ)(アッシュ、あーくん)


「君の名は」でジブンの1人称に関する(外国の人には絶対伝わらないと思う)「ギャグ」があり、気に入っています。1人称がこれだけ多岐にわたり、発言する人の社会的地位、性別、シュチュエーションでバリエーションがある言語は、日本語がトップクラスであるとききました。ということで、1人称で遊んでいます。なおこのブログでは「わたし」は大好きな「人類は衰退しました」の「わたし」ちゃんの固有名詞である扱いなのでだれも使えません。(ああ、Voltaよりもこのえんばんがほしい。ねたばれ、みるです?*4) 

*1:一般的に考えると統計的に十分な数の「1人称主観」の判断を、主観者についてグループ化すれば、そのグループごとの客観視点(おおまかな総意)とバリエーション(個々の主観のブレ)があきらかになります。もっと大数でサンプリングすれば、人類の思考パターン(の流行)が明確になります。そのうち「人工知能」にこれらの情報がinputされると考えています。

*2:助手の造語と思われます。「執筆依頼があれば書くよ」と助手たちの言動は本当に訳がわかりません。自在主観とは対象物そのものに「本当になったつもり」になって思考する発想テクニックです。(本気度がないと単なる思考の遊びにおわります)ジブンが孫〇義や、イー論マ〇クになったつもりで思考し、そのビジネス思考パタンをなぞる練習にも使えます。絶対絶命の状態や社内的窮地を想像できると、臨場感が増し効果があると考えます。ヒトではなく「モノ」になりきる主観のほうが、実験や研究では違った発想を思いつけることがあるので有用だと力説してました。

*3:1人称の決定権は皆には不評ですがボクが持っています。

*4:妖精さんのちからでもいいから、このブログ「せんきゃくばんらいですからー」と言ってみたい。妖精さん密度100fくらいになれば、きっと人工知能なんて1晩で完成するんでしょうが。

計算機音楽の自由研究(準備:その2.8)~機械学習用サウンドデータベースをつくる(結合編)

はじめに

今年は春のけだるさ病*1にはかからなかったようです。熱中できることを持つことは素晴らしいと感じました。

(準備:その2.6)で、一連の音の作成(たとえばあるVSTi音源のMIDIノート21~108の音)までは、設定して実行すれば簡単に行えるようになりました。

f:id:np2LKoo:20170519231630p:plain

パソコンの処理能力が低いので音を出すと(録音すると)よくノイズが乗ることがあります。外部ノイズではなく、明らかにCPU側能力不足のノイズです。そのため、もっと多数の音を一度に作成することはぜず、一旦作成単位のwavファイル(30音~100音くらい)ごとに、ノイズが乗っていないかチェックします。そのあとで、まとめて1つのDBに結合することを考えます。(6月末まで反省キャンペーン中です。内容を順次リファインします。)

機械学習用ファイル作成プログラムの要件

・複数の所定のフォルダに格納されたwavファイルを結合する。
・同じ条件(サンプリングレートやビット数など)の録音でないとチェックしてエラーとする。
所定のフォルダは数字5桁(00001,00002...)などに決め、その中にフォルダと同名のwavファイル(名前は任意、拡張子は.wav)を置く。(わざわざ00001などのフォルダをつくるのは、その中に複数の候補や作成補助用の(DBには直接関係しない)ファイルをもたせたいからです。)

以下の実装はまた今度しますが、定義だけしておきます。
・準備:その2.7で確認したタグのフォーマットを参考にコメント(ICMT)欄に音(0.68秒のサンプル単位)に関する基本情報を書く。(内容は別途きめる)
・ソース(ISRC)欄に音に関する情報を書く(音源の単位)
・DBに関するサマリ情報をプロダクト(アルバム)欄(IPRD)に書く
・いろいろな情報を乗せても、wavファイル単独で音が聞けるようにする。
・データベースが大きくなると、音の頭出しが難しくなるので、情報を指定すると特定の音を簡単に再生できるしくみを考える。(これは結合用プログラムとは別に考える)

結合用のプログラムを作成してみます。

準備:その2.7のプログラムを元にもうすこし汎用化して結合機能をもたせてみます。

汎用化すると逆に「読みにくい」ソースとなってしまいました。*2小出しで本当に申し訳ないですが、今回は結合する部分だけです。作成中ながら貼っちゃいます。結合する部分と出力する部分だけならあわせて10~20行程度なのですが、内容確認用の情報表示を汎用的にできるように作成したので長くなってしまいました。Python標準的な命名規約には全く従っていません。わかりやすいソースが書けるように勉強中です。

waveファイルのフォーマットについては前にも貼りましたが、こちらを参照してください。実験用でテストも十分行っていないので、間違いがあっらこっそり張り替えます。


import numpy as np
import os.path
import re

STRCODE = 'utf-8'
'''
=====================================================================================
Waveファイルに関するフォーマット情報を地道に定義してみます。
とりあえず、今回はwavファイルを結合するところまでやります。(クラスは未完成です)
=====================================================================================
'''

class VWave:
# 読み込んだwaveファイルの情報を格納するクラスです。
SAMPLING_COUNT = 32768
# 地道にwavフォーマット情報を定義していきます。
IFF_ALL = 0
IFF_ID, IFF_SIZE, IFF_FMT, IFF_SUBID, IFF_SUBSIZE = 1, 2, 3, 4, 5
IFF_WAVFOMT, IFF_CHANNEL, IFF_SAMPLING, IFF_BYTEPS, IFF_BLKSIZE = 6, 7, 8, 9, 10
IFF_BIT, IFF_DATAID, IFF_DATASIZE, IFF_DATA, IFF_LIST = 11, 12, 13, 14, 15
IFF_LISTID, IFF_LISTSIZE, IFF_INFOID = 16, 17, 18
TYPE_BYTE = "byte"
TYPE_STR = "string"
TYPE_LITTLE = "little"
DEF_METAID, DEF_TITLE, DEF_TYPE, DEF_START, DEF_BYTE, DEF_ENC = 0, 1, 2, 3, 4, 5
IFF_DEF = [
[IFF_ALL, "ALL DATA ", TYPE_BYTE, None, None, None ],
[IFF_ID, "ID ", TYPE_STR, 0, 4, STRCODE],
[IFF_SIZE, "Chunk Size", TYPE_LITTLE, 4, 4, None],
[IFF_FMT, "FormatName", TYPE_STR, 8, 4, STRCODE],
[IFF_SUBID, "Sub ID ", TYPE_STR, 12, 4, STRCODE],
[IFF_SUBSIZE, "Sub Size ", TYPE_LITTLE, 16, 4, None],
[IFF_WAVFOMT, "WavFomat ", TYPE_LITTLE, 20, 2, None],
[IFF_CHANNEL, "Channel ", TYPE_LITTLE, 22, 2, None],
[IFF_SAMPLING,"Sampling ", TYPE_LITTLE, 24, 4, None],
[IFF_BYTEPS, "BytePS ", TYPE_LITTLE, 28, 4, None],
[IFF_BLKSIZE, "BlockSize ", TYPE_LITTLE, 32, 2, None],
[IFF_BIT, "Bit ", TYPE_LITTLE, 34, 2, None],
[IFF_DATAID, "DataID ", TYPE_STR, 36, 4, STRCODE],
[IFF_DATASIZE,"DataSize ", TYPE_LITTLE, 40, 4, None],
[IFF_DATA, "IFF Data ", TYPE_BYTE, 44, None, None],
[IFF_LIST, "List ", TYPE_BYTE, 0, None, None ],
[IFF_LISTID, "List ID ", TYPE_STR, 0, 4, STRCODE ],
[IFF_LISTSIZE,"List Size ", TYPE_LITTLE, 4, 4, None],
[IFF_INFOID, "INFO ID ", TYPE_STR, 8, 4, STRCODE]
]
#読み込んだ情報を格納する配列です。最初はクラス変数を使っていましたが、多すぎてわかりにくくなったため、
#すべて配列で持つことにしました。
iff = []
iffSubChunkID = []
iffSubChunkSize = []
iffSubChunkData = []

def __init__(self, data):
self.iff =[b'', "", 0, "", "", 0, 0, 0, 0, 0, 0, 0, "", 0, b'', b'', "", 0, ""]
siff = self.iff
sALL = self.IFF_ALL
dMetaID, dTitle, dType, dStart, dByte, dEnc = self.DEF_METAID, self.DEF_TITLE, self.DEF_TYPE, self.DEF_START, self.DEF_BYTE, self.DEF_ENC
tByte, tStr, tLittle = self.TYPE_BYTE, self.TYPE_STR, self.TYPE_LITTLE
# 以降全体から特定部分へアクセスするためにバイト配列にして格納します。
siff[sALL] = np.frombuffer(data, dtype=self.IFF_DEF[sALL][dType])
#順次定義の内容に基づき、data内容を解釈して配列に格納します。
for i in range(14)[1:]:
iDEF = self.IFF_DEF[i]
if iDEF[dType] == tStr:
siff[i] = (b''.join(siff[sALL][iDEF[dStart]:iDEF[dStart] + iDEF[dByte]])).decode(iDEF[dEnc])
elif iDEF[dType] == tLittle:
siff[i] = int.from_bytes(siff[sALL][iDEF[dStart]:iDEF[dStart] + iDEF[dByte]], tLittle)

#Waveデータ部分を格納します。この部分が可変長なんです。
iDEF = self.IFF_DEF[self.IFF_DATA]
siff[self.IFF_DATA] = b''.join(siff[sALL][iDEF[dStart]:iDEF[dStart] + siff[self.IFF_DATASIZE]])
#タグの部分はIFF_LISTで示す配列に格納します。
siff[self.IFF_LIST] = siff[sALL][44 + siff[self.IFF_DATASIZE]:]

#タグの部分の範囲を解釈して配列「XXXiffSubChunk」に格納します。
if (siff[self.IFF_LIST].size != 0):
sList = siff[self.IFF_LIST]
iDEF = self.IFF_DEF[self.IFF_LISTID]
siff[self.IFF_LISTID] = (b''.join(sList[iDEF[dStart]:iDEF[dStart] + iDEF[dByte]])).decode(iDEF[dEnc])
iDEF = self.IFF_DEF[self.IFF_LISTSIZE]
siff[self.IFF_LISTSIZE] = int.from_bytes(sList[iDEF[dStart]:iDEF[dStart] + iDEF[dByte]], tLittle)
iDEF = self.IFF_DEF[self.IFF_INFOID]
siff[self.IFF_INFOID] = (b''.join(sList[iDEF[dStart]:iDEF[dStart] + iDEF[dByte]])).decode(iDEF[dEnc])
offset = 12
for i in range(999):
chunkID = (b''.join(sList[offset:offset + 4])).decode(STRCODE)
subChunkSize = int.from_bytes((b''.join(sList[offset + 4:offset + 8])), tLittle)
chunkData = (b''.join(sList[offset + 8:offset + 8 + subChunkSize]).decode('SJIS'))
offset += (8 + subChunkSize + (subChunkSize % 2))
self.iffSubChunkID.append(chunkID)
self.iffSubChunkSize.append(subChunkSize)
self.iffSubChunkData.append(chunkData)
if siff[self.IFF_LISTSIZE] <= offset + 12:
break

def print(self):
#読み込んだwavファイルの内容をレポートします。
siff = self.iff
sALL = self.IFF_ALL
dMetaID, dTitle, dType, dStart, dByte, dEnc = self.DEF_METAID, self.DEF_TITLE, self.DEF_TYPE, self.DEF_START, self.DEF_BYTE, self.DEF_ENC
tByte, tStr, tLittle = self.TYPE_BYTE, self.TYPE_STR, self.TYPE_LITTLE
print('Toral size = ' + "{0:,d}".format(siff[sALL].size))
for i in range(19)[1:]:
if (i == 14):
if (siff[self.IFF_LIST].size != 0):
print("-------------------------------------------")
continue
else:
#このブロックは調整中です
break
iDEF = self.IFF_DEF[i]
if iDEF[dType] == tStr:
print(iDEF[dTitle] + '=' + siff[i])
elif iDEF[dType] == tLittle:
print(iDEF[dTitle] + '=' + "{0:,d}".format(siff[i]))
print("<<This wave file contains [ " + "{0:,d}".format(siff[self.IFF_DATASIZE] // (self.SAMPLING_COUNT * siff[self.IFF_BLKSIZE])) + "] sound>>")
print("-------------------------------------------")

def printSize(self):
siff = self.iff
print("Chunk Size=" + siff[self.IFF_SIZE])

def getList(self):
return self.iffSubChunkID, self.iffSubChunkSize, self.iffSubChunkData

def cat(self, data):
#結合用のメソッドです。元のソースとチャンネル数、サンプリングレート、ビット数が異なればエラーにします。
#エラーがあれば結合しません。
if (self.iff[self.IFF_CHANNEL] != data.iff[data.IFF_CHANNEL]):
print("Channel is different base=" + "0:d".format(self.iff[self.IFF_CHANNEL]) +
"source=" + "0:d".format(data.iff[self.IFF_CHANNEL]))
return -1
if (self.iff[self.IFF_SAMPLING] != data.iff[data.IFF_SAMPLING]):
print("Samplint is different base=" + "0:d".format(self.iff[self.IFF_SAMPLING]) +
":source=" + "0:d".format(data.iff[self.IFF_SAMPLING]))
return -1
if (self.iff[self.IFF_BIT] != data.iff[data.IFF_BIT]):
print("Bit is different base=" + "0:d".format(self.iff[self.IFF_BIT]) +
":source=" + "0:d".format(data.iff[self.IFF_BIT]))
return -1
#結合するサンプリング数がSAMPLING_COUNTの整数倍でないと、エラーとします。
if (data.iff[data.IFF_DATASIZE] % self.SAMPLING_COUNT != 0):
print("Sampling count is not base on :" + self.SAMPLING_COUNT )

#結合は単純に足しているだけです。
self.iff[self.IFF_DATA] += data.iff[data.IFF_DATA]
self.iff[self.IFF_DATASIZE] += data.iff[data.IFF_DATASIZE]
self.iff[self.IFF_SIZE] += data.iff[data.IFF_DATASIZE]


def getWave(self):
#Waveデータのフォーマットでバイナリで取り出すメソッドです。
dMetaID, dTitle, dType, dStart, dByte, dEnc = self.DEF_METAID, self.DEF_TITLE, self.DEF_TYPE, self.DEF_START, self.DEF_BYTE, self.DEF_ENC
work = b''
for i in range(14):
siffData = self.iff[i]
iDEF = self.IFF_DEF[i]
if (iDEF[dType] == self.TYPE_STR):
work = work + siffData.encode(iDEF[dEnc])
elif (iDEF[dType] == self.TYPE_LITTLE and iDEF[dByte] == 2 ):
work = work + siffData.to_bytes(2, 'little')
elif (iDEF[dType] == self.TYPE_LITTLE and iDEF[dByte] == 4):
work = work + siffData.to_bytes(4, 'little')
work = work + self.iff[self.IFF_DATA]
return work

#出力するDBの名前です。
CAT_WAVE_FILE='KooSoundDB.wav'
sCount = 0
#カレントディレクトリで、"00001"から"99999"(5桁)のフォルダがあれば名前を取得してソートします
output_path = "."
files = os.listdir(output_path)
list_dir = [f for f in files if os.path.isdir(os.path.join(output_path, f))]
sound_dir = [i for i in list_dir if re.search(r'[0-9][0-9][0-9][0-9][0-9]', i)]
sound_dir.sort()
print(sound_dir)
#フォルダ名と同じ番号のwavファイルがあるか調べます。
for dir_name in sound_dir:
fileName = dir_name + "\\" + dir_name + ".wav"
if os.path.isfile(fileName):
sCount += 1
print ("exist:" + fileName)
f = open(fileName, 'rb')
aData = f.read()
waveData = VWave(aData)
if (sCount == 1):
# 1個目は元データそのものです。
catWave = waveData
else:
# 2個目以降は結合していきます。
catWave.cat(waveData)
waveData.print()
#タグリストはget/setするので確認用です。setはまだ作ってません。
subChunkID, subChunkSize, subChunkData = waveData.getList()
for i in range(len(subChunkID)):
print(">" + subChunkID[i] + ":{0:4d}:".format(subChunkSize[i]) + subChunkData[i])
f.close()
print("===========================================")
print("Output file name:" + CAT_WAVE_FILE)
print("===========================================")
catWave.print()
#出力用のファイルをオープンし、結合演算済の内容をwavファイルに出力します。
fw = open(CAT_WAVE_FILE, 'wb')
fw.write(catWave.getWave())
fw.close()

wavフォーマットの定義を配列(リスト)で行いました。本当はPythonstruct(バイナリ構造の定義、解釈)を使いたかったのですが、可変長のbyteデータの扱いがうまくできなかったので、このようになりました。
RIFF形式のファイルであれば少し改造するだけでなんでも読めるようになるはずです。(作ったボクでもわかりにくいソースになっており反省です)

実行結果例です。(テスト用)

['02001', '02002', '04001', '07001']
exist:02001\02001.wav
Toral size = 5,767,212
ID        =RIFF
Chunk Size=5,767,204
FormatName=WAVE
Sub ID    =fmt 
Sub Size  =16
WavFomat  =1
Channel   =1
Sampling  =48,000
BytePS    =96,000
BlockSize =2
Bit       =16
DataID    =data
DataSize  =5,767,168
<<This wave file contains [ 88] sound>>
-------------------------------------------
exist:02002\02002.wav
...
===========================================
Output file name:KooSoundDB.wav
===========================================
Toral size = 5,767,212
ID        =RIFF
Chunk Size=14,614,564
FormatName=WAVE
Sub ID    =fmt 
Sub Size  =16
WavFomat  =1
Channel   =1
Sampling  =48,000
BytePS    =96,000
BlockSize =2
Bit       =16
DataID    =data
DataSize  =14,614,528
<<This wave file contains [ 223] sound>>
-------------------------------------------

あとは、機械学習用のタグ情報を付加させる機能をつければ、機械学習用サウンドDB作成プログラムはほぼ完成です。

お元気で(2.7)!こんにちは(3.6)!!

 余談ですが、世の中の流れに従って完全にPython 3.xにしています。昨年はじめたときは2.xでしか動かない太古のソースをたくさん参照していたので、おのずと2.xを多用していたのですが、今年は完全に3.xベースにします。今年作成のソースは2.xでは動作しません*3のであしからず。

f:id:np2LKoo:20170520124131p:plain

2.7おくえんのパガーニ ウアイラロードスター

f:id:np2LKoo:20170520123120p:plain

おいしい3.6牛乳

次回は、この「機械学習用サウンドDB」(だけどwavファイルそのもの)に、機械学習に必要なタグ情報を付加する方法を考えます。

プログラムが完成すれば、あとは「ねこ音あつめ」です!めざせ!10万音!!

 

プロモーションキャンペーン終了のお知らせ

プロモーション空しく全く再生されません。2週間くらいカウントアップなしです。15HITからいっこうにアップしません!そこで、プロモーションは今月末までの期間限定となりました。(ジョーンズ調査員より:地球人は「限定」に弱い。)

f:id:np2LKoo:20170601000756p:plain

月末までなら再生すると「小さな幸せ音ずれ訪れる」という特典付きです。(秘密結社「柔らか銀行」マーケット報告書より:日本人は「お得」と「特典」に弱い。

地域限定性をさりげなくアピールしSNSをよいスパイラルで巻き込むと相当の効果がある(大正製菓販売戦略部:(社外秘)一発勝負の列島分断飢餓作戦資料より)
よろしくお願いいたします!めざせ20HIT!!!

→カール便乗キャンペーンはあと1ポ及ばず、不成功におわりました。(19Hitでした)

ご視聴いただきありがとうございました。

*1:蛙界に存在する、生きることの意義に疑問を感じる青春期/思春期特有の病気。「蛙はなぜ生きるのか」をつきつめ、崇高な自己実現目的意識と自己潜在能力とのギャップに失望し、なにもヤルキが起こらなくなる、モチベーション低下スパイラルパターン。失望が大きいと食欲もなくなり死に至る病でもある。:おたまじゃくしから蛙になった年と翌年(感受性の強い蛙は毎年春期に)かかりやすいといわれている。

*2:余談ですが、クラスを使ったので「self.」がやまほどでてきました。あまりに多いところは、一旦別の変数におきかえることをしています。「self.」を1文字であらわす略記方法を採用してくれないかなぁ。。。1行の半分がself.である行が何行も続くと誰でもうんざりすると思います。慣れれば気にならないのかもしれませんが、初心者には辛いです。

*3:「今時、『機械学習するならPython2.xだよ!』なんて言っていると小学生に笑われる。」と、どなたかが書いていましたが、ドキッとしました

計算機音楽の自由研究(準備:その2.7)~wavファイルのフォーマットを勉強する

はじめに

今回は(機械学習向けの音のデータベースとして使用する予定の)、wavファイルへの波形情報以外の情報の持たせ方と、Pythonでの波形情報以外の取得方法について確認します。準備が進まず、実験にまだまだはいれません。準備ブログについて、亀の歩みで番号を0.1ずつアップさせています。

f:id:np2LKoo:20170514104105j:plain

よく使われるwav/waveフォーマットを実験用の標準データベースフォーマットにする方向で考えているのは前回まで書いたとおりです。
このwavフォーマットについて、実験用の情報をいろいろ持たせるための確認をしますです。wav(の中のRIFF情報)のタグ情報をどう扱うかという、超マイナーな話題です。

Pythonの標準のwaveライブラリなどではタグ情報にアクセスできない*1ことによるお題です。手抜きで英語のリンクを貼っていますが、訳す力がありません。あしからず。(6月末まで反省キャンペーン中です。内容を順次リファインします。)

なんのあしあと?かえるのあしあと!(雪の上ならそれは違いますよ)

 最初に蛇足をかくのもなんですが、助手たちが書いているのは「聖なる館」以下の部分だけで、それ以外の部分はボクが書いてます。

どのような情報を持たせるのか

手書き数字画像学習用のMNISTデータベースがとても優れており、現在も確認用やチュートリアルとしてよくつかわれています。今後も当ブログではよく使うと思います。データベースのフォーマットは扱いやすければなんでもいいと思っていますが、以下の要件が必要かと思っています。


学習用(実験用)データベースの要件

・一度リリースしたら初志貫徹。内容を変えない。

  改善したくてもしない。してしまうと以前の実験との比較が困難になる。

・扱いやすい容量にまとまっている。

  1つ1つの情報の粒度がちいさすぎず、大きすぎない

  全体の情報の「個数」は情報の内容に対して、統計的に考えても十分大きい

・学習用とテスト用の境界がはっきりしている。

  利用する人がまちがいようがないようにする。(ここがまちまちになると比較にならない)

・ダウンロードが容易

  特定コードを書けば無条件で使用できるなど。

  アクセス・使用するためのメソッドが標準化されている。

・一部のみの改変がしにくい

  どうしても応用したものをつくりたくなるが、データ差し替えや書き換えがある程度しにくいとやろうと思わない。


手書きの数字を学習させる場合は、その正解がなんであるかは0~9までの数字を持てばよく、ほかにあまり情報が要りません。
当ブログでの音の実験では、音の種類だけでなく、いろいろな情報を持たせたいと考えています。
バイオリンかピアノかを聞き分けるだけでなく、バイオリンなら1億円超えのストラディバリウスと10万円の練習用を聞き分けたり、ピアノならスタンウェイかヤマハかなどを聞き分けるようなこともやりたいと考えています。(目指せ一流!)
そのため「ピアノの中央ドの音」ではなく、「KeppyがサンプリングしたスタンウェイのサウンドフォントV6.xのMIDIノート60の音」のような情報を持たせたいと考えています。
できれば、wavファイルの中にそれらの情報を持たせたいと考えています。*2
wavファイルのフォーマットを調べて、データをどのように持てるのか、(または持てないのか)を確認します。

おさらい
pythonでwaveファイルを扱う場合はimport wave とすれば簡単に行えます。ところが、pythonのwave機能ではタイトルやアーチスト、コメントの情報を取得できません。

マニュアルを読んでもコメント情報にアクセスできる手段は書いてありません。

flacは大好きですが、今回はあえてPASSしています。*3

機械学習向けの正解や補助情報をwavファイルの「タグ」情報として入れたいと考えていますので、pythonで扱う方法を確認します。

ポイントを列記します
・wavファイルのフォーマットはRIFFというフォーマット規格を基本にしている。

・RCFとかの標準規格ではない。「AS IS」(あるがまま)な規格で悪い意味いい加減。いい意味で柔軟性あり。不運なことに悪い面が目立ってしまっている。

・wavファイルのRIFF内タグはRFC 4180を解説してるページの参照としてはあるが、「定義」ではない模様。MS社ソースのaafile.cの内容そのものが仕様定義のようです。
Pythonにはいろいろなwavファイルへのアクセスメソッドやライブラリがあるが、タグアクセスについてはほとんど機能がない。
・タグにアクセス(読むだけ)したいなら通常バイナリファイルとして読み込んで、ジブンで直接アクセスしたほうが手っ取り早い。(Pythonなので、どこかにwavファイルのタグを簡単に扱えるライブラリが「ある」とおもいますが、少し探して見つからないものは探すのがとってもたいへん。)

フォーマットについての説明は初心者につき、他のサイトを参考にさせていただきます。フォーマットの説明は(力が及ばないので)しませんのであしからず。

こちらの説明がわかりやすかったです。どうも有難うございます。

wavファイルの「タグ」情報について

 wavファイルのタグは参照ページのとおり、RIFFの仕様策定はMS社とIBM社の提案によるものですが、厳密な定義をしていない部分やもともと自由度が高いことを想定して策定されているので、かなり混乱したようです。
とくに各タグの意味やフォーマットの例示や定義が薄く、策定時には多言語環境がまとまっていなかったこともあり、多言語及び複数表記(複数情報をデリミタ;で区切るかどうかなど)の不統一により、多くのソフトで非互換部分が発生している模様です。flacのタグなどは後で作成されたのでそのあたりの状況もふまえて設計されており、このあたりの非互換はない模様です。

プログラム

wavフォーマットのページを参考にして、またジブンで作成したwavファイルをバイナリエディタで確認してプログラムしました。仕様にでているフォーマット内容を参考に各情報をそのまま表示しているプログラムです。
ベタベタなコードですが、実験用ということでご容赦ください。(あとでもうすこし汎用的なものに差し替えるかもしれません)


import wave #使ってません
import numpy as np

STRCODE ='utf-8'

class vWave:
iffAll = None
iffID = None
iffSize = 0
iffFormatName = None
iffSubID = None
iffSubSize = 0
iffWavFomat = 0
iffChannel = 0
iffSampling = 0
iffBytePS = 0
iffBlockSize = 0
iffBit = 0
iffEXParaSize = 0
# self.iffEXParam = 0
iffDataID = None
iffDataSize = 0
iffData = None
iffList = None
iffListID = None
iffSubChunkID = []
iffSubChunkSize = []
iffSubChunkData = []

def __init__(self, data):
self.iffAll = np.frombuffer(data, dtype="byte")
self.iffID = (b''.join(self.iffAll[0:4])).decode(STRCODE)
self.iffSize = int.from_bytes(self.iffAll[4:8], 'little')
self.iffFormatName = (b''.join(self.iffAll[8:12])).decode(STRCODE)
self.iffSubID = (b''.join(self.iffAll[12:16])).decode(STRCODE)
self.iffSubSize = int.from_bytes(b''.join(self.iffAll[16:20]), 'little')
self.iffWavFomat = int.from_bytes(self.iffAll[20:22], 'little')
self.iffChannel = int.from_bytes(self.iffAll[22:24], 'little')
self.iffSampling = int.from_bytes(self.iffAll[24:28], 'little')
self.iffBytePS = int.from_bytes(self.iffAll[28:32], 'little')
self.iffBlockSize = int.from_bytes(self.iffAll[32:34], 'little')
self.iffBit = int.from_bytes(self.iffAll[34:36], 'little')
self.iffDataID = (b''.join(self.iffAll[36:40])).decode(STRCODE)
self.iffDataSize = int.from_bytes(self.iffAll[40:44], 'little')
self.iffData = b''.join(self.iffAll[44:44 + self.iffDataSize])
self.iffList = self.iffAll[44 + self.iffDataSize:]
if (self.iffList.size != 0):
self.iffListID = (b''.join(self.iffList[0:4])).decode(STRCODE)
self.iffListSize = int.from_bytes(self.iffList[4:8], 'little')
self.iffInfoID = (b''.join(self.iffList[8:12])).decode(STRCODE)
offset = 12
for i in range(999):
chunkID = (b''.join(self.iffList[offset:offset + 4])).decode(STRCODE)
subChunkSize = int.from_bytes((b''.join(self.iffList[offset + 4:offset + 8])), 'little')
chunkData = (b''.join(self.iffList[offset + 8:offset + 8 + subChunkSize]).decode('SJIS'))
offset += (8 + subChunkSize + (subChunkSize % 2))
self.iffSubChunkID.append(chunkID)
self.iffSubChunkSize.append(subChunkSize)
self.iffSubChunkData.append(chunkData)
if self.iffListSize <= offset + 12:
break

def print(self):
print('Toral size = ' + "{0:d}".format(self.iffAll.size))
print('ID = ' + self.iffID)
print('Chunk Size = ' + "{0:d}".format(self.iffSize))
print('FormatName = ' + self.iffFormatName)
print('Sub ID = ' + self.iffSubID)
print('Sub Size = ' + "{0:d}".format(self.iffSubSize))
print('WavFomat = ' + "{0:d}".format(self.iffWavFomat))
print('Channel = ' + "{0:d}".format(self.iffChannel))
print('Sampling = ' + "{0:d}".format(self.iffSampling))
print('BytePS = ' + "{0:d}".format(self.iffBytePS))
print('BlockSize = ' + "{0:d}".format(self.iffBlockSize))
print('Bit = ' + "{0:d}".format(self.iffBit))
print('DataID = ' + self.iffDataID)
print('DataSize = ' + "{0:d}".format(self.iffDataSize))
print('--------------------------------')
print('List ID = ' + self.iffListID)
print('List Size = ' + "{0:d}".format(self.iffListSize))
print('INFO ID = ' + self.iffInfoID)

def getData(self):
return self.iffData

def getList(self):
return self.iffSubChunkID, self.iffSubChunkSize, self.iffSubChunkData

WAVE_INPUT_FILENAME = "test\Check055B.wav"

f = open(WAVE_INPUT_FILENAME, 'rb')
aData = f.read()
waveData = vWave(aData)
waveData.print()
subChunkID, subChunkSize, subChunkData = waveData.getList()
for i in range(len(subChunkID)):
print(">" + subChunkID[i] + ":{0:4d}:".format(subChunkSize[i]) + subChunkData[i])



 実行結果(例)

例ではモノラル16Bit48KHzサンプル数=32の音声データに対し、フリーソフトmp3infpでタグ情報を付加してその内容を表示したものです。

実行結果


Toral size = 322
ID         = RIFF
Chunk Size = 314
FormatName = WAVE
Sub ID     = fmt
Sub Size   = 16
WavFomat   = 1
Channel    = 1
Sampling   = 48000
BytePS     = 96000
BlockSize  = 2
Bit        = 16
DataID     = data
DataSize   = 64
--------------------------------
List ID    = LIST
List Size  = 206
INFO ID    = INFO
>ISRC:   7:ソース
>ICRD:  11:2017/05/13
>IPRD:   9:アルバム
>IENG:   7:製作者
>ITRK:   5:9999
>INAM:  12:Title Name 
>ICOP:   7:著作権
>IGNR:  11:A Cappella
>ISFT:  13:ソフトウェア
>ICMT:   9:コメント
>IART:  13:アーティスト 

元にしたファイルの情報

f:id:np2LKoo:20170514143304p:plain

f:id:np2LKoo:20170514143103p:plain

まとめ 

勢いでタグ全般を確認しましたが、コメント(ICMT)タグに実験用サウンドの各種情報を入れて登録をすればよいと考えます。(4バイトあるので、4GBまで情報をいれられるはずです。全体でも4バイト容量(4GB)が限界です)機械学習向けコメント情報のフォーマットは別途考えようと思いますが、[JSON形式]でよいと思います。

補足

 Windowsの標準機能では、タグ情報を自由に入れることはできません。専用のソフトを使って入れることができます。フリーでいろいろあります。

ボクはmp3infpというソフトを使っています。

フォーマットがわかれば自作プログラムから書いてもいいと思っています。

何もタグ情報を入れていないwav(上側ファイル)とタグ情報をいれたwav(下側ファイル)でバイナリエディタでの確認。下側ファイルの黒枠部分が上側ファイルに相当します。

f:id:np2LKoo:20170514211645p:plain

Python足 (もしくは Silly Walk)

 (参考)以下の表はMS社のRIFF定義をしたaafile.cの内容からの抜粋です。各種関連情報の紹介とともに訳しておられる方がいらっしゃるのでそちらでどうぞ(苦笑)

ID 内容 内容(英語) 説明(英語)
IARL アーカイブされた所在 Archival Location Indicates where the subject of the file is archived.
IART 参加アーチスト(複数は;でデリミト:しないソフトもある) Artist Lists the artist of the original subject of the file. For example, \"Michaelangelo.\"
ICMS 著作権代理人 Commissioned Lists the name of the person or organization that commissioned the subject of the file. For example, \"Pope Julian II.\"
ICMT コメント Comments Provides general comments about the file or the subject of the file. If the comment is several sentences long, end each sentence with a period. Do not include newline characters.
ICOP 著作権情報(複数は;でデリミト:しないソフトもある模様) Copyright Records the copyright information for the file. For example, \"Copyright Encyclopedia International 1991.\" If there are multiple copyrights, separate them by a semicolon followed by a space.
ICRD 作成日→年のみ表示するソフトもある Creation date Specifies the date the subject of the file was created. List dates in year-month-day format, padding one-digit months and days with a zero on the left. For example, \"1553-05-03\" for May 3, 1553.*4
ICRP

(AVI)

一部切り取り

Cropped Describes whether an image has been cropped and, if so, how it was cropped. For example, \"lower right corner.\"
IDIM

(AVI)縦横サイズ

Dimensions Specifies the size of the original subject of the file. For example, \"8.5 in h, 11 in w.\"
IDPI (AVI)解像度 Dots Per Inch Stores dots per inch setting of the digitizer used to produce the file, such as \"300.\"
IENG (録音/録画)エンジニア Engineer Stores the name of the engineer who worked on the file. If there are multiple engineers, separate the names by a semicolon and a blank. For example, \"Smith, John; Adams, Joe.\"
IGNR ジャンル Genre Describes the original work, such as, \"landscape,\" \"portrait,\" \"still life,\" etc.
IKEY キーワード Keywords Provides a list of keywords that refer to the file or subject of the file. Separate multiple keywords with a semicolon and a blank. For example, \"Seattle; aerial view; scenery.\"
ILGT

(AVI)

明度

Lightness Describes the changes in lightness settings on the digitizer required to produce the file. Note that the format of this information depends on hardware used.
IMED メディア形式 Medium Describes the original subject of the file, such as, \"computer image,\" \"drawing,\" \"lithograph,\" and so forth.
INAM タイトル Name Stores the title of the subject of the file, such as, \"Seattle From Above.\"
IPLT (AVI)色数 Palette Setting Specifies the number of colors requested when digitizing an image, such as \"256.\"
IPRD アルバム Product Specifies the name of the title the file was originally intended for, such as \"Encyclopedia of Pacific Northwest Geography.\"
ISBJ サブジェクト/サブタイトル/内容説明 ※ソフトにより扱いがまちまち Subject Describes the contents of the file, such as \"Aerial view of Seattle.\"
ISFT ソフトウェア Software Identifies the name of the software package used to create the file, such as \"Microsoft WaveEdit.\"
ISHP (AVI)鮮明度 Sharpness Identifies the changes in sharpness for the digitizer required to produce the file (the format depends on the hardware used).
ISRC ソース Source Identifies the name of the person or organization who supplied the original subject of the file. For example, \"Trey Research.\"
ISRF ソースの形態 Source Form Identifies the original form of the material that was digitized, such as \"slide,\" \"paper,\" \"map,\" and so forth. This is not necessarily the same as IMED.
ITCH (デジタル編集加工した)技術者 Technician Identifies the technician who digitized the subject file. For example, \"Smith, John.\"
邪の道 にねそべるカエル(ボク)

wavのアクセスを確認する過程で、Python for .NET というのを使ってみました。(リンクは英語です。ごめんなさい)すんなり動き、何でもできて「にんまり」と笑いました。ボクはピュアなPythonには別にこだわっておらず、(実験なので動けばいいので、)「これもあり」だと思いました。Pythonから.NETのライブラリや.NET経由でシステムCALLが読み放題です。


*1:chunkライブラリではできますが、AIFFなどを対象にしているので、wavファイルに対して使うには逆に手間がかかる感じがします。wavのLISTタグは入れ子のchunkをもつなどがありますが、wavフォーマットそのものには対応していないため、どう使えばいいかがわかりません。。。

*2:MNISTの手書き文字データベースは、「数少ない(集約された)ファイルから構成されており、手軽に改変できない」ことが重要だと思っています。wavファイルの中に各種情報を持たせることにより、改変しにくく、ファイルも少ない状態となると考えます。

*3:各種の情報をいろいろな再生方法で確実に共有したい場合はflacなどを使うべきだ。との見解がほとんどでした。flacは大好きなのですが、実験用の再加工することもあるデータとしては、wavファイルのほうが扱いやすいと考えています。

*4:アスカニオ・コンディヴィの「ミケランジェロの生涯」の著作をイメージした日付かも