このサイトには他の質問と回答があり、エコーまたは遅延効果を作成するには、過去から保存されたオーディオ サンプルを使用して 1 つのオーディオ サンプルを追加するだけでよいことが示唆されています。そのため、次の Java クラスがあります。
public class DelayAMod extends AudioMod {
private int delay = 500;
private float decay = 0.1f;
private boolean feedback = false;
private int delaySamples;
private short[] samples;
private int rrPointer;
@Override
public void init() {
this.setDelay(this.delay);
this.samples = new short[44100];
this.rrPointer = 0;
}
public void setDecay(final float decay) {
this.decay = Math.max(0.0f, Math.min(decay, 0.99f));
}
public void setDelay(final int msDelay) {
this.delay = msDelay;
this.delaySamples = 44100 / (1000/this.delay);
System.out.println("Delay samples:"+this.delaySamples);
}
@Override
public short process(short sample) {
System.out.println("Got:"+sample);
if (this.feedback) {
//Delay should feed back into the loop:
sample = (this.samples[this.rrPointer] = this.apply(sample));
} else {
//No feedback - store base data, then add echo:
this.samples[this.rrPointer] = sample;
sample = this.apply(sample);
}
++this.rrPointer;
if (this.rrPointer >= this.samples.length) {
this.rrPointer = 0;
}
System.out.println("Returning:"+sample);
return sample;
}
private short apply(short sample) {
int loc = this.rrPointer - this.delaySamples;
if (loc < 0) {
loc += this.samples.length;
}
System.out.println("Found:"+this.samples[loc]+" at "+loc);
System.out.println("Adding:"+(this.samples[loc] * this.decay));
return (short)Math.max(Short.MIN_VALUE, Math.min(sample + (int)(this.samples[loc] * this.decay), (int)Short.MAX_VALUE));
}
}
入力ストリームから一度に 1 つの 16 ビット サンプルを受け取り、以前のサンプルを見つけて、それに応じてそれらを加算します。ただし、特に減衰が実際にかなりの結果を引き起こすレベルまで上げられた場合、出力はひどいノイズの多い静的なものです。ディケイを 0.01 に減らすと元のオーディオはほとんど聞こえなくなりますが、その時点ではエコーはありません。
基本的なトラブルシューティングの事実:
- この処理をスキップすると、オーディオ ストリームは正常に聞こえます。
- 減衰が 0 (何も追加しない) の場合、オーディオ ストリームのサウンドは良好です。
- 保存されたサンプルは実際に保存され、適切な順序と適切な場所でアクセスされます。
- 保存されたサンプルは減衰され、入力サンプルに適切に追加されます。
process()
toの呼び出しからのすべての数値は、return sample
まさにこのアルゴリズムから期待されるものであり、このクラスの外でもそのままです。
問題は単に符号付きショートを一緒に追加することから生じるようであり、結果として生じる波形は絶対的な大惨事です。この特定のメソッドがさまざまな場所 (C#、C++、さらにはマイクロコントローラー) で実装されているのを見てきましたが、なぜここでそれほどうまくいかないのでしょうか?
編集:私はこれについて完全に間違っていたようです。FFmpeg/avconv なのか、それとも他の要因なのかはわかりませんが、ここでは通常の PCM 信号を扱っていません。波形のグラフ化、トーン ジェネレーターの試行の失敗、およびその結果の分析を通じて、これが差動パルス符号変調の何らかのバージョンであると判断しました。ピッチは、あるサンプルから次のサンプルへの変化によって決定され、純粋な正弦波で意図した「ボリューム」乗数を半分にすると、実際にはピッチが下がり、ボリュームは同じままになります。(非サイン シーケンスでボリューム乗数をいじると、このエコー アルゴリズムと同じスタティックが作成されます。)パルス符号変調、まず適切なオーディオ ストリームを取得する方法が必要です。