Android用のSoXポートまたは完璧なプレーヤーを作成しよう

こんにちは、Habrauser!



数か月前、私はAndroid向けに膨大な量のエフェクトを備えたプレーヤーを作成することを考えていました。 その時点で唯一のプレーヤー(現在どのようにわかっているのかわかりません:)少なくともいくつかのサウンド処理を備えたプレーヤーはPowerAMPでしたが、その中のオーディオエフェクトの数は、控えめに言っても不十分でした。 私はこのアイデアを実装しようとしました。 これについてはほとんど説明していませんが、このトピックで何が起こったのかを説明します。 だから、猫の下で興味を持っている人は、してください。



ライブラリを探しています...




最初に、さまざまなエフェクトを使用してサウンドを柔軟に処理できる非常にオープンソースのライブラリを見つけることにしました。 結局、私は偶然SoXに会った。 一見、このようなプロジェクトを実装するための理想的なライブラリでしたが、それほど単純ではないことが判明しました...



最初の問題




SoXに慣れる過程で、次のような問題が見つかりました。

1.ライブラリはすべての主要なオペレーティングシステムで正常に動作しますが、ARM用に最適化されていません。

2. APIだけでなくライブラリAPIの説明もかなり貧弱で、ほとんどすべての機能はコマンドラインから実装する方が簡単でした。

3. SoXは、デコードに1つのFFmpegを使用する代わりに、多数のライブラリを使用します(公式Webサイトをご覧ください)。 したがって、これらすべてのライブラリもAndroid NDKでビルドする必要があります。

4. SoXはほぼすべての形式を完全に再現およびデコードしますが、エフェクトを適用する場合、オーディオをファイルまたはバイト配列にデコードするか、Alsa / CoreAudioで再生することができます。 Androidには理論的にはAlsaが存在するため、3番目のオプションは明確に適合しませんでしたが、常に機能するとは限らず、一般的にこれは推奨される音声再生方法ではありません。 したがって、唯一のオプションは、バイト配列内のすべてをデコードし、Java(AudioTrack)で提供することです。 しかし、これでさえ実装が困難でした。

エフェクトを使用してサウンド処理を適用する公式例のコードの一部を次に示します。



assert(sox_init() == SOX_SUCCESS); assert(in = sox_open_read(argv[1], NULL, NULL, NULL)); /* Change "alsa" in this line to use an alternative audio device driver: */ assert(out= sox_open_write("default", &in->signal, NULL, "alsa", NULL, NULL)); chain = sox_create_effects_chain(&in->encoding, &out->encoding); e = sox_create_effect(sox_find_effect("input")); args[0] = (char *)in, assert(sox_effect_options(e, 1, args) == SOX_SUCCESS); assert(sox_add_effect(chain, e, &in->signal, &in->signal) == SOX_SUCCESS); e = sox_create_effect(sox_find_effect("trim")); args[0] = "10", assert(sox_effect_options(e, 1, args) == SOX_SUCCESS); assert(sox_add_effect(chain, e, &in->signal, &in->signal) == SOX_SUCCESS); if (in->signal.rate != out->signal.rate) { e = sox_create_effect(sox_find_effect("rate")); assert(sox_effect_options(e, 0, NULL) == SOX_SUCCESS); assert(sox_add_effect(chain, e, &in->signal, &out->signal) == SOX_SUCCESS); } if (in->signal.channels != out->signal.channels) { e = sox_create_effect(sox_find_effect("channels")); assert(sox_effect_options(e, 0, NULL) == SOX_SUCCESS); assert(sox_add_effect(chain, e, &in->signal, &out->signal) == SOX_SUCCESS); } e = sox_create_effect(sox_find_effect("output")); args[0] = (char *)out, assert(sox_effect_options(e, 1, args) == SOX_SUCCESS); assert(sox_add_effect(chain, e, &in->signal, &out->signal) == SOX_SUCCESS); sox_flow_effects(chain, NULL, NULL);
      
      





この場合、オーディオがデコードされ、いくつかのエフェクトが適用され、すべてがALSAを介して出力されます。 ご覧のとおり、effect_chainを作成するには、最初に情報の読み取り用と出力用の2つのストリームが必要です。 バイト配列の一部のオーディオファイルをデコードする公式の例を次に示します。

 assert(sox_init() == SOX_SUCCESS); /* Open the input file (with default parameters) */ assert(in = sox_open_read(argv[1], NULL, NULL, NULL)); #if defined FIXED_BUFFER assert(out = sox_open_mem_write(buffer, buffer_size, &in->signal, NULL, "sox", NULL)); #else assert(out = sox_open_memstream_write(&buffer, &buffer_size, &in->signal, NULL, "sox", NULL)); #endif while ((number_read = sox_read(in, samples, MAX_SAMPLES))) assert(sox_write(out, samples, number_read) == number_read);
      
      





ご覧のとおり、この場合、オーディオは部分的にデコードされ、プログラムはバッファを受け取ります。 この例は完全に機能していますが、オーディオの各部分(サイズが16484バイト)の別のバッファーへの読み取りおよび書き込みストリームを作成し、これらのストリームを処理する必要があるため、エフェクト(プログラムの目的)を適用することは実際上不可能です。 私にとってはうまくいきませんでしたし、そのような機会が説明された例もありません。

次に、1つのバッファのエフェクトを使用してすべてのオーディオをデコードするのが論理的ですが、このオプションは多くのRAMを使用します(テストしたとき、10〜11メガバイトの小さなオーディオファイルをデコードすると100mbに達しました)。



しかし、それでも試してみることにしました...




これらの問題にもかかわらず、私はSoXと関連するすべてのライブラリの移植を開始することにしました。 Android NDKを知るために1週間が費やされました。 原則として、移植は複雑で均質なプロセスではなく、前の記事で説明しました。 一部のライブラリは既にコンパイルされています(例:FFmpeg)。 最終的に、コンパイル済みのsox.soを入手しました。これは実際に機能し、動作するようになりました:)問題を解決する時が来ました。すべてはそれほど難しくないことが判明しました。 メモリの問題はほぼ解決されました(結局、それは頻繁に使用されますが、アプリケーションはそれを削除しません)。 ほとんどすべてのオーディオ形式を再生し、それにエフェクトを追加するアプリケーションを入手しました(今ではフランジャー、他のものを追加できます)。 一方で、開発を継続することはすでに可能ですが、同時に2つの新しい問題が発生しました。



1.プログラムがプロセッサを使いすぎています(デコード時に80%に達します)。 ARM用にCコードを最適化する方法がわからないため、自分で解決することはできません。

2.プログラムが不安定です。 10回の起動のうち約1-2回は、何も再生しません(Galaxy Tabでテスト済み)。 私もこの問題を解決できませんでした...



全体として、作業が消えないように、GitHubですべてのコードを公開し、ここに記事を書くことにしました。 コードへのリンク。 誰かがこれらの問題を解決する機会を見つけたら-メールまたはPMで私に手紙を書いてください。 私のアイデアが誰にも興味があることを願っています:)



All Articles