質問

転記を行うミュージシャンを支援するシステムを開発しています。目的は、単一の楽器のモノラル録音で自動音楽転写を実行することです(ユーザーが後でグリッチ/ミスを修正するため、完璧である必要はありません)。ここの誰かが自動音楽転写の経験を持っていますか?それともデジタル信号処理ですか?あなたの背景に関係なく、誰からの助けも大歓迎です。

これまで、ピッチ検出のための高速フーリエ変換の使用を調査してきましたが、MATLABと私自身のJavaテストプログラムの両方で、多くのテストがニーズに十分に高速かつ正確であることを示しました。取り組む必要があるタスクのもう1つの要素は、生成されたMIDIデータを楽譜形式で表示することですが、これは今のところ気にしないことです。

簡単に言えば、私が探しているのは、音の開始を検出するのに適した方法、つまり新しい音が始まる信号内の位置です。遅い開始は適切に検出するのが非常に難しいので、最初はピアノの録音でシステムを使用します。これもまた、私がピアノを弾いているという事実によるものであり、テストに適した録音を取得するためにより良い位置にあるべきです。前述のように、このシステムの初期バージョンは単純なモノフォニック録音に使用され、今後数週間の進捗状況に応じて後でより複雑な入力に進む可能性があります。

役に立ちましたか?

解決

これは、開始検出に注意するためのしきい値アプローチを示すグラフィックです。

alt text

この画像は、3つの個別のノートが連続して再生される典型的なWAVファイルを示しています。赤い線は選択した信号のしきい値を表し、青い線は信号レベルがしきい値を超えたときに開始をマークする単純なアルゴリズムによって返されるノートの開始位置を表します。

画像が示すように、適切な絶対しきい値を選択することは困難です。この場合、最初の音はうまく拾われ、2番目の音は完全に失われ、3番目の音は(ほとんど)遅く開始されます。一般に、しきい値を低くすると幻のノートが拾われ、値を上げるとノートを見逃します。この問題の1つの解決策は、特定の時間にわたって信号が特定の割合だけ増加した場合に開始をトリガーする相対しきい値を使用することですが、これには独自の問題があります。

より簡単な解決策は、最初にWaveファイルでやや逆に名付けられた圧縮( MP3圧縮ではなく、まったく別のものです)を使用することです。圧縮は、基本的にオーディオデータのスパイクを平坦化し、すべてを増幅して、より多くのオーディオが最大値に近づくようにします。上記のサンプルに対する効果は次のようになります(名前<!> quot; compression <!> quot;が意味をなさないように見える理由を示します-オーディオ機器では、通常<!> quot; loudness <!> quotというラベルが付けられます。 ):

alt text

圧縮後、絶対しきい値アプローチは非常によく機能します(ただし、しきい値を下げるのと同じ効果で、圧縮しすぎて架空のメモのピックアップを開始するのは簡単ですが)。圧縮の良い仕事をする波動エディタがたくさんあります、そして、彼らにこのタスクを処理させるほうが良いです-あなたはおそらくかなりの量の仕事をする必要があるでしょう<!> quot; cleaning up <!> quot ;とにかくノートを検出する前にWaveファイルを作成します。

コーディング用語では、メモリにロードされるWAVファイルは基本的に2バイト整数の配列にすぎません。0は信号なしを表し、32,767と-32,768はピークを表します。最も単純な形式では、しきい値検出アルゴリズムは最初のサンプルから開始し、しきい値を超える値が見つかるまで配列全体を読み取ります。

short threshold = 10000;
for (int i = 0; i < samples.Length; i++)
{
    if ((short)Math.Abs(samples[i]) > threshold) 
    {
        // here is one note onset point
    }
}

実際には、通常のオーディオには特定のしきい値を超えるあらゆる種類の一時的なスパイクがあるため、これは恐ろしく機能します。 1つの解決策は、移動平均信号強度を使用することです(つまり、最後のn個のサンプルの平均がしきい値を超えるまで開始をマークしないでください)。

