1

音楽のオーディオ ファイルがあり、曲の小さなクリップを録音し、別の時間に音楽ファイルに追加する必要があります。そのようにして、私が長い紙切れを持っていて、大きな紙のさまざまな位置に小さな紙を貼り付けなければならないことを理解できます. 何らかの方法を提案してください。

ここで詳細を説明しましょう。それぞれ 5 秒の小さなサウンド クリップが 10 個あり、50 秒の音楽ファイルがあるとします。全部で 11 個のサウンド ファイルがあります。ここで、音楽ファイルのさまざまな時間の後に小さな 10 個のクリップを追加して、最終的なオーディオ ファイルを 1 つ作成する必要があります。たとえば、最初のファイルを 5.22 秒で追加し、2 番目のファイルを 10.34 秒で追加する必要があります。

4

1 に答える 1

2

コメントであなたの説明に従って答えます:

2つのmp3ファイル(5秒のa.mp3と7秒のb.mp3)があり、7秒の長さのc.mp3を生成するためにそれらを混合したいとします。

コメントで述べたように、iOSの詳細を説明することはできませんが、使用するプラットフォームやライブラリに関係なく、このプロセスを実行するために論理的に何が必要かを確認できます。簡単なC++スニペットを使用して説明します。ただし、a.mp3(以降A)をb.mp3(以降B)のどこかにミックスして(たとえば、AをBの先頭にミックスして)、結果のオーディオクリップCを生成するように聞こえます。

S16_LEまず第一に、それらはMP3ファイルであり、WAVやRAWやAIFFなどの他の非圧縮PCM形式ではないと述べたので、最初にAとBをPCM(CDオーディオ形式-署名付き16)などの非圧縮形式に変換する必要があります。-ビット整数サンプル、リトルエンディアン)。これは、AとB、したがってCのサンプル値の配列(ステレオオーディオの場合は左右のチャンネルがインターリーブされている)で作業することを意味します。ミキシングが完了したら、オプションでMP3に再エンコードします。

ライブラリを使用してファイルのエンコード/フォーマットの問題を処理する必要がありますが、それらを使用すると、直接記録または再生用のシステムインターフェイスを含め、すべてが生成(つまり、読み取り時)または期待(つまり、書き込み)基本的に、これと同じ基本的な非圧縮PCMサンプルストリーム形式。一般的な開発では、ユビキタスlibsndfileCライブラリは、おそらくフォーカシング。

簡単にするために、モノラルサウンドクリップAとBのみを検討します(つまり、AとBのサンプル値の単純な配列であり、インターリーブされた左/右チャネルについて心配する必要はありません)。重要な場合は、各ステレオチャンネルを個別に検討することで(A.leftはB.leftとミックスし、A.rightはB.rightとミックスします)、概念をステレオに簡単に拡張できます。特定のAとBがステレオであるが、Cがステレオである必要がない場合は、アプリケーションに応じて、両方の入力オーディオクリップを事前にモノラルに変換することもできます。

さらに、通常、オーディオサンプルを浮動小数点値として処理する方が簡単なのでlibsndfile、非圧縮サンプル形式を[-1.0の範囲の浮動小数点に変換します(または、通常、オーディオファイルライブラリが自動的に行います)。 、+ 1.0]、ここで、1.0の絶対値は可能な限り最大のサンプル値を表し、0.0は無音を表します。これらのサンプル値は、時間の経過に伴う(つまり、アレイ全体での)任意のオーディオ波形の変化を構成します。

まず、ミキシングする前に、十分な「ヘッドルーム」(出力のクリッピングを防ぐ)があることを確認する必要があります。なんで?ミキシングでは、信号の重ね合わせ(加算)の原理を使用して、信号/サウンドを結合します。オーバーラップするサンプルごとにAとBを加算するため、対応するサンプルのAとBの合計が、混合された出力サンプルが「クリップ」する可能性があります。 1.0を超えるか、-1.0を下回ります。

それぞれの入力レベルと、それらの音量比を維持するか、単にそれらを均等に組み合わせるか(またはステレオで作業していて、Aの最も大きいチャンネルのいずれかを使用するかどうか)に応じて、クリッピングを防ぐ方法がいくつかあります。またはBを基準点として使用します。これはステレオについて最後に聞くものです)。

最も単純なルートを取り、AとBの両方のボリュームを正規化して、フルスケールの半分(0.5)以下でピークに達するようにします。これにより、それらを足し合わせたときにクリップしないようになります(つまり、混合出力サンプルがなくなることはありません)。範囲[-1.0、+ 1.0])を超えています。2つの入力ではなく、この方法で同時にミキシングされる3つの入力オーディオクリップX、Y、およびZがある場合、ピーク時のフルスケールの1/3(0.33)にそれぞれを正規化します。

