none
如何使WAV聲音檔播放進度對應timer的時間? RRS feed

  • 問題

  • 我的系統應用需要透過timer去播放預先儲存的聲音與color影片與kinect骨架資訊(需要三個同步)

    以下為使用NAudio庫,將聲音檔每40ms切割透過timer(40ms)播放的程式碼

    public partial class MainWindow : Window
        {
            static int MS = 40;
            DispatcherTimer FrameTimer = new DispatcherTimer() { Interval = TimeSpan.FromMilliseconds(MS) };
            
            public MainWindow()
            {
                InitializeComponent();
    
    
                FrameTimer.Tick += FrameTimer_Tick;
    
                FrameTimer.Start();
            }
            public static void TrimWavFile(string inPath, string outPath, TimeSpan cutFromStart, TimeSpan cutFromEnd)
            {
                using (WaveFileReader reader = new WaveFileReader(inPath))
                {
                    using (WaveFileWriter writer = new WaveFileWriter(outPath, reader.WaveFormat))
                    {
                        int bytesPerMillisecond = reader.WaveFormat.AverageBytesPerSecond / 1000;
                        
                        int startPos = (int)cutFromStart.TotalMilliseconds * bytesPerMillisecond;
                        startPos = startPos - startPos % reader.WaveFormat.BlockAlign;
    
                        int endBytes = (int)cutFromEnd.TotalMilliseconds * bytesPerMillisecond;
                        endBytes = endBytes - endBytes % reader.WaveFormat.BlockAlign;
    
                        int endPos = endBytes;
                        //int endPos = (int)reader.Length - endBytes;
    
                        TrimWavFile(reader, writer, startPos, endPos);
                    }
                }
            }
    
            private static void TrimWavFile(WaveFileReader reader, WaveFileWriter writer, int startPos, int endPos)
            {
                reader.Position = startPos;
                byte[] buffer = new byte[1024];
                while (reader.Position < endPos)
                {
                    int bytesRequired = (int)(endPos - reader.Position);
                    if (bytesRequired > 0)
                    {
                        int bytesToRead = Math.Min(bytesRequired, buffer.Length);
                        int bytesRead = reader.Read(buffer, 0, bytesToRead);
                        if (bytesRead > 0)
                        {
                            writer.WriteData(buffer, 0, bytesRead);
                        }
                    }
                }
            }
            int count = 0;
            void FrameTimer_Tick(object sender, EventArgs e)
            {
                count++;
                TrimWavFile(@"G:\input.wav", @"G:\40ms.wav", TimeSpan.FromMilliseconds((count - 1) * MS ), TimeSpan.FromMilliseconds(count * MS ));
                SoundPlayer sp = new SoundPlayer(@"G:\40ms.wav");
                sp.Play();
            }
        }

    但是由於timer的時間並不準確,例如設定Interval = TimeSpan.FromMilliseconds(40)

    實際測試都發現每個Tick間隔不是40ms,而是大約60ms左右(看CPU執行速度)
    所以我想要在每個tick內只播放40ms的聲音,使我能掌控聲音與color影片和kinect骨架資訊能夠全部時間同步

    但是這樣子聽起來會斷斷續續的很奇怪,因為timer設定40ms實際卻是60ms,而播放40ms的聲音會有20ms的中斷時間
    有沒有辦法讓每40ms的聲音tempo減慢,自動對應到timer的40ms(實際60ms多)

    或是有沒有辦法讓聲音檔透過timer播放得更好範例?



    • 已編輯 Bone_jacky 2015年4月12日 上午 06:48
    2015年4月12日 上午 06:44

所有回覆

  • 55 ms 吧...

    看下面那篇:

    https://tlcheng.wordpress.com/2007/03/07/vb6vbnet-cpu-%e8%b3%87%e6%ba%90%e9%87%8b%e5%87%ba/


    不精確的問法,就會得到隨便猜的答案;自己都不肯花時間好好描述問題,又何必期望網友會認真回答?

    2015年4月12日 下午 02:24
  • 我簡化我的問題好了...
    簡單說,我該如何錄影+錄音使這兩個流能夠同步?(或是播放時使兩個流同步)

    影片的動作能對準到音樂的Tempo?

    目前影片部分是使用EmguCV的VideoWrite一張一張的frame透過timer寫入

    播放的時候若要透過timer一張一張的frame提出來轉成bitmap來播放的話

    聲音要如何跟影片同步?

    本身對影像處理比較熟,對音效處理不太熟,有前輩能指導一二嗎?

    • 已編輯 Bone_jacky 2015年4月14日 下午 12:11
    2015年4月14日 下午 12:10