2009-10-26 139 views
3

我想用C#來實現一個可以同時播放多個音頻流的應用程序。花生 - 現在有趣的部分:假設每個流都是單聲道(單聲道),我想爲每個流分別調整每個揚聲器的音量(5.1甚至7.1)。我可以使用Windows混音器來做到這一點,但問題是,只有一個混音器,我想單獨調整每個流。任何想法如何實現這一點?如何實現一個多通道音頻預混合器.net

我的第一個猜測是將流多路複用八次(7.1),對每個「通道」應用音量電平,然後將其發送到窗口混音器,例如對於80%的所有通道均勻混音。你知道任何可能支持這種用例的庫嗎?

AFAIK低音和fmod不能做到這一點,但糾正我,如果我錯了。作爲另一種選擇,我正在考慮對XNA進行黑客攻擊:使用一個向量來描述與偵聽器相關的流的位置,並使用它來應用音量補償......只是ramblings。

(請不要點我這方面的一些C++/WinAPI的想法,這個項目是不是值得我們學習另一種語言。)

+0

也許一個想法剛剛到達我的大腦:要求將可用的聲音文件導入並最初轉碼爲一種聲音庫是完全可以的。 vorbis格式支持多達255個通道,並有一個(可能被放棄的)lib可用:http://vorbisdotnet.sourceforge.net/ – 2009-10-26 15:10:50

+0

有點碰撞:我在Codeplex上找到了NAudio庫。好東西... – 2009-10-27 10:59:30

回答

1

終於得到它:bass.dll允許應用矩陣分別使用方法BassMix.BASS_Mixer_ChannelSetMatrix(int streamHandle, float[,] volumeMatrix)爲每個揚聲器設定音量。您可以看到一個示例here,他們正在使用它將立體聲流上混爲四個揚聲器。低於我創建的完整課程來解決我的問題。

public class SeparateVolumeLevelPlayer : IDisposable 
{ 
    private readonly int outputMixerStream; 
    private readonly int inputStream; 
    private readonly int numberOfSpeakers; 

    public SeparateVolumeLevelPlayer(string fileName, int numberOfSpeakers) 
    { 
     this.numberOfSpeakers = numberOfSpeakers; 
     outputMixerStream = BassMix.BASS_Mixer_StreamCreate(44100, numberOfSpeakers, BASSFlag.BASS_MIXER_MATRIX); 
     ThrowOnError(); 

     // create a stream from the media file 
     inputStream = Bass.BASS_StreamCreateFile(fileName, 0L, 0L, BASSFlag.BASS_STREAM_DECODE | BASSFlag.BASS_MIXER_MATRIX | BASSFlag.BASS_SAMPLE_MONO); 
     ThrowOnError(); 

     // add the stream to the mixer 
     BassMix.BASS_Mixer_StreamAddChannel(outputMixerStream, inputStream, BASSFlag.BASS_MIXER_MATRIX); 
     ThrowOnError(); 
    } 

    public void Play() 
    { 
     // start playback of the mixed streams 
     Bass.BASS_ChannelPlay(outputMixerStream, false); 
     ThrowOnError(); 
    } 

    public void SetVolume(float[] volumeValues) 
    { 
     if (volumeValues == null) 
     { 
      throw new ArgumentNullException("volumeValues"); 
     } 

     if (volumeValues.Length != numberOfSpeakers) 
     { 
      string message = 
       string.Format("You must pass a volume level for every speaker. You provided {0} values for {1} speakers", 
              volumeValues.Length, numberOfSpeakers); 
      throw new ArgumentException(message); 
     } 

     var volumeMatrix = new float[numberOfSpeakers, 1]; 

     for (int i = 0; i < numberOfSpeakers; i++) 
     { 
      volumeMatrix[i, 0] = volumeValues[i]; 
     } 

     // adjust the volume using the matrix 
     BassMix.BASS_Mixer_ChannelSetMatrix(inputStream, volumeMatrix); 
     ThrowOnError(); 

    } 

    private static void ThrowOnError() 
    { 
     BASSError err = Bass.BASS_ErrorGetCode(); 
     if (err != BASSError.BASS_OK) 
     { 
      throw new ApplicationException(string.Format("bass.dll reported {0}.", err)); 
     } 
    } 

    public void Dispose() 
    { 
     Bass.BASS_StreamFree(inputStream); 
     Bass.BASS_StreamFree(outputMixerStream); 
    } 
}