short threshold = 10000;
int window_length = 100;
int running_total = 0;
// tally up the first window_length samples
for (int i = 0; i < window_length; i++)
{
    running_total += samples[i];
}
// calculate moving average
for (int i = window_length; i < samples.Length; i++)
{
    // remove oldest sample and add current
    running_total -= samples[i - window_length];
    running_total += samples[i];
    short moving_average = running_total / window_length;
    if (moving_average > threshold)
    {
        // here is one note onset point 
        int onset_point = i - (window_length / 2);
    }
}

これらのすべては、WAVファイルの開始位置を正確に見つけるために、設定を調整したり遊んだりする必要があり、通常、あるファイルで機能するものは別のファイルではうまく機能しません。これは、あなたが選んだ非常に困難で完全に解決されていない問題領域ですが、あなたがそれに取り組むことはクールだと思います。

更新:この図は、私が省略したノート検出の詳細、つまりノートの終了を検出することを示しています。

alt text

黄色の線は、しきい値を表します。アルゴリズムが音符の開始を検出すると、移動平均信号強度がこの値を下回るまで音符が続くと仮定します(ここでは紫色の線で示されています)。これはもちろん、2つ以上の音符が重なっている場合(ポリフォニー)と同様に、別の問題の原因です。

各ノートの開始点と終了点を検出したら、WAVファイルデータの各スライスを分析してピッチを決定できます。

更新2:更新された質問を読みました。独自にゼロから作成する場合、自動相関によるピッチ検出はFFTよりも実装がはるかに簡単ですが、既にビルド済みのFFTライブラリをチェックアウトして使用している場合は、確かにそれを使用することをお勧めします。各ノートの開始位置と停止位置を特定したら(そして、ミスしたアタックとリリース部分の開始と終了にパディングを含めて)、オーディオデータの各スライスを引き出してFFT関数に渡すことができます。ピッチを決定します。

ここで重要な点の1つは、圧縮されたオーディオデータのスライスを使用するのではなく、元の変更されていないデータのスライスを使用することです。圧縮プロセスはオーディオを歪め、不正確なピッチ測定値を生成する場合があります。

ノートアタックタイムに関する最後のポイントは、あなたが思っているよりも問題が少ないかもしれないということです。多くの場合、音楽ではスローアタックの楽器(ソフトシンセなど)がシャープなアタック楽器(ピアノなど)よりも早く音を開始し、両方の音が同時に開始しているように聞こえます。この方法で楽器を演奏している場合、アルゴリズムは両方の種類の楽器で同じ開始時間を選択します。これはWAVからMIDIの観点からは優れています。

最後の更新(希望):各ノートの初期のアタック部分からのパディングサンプルを含めることについて私が言ったことを忘れてください-これは実際にはピッチ検出のための悪いアイデアではないことを忘れていました。多くの楽器(特にピアノやその他の打楽器型楽器)のアタック部分には、基本ピッチの倍数ではないトランジェントが含まれており、ピッチ検出を台無しにする傾向があります。このため、実際には攻撃の少し後に各スライスを開始する必要があります。

ああ、重要な種類: <!> quot; compression <!> quot;ここではMP3スタイルの圧縮を参照していません

再度更新:非動的圧縮を行う単純な関数を次に示します。

public void StaticCompress(short[] samples, float param)
{
    for (int i = 0; i < samples.Length; i++)
    {
        int sign = (samples[i] < 0) ? -1 : 1;
        float norm = ABS(samples[i] / 32768); // NOT short.MaxValue
        norm = 1.0 - POW(1.0 - norm, param);
        samples[i] = 32768 * norm * sign;
    }
}

param = 1.0の場合、この関数はオーディオに影響を与えません。パラメーター値を大きくすると(2.0が良好で、各サンプルと最大ピーク値の正規化された差を2乗します)、より多くの圧縮とより大きな(しかしくだらない)サウンドが生成されます。 1.0未満の値は、拡張効果を生成します。

もう1つの明白なポイント:エコーはこのアルゴリズムによって幻影として拾われることが多いため、小さな無響室で音楽を録音する必要があります。

