6

同時に再生されるはずのオーディオ信号を生成するプログラムがあります。このために、100 ミリ秒ごとに 100 ミリ秒の間隔でオーディオ ストリームを再生します。しかし、信号の値が同じであっても出力音が滑らかにならないように、各 100 ms オーディオ ストリームの最初と最後に (DC のため) 望ましくない信号があります。私のコードは以下に添付されています。正しいリアルタイムオーディオを得るために何をすべきか教えてください。

using System;
using System.Windows.Forms;
using Microsoft.DirectX.DirectSound;
using System.IO;

namespace TestSound
{
    class CSound : Form
    {
        const int HEADER_SIZE = 44;
        const bool FLAG_STEREO = true;
        const short BITS_PER_SAMPLE = 16;
        const int SAMPLE_RATE = 44100;

        int numberOfSamples;
        MemoryStream stream;
        BinaryWriter writer;
        Device ApplicationDevice = null;
        SecondaryBuffer buffer = null;
        BufferDescription description;

        public CSound()
        {
            try
            {
                ApplicationDevice = new Device();
            }
            catch
            {
                MessageBox.Show("Unable to create sound device.");
                ApplicationDevice = null;
                return;
            }
            ApplicationDevice.SetCooperativeLevel(this, CooperativeLevel.Priority);
            description = new BufferDescription();
            description.ControlEffects = false;
            stream = new MemoryStream();
            writer = new BinaryWriter(stream);
        }

        private void AddHeader()
        {
            stream.Position = 0;

            writer.Write(0x46464952); // "RIFF" in ASCII
            writer.Write((int)(HEADER_SIZE + (numberOfSamples * BITS_PER_SAMPLE * (FLAG_STEREO ? 2 : 1) / 8)) - 8);
            writer.Write(0x45564157); // "WAVE" in ASCII
            writer.Write(0x20746d66); // "fmt " in ASCII
            writer.Write(16);
            writer.Write((short)1);
            writer.Write((short)(FLAG_STEREO ? 2 : 1));
            writer.Write(SAMPLE_RATE);
            writer.Write(SAMPLE_RATE * (FLAG_STEREO ? 2 : 1) * BITS_PER_SAMPLE / 8);
            writer.Write((short)((FLAG_STEREO ? 2 : 1) * BITS_PER_SAMPLE / 8));
            writer.Write(BITS_PER_SAMPLE);
            writer.Write(0x61746164); // "data" in ASCII
            writer.Write((int)(numberOfSamples * BITS_PER_SAMPLE * (FLAG_STEREO ? 2 : 1) / 8));
        }

        public void Play(short[] samples)
        {
            if (ApplicationDevice == null)
                return;

            stream.Position = HEADER_SIZE;
            numberOfSamples = samples.Length;
            for (int i = 0; i < numberOfSamples; i++)
            {
                writer.Write(samples[i]);
                if (FLAG_STEREO)
                    writer.Write(samples[i]);
            }
            AddHeader();
            stream.Position = 0;

            try
            {
                if (buffer != null)
                {
                    buffer.Dispose();
                    buffer = null;
                }
                buffer = new SecondaryBuffer(stream, description, ApplicationDevice);
                buffer.Play(0, BufferPlayFlags.Default);
            }
            catch (Exception e)
            {
                MessageBox.Show(e.Message);
            }
        }

        static short[] samples = new short[4410]; // 100 ms
        static CSound sound;

        static void Main()
        {
            Form form = new Form();
            form.Show();

            sound = new CSound();
            Random random = new Random();
            for (int i = 0; i < samples.Length; i++)
                samples[i] = 1000; // constant value

            while (true)
            {
                sound.Play(samples);
                System.Threading.Thread.Sleep(100); // 100 ms
            }
        }
     }
}
4

3 に答える 3

4

定義されたストリームを介してオーディオを再生する方法を探している場合、NAudio http://naudio.codeplex.com/を検討しましたか?

ファイルまたはその他の場所 (メモリーなど) からストリームを定義し、再生したいデータをストリームに入れることができます。読み取りポインターがバッファーの最後に到達する前にオーディオ データをストリームに提供し続けることができる限り、生成されたオーディオでこれらのアーティファクトが聞こえることはありません。

ところで - .Net 用の Managed Direct X ライブラリは開発されておらず、事実上、この種のオーディオ開発は行き止まりになっていることをご存知でしょうか?

于 2009-08-19T22:21:06.117 に答える
1

このコードには多くの問題があります。このコードを実行すると、100 ミリ秒ごとにクリック音またはポップ音が聞こえると思います。これは、while(true) ループ内の Thread.Sleep(100) 呼び出しが原因です。基本的に、アプリは 100 ミリ秒待機し (多少の時間はかかる)、Play() を呼び出します。Play() は少し処理を行い、再生のために配列をキューに入れます。その結果、各 100 ミリ秒配列の再生の間にわずかな時間のギャップがあり、これがクリック音を生成しています。

ただし、Thread.Sleep(100) 行をコメントアウトしただけでは、アプリは無限ループに入り、メモリが不足するまで 100 ミリ秒配列の後に 100 ミリ秒配列をキューに入れ続けます。しかし、少なくとも再生には 100 ミリ秒ごとのアーティファクトはありません。

行を Thread.Sleep(80) に変更すると、メモリ不足になるまでに時間がかかるという意味で、少しはうまく機能しますが、オーディオにバッファをダンプしているため、これは依然として発生します。システムがそれらを再生できるよりも速く再生システム。

また、100 ミリ秒ごとにクリック音をなくしても、コードですべてのサンプル値を 1000 に設定しているため、スピーカーからは何も聞こえません。経時的なサンプル値。ちなみに、クリック音が聞こえる唯一の理由は、このサンプル値が 1000 に設定されており、チャンク間のわずかな時間間隔で再生値が 0 に戻るためです。各サンプル値を 0 に設定すると、何でも聞く。

これについてさらにお手伝いすることはできますが、あなたが何をしようとしているのかを正確に把握する必要があります. 特定の周波数で連続音を再生しようとしていますか?

于 2009-08-19T21:33:22.580 に答える
0

「望ましくない信号」とは、どちらかの端でわずかなポップ音を意味する場合、それはエンベロープの問題である可能性があり、Csound では「リネン」オペコードまたは同様のものによって制御できます。つまり、フロントエンドの振幅を上げ、バックエンドの振幅をわずかに下げて、ラウドスピーカーのカチッという音が中波で出力を突然停止するのを避ける必要があるということです。数ミリ秒で十分です。振幅変調に気付かずにポッピングがなくなるまで試してみてください。

ここを見てください: http://www.csounds.com/journal/issue11/csoundEnvelopes.html

同じ波形を一定の間隔で連続して発音することでシームレスな信号を生成しようとしている場合、1 つの波形の終わりが次の波形の始まりと一致しないため、常にこのポップ音が聞こえます。波形を正確に整列させることは非常に難しく、それは実際には良い戦略ではありません。より良い戦略は、エンベロープを使用して (上記のように)、波形をオーバーラップさせて (ダブテイルと呼ばれます)、古いアーティキュレーションの減衰が新しいアーティキュレーションの立ち上がりと同時に発生するようにすることです。

ただし、この戦略では、完全に純粋なサウンドは生成されません。非同期にオーバーラップする 2 つのほぼ同一の波形の存在により、互いに少し相殺され、波形の接合点ごとに振幅が減少するためです。

于 2011-09-07T14:43:16.200 に答える