1

私は、C#/ WPFデスクトップアプリケーションで優れたNAudioライブラリを使用して、専用のmp3 / wav /(後でwma?)プレーヤーに取り組んでいます。Skypeボイスチェンジャーで使用されているJSNetライブラリにも追加しました。

私の目的は、サウンドファイルの再生中にパンピッチを変更できるようにすることです。

再生中にPanプロパティを変更することに成功しました。また、JSNetSuperPitchオブジェクトを使用してピッチを変更する方法も理解しました。ただし、再生前にピッチを変更することしかできませんでした。再生が開始されると、SuperPitchオブジェクトのコントロールはサウンドに影響を与えないように見えます。

SuperPitchを使用したピッチコントロールとWaveChannel32.Panを使用したパンコントロールを組み合わせることに成功した人はいますか?

WaveStreamこの問題は、効果がaに適用され、次にaに変換されWaveChannel32てプロパティが公開されるという事実に起因し.Panます。ただし、WaveChannel32への変換が発生すると、EffectChainは接続されていないように見えます。

これが私の基本的なアプローチを説明する簡略化されたWPFプロジェクトです。

単純なWPFウィンドウ:

<Window x:Class="NAudioDebug.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <Slider x:Name="sldPan" TickFrequency="0.2" Minimum="-1.0" Maximum="1.0" ToolTip="Balance" 
                Grid.Row="0" TickPlacement="Both" IsSnapToTickEnabled="True" 
                Value="{Binding Path=Pan, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
        <Slider x:Name="sldPitch" TickFrequency="1" Minimum="-12" Maximum="12.0" ToolTip="Pitch" 
                Grid.Row="1" TickPlacement="Both" IsSnapToTickEnabled="True" 
                Value="{Binding Path=Pitch, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
        <Button x:Name="btnPlayStop" Content="Play/Stop" Grid.Row="2" Click="btnPlayStop_Click" />
    </Grid>
</Window>

上記のXAMLのコードビハインドは次のとおりです...

using System.Windows;

namespace NAudioDebug
{
    public partial class MainWindow : Window
    {
        private Player _Player;

        public MainWindow()
        {
            InitializeComponent();
            _Player = new Player();
            this.DataContext = _Player;
        }

        private void btnPlayStop_Click(object sender, RoutedEventArgs e)
        {
            _Player.PlayStop();
        }
    }
}

サウンドファイル再生オブジェクト

コードの重要な部分は、再生を制御し、WPFコントロールがバインドできるプロパティを提供するこのオブジェクトです。そのPlayStop()方法が問題だと思います。

using System;
using System.ComponentModel;
using JSNet;
using NAudio.Wave;

namespace NAudioDebug
{
    public class Player : INotifyPropertyChanged, IDisposable
    {
        private IWavePlayer _WaveOutDevice;
        private WaveChannel32 _MainOutputStream;
        private EffectStream _EffectStream;
        private EffectChain _Effects;
        private SuperPitch _PitchEffect;
        private bool _bDisposed = false;

        public Player()
        {
            Pan = 0.0f;
            Pitch = 0.0f;
        }

        private float _Pan;
        public float Pan
        {
            get { return _Pan; }
            set
            {
                _Pan = value;
                if (_MainOutputStream != null)
                {
                    _MainOutputStream.Pan = _Pan;
                }
                OnPropertyChanged("Pan");
            }
        }

        private float _Pitch;
        public float Pitch
        {
            get { return _Pitch; }
            set
            {
                _Pitch = value;
                if (_PitchEffect != null)
                {
                    _PitchEffect.Sliders[1].Value = value;  // Slider 1 is the pitch bend in semitones from -12 to +12;
                }
                OnPropertyChanged("Pitch");
            }
        }

        public void PlayStop()
        {
            if (_WaveOutDevice != null && _WaveOutDevice.PlaybackState == PlaybackState.Playing)
            {
                _WaveOutDevice.Stop();
                DisposeAudioResources();
            }
            else
            {   // Starting a new stream...
                DisposeAudioResources();

                _Effects = new EffectChain();
                _PitchEffect = new SuperPitch();
                _PitchEffect.Sliders[1].Value = _Pitch;      // Slider 1 is the pitch bend in semitones from -12 to +12;
                _PitchEffect.Sliders[2].Value = 0.0F;        // Slider 2 is the pitch bend in octaves.
                _Effects.Add(_PitchEffect);

                WaveStream inputStream;     // NOTE: Use a WaveStream here because the input might be .mp3 or .wav (and later .wma?)
                WaveStream mp3Reader = new Mp3FileReader(@"C:\Temp\Test.mp3");
                if (mp3Reader.WaveFormat.Encoding != WaveFormatEncoding.Pcm)
                {
                    mp3Reader = WaveFormatConversionStream.CreatePcmStream(mp3Reader);
                }
                inputStream = mp3Reader;

                _EffectStream = new EffectStream(_Effects, inputStream);

                _MainOutputStream = new WaveChannel32(_EffectStream);
                _MainOutputStream.PadWithZeroes = false;
                _MainOutputStream.Pan = Pan;

                _WaveOutDevice = new WaveOut();
                _WaveOutDevice.Init(_MainOutputStream);
                _WaveOutDevice.Play();

                this._WaveOutDevice.PlaybackStopped += OnPlaybackStopped;
            }
        }

        private void OnPlaybackStopped(object sender, EventArgs e)
        {   // Clean up the audio stream resources...
            DisposeAudioResources();
        }

        private void DisposeAudioResources()
        {
            if (_WaveOutDevice != null) { _WaveOutDevice.Stop(); }
            if (_MainOutputStream != null) { _MainOutputStream.Close(); _MainOutputStream = null; }
            if (_PitchEffect != null) { _PitchEffect = null; }
            if (_Effects != null) { _Effects = null; }
            if (_EffectStream != null) { _EffectStream = null; }
            if (_WaveOutDevice != null) { _WaveOutDevice.Dispose(); _WaveOutDevice = null; }
        }

        protected void OnPropertyChanged(PropertyChangedEventArgs e)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null) { handler(this, e); }
        }

        protected void OnPropertyChanged(string sPropertyName)
        {
            OnPropertyChanged(new PropertyChangedEventArgs(sPropertyName));
        }

        public event PropertyChangedEventHandler PropertyChanged;

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool bDisposing)
        {   // Check to see if Dispose has already been called...
            if (!_bDisposed)
            {
                DisposeAudioResources();
                _bDisposed = true;
            }
        }
    }
}
4

1 に答える 1

1

effect.Slider()スライダーの値が変更された後に呼び出すことを忘れないでください。多くのエフェクトでは、スライダーが変更されるたびにパラメーターを再計算する必要があるため、パフォーマンス上の理由から、値を変更した後に通知する必要があります。

SkypeFx用に作成した多くのエフェクトをISampleProviderインターフェイスで再実装したいと思っています。これにより、NAudioでの操作がはるかに簡単になります。

于 2012-12-05T09:04:04.657 に答える