更新:C#でコンパイルし、明示的にすべてをキャストするStaticCompressのバージョンです。これは期待される結果を返します:

public void StaticCompress(short[] samples, double param)
{
    for (int i = 0; i < samples.Length; i++)
    {
        Compress(ref samples[i], param);
    }
}

public void Compress(ref short orig, double param)
{
    double sign = 1;
    if (orig < 0)
    {
        sign = -1;
    }
    // 32768 is max abs value of a short. best practice is to pre-
    // normalize data or use peak value in place of 32768
    double norm = Math.Abs((double)orig / 32768.0);
    norm = 1.0 - Math.Pow(1.0 - norm, param);
    orig = (short)(32768.0 * norm * sign); // should round before cast,
        // but won't affect note onset detection
}

申し訳ありませんが、Matlabでの私の知識スコアは0です。Matlab関数が期待どおりに動作しない理由について別の質問を投稿した場合、回答が返されます(私だけではありません)。

他のヒント

やりたいことは、しばしば WAV-to-MIDI (google <!> quot; wav-to-midi <!> quot;)と呼ばれます。このプロセスには多くの試みがあり、さまざまな結果が得られています(開始は困難の1つであり、ポリフォニーの処理ははるかに困難です)。既製のソリューションを徹底的に検索して開始することをお勧めします。受け入れ可能なものがない場合は、自分で作業を開始することをお勧めします。

必要なプロセスの他の部分は、MIDI出力を従来の楽譜としてレンダリングするものですが、それを行う製品は数え切れないほどあります。

別の答えは:はい、私は多くのデジタル信号処理を行いました(私のWebサイトのソフトウェアを参照してください-VBおよびCで書かれた無限音声ソフトウェアシンセサイザーです)。この問題。 WAVからMIDIへの変換は、概念的にはそれほど難しくはありませんが、実際には確実に動作するようになっているだけです。ノートオンセットはしきい値を設定するだけです。エラーは、ノートアタックの違いを補正するために、時間を前後に簡単に調整できます。ピッチ検出は、リアルタイムで行うよりもレコーディングで行う方がはるかに簡単であり、自己相関ルーチンを実装するだけです。

MIRToolbox をご覧ください。 -Matlab用に書かれており、オンセット検出器が組み込まれています-それは非常にうまく機能します。ソースコードはGPL化されているため、どの言語でも機能するアルゴリズムを実装できます。本番コードで使用する言語は何ですか?

このライブラリは、オーディオのラベル付けを中心にしています:

aubio

  

aubioは、音声ラベル付け用のライブラリです。その機能には、各攻撃の前にサウンドファイルをセグメント化すること、ピッチ検出を実行すること、ビートをタップすること、ライブオーディオからミディストリームを生成することが含まれます。 aubioという名前は、タイプミスのある「オーディオ」に由来します。結果にもいくつかの転写エラーが見つかる可能性があります。

そして、私はそれをオンセット検出とピッチ検出のために幸運にしました。 cにありますが、swig / pythonラッパーがあります。

また、ライブラリの著者は、ページに彼の論文のpdfを持っています。これには、ラベル付けに関する素晴らしい情報と背景があります。

平均エネルギー測定値を使用すると、時間領域でハードオンセットを簡単に検出できます。

0からNまでの合計(X ^ 2)

これを信号全体のチャンクで行います。オンセットが発生するとピークが表示されるはずです(ウィンドウサイズはあなた次第です。私の提案は50ms以上です)。

発症検出に関する豊富な論文:

ハードコアエンジニア向け:

http://www.nyu.edu/classes/bello/MIR_files /2005_BelloEtAl_IEEE_TSALP.pdf

一般の人が理解しやすい:

http://bingweb.binghamton.edu/~ahess2/Onset_Detection_Nov302011.pdf

wav信号を時間に対する振幅のグラフに変換することができます。その後、一貫した開始を決定する方法は、信号の立ち上がりフランクの変曲点での接線とx軸の交点を計算することです。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top