4

NET が提供するSystem.Media.SoundPlayerメカニズムを使用して、Web からダウンロードした MP3 ファイルを再生したいと考えています。WAV フォーマットで動作するため、NAudioライブラリなどのサポートが必要です。MP3 を WAV に変換する必要があります。

いわゆる高速である必要があるため、すべての操作をメモリ内で実行したいのですが、問題があります。以下に、期待どおりに動作するコードを示しましたが、ファイルと連携します。代わりに、メモリ操作のみを使用して動作させる必要があります。

(1) 動作しますが、ディスク操作が必要です:

public void Speak(Uri mp3FileUri)
{
    using (var client = new WebClient())
    {
        using (var networkStream = client.OpenRead(mp3FileUri))
        {
            if (networkStream != null)
            {
                var temp = Path.GetTempPath();
                var mp3File = Path.Combine(temp, "file.mp3");
                var wavFile = Path.Combine(temp, "file.wav");
                using (var fileStream = File.Create(mp3File))
                {
                    networkStream.CopyTo(fileStream);
                }
                using (var reader = new Mp3FileReader(mp3File))
                {
                    WaveFileWriter.CreateWaveFile(wavFile, reader);
                }                        
                using(var player = new SoundPlayer(wavFile))
                {
                    player.Play();
                }
            }
        }
    }
}

(2) 動作しません - 例外はスローされませんが、何も再生されません:

public void Speak(Uri mp3FileUri)
{
    using (var client = new WebClient())
    {
        using (var networkStream = client.OpenRead(mp3FileUri))
        {
            if (networkStream != null)
            {
                var memStream = new MemoryStream();
                networkStream.CopyTo(memStream);
                memStream.Position = 0;
                using (var reader = new Mp3FileReader(memStream))
                {
                    var outStream = new MemoryStream();
                    using (var writer = new WaveFileWriter(outStream, reader.WaveFormat))
                    {
                        var num = 0L;
                        var buffer = new byte[reader.WaveFormat.AverageBytesPerSecond * 4];
                        while (true)
                        {
                            var count = reader.Read(buffer, 0, buffer.Length);
                            if (count != 0)
                            {
                                num += count;
                                if (num <= int.MaxValue)
                                    writer.Write(buffer, 0, count);
                                else
                                    throw new InvalidOperationException("Too large file or endless stream.");
                            }
                            else
                                break;
                        }
                        writer.Flush();
                        outStream.Position = 0;
                        using(var player = new SoundPlayer(outStream))
                        {
                            player.Play(); /* why silence ? */
                        }
                    }                            
                }
            }
        }
    }
}

2 番目のコード サンプルの何が問題なのですか?

4

2 に答える 2

3

Lee Harrison の回答に基づいて、より優れた代替コードを作成しました。

(3) WAV に変換せず、ディスク操作を使用せずに、WEB から直接 MP3 ファイルを再生します。

public void Speak(Uri mp3FileUri)
{
    using (var client = new WebClient())
    {
        using (var networkStream = client.OpenRead(mp3FileUri))
        {
            if (networkStream != null)
            {
                using (var memStream = new MemoryStream())
                {
                    networkStream.CopyTo(memStream);
                    memStream.Position = 0;                            
                    using (var waveOut = new WaveOut(WaveCallbackInfo.FunctionCallback()))
                    {
                        var waveEvent = new ManualResetEvent(false);
                        waveOut.PlaybackStopped += (sender, e) => waveEvent.Set();
                        waveEvent.Reset();
                        using (var rdr = new Mp3FileReader(memStream))
                        using (var waveStream = WaveFormatConversionStream.CreatePcmStream(rdr))
                        using (var baStream = new BlockAlignReductionStream(waveStream))
                        {
                            waveOut.Init(baStream);
                            waveOut.Play();
                            if (waveOut.PlaybackState != PlaybackState.Stopped)
                            { 
                                waveEvent.WaitOne(); /* block thread for a while because I don't want async play back                                
                                                        (to be analogical as usage of SoundPlayer Play method) */
                            }
                        }
                    }
                }
            }
        }
    }
}

それにもかかわらず(これは私にとっては非常に良いことですが)、サンプル(2)の何が問題なのかまだわかりません。

于 2013-01-30T12:47:37.383 に答える
2

SoundPlayerの使用をスキップして、NAudioから直接MP3を再生してみませんか?NAudioはこれを行うように設計されています。MP3をどこかの一時ファイルにダウンロードしてNAudioで再生し、終了したら一時ファイルを削除するだけです。ただし、ファイルのダウンロードの遅延を減らすためにできることはないと思います。

http://naudio.codeplex.com/wikipage?title=MP3

于 2013-01-29T15:52:33.967 に答える