それぞれのサンプルバッファ/アレイを反復処理し、それぞれの最大サンプル値を決定することにより、AA_peakとBの両方のピーク値を見つけます。B_peak[従うべきコード。]

それぞれのピーク値に対する乗算がハーフスケールになるように、スケーリング値A_scaleと各サンプルバッファAおよびBをそれぞれ決定します。B_scale[従うべきコード。]

A_scale * A_peak == 0.5
B_scale * B_peak == 0.5

エルゴ:

A_scale = 1 / (2 * A_peak)
B_scale = 1 / (2 * B_peak)

A_scaleこれで、サンプルバッファーAとB全体にそれぞれとを掛けることができます。B_scaleこれらはそれぞれ正確にハーフスケールでピークになるように正規化され、2つの混合サンプルがフルスケールを超えることはありません。つまり、AとBの最大値がサンプルに対して整列されている場合でも、それらのスケーリングおよび合計されたミックス出力は正確に1.0になり、それより大きくなることはありません。このようなスケーリング係数は、「ゲイン」と呼ばれることがよくあります。

繰り返しになりますが、ミキシング時に2つ以上のサンプルバッファー(オーディオクリップ)間のゲインを正規化する方法は複数ありますが、これはデモンストレーションで最も単純で最も一般的な方法です。さらに、N個の異なるオーディオクリップを一緒にミキシングするのに簡単に適応でき(上記のように)、わずかに単純化して、サンプルストリームのリアルタイムミキシングに適応します(オーディオクリップのサンプルバッファ全体が利用できず、サンプル処理が行われます)記録時によくあるように、チャンクで)。

これで、ミキシングに取り掛かることができます。

この場合、A(5秒)はB(7秒)内に収まるため、ミックスをBに直接出力できますが、一般的には、ミックスを別のサンプルバッファーC(7秒)に出力し、入力AとBは浮動小数点サンプルバッファとして変更されていません(おそらく再利用される可能性があります)。

サンプルA_lenカウントのAの長さ(簡単に決定されます。基本的には時間とサンプルレートのみに依存しますが、ライブラリはファイルをロードするときに通知します)、B_lenB、および出力Cの場合と同様に、C_len == B_lenB_len > A_len問題の説明にあるからです。

ミックス出力であるCを割り当てます。

unsigned int C_len = max(A_len, B_len);
double C[] = new double[ C_len ];

AとBのサンプルの絶対値のピークを見つけます。

double A_peak = -1.0, B_peak = -1.0;

for (unsigned int i = 0; i < A_len; ++i) A_peak = max( A_peak, fabs(A[i]) );
for (unsigned int i = 0; i < B_len; ++i) B_peak = max( B_peak, fabs(B[i]) );

AとBのハーフスケール正規化ゲインを見つけます。

double A_scale = 1 / ( 2 * A_peak );
double B_scale = 1 / ( 2 * B_peak );

AをBに混ぜてCに入れます。

assert(A_len <= B_len);
assert(B_len == C_len);

unsigned int x = 0;

for (; x < A_len; ++x)
  C[x] = A_scale * A[x] + B_scale * B[x]; // actual mixing of A and B, finally

for (; x < B_len; ++x)
  C[x] = B_scale * B[x]; // as if A[x] were zero & no abrupt gain change

浮動小数点バッファーAとBは、混合と正規化の後も変更されていないことに注意してください。

Aは、混合されていないすべての場所でゼロ/サイレントと考えることができます。

(ここで想定されている開始時ではなく)B内の任意のオフセットでAのミキシングを開始したい場合は、時間オフセットに対応するサンプル数(t_offset秒単位、s_offset = t * sample_rate整数サンプル単位)を単純に計算し、x == s_offset上記のループ構成のミックスにAを含め始めます。[オーバーフローを防ぐためにそれを想定していs_offset + A_len <= C_lenます。]

多くの可能性があるため、混合入力を正規化するアプリケーション固有の方法を試すことをお勧めします。たとえば、それぞれのピークを個別に計算するのではなく、AとBのサンプルの合計のピークを計算した場合はどうなりますか(基本的に最初に混合し、後で修正します)。この[より良い]テクニックが不可能なのはいつですか?

最後に、信号をミキシングするときはいつでも、ミキシングが開始および終了する遷移ポイント(たとえば、クリック)(たとえば、Aが終了するがBがCに入り続けるポイント)でアーティファクトが発生する可能性があります。ここでは、これは比較的リスクが低いです。ただし、このようなアーティファクトの一般的な解決策は、ミックスへの入力の入力/終了の短時間のフェードインとフェードアウトを行うことです。これにより、混合波形をスムージングすることでアーティファクトを排除し、聞こえないほど速く実行できます。 。

于 2012-11-28T01:25:34.533 に答える